@akinon/pz-otp 2.0.0-beta.9 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,45 +1,154 @@
1
1
  # @akinon/pz-otp
2
2
 
3
- ## 2.0.0-beta.9
3
+ ## 2.0.1
4
+
5
+ ## 2.0.0
6
+
7
+ ## 2.0.0-beta.27
8
+
9
+ ## 2.0.0-beta.26
10
+
11
+ ## 2.0.0-beta.25
12
+
13
+ ## 2.0.0-beta.24
14
+
15
+ ## 2.0.0-beta.23
16
+
17
+ ## 2.0.0-beta.22
18
+
19
+ ## 2.0.0-beta.21
20
+
21
+ ## 2.0.0-beta.20
22
+
23
+ ## 1.126.0
24
+
25
+ ## 1.125.2
26
+
27
+ ## 1.125.1
28
+
29
+ ## 1.125.0
30
+
31
+ ## 1.124.0
32
+
33
+ ## 1.123.0
34
+
35
+ ## 1.122.0
36
+
37
+ ## 1.121.0
38
+
39
+ ## 1.120.0
4
40
 
5
41
  ### Minor Changes
6
42
 
7
- - 0fe7711: ZERO-3387: Upgrade nextjs, eslint-config-next
43
+ - 6ad72e8d: ZERO-4032: Add loading state management for payment submissions across multiple components and add safe guarding
44
+
45
+ ## 1.119.0
46
+
47
+ ## 1.118.0
48
+
49
+ ## 1.117.0
50
+
51
+ ## 1.116.0
52
+
53
+ ## 1.115.0
54
+
55
+ ## 1.114.0
56
+
57
+ ## 1.113.0
58
+
59
+ ## 1.112.0
60
+
61
+ ## 1.111.0
62
+
63
+ ## 1.110.0
64
+
65
+ ## 1.109.0
8
66
 
9
- ## 2.0.0-beta.8
67
+ ## 1.108.0
10
68
 
11
- ## 2.0.0-beta.7
69
+ ## 1.107.0
12
70
 
13
- ## 2.0.0-beta.6
71
+ ## 1.106.0
14
72
 
15
73
  ### Minor Changes
16
74
 
17
- - 8f05f9b: ZERO-3250: Beta branch synchronized with Main branch
75
+ - ae010f0: ZERO-3410: Update readme
18
76
 
19
- ## 2.0.0-beta.5
77
+ ## 1.105.0
20
78
 
21
- ## 2.0.0-beta.4
79
+ ## 1.104.0
22
80
 
23
- ## 2.0.0-beta.3
81
+ ## 1.103.0
24
82
 
25
- ## 2.0.0-beta.2
83
+ ## 1.102.0
84
+
85
+ ## 1.101.0
86
+
87
+ ## 1.100.0
88
+
89
+ ## 1.99.0
90
+
91
+ ### Minor Changes
92
+
93
+ - d58538b: ZERO-3638: Enhance RC pipeline: add fetch, merge, and pre-release setup with conditional commit
94
+
95
+ ## 1.98.0
96
+
97
+ ## 1.97.0
98
+
99
+ ## 1.96.0
100
+
101
+ ## 1.95.0
102
+
103
+ ## 1.94.0
104
+
105
+ ## 1.93.0
106
+
107
+ ## 1.92.0
108
+
109
+ ## 1.91.0
110
+
111
+ ## 1.90.0
112
+
113
+ ### Minor Changes
114
+
115
+ - 9c3a22a: ZERO-3382: Enhance OTP component with customizable UI rendering support
116
+
117
+ ## 1.89.0
118
+
119
+ ## 1.88.0
120
+
121
+ ## 1.87.0
122
+
123
+ ## 1.86.0
124
+
125
+ ## 1.85.0
26
126
 
27
127
  ### Minor Changes
28
128
 
29
- - a006015: ZERO-3116: Add not-found page and update default middleware.
30
- - 1eeb3d8: ZERO-3116: Add not found page
129
+ - a0a1bac: ZERO-3228 :edit OTP login flow to use Redux for popup visibility and clean up unused props
31
130
 
32
- ## 2.0.0-beta.1
131
+ ## 1.84.0
33
132
 
34
133
  ### Minor Changes
35
134
 
36
- - ZERO-3091: Upgrade Next.js to v15 and React to v19
135
+ - 624a4eb: ZERO-3276: Update installation instructions across multiple README files to standardize format and improve clarity
136
+
137
+ ## 1.83.0
138
+
139
+ ## 1.82.0
140
+
141
+ ## 1.81.0
142
+
143
+ ## 1.80.0
144
+
145
+ ## 1.79.0
37
146
 
38
- ## 2.0.0-beta.0
147
+ ## 1.78.0
39
148
 
40
- ### Major Changes
149
+ ## 1.77.0
41
150
 
42
- - be6c09d: ZERO-3114: Create beta version.
151
+ ## 1.76.0
43
152
 
44
153
  ## 1.75.0
45
154
 
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "@akinon/pz-otp",
3
- "version": "2.0.0-beta.9",
3
+ "version": "2.0.1",
4
4
  "license": "MIT",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
7
7
  "peerDependencies": {
8
- "react": "^19.0.0",
9
- "react-dom": "^19.0.0"
8
+ "react": "^18.0.0 || ^19.0.0",
9
+ "react-dom": "^18.0.0 || ^19.0.0"
10
10
  },
11
11
  "devDependencies": {
12
- "@types/node": "^22.10.2",
13
- "@types/react": "^19.0.2",
14
- "@types/react-dom": "^19.0.2",
15
- "prettier": "^3.4.2",
12
+ "@types/node": "^18.7.8",
13
+ "@types/react": "^18.0.17",
14
+ "@types/react-dom": "^18.0.6",
15
+ "prettier": "3.0.3",
16
16
  "prettier-plugin-tailwindcss": "0.5.6",
17
- "react": "^19.0.0",
18
- "react-dom": "^19.0.0",
17
+ "react": "19.2.5",
18
+ "react-dom": "19.2.5",
19
19
  "react-hook-form": "7.31.3",
20
- "typescript": "^5.7.2"
20
+ "typescript": "^4.7.4"
21
21
  },
22
22
  "dependencies": {
23
23
  "react-otp-input": "^3.1.0",
package/readme.md CHANGED
@@ -9,3 +9,119 @@ You can use the following command to install the extension with the latest plugi
9
9
  npx @akinon/projectzero@latest --plugins
10
10
 
11
11
  ```
12
+
13
+ ### Props
14
+
15
+ | Property | Type | Required | Description |
16
+ | --- | --- | --- | --- |
17
+ | `customUIRender` | `React.ReactNode` | `Optional` | function to fully customize the otp. Receives closeHandler, resendHandler, otp, setOtp, hasError, error, canResend, time, codeLength, setHasError and onSubmit props. |
18
+ | `submitAction` | `SubmitHandler<{ [key: string]: any }>` | `Required` | A submit handler function triggered when OTP form is submitted. |
19
+ | `data` | `{ [key: string]: any }` | `Required` | Data object containing required fields like phone number. OTP code will be appended here before submission |
20
+
21
+ ### Default Usage
22
+
23
+ ```js
24
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
25
+
26
+ <PluginModule
27
+ component={Component.Otp}
28
+ props={{
29
+ data: getValues(),
30
+ submitAction: registerHandler
31
+ }}
32
+ />;
33
+ ```
34
+
35
+ ### Customizing OTP
36
+
37
+ ```js
38
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
39
+
40
+ <PluginModule
41
+ component={Component.Otp}
42
+ props={{
43
+ data: getValues(),
44
+ submitAction: registerHandler,
45
+ customUIRender: ({
46
+ closeHandler,
47
+ resendHandler,
48
+ onSubmit,
49
+ otp,
50
+ setOtp,
51
+ hasError,
52
+ error,
53
+ canResend,
54
+ time,
55
+ codeLength,
56
+ setHasError
57
+ }) => {
58
+ return (
59
+ <div className="fixed left-0 top-0 z-50 flex h-screen w-screen items-end md:items-center md:justify-center md:bg-black/10">
60
+ <div className="h-[calc(100vh-48px)] w-screen flex md:h-auto md:max-w-lg flex-col items-center rounded-sm bg-white p-8 shadow-xl">
61
+ <div className="w-full flex items-center justify-end">
62
+ <div className="cursor-pointer" onClick={closeHandler}>
63
+ <svg
64
+ width="14"
65
+ height="14"
66
+ viewBox="0 0 14 14"
67
+ xmlns="http://www.w3.org/2000/svg"
68
+ >
69
+ <g fill="#000" fillRule="nonzero">
70
+ <path d="M.684 14A.684.684 0 0 1 .2 12.833L12.833.2a.684.684 0 1 1 .967.967L1.167 13.8a.682.682 0 0 1-.483.2z" />
71
+ <path d="M13.316 14a.682.682 0 0 1-.483-.2L.2 1.167A.684.684 0 0 1 1.167.2L13.8 12.833A.684.684 0 0 1 13.316 14z" />
72
+ </g>
73
+ </svg>
74
+ </div>
75
+ </div>
76
+ <div className="flex flex-col items-center px-14 mt-5">
77
+ <div className="text-2xl font-medium">OTP Verification</div>
78
+ <div className={twMerge('mt-2.5 text-center text-gray-700')}>
79
+ {`Please enter the ${codeLength}-digit sms code sent to your registered number and email address`}
80
+ </div>
81
+ </div>
82
+ <form
83
+ onSubmit={onSubmit}
84
+ className="flex flex-col items-center w-full"
85
+ >
86
+ <OtpInput
87
+ value={otp}
88
+ onChange={(otp) => {
89
+ setOtp(otp);
90
+ setHasError(false);
91
+ }}
92
+ numInputs={codeLength}
93
+ containerStyle="mt-12 gap-2 flex-wrap"
94
+ inputStyle={twMerge(
95
+ 'h-12 w-8 md:h-16 md:w-12 rounded-md border border-gray-600 text-center text-lg',
96
+ hasError && 'border-error'
97
+ )}
98
+ renderInput={({ ...props }) => <input {...props} />}
99
+ skipDefaultStyles={true}
100
+ />
101
+ {error && <p className="text-xs text-error mt-2">{error}</p>}
102
+ <Button
103
+ type="submit"
104
+ className="mt-5 h-auto w-full py-4 text-lg font-medium uppercase"
105
+ >
106
+ Verify
107
+ </Button>
108
+ </form>
109
+ <div className="mt-6 flex flex-col items-center">
110
+ <span className="text-gray-700">I didn`t receive a code</span>
111
+ <div
112
+ className={twMerge(
113
+ ' font-medium underline cursor-pointer',
114
+ !canResend && 'cursor-not-allowed text-gray-700'
115
+ )}
116
+ onClick={resendHandler}
117
+ >
118
+ RESEND
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ );
124
+ }
125
+ }}
126
+ />;
127
+ ```
package/src/views/Otp.tsx CHANGED
@@ -43,6 +43,19 @@ type OtpProps = {
43
43
  [c in ComponentClasses]?: string;
44
44
  };
45
45
  error?: string;
46
+ customUIRender?: (props: {
47
+ closeHandler?: () => void;
48
+ resendHandler?: () => void;
49
+ onSubmit?: (event: FormEvent<HTMLFormElement>) => Promise<void>;
50
+ otp?: string;
51
+ setOtp?: (otp: string) => void;
52
+ hasError?: boolean;
53
+ error?: string;
54
+ canResend?: boolean;
55
+ time?: number;
56
+ codeLength?: number;
57
+ setHasError?: (hasError: boolean) => void;
58
+ }) => ReactNode;
46
59
  };
47
60
 
48
61
  export const Otp = ({
@@ -52,13 +65,15 @@ export const Otp = ({
52
65
  timer = 60,
53
66
  texts,
54
67
  classes,
55
- error
68
+ error,
69
+ customUIRender
56
70
  }: OtpProps) => {
57
71
  const { phone } = data;
58
72
  const [otp, setOtp] = useState('');
59
73
  const [canResend, setCanResend] = useState(false);
60
74
  const [time, setTime] = useState(timer);
61
75
  const [hasError, setHasError] = useState(false);
76
+ const [isSubmitting, setIsSubmitting] = useState(false);
62
77
  const dispatch = useAppDispatch();
63
78
  const { isPopupVisible } = useAppSelector((state) => state.otp);
64
79
 
@@ -70,18 +85,26 @@ export const Otp = ({
70
85
  const onSubmit = async (event: FormEvent<HTMLFormElement>) => {
71
86
  event.preventDefault();
72
87
 
73
- if (submitAction) {
74
- data.code = otp;
75
- data.phone = phone;
76
- const res = await submitAction(data);
88
+ if (isSubmitting) return;
77
89
 
78
- if (res?.status !== 200 || error) {
79
- setHasError(true);
80
- }
90
+ setIsSubmitting(true);
81
91
 
82
- if (res?.status === 200) {
83
- dispatch(hidePopup());
92
+ try {
93
+ if (submitAction) {
94
+ data.code = otp;
95
+ data.phone = phone;
96
+ const res = await submitAction(data);
97
+
98
+ if (res?.status !== 200 || error) {
99
+ setHasError(true);
100
+ }
101
+
102
+ if (res?.status === 200) {
103
+ dispatch(hidePopup());
104
+ }
84
105
  }
106
+ } finally {
107
+ setIsSubmitting(false);
85
108
  }
86
109
  };
87
110
 
@@ -129,9 +152,25 @@ export const Otp = ({
129
152
 
130
153
  if (!isPopupVisible) return null;
131
154
 
155
+ if (customUIRender) {
156
+ return customUIRender({
157
+ closeHandler,
158
+ resendHandler,
159
+ onSubmit,
160
+ otp,
161
+ setOtp,
162
+ hasError,
163
+ error,
164
+ canResend,
165
+ time,
166
+ codeLength,
167
+ setHasError
168
+ });
169
+ }
170
+
132
171
  return (
133
172
  <div className="fixed left-0 top-0 z-50 flex h-screen w-screen items-end md:items-center md:justify-center md:bg-black/10">
134
- <div className="h-[calc(100vh-48px)] w-screen flex md:h-auto md:max-w-lg flex-col items-center rounded-xs bg-white p-8 shadow-xl">
173
+ <div className="h-[calc(100vh-48px)] w-screen flex md:h-auto md:max-w-lg flex-col items-center rounded-sm bg-white p-8 shadow-xl">
135
174
  <div className="w-full flex items-center justify-end">
136
175
  <div className="cursor-pointer" onClick={closeHandler}>
137
176
  <svg
@@ -195,6 +234,7 @@ export const Otp = ({
195
234
  {error && <p className="text-xs text-error mt-2">{error}</p>}
196
235
  <Button
197
236
  type="submit"
237
+ disabled={isSubmitting}
198
238
  className={twMerge(
199
239
  'mt-5 h-auto w-full py-4 text-lg font-medium uppercase',
200
240
  classes?.submitButton