@eka-care/abha-stg 0.1.0 → 0.1.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.
Files changed (119) hide show
  1. package/{index.html → dist/index.html} +2 -1
  2. package/dist/sdk/abha/css/abha.css +1 -0
  3. package/dist/sdk/abha/js/abha.js +63 -0
  4. package/package.json +1 -1
  5. package/.eslintignore +0 -3
  6. package/.eslintrc +0 -29
  7. package/.prettierrc +0 -7
  8. package/.turbo/daemon/da13e0828a6aedf8-turbo.log.2025-10-30 +0 -0
  9. package/package/styles/pds2/border.ts +0 -69
  10. package/package/styles/pds2/colors.ts +0 -70
  11. package/package/styles/pds2/spacing.ts +0 -1007
  12. package/package/tailwind/tailwind.config.ts +0 -124
  13. package/postcss.config.js +0 -6
  14. package/scripts/build-purged-css.cjs +0 -70
  15. package/src/App.css +0 -0
  16. package/src/App.tsx +0 -43
  17. package/src/api-queries/aorta-go/v3/get-profile-patient.ts +0 -32
  18. package/src/api-queries/aorta-go/v3/get-profiles-phr-user.ts +0 -26
  19. package/src/api-queries/aorta-go/v3/post-auth-init-v2.ts +0 -34
  20. package/src/api-queries/aorta-go/v3/post-auth-logout-v2.ts +0 -32
  21. package/src/api-queries/aorta-go/v3/post-auth-verify-v2.ts +0 -38
  22. package/src/api-queries/aorta-go/v3/post-profile-switch.ts +0 -39
  23. package/src/api-queries/ndhm/get-abdm-register-suggest.ts +0 -37
  24. package/src/api-queries/ndhm/get-pincode-details.ts +0 -28
  25. package/src/api-queries/ndhm/post-abdm-login-init.ts +0 -37
  26. package/src/api-queries/ndhm/post-abdm-login-phr.ts +0 -37
  27. package/src/api-queries/ndhm/post-abdm-login-verify.ts +0 -37
  28. package/src/api-queries/ndhm/post-abdm-profile-eka-link-phr.ts +0 -40
  29. package/src/api-queries/ndhm/post-abdm-profile-eka.ts +0 -66
  30. package/src/api-queries/ndhm/post-abdm-register-abha-number-create-phr.ts +0 -37
  31. package/src/api-queries/ndhm/post-abdm-register-mobile-create-phr.ts +0 -66
  32. package/src/api-queries/ndhm/post-abdm-register-mobile-resend-otp.ts +0 -32
  33. package/src/api-queries/ndhm/post-abdm-register-mobile-verify.ts +0 -38
  34. package/src/api-queries/ndhm/post-abdm-register-phr-check.ts +0 -34
  35. package/src/api-queries/ndhm/post-register-aadhaar-create-phr.ts +0 -37
  36. package/src/api-queries/ndhm/post-register-aadhaar-init.ts +0 -34
  37. package/src/api-queries/ndhm/post-register-aadhaar-mobile-resend-otp.ts +0 -34
  38. package/src/api-queries/ndhm/post-register-aadhaar-mobile-verify.ts +0 -37
  39. package/src/api-queries/ndhm/post-register-aadhaar-resend-otp.ts +0 -34
  40. package/src/api-queries/ndhm/post-register-aadhaar-verify.ts +0 -40
  41. package/src/api-queries/ndhm/post-register-mobile-init.ts +0 -34
  42. package/src/api-queries/use-get-profiles-patient.ts +0 -12
  43. package/src/api-queries/use-get-profiles-phr-user.ts +0 -28
  44. package/src/api-queries/use-post-abdm-login-verify-v1.ts +0 -26
  45. package/src/api-queries/use-post-auth-verify-v2.ts +0 -50
  46. package/src/api-queries/use-post-profile-switch.ts +0 -58
  47. package/src/api-queries/use-post-register-mobile-create-phr.ts +0 -39
  48. package/src/api-queries/user-post-abdm-profile-login-phr.ts +0 -26
  49. package/src/assets/Success.json +0 -1
  50. package/src/assets/react.svg +0 -1
  51. package/src/atoms/button/custom-button.tsx +0 -32
  52. package/src/atoms/button/index.tsx +0 -40
  53. package/src/atoms/button/types.d.ts +0 -31
  54. package/src/atoms/header.tsx +0 -25
  55. package/src/atoms/input-field/index.tsx +0 -63
  56. package/src/atoms/input-field/patient-input-field.tsx +0 -16
  57. package/src/atoms/input-field/types.ts +0 -24
  58. package/src/atoms/pds2-otp-input/index.tsx +0 -35
  59. package/src/atoms/pds2-otp-input/types.d.ts +0 -3
  60. package/src/atoms/single-input-chip/index.tsx +0 -32
  61. package/src/atoms/single-input-chip/types.ts +0 -6
  62. package/src/atoms/spinner.tsx +0 -33
  63. package/src/atoms/text-separator.tsx +0 -11
  64. package/src/atoms/ui/spinner.tsx +0 -75
  65. package/src/constants/constants.ts +0 -376
  66. package/src/fetch-client/index.ts +0 -164
  67. package/src/index.css +0 -152
  68. package/src/main.tsx +0 -374
  69. package/src/molecules/abha/bottom-sheet/bottom-sheet-wrapper.tsx +0 -40
  70. package/src/molecules/abha/bottom-sheet/index.tsx +0 -66
  71. package/src/molecules/abha/spaced-input-component.tsx +0 -168
  72. package/src/molecules/copyright-year.tsx +0 -16
  73. package/src/molecules/exit-popup/index.tsx +0 -101
  74. package/src/molecules/pds2-otp-component/index.tsx +0 -147
  75. package/src/organisms/abha/abha-header.tsx +0 -25
  76. package/src/organisms/abha/abha-stepper.tsx +0 -83
  77. package/src/organisms/abha/error-bottom-sheet.tsx +0 -27
  78. package/src/organisms/abha/otp-card.tsx +0 -99
  79. package/src/organisms/abha/verification-status.tsx +0 -30
  80. package/src/organisms/choose-language/choose-language.tsx +0 -53
  81. package/src/organisms/choose-language/types.ts +0 -10
  82. package/src/organisms/screen-switcher/screen-switcher.tsx +0 -80
  83. package/src/routes/abha-aadhaar-verification-status-screen.tsx +0 -246
  84. package/src/routes/abha-created-screen.tsx +0 -45
  85. package/src/routes/abha-login-otp-verify-screen.tsx +0 -519
  86. package/src/routes/abha-mobile-linking-status-screen.tsx +0 -267
  87. package/src/routes/abha-otp-and-mobile-screen.tsx +0 -435
  88. package/src/routes/abha-phone-number-verification-screen.tsx +0 -388
  89. package/src/routes/create-abha-address-screen.tsx +0 -928
  90. package/src/routes/create-abha-with-aadhaar-screen.tsx +0 -986
  91. package/src/routes/create-eka-profile-screen.tsx +0 -831
  92. package/src/routes/get-all-profiles-screen.tsx +0 -161
  93. package/src/routes/login-or-create-abha-address-screen.tsx +0 -1056
  94. package/src/routes/login-with-abha-screen.tsx +0 -454
  95. package/src/routes/select-abha-from-list-screen.tsx +0 -792
  96. package/src/routes/select-eka-profile-screen.tsx +0 -446
  97. package/src/routes/utils/trackAbhaEvent.ts +0 -41
  98. package/src/stores/auth-abha-store/index.ts +0 -152
  99. package/src/stores/auth-abha-store/types.ts +0 -217
  100. package/src/utils/mock-auth-response.ts +0 -29
  101. package/src/utils/send-event-utils.ts +0 -76
  102. package/src/utils/validations.ts +0 -89
  103. package/src/vite-env.d.ts +0 -1
  104. package/tailwind.config.ts +0 -9
  105. package/tsconfig.json +0 -25
  106. package/tsconfig.node.json +0 -10
  107. package/tsconfig.node.tsbuildinfo +0 -1
  108. package/tsconfig.tsbuildinfo +0 -1
  109. package/vite.config.d.ts +0 -2
  110. package/vite.config.js +0 -45
  111. package/vite.config.ts +0 -50
  112. /package/{public → dist}/images/adhaar.webp +0 -0
  113. /package/{public → dist}/images/at-the-rate.webp +0 -0
  114. /package/{public → dist}/images/avatar.webp +0 -0
  115. /package/{public → dist}/images/ayushman-bharat.webp +0 -0
  116. /package/{public → dist}/images/circle-checkmark.webp +0 -0
  117. /package/{public → dist}/images/link-abha.webp +0 -0
  118. /package/{public → dist}/images/national-authority.webp +0 -0
  119. /package/{public → dist}/images/three-dots.webp +0 -0
@@ -1,986 +0,0 @@
1
- import {
2
- ArrowLeftRegularIcon,
3
- CheckSquareSolidIcon,
4
- ChevronDownRegularIcon,
5
- CircleInfoSolidIcon,
6
- PhoneSolidIcon,
7
- SquareRegularIcon,
8
- XMarkRegularIcon,
9
- } from '@eka-care/icons';
10
-
11
- import {
12
- ABHA_AUTH_FLOW_METHOD,
13
- AUTH_METHOD,
14
- LOADING_STATE,
15
- REGISTRATION_TYPE,
16
- } from '../constants/constants';
17
- import { useEffect, useRef, useState } from 'react';
18
- import Pds2Button from '../atoms/button';
19
- import Pds2CustomButton from '../atoms/button/custom-button';
20
- import Pds2Header from '../atoms/header';
21
- import PatientPds2InputField from '../atoms/input-field/patient-input-field';
22
- import Pds2Spinner from '../atoms/spinner';
23
- import TextSeparator from '../atoms/text-separator';
24
- import BottomSheetWrapper from '../molecules/abha/bottom-sheet/bottom-sheet-wrapper';
25
- import SpacedInputComponent from '../molecules/abha/spaced-input-component';
26
- import AbhaErrorBottomSheet from '../organisms/abha/error-bottom-sheet';
27
- import useAuthAbhaStore from '../stores/auth-abha-store';
28
- import { SCREEN_NAMES } from '../stores/auth-abha-store/types';
29
- import { unMount } from '../main';
30
- import AbhaStepper from '../organisms/abha/abha-stepper';
31
- import handleSendEvent from '../utils/send-event-utils';
32
- import postAuthInitV2 from '../api-queries/aorta-go/v3/post-auth-init-v2';
33
- import postAuthLogoutV2 from '../api-queries/aorta-go/v3/post-auth-logout-v2';
34
- import postRegisterAadhaarInit from '../api-queries/ndhm/post-register-aadhaar-init';
35
- import postRegisterMobileInit from '../api-queries/ndhm/post-register-mobile-init';
36
-
37
- type InitMethod = 'aadhaar' | 'mobile';
38
-
39
- const CreateAbhaWithAadhaarScreen = () => {
40
- const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false);
41
- const setScreen = useAuthAbhaStore((state) => state.setScreen);
42
- const goBackLoginScreen = useAuthAbhaStore((state) => state.goBackLoginScreen);
43
- const setAbhaAuthFlowMethod = useAuthAbhaStore((state) => state.setAbhaAuthFlowMethod);
44
- const initAbhaAppMethod = useAuthAbhaStore((state) => state.initAbhaAppMethod);
45
- const clientId = useAuthAbhaStore((state) => state.clientId);
46
-
47
- useEffect(() => {
48
- handleSendEvent({
49
- eventName: 'page_view',
50
- eventData: {
51
- page_view: 'abha_landing_screen',
52
- platform: clientId,
53
- },
54
- });
55
-
56
- window.curio?.pushToMixpanel?.('page_view', {
57
- platform: clientId,
58
- page_view: 'abha_landing_screen',
59
- });
60
-
61
- if (window.EkaAbha?.changeStatusBarColor) {
62
- window.EkaAbha.changeStatusBarColor('#E4E1FA');
63
- return () => {
64
- if (window.EkaAbha?.changeStatusBarColor) window?.EkaAbha?.changeStatusBarColor('#FFFFFF');
65
- };
66
- }
67
-
68
- // Default create flow will be mobile flow.
69
- setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.MOBILE);
70
- }, []);
71
-
72
- const handleBackButtonClick = () => {
73
- window.EkaAbha?.onAbhaClose();
74
- unMount();
75
- };
76
-
77
- const hideBackButtonFor = ['eka-web', 'phr'];
78
-
79
- return (
80
- <div className="pds2-bg-bg-01 pds2-h-full">
81
- {/* * if clientId is eka-web or phr, do not show back button */}
82
- {!hideBackButtonFor.includes(clientId) ? (
83
- <Pds2Header
84
- prefixIcon={
85
- <button
86
- className="pds2-w-24 pds2-bg-white pds2-h-24 pds2-rounded-full pds2-flex pds2-items-center pds2-justify-center ripple"
87
- onClick={handleBackButtonClick}
88
- >
89
- <ArrowLeftRegularIcon />
90
- </button>
91
- }
92
- title=""
93
- className="pds2-bg-white"
94
- />
95
- ) : (
96
- <Pds2Header
97
- prefixIcon={<div className="pds2-w-24 pds2-h-24" aria-hidden="true" />}
98
- title=""
99
- className="pds2-bg-white"
100
- />
101
- )}
102
-
103
- <AbhaStepper/>
104
- <LoginWithAadhaar openInfoDialog={() => setIsBottomSheetOpen(true)} />
105
- <OtherLoginOptions />
106
-
107
- <BottomSheetWrapper
108
- isOpen={isBottomSheetOpen}
109
- setIsOpen={setIsBottomSheetOpen}
110
- shouldCloseOnClickOutside={true}
111
- >
112
- <BottomSheetContent onClose={() => setIsBottomSheetOpen(false)} />
113
- </BottomSheetWrapper>
114
- </div>
115
- );
116
- };
117
-
118
- export default CreateAbhaWithAadhaarScreen;
119
-
120
- const BottomSheetContent = ({ onClose }: { onClose: () => void }) => {
121
- return (
122
- <div className="pds2-flex pds2-flex-col pds2-p-16 pds2-text-center">
123
- <div className="pds2-flex pds2-justify-end pds2-items-center">
124
- <button
125
- onClick={onClose}
126
- className="pds2-w-24 pds2-h-24 pds2-rounded-full pds2-flex pds2-items-center pds2-justify-center ripple"
127
- >
128
- <XMarkRegularIcon className="pds2-w-18 pds2-h-18 pds2-text-text-03" />
129
- </button>
130
- </div>
131
- <div className="pds2-space-y-12 pds2-flex pds2-flex-col pds2-items-center pds2-justify-center">
132
- <img
133
- src="https://cdn.eka.care/vagus/cm5m4sx4a000c0tg9a5fo1gkz.webp"
134
- alt="national health authority"
135
- className="pds2-h-52"
136
- />
137
- <div className="Heading4Semibold pds2-text-text-black">Terms & Conditions</div>
138
- </div>
139
- <div className="pds2-space-y-8">
140
- <div className="Body2Regular pds2-text-text-03 pds2-py-16">
141
- I, hereby declare that I am voluntarily sharing my identity information with National
142
- Health Authority (NHA) for the sole purpose of creation of ABHA number. I understand that
143
- my ABHA number can be used and shared for purposes as may be notified by ABDM (Ayushman
144
- Bharat Digital Mission) from time to time including provision of healthcare services.
145
- Further, I am aware that my personal identifiable information (Name, Address, Age, Date of
146
- Birth, Gender and Photograph) may be made available to the entities working in the
147
- National Digital Health Ecosystem (NDHE) which inter alia includes stakeholders and
148
- entities such as healthcare professionals (e.g. doctors), facilities
149
- </div>
150
- <Pds2Button
151
- title="Okay, Got it!"
152
- onClick={onClose}
153
- state={'enabled'}
154
- className="pds2-w-full"
155
- />
156
- </div>
157
- </div>
158
- );
159
- };
160
-
161
- const loginOptions = [
162
- {
163
- textSeparatorTitle: 'Other options to create ABHA',
164
- loginCTA: [
165
- {
166
- method: ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER,
167
- title: 'Use Aadhaar to create ABHA',
168
- prefixIcon: (
169
- <img
170
- src="https://cdn.eka.care/vagus/cm5mcdm3h00070tfs9fjkepff.webp"
171
- alt="Aadhaar Icon"
172
- className="pds2-h-24 pds2-w-24"
173
- loading="lazy"
174
- />
175
- ),
176
- },
177
- {
178
- method: ABHA_AUTH_FLOW_METHOD.MOBILE,
179
- title: 'Use mobile to create ABHA',
180
- prefixIcon: <PhoneSolidIcon className="pds2-w-20 pds2-h-20 pds2-text-icon-success-02" />,
181
- },
182
- ],
183
- },
184
- {
185
- textSeparatorTitle: 'Login with ABHA',
186
- loginCTA: [
187
- {
188
- method: ABHA_AUTH_FLOW_METHOD.ABHA_NUMBER,
189
- title: 'ABHA',
190
- prefixIcon: (
191
- <img
192
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
193
- alt="ABHA Address Icon"
194
- className="pds2-h-24 pds2-w-24"
195
- loading="lazy"
196
- />
197
- ),
198
- },
199
- ],
200
- },
201
- ];
202
-
203
- const OtherLoginOptions = () => {
204
- const setAbhaAuthFlowMethod = useAuthAbhaStore((state) => state.setAbhaAuthFlowMethod);
205
- const setScreen = useAuthAbhaStore((state) => state.setScreen);
206
- const selectedMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
207
- // android is faster to load the state, so it gets the correct value before rendering.
208
- // iOS is a bit slower, so it shows 'MOBILE' first before the correct state kicks in —
209
- // causing both Aadhaar form and Aadhaar button to show.
210
- const [selectedFlow, setSelectedFlow] = useState<string>(
211
- selectedMethod ?? ABHA_AUTH_FLOW_METHOD.MOBILE
212
- );
213
- const initAbhaAppMethod = useAuthAbhaStore((state) => state.initAbhaAppMethod);
214
- const clientId = useAuthAbhaStore((state) => state.clientId);
215
- const isNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.isNewLoginOrCreateFlow);
216
-
217
- useEffect(() => {
218
- if (selectedMethod && selectedMethod !== selectedFlow) {
219
- setSelectedFlow(selectedMethod);
220
- }
221
- }, [selectedMethod]);
222
-
223
- return (
224
- <div className="pds2-p-16 pds2-space-y-12">
225
- {loginOptions.map((option) => (
226
- <>
227
- <TextSeparator title={option.textSeparatorTitle} />
228
- {option.loginCTA
229
- .filter((CTA) => {
230
- // Login with 'ABHA' button is always displayed(not in web)
231
- if (CTA.title === 'ABHA') return true;
232
-
233
- // Show only Aadhaar when Mobile is selected and vice versa
234
- if (selectedFlow === ABHA_AUTH_FLOW_METHOD.MOBILE)
235
- return CTA.method === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER;
236
- if (selectedFlow === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER)
237
- return CTA.method === ABHA_AUTH_FLOW_METHOD.MOBILE;
238
-
239
- return true;
240
- })
241
- .map((CTA) => (
242
- <Pds2CustomButton
243
- key={CTA.method}
244
- prefixIcon={CTA.prefixIcon}
245
- title={CTA.title}
246
- suffixIcon={
247
- <ChevronDownRegularIcon
248
- className="pds2-ml-auto pds2-h-16 pds2-w-16 pds2-text-text-04 -pds2-rotate-90"
249
- aria-hidden="true"
250
- />
251
- }
252
- onClick={() => {
253
- window.curio?.pushToMixpanel?.('abha_landing_screen_clicks', {
254
- platform: clientId,
255
- type:
256
- CTA.method === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
257
- ? 'use Aadhaar'
258
- : 'use Mobile',
259
- });
260
- if (CTA.title === 'ABHA') {
261
- if (isNewLoginOrCreateFlow) {
262
- setScreen(SCREEN_NAMES.LOGIN_OR_CREATE_ABHA);
263
- } else {
264
- setScreen(SCREEN_NAMES.LOGIN_WITH_ABHA);
265
- }
266
- return;
267
- }
268
- if (CTA.method === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) {
269
- setSelectedFlow(ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER);
270
- } else if (CTA.method === ABHA_AUTH_FLOW_METHOD.MOBILE) {
271
- setSelectedFlow(ABHA_AUTH_FLOW_METHOD.MOBILE);
272
- }
273
-
274
- setAbhaAuthFlowMethod(CTA.method);
275
- }}
276
- />
277
- ))}
278
- </>
279
- ))}
280
- </div>
281
- );
282
- };
283
-
284
- const LoginWithAadhaar = ({ openInfoDialog }: { openInfoDialog: () => void }) => {
285
- const setScreen = useAuthAbhaStore((state) => state.setScreen);
286
- const selectedMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
287
- const setRegistrationType = useAuthAbhaStore((state) => state.setRegistrationType);
288
-
289
- const setAadhaarInitResponse = useAuthAbhaStore((state) => state.setAadhaarInitResponse);
290
- const setMobileInitResponse = useAuthAbhaStore((state) => state.setMobileInitResponse);
291
- const setBottomsheetErrorInfo = useAuthAbhaStore((state) => state.setBottomsheetErrorInfo);
292
- const clearAbhaAuthStore = useAuthAbhaStore((state) => state.clearAbhaAuthStore);
293
- const initAbhaAppMethod = useAuthAbhaStore((state) => state.initAbhaAppMethod);
294
- const initAbhaAppMobileNumber = useAuthAbhaStore((state) => state.initAbhaAppMobileNumber);
295
- const isLoggedInFromRedirect = useAuthAbhaStore((state) => state.isLoggedInFromRedirect);
296
-
297
- const [aadhaarNo, setAadhaarNo] = useState<string>('');
298
- const [mobileNumber, setMobileNumber] = useState('');
299
- const [isValidAadhaar, setIsValidAadhaar] = useState<boolean>(false);
300
- const [isValidMobileNumber, setIsValidMobileNumber] = useState(false);
301
-
302
- const [error, setError] = useState<string | null>(null);
303
-
304
- const [isNhaConsent, setIsNhaConsent] = useState<boolean>(true);
305
- const [isErrorNhaConsent, setIsErrorNhaConsent] = useState<boolean>(false);
306
-
307
- const [initApiStatus, setInitApiStatus] = useState<Record<InitMethod, LOADING_STATE>>({
308
- aadhaar: LOADING_STATE.IDLE,
309
- mobile: LOADING_STATE.IDLE,
310
- });
311
-
312
- const isMobileNonEditable = !!initAbhaAppMobileNumber;
313
- const clientId = useAuthAbhaStore((state) => state.clientId);
314
- const isEkaAppLogin = useAuthAbhaStore((state) => state.isEkaAppLogin);
315
- const isDocAppRequest = useAuthAbhaStore((state) => state.isDocAppRequest);
316
- const setIsApiTriggered = useAuthAbhaStore((state) => state.setIsApiTriggered);
317
- const isApiTriggered = useAuthAbhaStore((state) => state.isApiTriggered);
318
- const setSelectedAbhaFlow = useAuthAbhaStore((state) => state.setSelectedAbhaFlow);
319
- const isNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.isNewLoginOrCreateFlow);
320
-
321
- // 1. First useEffect: Initialize the mobile number (runs only once)
322
- useEffect(() => {
323
- if (initAbhaAppMobileNumber) {
324
- setMobileNumber(initAbhaAppMobileNumber);
325
- setIsValidMobileNumber(initAbhaAppMobileNumber.length === 10);
326
- }
327
- }, [initAbhaAppMobileNumber]);
328
-
329
- // 2. Second useEffect: Trigger handleRegister (fixed to prevent multiple calls)
330
- useEffect(() => {
331
- if (isApiTriggered) {
332
- console.log('Api is already triggered: ', isApiTriggered);
333
- return;
334
- }
335
-
336
- const shouldTriggerAadhaar = aadhaarNo && aadhaarNo.length === 12 && isNhaConsent;
337
- const shouldTriggerMobile = mobileNumber && mobileNumber.length === 10 && isNhaConsent;
338
-
339
- console.log(
340
- 'Conditions check:',
341
- 'isLoggedInFromRedirect:',
342
- isLoggedInFromRedirect,
343
- 'shouldTriggerAadhaar:',
344
- shouldTriggerAadhaar,
345
- 'shouldTriggerMobile:',
346
- shouldTriggerMobile
347
- );
348
-
349
- if (isLoggedInFromRedirect || shouldTriggerAadhaar || shouldTriggerMobile) {
350
- // Set the flag BEFORE any async operations to prevent race conditions
351
- setIsApiTriggered(true);
352
- console.log('Setting hasTriggered to true and proceeding with registration');
353
-
354
- // Track events before API call
355
- let eventName = '';
356
- if (shouldTriggerAadhaar) {
357
- eventName = 'abha_aadhaar_otp_verify_clicks';
358
- } else if (shouldTriggerMobile) {
359
- eventName = 'abha_mobile_otp_verify_clicks';
360
- }
361
-
362
- if (eventName) {
363
- window.curio?.pushToMixpanel?.(eventName, {
364
- platform: clientId,
365
- type: 'next',
366
- });
367
- }
368
-
369
- // Now call the memoized handler
370
- handleRegister();
371
- }
372
- }, [isLoggedInFromRedirect, aadhaarNo, mobileNumber, isNhaConsent, isApiTriggered]);
373
-
374
- // Create a helper function to update status
375
- const updateInitStatus = (method: InitMethod, status: LOADING_STATE) => {
376
- setInitApiStatus((prev) => ({
377
- ...prev,
378
- [method]: status,
379
- }));
380
- };
381
-
382
- // Mobile number handler
383
- const handleMobileNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
384
- const value = e.target.value;
385
- if (value.length <= 10) {
386
- setMobileNumber(value);
387
- setIsValidMobileNumber(value.length === 10);
388
- setError(null);
389
- }
390
- };
391
-
392
- const handleOnAadhaarInputComplete = ({ inputVal: newAadhaarNo }: { inputVal: string }) => {
393
- if (error) setError(null);
394
- if (newAadhaarNo.length === 12) {
395
- setAadhaarNo(newAadhaarNo);
396
- }
397
- };
398
-
399
- const handleRegister = async () => {
400
- setError(null);
401
-
402
- const method: InitMethod =
403
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER ? 'aadhaar' : 'mobile';
404
- updateInitStatus(method, LOADING_STATE.LOADING);
405
-
406
- let authTxnId = '';
407
- // if the trigger is not from the eka app, then get the auth txn id
408
- if (!isEkaAppLogin) {
409
- // Get auth transaction ID first
410
- handleSendEvent({
411
- eventName: 'abha_create_auth_api_trigger',
412
- eventData: {
413
- type: 'api_trigger',
414
- platform: clientId,
415
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
416
- },
417
- });
418
-
419
- window.curio?.pushToMixpanel?.('abha_create_auth_api_trigger', {
420
- platform: clientId,
421
- type: 'api_trigger',
422
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
423
- });
424
- const { txn_id: txnId, error: authInitError } = await postAuthInitV2({
425
- method: AUTH_METHOD.ABHA,
426
- });
427
- if (!txnId) {
428
- handleSendEvent({
429
- eventName: 'abha_create_auth_txnId_not_found',
430
- eventData: {
431
- type: 'api_trigger',
432
- platform: clientId,
433
- transactionId: txnId || '',
434
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
435
- },
436
- });
437
-
438
- window.curio?.pushToMixpanel?.('abha_create_auth_txnId_not_found', {
439
- platform: clientId,
440
- type: 'api_trigger',
441
- transactionId: txnId || '',
442
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
443
- });
444
- setError(authInitError?.message || 'Something went wrong');
445
- updateInitStatus(method, LOADING_STATE.REJECTED);
446
- return;
447
- }
448
- authTxnId = txnId;
449
- handleSendEvent({
450
- eventName: 'abha_create_auth_api_trigger_success',
451
- eventData: {
452
- type: 'api_trigger',
453
- platform: clientId,
454
- authTransactionId: authTxnId,
455
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
456
- },
457
- });
458
-
459
- window.curio?.pushToMixpanel?.('abha_create_auth_api_trigger_success', {
460
- platform: clientId,
461
- type: 'api_trigger',
462
- authTransactionId: authTxnId,
463
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
464
- });
465
- // call the auth logout api
466
- await postAuthLogoutV2();
467
- }
468
-
469
- // depending on aadhaar flow or mobile flow, take the action
470
- // aadhaar flow
471
- if (selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) {
472
- handleSendEvent({
473
- eventName: 'abha_aadhaar_init_api_trigger_initiate',
474
- eventData: {
475
- type: 'api_trigger',
476
- platform: clientId,
477
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
478
- },
479
- });
480
-
481
- window.curio?.pushToMixpanel?.('abha_aadhaar_init_api_trigger_initiate', {
482
- platform: clientId,
483
- type: 'api_trigger',
484
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
485
- });
486
- // set the initial status to loading
487
- updateInitStatus('aadhaar', LOADING_STATE.LOADING);
488
- // check if aadhaar number is valid
489
- if (aadhaarNo.length !== 12) {
490
- setError('Please enter valid 12 digit Aadhaar number');
491
- updateInitStatus('aadhaar', LOADING_STATE.REJECTED);
492
- return;
493
- }
494
- // check if aadhaar consent is given
495
- if (!isNhaConsent) {
496
- setError('Please provide consent to create ABHA');
497
- updateInitStatus('aadhaar', LOADING_STATE.REJECTED);
498
- return;
499
- }
500
- // trigger aadhaar init api
501
- const {
502
- txn_id,
503
- hint,
504
- error: aadhaarError,
505
- action: errorAction,
506
- } = await postRegisterAadhaarInit({
507
- aadhaar_number: aadhaarNo,
508
- });
509
- if (txn_id && hint) {
510
- setAadhaarInitResponse({
511
- authTxnId,
512
- txnId: txn_id,
513
- aadhaarOtpSentToHint: hint,
514
- });
515
- handleSendEvent({
516
- eventName: 'abha_aadhaar_init_api_trigger_success',
517
- eventData: {
518
- type: 'api_trigger',
519
- platform: clientId,
520
- transactionId: txn_id,
521
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
522
- },
523
- });
524
-
525
- window.curio?.pushToMixpanel?.('abha_aadhaar_init_api_trigger_success', {
526
- platform: clientId,
527
- type: 'api_trigger',
528
- transactionId: txn_id,
529
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
530
- });
531
- updateInitStatus('aadhaar', LOADING_STATE.RESOLVED);
532
- setRegistrationType(REGISTRATION_TYPE.CREATE);
533
- setScreen(SCREEN_NAMES.ABHA_OTP_AND_MOBILE);
534
- return;
535
- }
536
-
537
- handleSendEvent({
538
- eventName: 'abha_aadhaar_init_api_trigger_failure',
539
- eventData: {
540
- type: 'api_trigger',
541
- platform: clientId,
542
- transactionId: txn_id || '',
543
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
544
- },
545
- });
546
-
547
- window.curio?.pushToMixpanel?.('abha_aadhaar_init_api_trigger_failure', {
548
- platform: clientId,
549
- type: 'api_trigger',
550
- transactionId: txn_id || '',
551
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
552
- });
553
-
554
- updateInitStatus('aadhaar', LOADING_STATE.REJECTED);
555
- if (errorAction) {
556
- setBottomsheetErrorInfo(errorAction);
557
- } else {
558
- setError(aadhaarError || 'Something went wrong');
559
- }
560
- } else {
561
- // mobile flow
562
- // set initial status to loading
563
- updateInitStatus('mobile', LOADING_STATE.LOADING);
564
- const mobileNo = initAbhaAppMobileNumber || mobileNumber;
565
- // check if mobile number is valid
566
- if (!mobileNo || mobileNo.length !== 10) {
567
- handleSendEvent({
568
- eventName: 'abha_mobile_number_length_error',
569
- eventData: {
570
- type: 'verify',
571
- platform: clientId,
572
- mobileNumber: mobileNo,
573
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
574
- },
575
- });
576
-
577
- window.curio?.pushToMixpanel?.('abha_mobile_number_length_error', {
578
- platform: clientId,
579
- type: 'verify',
580
- mobileNumber: mobileNo,
581
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
582
- });
583
- setError('Please enter valid 10 digit mobile number');
584
- updateInitStatus('mobile', LOADING_STATE.REJECTED);
585
- return false;
586
- }
587
-
588
- handleSendEvent({
589
- eventName: 'abha_mobile_init_api_trigger_initiate',
590
- eventData: {
591
- type: 'api_trigger',
592
- platform: clientId,
593
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
594
- },
595
- });
596
-
597
- window.curio?.pushToMixpanel?.('abha_mobile_init_api_trigger_initiate', {
598
- platform: clientId,
599
- type: 'api_trigger',
600
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
601
- });
602
-
603
- // trigger mobile init api
604
- const {
605
- txn_id,
606
- hint,
607
- error: mobileError,
608
- action: errorAction,
609
- } = await postRegisterMobileInit({
610
- mobile_number: mobileNo,
611
- });
612
- if (txn_id && hint) {
613
- setMobileInitResponse({
614
- authTxnId,
615
- txnId: txn_id,
616
- mobileOtpSentToHint: hint,
617
- });
618
- handleSendEvent({
619
- eventName: 'abha_mobile_init_api_trigger_success',
620
- eventData: {
621
- type: 'api_trigger',
622
- platform: clientId,
623
- transactionId: txn_id,
624
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
625
- authTransactionId: authTxnId,
626
- },
627
- });
628
-
629
- window.curio?.pushToMixpanel?.('abha_mobile_init_api_trigger_success', {
630
- platform: clientId,
631
- type: 'api_trigger',
632
- transactionId: txn_id,
633
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
634
- authTransactionId: authTxnId,
635
- });
636
- setSelectedAbhaFlow('mobile');
637
- updateInitStatus('mobile', LOADING_STATE.RESOLVED);
638
- setRegistrationType(REGISTRATION_TYPE.CREATE);
639
- setSelectedAbhaFlow('mobile');
640
- console.log('update the selected abha flow to mobile');
641
- setScreen(SCREEN_NAMES.ABHA_PHONE_NUMBER_VERIFICATION);
642
- return;
643
- }
644
-
645
- handleSendEvent({
646
- eventName: 'abha_mobile_init_api_trigger_failure',
647
- eventData: {
648
- type: 'api_trigger',
649
- platform: clientId,
650
- transactionId: txn_id || '',
651
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
652
- authTransactionId: authTxnId,
653
- },
654
- });
655
-
656
- window.curio?.pushToMixpanel?.('abha_mobile_init_api_trigger_failure', {
657
- platform: clientId,
658
- type: 'api_trigger',
659
- transactionId: txn_id || '',
660
- isEkaAppLogin: isEkaAppLogin ? 'true' : 'false',
661
- authTransactionId: authTxnId,
662
- });
663
-
664
- updateInitStatus('mobile', LOADING_STATE.REJECTED);
665
- if (errorAction) {
666
- setBottomsheetErrorInfo(errorAction);
667
- } else {
668
- setError(mobileError || 'Something went wrong');
669
- }
670
- }
671
- return;
672
- };
673
-
674
- const handleSubmitClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {
675
- e.stopPropagation();
676
- // Send event for 'Next' click'
677
- console.log('selectedMethod : ', selectedMethod);
678
- const eventName =
679
- selectedMethod === 'aadhaar_number'
680
- ? 'abha_aadhaar_otp_verify_clicks'
681
- : 'abha_mobile_otp_verify_clicks';
682
-
683
- handleSendEvent({
684
- eventName: eventName,
685
- eventData: {
686
- type: 'verify',
687
- platform: clientId,
688
- },
689
- });
690
-
691
- window.curio?.pushToMixpanel?.(eventName, {
692
- platform: clientId,
693
- type: 'next',
694
- });
695
-
696
- if (error) setError(null);
697
- handleRegister();
698
- };
699
-
700
- const handleErrorBottomsheetButtonClick = () => {
701
- const mobileNumber = useAuthAbhaStore.getState().initAbhaAppMobileNumber;
702
- const abhaAppMethod = useAuthAbhaStore.getState().initAbhaAppMethod;
703
- const isAppLogin = useAuthAbhaStore.getState().isEkaAppLogin;
704
- const isTriggered = useAuthAbhaStore.getState().isApiTriggered;
705
- const client = useAuthAbhaStore.getState().clientId;
706
- setScreen(SCREEN_NAMES.CREATE_ABHA_WITH_AADHAAR);
707
- clearAbhaAuthStore();
708
- useAuthAbhaStore.setState({ initAbhaAppMobileNumber: mobileNumber });
709
- useAuthAbhaStore.setState({
710
- screen: [SCREEN_NAMES.LOGIN_WITH_ABHA],
711
- });
712
- useAuthAbhaStore.setState({ isEkaAppLogin: isAppLogin });
713
- useAuthAbhaStore.setState({ initAbhaAppMethod: abhaAppMethod });
714
- useAuthAbhaStore.setState({ isApiTriggered: isTriggered });
715
- useAuthAbhaStore.setState({ clientId: client });
716
- setBottomsheetErrorInfo(null);
717
- };
718
-
719
- return (
720
- <>
721
- <div className="pds2-space-y-16 pds2-p-16 pds2-text-center">
722
- <div className="pds2-flex pds2-justify-center pds2-items-center">
723
- <img
724
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
725
- alt="adaar"
726
- className="pds2-w-64 pds2-h-64 pds2-rounded-16"
727
- />
728
- </div>
729
- <div className="pds2-space-y-16">
730
- <div className="pds2-space-y-4">
731
- <div className="pds2-text-text-black Heading3Semibold">
732
- {isDocAppRequest ? 'Create ABHA' : 'Create your ABHA'}
733
- </div>
734
- <div className="pds2-text-text-03 Body2Regular">
735
- {selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
736
- ? 'Enter 12 digit Aadhaar number'
737
- : 'Enter 10 digit mobile number'}
738
- </div>
739
- </div>
740
- {selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER ? (
741
- <SpacedInputComponent
742
- numberOfInputs={3}
743
- length={4}
744
- placeholder="XXXX"
745
- onSubmit={handleOnAadhaarInputComplete}
746
- setIsValid={setIsValidAadhaar}
747
- error={error}
748
- />
749
- ) : (
750
- <div className="pds2-flex pds2-flex-col pds2-justify-center pds2-items-center pds2-gap-y-16 pds2-px-09">
751
- <PatientPds2InputField
752
- value={mobileNumber}
753
- onChange={handleMobileNumberChange}
754
- disabled={isMobileNonEditable}
755
- type="tel"
756
- placeholder="Mobile Number"
757
- PrefixComponent={
758
- <div className="pds2-flex pds2-items-center pds2-gap-x-8 pds2-border-r pds2-border-border-brand-02 pds2-pr-24">
759
- <img
760
- src="https://cdn.eka.care/vagus/cm4mlct2900000tg98p8u967s.webp"
761
- alt="India Flag"
762
- className="pds2-w-24 pds2-h-24"
763
- />
764
- <span className="pds2-text-text-black">+91</span>
765
- </div>
766
- }
767
- />
768
- </div>
769
- )}
770
- </div>
771
- <CustomCheckBox
772
- id="aadhaar-number"
773
- label="I give consent to NHA to share my identity info"
774
- openInfoDialog={openInfoDialog}
775
- className="pds2-justify-between"
776
- isCheckboxChecked={isNhaConsent}
777
- onCheckboxChange={(checkedStatus) => {
778
- if (error) setError(null);
779
- setIsErrorNhaConsent(false);
780
- setIsNhaConsent(checkedStatus);
781
- }}
782
- isErrored={isErrorNhaConsent}
783
- />
784
- <div
785
- onClick={() => {
786
- if (!isNhaConsent) {
787
- setIsErrorNhaConsent(true);
788
- }
789
- }}
790
- >
791
- <Pds2Button
792
- title={
793
- initApiStatus[
794
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER ? 'aadhaar' : 'mobile'
795
- ] === LOADING_STATE.LOADING
796
- ? 'Verifying'
797
- : 'Next'
798
- }
799
- onClick={handleSubmitClick}
800
- IconComponent={
801
- initApiStatus[
802
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER ? 'aadhaar' : 'mobile'
803
- ] === LOADING_STATE.LOADING
804
- ? () => <Pds2Spinner className="pds2-ml-8" size={16} />
805
- : undefined
806
- }
807
- state={
808
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
809
- ? isValidAadhaar && isNhaConsent
810
- ? 'enabled'
811
- : 'disabled'
812
- : isValidMobileNumber && isNhaConsent
813
- ? 'enabled'
814
- : 'disabled'
815
- }
816
- className="pds2-w-full"
817
- />
818
- </div>
819
- {error && <div className="pds2-text-text-error Body3Semibold">{error}</div>}
820
- </div>
821
-
822
- <AbhaErrorBottomSheet onSubmitClick={handleErrorBottomsheetButtonClick} />
823
- </>
824
- );
825
- };
826
-
827
- export const CustomCheckBox = ({
828
- id,
829
- label,
830
- onCheckboxChange,
831
- openInfoDialog,
832
- className = '',
833
- isCheckboxChecked = false,
834
- isErrored = false,
835
- }: {
836
- id: string;
837
- label: string;
838
- onCheckboxChange: (isChecked: boolean) => void;
839
- openInfoDialog?: () => void;
840
- className?: string;
841
- isCheckboxChecked?: boolean;
842
- isErrored?: boolean;
843
- }) => {
844
- return (
845
- <div
846
- className={`pds2-flex pds2-items-center pds2-space-x-8 ${className} ${isErrored ? 'pds2-text-text-error' : 'pds2-text-text-03'}`}
847
- >
848
- <label htmlFor={id} className="Body2Regular pds2-flex pds2-items-center pds2-space-x-8">
849
- <input
850
- type="checkbox"
851
- checked={isCheckboxChecked}
852
- onChange={(e) => onCheckboxChange(e.target.checked)}
853
- id={id}
854
- className="pds2-hidden"
855
- />
856
- {isCheckboxChecked ? (
857
- <CheckSquareSolidIcon className="pds2-w-14 pds2-h-14 pds2-text-icon-brand" />
858
- ) : (
859
- <SquareRegularIcon className="pds2-w-14 pds2-h-14" />
860
- )}
861
-
862
- <span>{label}</span>
863
- </label>
864
- {openInfoDialog && (
865
- <button
866
- onClick={openInfoDialog}
867
- className="pds2-w-24 pds2-h-24 pds2-rounded-full pds2-flex pds2-items-center pds2-justify-center ripple"
868
- >
869
- <CircleInfoSolidIcon className="pds2-w-14 pds2-h-14 pds2-text-text-04" />
870
- </button>
871
- )}
872
- </div>
873
- );
874
- };
875
-
876
- export const OTPInput = ({
877
- numberOfInputs,
878
- length = 1,
879
- placeholder = '',
880
- setIsValid,
881
- onSubmit,
882
- }: {
883
- numberOfInputs: number;
884
- length?: number;
885
- placeholder?: string;
886
- setIsValid?: (val: boolean) => void;
887
- onSubmit: ({ inputVal }: { inputVal: string }) => void;
888
- }) => {
889
- const inputRefs = useRef<HTMLInputElement[]>([]);
890
- const [inputValues, setInputValues] = useState<string[]>(Array(numberOfInputs).fill(''));
891
- const handleInput = (e: React.FormEvent<HTMLInputElement>, index: number) => {
892
- const value = (e.target as HTMLInputElement).value;
893
-
894
- const isValueNan = isNaN(Number(value));
895
- if (isValueNan) return;
896
-
897
- // Ensure total length doesn't exceed 12 digits
898
- const currentValues = [...inputValues];
899
- currentValues[index] = value;
900
- const totalLength = currentValues.join('').length;
901
- if (totalLength > numberOfInputs * length) return;
902
-
903
- // Update current input value
904
- setInputValues(currentValues);
905
-
906
- if (totalLength === numberOfInputs * length) {
907
- setIsValid?.(true);
908
- onSubmit({ inputVal: currentValues.join('') });
909
- } else {
910
- setIsValid?.(false);
911
- }
912
-
913
- // Move to next input if current is full
914
- if (value.length === length && index < numberOfInputs - 1) {
915
- inputRefs.current[index + 1]?.focus();
916
- }
917
- };
918
-
919
- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
920
- if (e.key === 'Backspace' && !inputValues[index] && index > 0) {
921
- inputRefs.current[index - 1]?.focus();
922
- setInputValues((prev) => {
923
- const newValues = [...prev];
924
- newValues[index - 1] = '';
925
- return newValues;
926
- });
927
- }
928
- };
929
-
930
- const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>, index: number) => {
931
- e.preventDefault();
932
- const pastedData = e.clipboardData.getData('text').replace(/\D/g, ''); // Only keep digits
933
-
934
- if (!pastedData) return;
935
-
936
- const maxLength = numberOfInputs * length;
937
- const validPastedData = pastedData.slice(0, maxLength);
938
-
939
- // Split pasted data into chunks based on input length
940
- const chunks = validPastedData.match(new RegExp(`.{1,${length}}`, 'g')) || [];
941
-
942
- const newValues = [...inputValues];
943
- chunks.forEach((chunk, i) => {
944
- if (index + i < numberOfInputs) {
945
- newValues[index + i] = chunk;
946
- }
947
- });
948
-
949
- setInputValues(newValues);
950
-
951
- // Focus the next empty input or the last input
952
- const nextEmptyIndex = newValues.findIndex((val, i) => i >= index && !val);
953
- if (nextEmptyIndex !== -1) {
954
- inputRefs.current[nextEmptyIndex]?.focus();
955
- } else {
956
- inputRefs.current[numberOfInputs - 1]?.focus();
957
- }
958
- };
959
- return (
960
- <div className="pds2-flex pds2-justify-center pds2-items-center pds2-space-x-8">
961
- {Array.from({ length: numberOfInputs }).map((_, index) => (
962
- <label
963
- key={index}
964
- className="focus-within:pds2-border-border-brand-01 focus-within:pds2-border pds2-border-border-03 pds2-rounded-16"
965
- >
966
- <input
967
- placeholder={placeholder}
968
- value={inputValues[index]}
969
- key={index}
970
- type="text"
971
- inputMode="numeric"
972
- pattern="[0-9]*"
973
- maxLength={length}
974
- onPaste={(e) => handlePaste(e, index)}
975
- ref={(el) => {
976
- if (el) inputRefs.current[index] = el;
977
- }}
978
- onInput={(e) => handleInput(e, index)}
979
- onKeyDown={(e) => handleKeyDown(e, index)}
980
- className={`pds2-w-full pds2-text-center pds2-rounded-16 pds2-p-16 pds2-outline-none`}
981
- />
982
- </label>
983
- ))}
984
- </div>
985
- );
986
- };