@eka-care/abha 0.0.6 → 0.0.7

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 (85) 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 +136 -0
  4. package/package.json +1 -1
  5. package/.eslintignore +0 -3
  6. package/.eslintrc +0 -29
  7. package/.prettierrc +0 -7
  8. package/dev-abha-ios-android.zip +0 -0
  9. package/postcss.config.js +0 -6
  10. package/prod-abha-mixpanel.zip +0 -0
  11. package/scripts/build-purged-css.cjs +0 -70
  12. package/src/App.css +0 -0
  13. package/src/App.tsx +0 -32
  14. package/src/api-queries/use-get-profiles-patient.ts +0 -12
  15. package/src/api-queries/use-get-profiles-phr-user.ts +0 -27
  16. package/src/api-queries/use-post-abdm-login-verify-v1.ts +0 -25
  17. package/src/api-queries/use-post-auth-verify-v2.ts +0 -74
  18. package/src/api-queries/use-post-profile-switch.ts +0 -57
  19. package/src/api-queries/use-post-register-mobile-create-phr.ts +0 -39
  20. package/src/api-queries/user-post-abdm-profile-login-phr.ts +0 -25
  21. package/src/assets/react.svg +0 -1
  22. package/src/atoms/button/custom-button.tsx +0 -32
  23. package/src/atoms/button/index.tsx +0 -40
  24. package/src/atoms/button/types.d.ts +0 -31
  25. package/src/atoms/header.tsx +0 -25
  26. package/src/atoms/input-field/index.tsx +0 -62
  27. package/src/atoms/input-field/patient-input-field.tsx +0 -16
  28. package/src/atoms/input-field/types.ts +0 -24
  29. package/src/atoms/pds2-otp-input/index.tsx +0 -35
  30. package/src/atoms/pds2-otp-input/types.d.ts +0 -3
  31. package/src/atoms/single-input-chip/index.tsx +0 -32
  32. package/src/atoms/single-input-chip/types.ts +0 -6
  33. package/src/atoms/spinner.tsx +0 -33
  34. package/src/atoms/text-separator.tsx +0 -11
  35. package/src/index.css +0 -118
  36. package/src/main.tsx +0 -313
  37. package/src/molecules/abha/bottom-sheet/bottom-sheet-wrapper.tsx +0 -40
  38. package/src/molecules/abha/bottom-sheet/index.tsx +0 -66
  39. package/src/molecules/abha/spaced-input-component.tsx +0 -150
  40. package/src/molecules/copyright-year.tsx +0 -16
  41. package/src/molecules/exit-popup/index.tsx +0 -99
  42. package/src/molecules/pds2-otp-component/index.tsx +0 -148
  43. package/src/organisms/abha/abha-header.tsx +0 -25
  44. package/src/organisms/abha/error-bottom-sheet.tsx +0 -27
  45. package/src/organisms/abha/otp-card.tsx +0 -99
  46. package/src/organisms/abha/verification-status.tsx +0 -40
  47. package/src/organisms/choose-language/choose-language.tsx +0 -53
  48. package/src/organisms/choose-language/types.ts +0 -10
  49. package/src/organisms/screen-switcher/screen-switcher.tsx +0 -80
  50. package/src/routes/abha-aadhaar-verification-status-screen.tsx +0 -209
  51. package/src/routes/abha-created-screen.tsx +0 -45
  52. package/src/routes/abha-login-otp-verify-screen.tsx +0 -523
  53. package/src/routes/abha-mobile-linking-status-screen.tsx +0 -267
  54. package/src/routes/abha-otp-and-mobile-screen.tsx +0 -429
  55. package/src/routes/abha-phone-number-verification-screen.tsx +0 -373
  56. package/src/routes/create-abha-address-screen.tsx +0 -928
  57. package/src/routes/create-abha-with-aadhaar-screen.tsx +0 -984
  58. package/src/routes/create-eka-profile-screen.tsx +0 -777
  59. package/src/routes/get-all-profiles-screen.tsx +0 -161
  60. package/src/routes/login-or-create-abha-address-screen.tsx +0 -953
  61. package/src/routes/login-with-abha-screen.tsx +0 -448
  62. package/src/routes/select-abha-from-list-screen.tsx +0 -718
  63. package/src/routes/select-eka-profile-screen.tsx +0 -444
  64. package/src/routes/utils/trackAbhaEvent.ts +0 -41
  65. package/src/stores/auth-abha-store/index.ts +0 -138
  66. package/src/stores/auth-abha-store/types.ts +0 -204
  67. package/src/utils/mock-auth-response.ts +0 -31
  68. package/src/vite-env.d.ts +0 -1
  69. package/tailwind.config.ts +0 -9
  70. package/tsconfig.app.json +0 -26
  71. package/tsconfig.json +0 -25
  72. package/tsconfig.node.json +0 -10
  73. package/tsconfig.node.tsbuildinfo +0 -1
  74. package/tsconfig.tsbuildinfo +0 -1
  75. package/vite.config.d.ts +0 -2
  76. package/vite.config.js +0 -30
  77. package/vite.config.ts +0 -35
  78. /package/{public → dist}/images/adhaar.webp +0 -0
  79. /package/{public → dist}/images/at-the-rate.webp +0 -0
  80. /package/{public → dist}/images/avatar.webp +0 -0
  81. /package/{public → dist}/images/ayushman-bharat.webp +0 -0
  82. /package/{public → dist}/images/circle-checkmark.webp +0 -0
  83. /package/{public → dist}/images/link-abha.webp +0 -0
  84. /package/{public → dist}/images/national-authority.webp +0 -0
  85. /package/{public → dist}/images/three-dots.webp +0 -0
@@ -1,953 +0,0 @@
1
- import React, { useEffect, useState, useRef } from 'react';
2
- import { unMount } from '../main';
3
- import useAuthAbhaStore from '../stores/auth-abha-store';
4
- import Pds2Header from '../atoms/header';
5
- import { ChevronDownRegularIcon, PhoneSolidIcon, ArrowLeftRegularIcon } from '@elixir/icons';
6
- import {
7
- ABHA_AUTH_FLOW_METHOD,
8
- LOADING_STATE,
9
- AUTH_METHOD,
10
- REGISTRATION_TYPE,
11
- } from '@elixir/types';
12
- import Pds2InputField from '../atoms/input-field';
13
- import SpacedInputComponent from '../molecules/abha/spaced-input-component';
14
- import Pds2Button from '../atoms/button';
15
- import { SCREEN_NAMES } from '../stores/auth-abha-store/types';
16
- import {
17
- postAbdmLoginInit,
18
- postAuthInitV2,
19
- postAuthLogoutV2,
20
- postRegisterMobileInit,
21
- postRegisterAadhaarInit,
22
- } from 'apis';
23
- import { handleSendEvent } from '@elixir/utils';
24
- import { GET_EXTRA_HEADERS } from 'apis';
25
-
26
- const isProd = import.meta.env.VITE_APP_ENV === 'PROD';
27
- type InitMethod = 'aadhaar' | 'mobile';
28
-
29
- const LoginorCreateAbhaScreen = () => {
30
- const clientId = useAuthAbhaStore((state) => state.clientId);
31
-
32
- useEffect(() => {
33
- if (window.EkaAbha?.changeStatusBarColor) {
34
- window.EkaAbha.changeStatusBarColor('#F2F4F7');
35
- return () => {
36
- if (window.EkaAbha?.changeStatusBarColor) window?.EkaAbha?.changeStatusBarColor('#FFFFFF');
37
- };
38
- }
39
- }, []);
40
-
41
- const handleBackButtonClick = () => {
42
- window.EkaAbha?.onAbhaClose();
43
- unMount();
44
- };
45
-
46
- return (
47
- <div className="pds2-bg-bg-01 pds2-pt-36">
48
- {/* * if clientId is not eka-web, show back button */}
49
- {clientId !== 'eka-web' && (
50
- <Pds2Header
51
- prefixIcon={
52
- <button onClick={handleBackButtonClick}>
53
- <ArrowLeftRegularIcon />
54
- </button>
55
- }
56
- title=""
57
- className="pds2-bg-bg-01"
58
- />
59
- )}
60
- <LoginOrCreateWithDifferentMethods />
61
- </div>
62
- );
63
- };
64
-
65
- const LoginOrCreateWithDifferentMethods = () => {
66
- // State management from custom store
67
- const selectedMethod = useAuthAbhaStore(
68
- (state) => state.abhaAuthFlowMethod || ABHA_AUTH_FLOW_METHOD.MOBILE
69
- );
70
- const setAbhaAuthFlowMethod = useAuthAbhaStore((state) => state.setAbhaAuthFlowMethod);
71
- const [identifierValue, setIdentifierValue] = useState<string>('');
72
- const [abdmLoginInitApiStatus, setAbdmLoginInitApiStatus] = useState<LOADING_STATE>(
73
- LOADING_STATE.IDLE
74
- );
75
- const isEkaAppLogin = useAuthAbhaStore((state) => state.isEkaAppLogin);
76
- const [error, setError] = useState<string | null>('');
77
- const setSelectedAbhaAddress = useAuthAbhaStore((state) => state.setSelectedAbhaAddress);
78
- const setLoginIdentifierValue = useAuthAbhaStore((state) => state.setLoginIdentifierValue);
79
- const setScreen = useAuthAbhaStore((state) => state.setScreen);
80
- const [initApiStatus, setInitApiStatus] = useState<Record<InitMethod, LOADING_STATE>>({
81
- aadhaar: LOADING_STATE.IDLE,
82
- mobile: LOADING_STATE.IDLE,
83
- });
84
- const setRegistrationType = useAuthAbhaStore((state) => state.setRegistrationType);
85
- const setAadhaarInitResponse = useAuthAbhaStore((state) => state.setAadhaarInitResponse);
86
- const setMobileInitResponse = useAuthAbhaStore((state) => state.setMobileInitResponse);
87
- const initAbhaAppMobileNumber = useAuthAbhaStore((state) => state.initAbhaAppMobileNumber);
88
-
89
- const [mobileNumber, setMobileNumber] = useState('');
90
- const [isValidMobileNumber, setIsValidMobileNumber] = useState(false);
91
-
92
- const [isValidAadhaar, setIsValidAadhaar] = useState<boolean>(false);
93
- const [aadhaarNumber, setAadhaarNumber] = useState('');
94
-
95
- const [abhaNumber, setAbhaNumber] = useState('');
96
- const [abhaAddress, setAbhaAddress] = useState('');
97
-
98
- const isNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.isNewLoginOrCreateFlow);
99
- const setIsNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.setIsNewLoginOrCreateFlow);
100
- const clientId = useAuthAbhaStore((state) => state.clientId);
101
- const hasInitApiTriggered = useRef(false);
102
- const isInitApiTriggered = useAuthAbhaStore((state) => state.isInitApiTriggered);
103
- const setIsInitApiTriggered = useAuthAbhaStore((state) => state.setIsInitApiTriggered);
104
- const setIdentityValue = useAuthAbhaStore((state) => state.setIdentityValue);
105
- const identityValue = useAuthAbhaStore((state) => state.identityValue);
106
- const extra_headers = GET_EXTRA_HEADERS();
107
- const setSelectedAbhaFlow = useAuthAbhaStore((state) => state.setSelectedAbhaFlow);
108
- const isDocAppRequest = useAuthAbhaStore((state) => state.isDocAppRequest);
109
- const txnId = useAuthAbhaStore((state) => state.txnId);
110
-
111
- // Analytics: Track screen view
112
- useEffect(() => {
113
- trackAbhaEvent({
114
- name: 'abha_login_or_create_screen',
115
- data: {
116
- flow: selectedMethod.toString()
117
- },
118
- });
119
- });
120
-
121
- // Prefill mobile number if present (from Eka app) and set validity
122
- useEffect(() => {
123
- if (!!initAbhaAppMobileNumber && selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE) {
124
- setIdentifierValue(initAbhaAppMobileNumber);
125
- setIsValidMobileNumber(initAbhaAppMobileNumber.length === 10);
126
- setError(null);
127
- return;
128
- }
129
-
130
- setIdentifierValue('');
131
- setError(null);
132
- setIsValidMobileNumber(false);
133
- }, [selectedMethod]);
134
-
135
- // Auto-submit for mobile method when 10 digits are entered
136
- useEffect(() => {
137
- if (isInitApiTriggered || hasInitApiTriggered.current) {
138
- return;
139
- }
140
- if (mobileNumber && mobileNumber.length === 10) {
141
- setIsInitApiTriggered(true);
142
- hasInitApiTriggered.current = true;
143
- handleNextClick("auto_submit_mobile");
144
- }
145
- }, [mobileNumber]);
146
-
147
- // Auto-submit for Aadhaar method when 12 digits are entered
148
- useEffect(() => {
149
- if (isInitApiTriggered || hasInitApiTriggered.current) {
150
- return;
151
- }
152
- if (aadhaarNumber && aadhaarNumber.length === 12) {
153
- setIsInitApiTriggered(true);
154
- hasInitApiTriggered.current = true;
155
- handleNextClick("auto_submit_aadhaar");
156
- }
157
- }, [aadhaarNumber]);
158
-
159
- // Analytics event tracker
160
- const trackAbhaEvent = ({ name, data = {} }: { name: string; data?: Record<string, any> }) => {
161
- const baseProps = {
162
- login_platform: clientId,
163
- is_eka_app_login: isEkaAppLogin ? 'true' : 'false',
164
- is_new_login_or_create_flow: isNewLoginOrCreateFlow ? 'true' : 'false',
165
- oid: extra_headers?.['X-User-ID'] ? 'true' : 'false',
166
- access_token: extra_headers?.['auth'] ? 'true' : 'false',
167
- txn_id: txnId || 'missing txnId',
168
- flow: selectedMethod ?? ""
169
- };
170
-
171
- const eventData = {
172
- ...baseProps,
173
- ...data,
174
- };
175
-
176
- handleSendEvent({
177
- eventName: name,
178
- eventData,
179
- });
180
-
181
- window.curio?.pushToMixpanel?.(name, eventData);
182
- };
183
-
184
- // Dynamic heading based on selected method
185
- const methodText = React.useMemo(() => {
186
- switch (selectedMethod) {
187
- case ABHA_AUTH_FLOW_METHOD.MOBILE:
188
- return 'Enter your Mobile Number';
189
- case ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER:
190
- return 'Enter your Aadhaar Number';
191
- default:
192
- return '';
193
- }
194
- }, [selectedMethod]);
195
-
196
- // Handle user input and apply formatting + validation
197
- const handleIdentifierValueChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
198
- const val = e.target.value;
199
- switch (selectedMethod) {
200
- case ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS:
201
- if (val.length > 20) return;
202
- setAbhaAddress(val);
203
- setIdentifierValue(val);
204
- break;
205
-
206
- case ABHA_AUTH_FLOW_METHOD.MOBILE:
207
- if ((val && !/^[0-9]+$/.test(val)) || val.length > 10) return;
208
- setMobileNumber(val);
209
- setIsValidMobileNumber(true);
210
- setIdentifierValue(val);
211
- break;
212
-
213
- case ABHA_AUTH_FLOW_METHOD.ABHA_NUMBER:
214
- if (!/^[\d-]*$/.test(val) || val.length > 17) return;
215
- const value = e.target.value.replace(/-/g, '');
216
- let abhaNumber = '';
217
- if (value.length > 0) abhaNumber += value.slice(0, 2);
218
- if (value.length > 2) abhaNumber += `-${value.slice(2, 6)}`;
219
- if (value.length > 6) abhaNumber += `-${value.slice(6, 10)}`;
220
- if (value.length > 10) abhaNumber += `-${value.slice(10, 14)}`;
221
- setAbhaNumber(abhaNumber);
222
- return setIdentifierValue(abhaNumber.trim());
223
-
224
- case ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER:
225
- if (val && !/^[0-9]+$/.test(val)) return;
226
- if (val.length > 12) return;
227
-
228
- setAadhaarNumber(val);
229
- setIsValidAadhaar(true);
230
- setIdentifierValue(val);
231
- break;
232
- }
233
- setIdentifierValue(val.trim());
234
- };
235
-
236
- // Disable editing if mobile is prefilled from Eka app
237
- const isMobileNonEditable =
238
- selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE && !!initAbhaAppMobileNumber;
239
-
240
- // Check if current identifier is valid based on method
241
- const isValidIdentifier = React.useMemo(() => {
242
- switch (selectedMethod) {
243
- case ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS:
244
- return identifierValue.length >= 4 && identifierValue.length <= 20; // changing the lower limit to 4, since the address can be as short as 4 characters
245
- case ABHA_AUTH_FLOW_METHOD.MOBILE:
246
- return identifierValue.length === 10;
247
- case ABHA_AUTH_FLOW_METHOD.ABHA_NUMBER:
248
- return identifierValue.length === 17;
249
- case ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER:
250
- return identifierValue.length === 12;
251
- }
252
- }, [selectedMethod, identifierValue]);
253
-
254
- // Utility to update API init status
255
- const updateInitStatus = (method: InitMethod, status: LOADING_STATE) => {
256
- setInitApiStatus((prev) => ({
257
- ...prev,
258
- [method]: status,
259
- }));
260
- };
261
-
262
- // When Aadhaar OTP input is completed
263
- const handleOnAadhaarInputComplete = ({ inputVal: newAadhaarNo }: { inputVal: string }) => {
264
- if (newAadhaarNo.length === 12) {
265
- setIdentifierValue(newAadhaarNo);
266
- setAadhaarNumber(newAadhaarNo);
267
- setIsValidAadhaar(true);
268
- }
269
- };
270
-
271
- // Debug log for method change
272
- useEffect(() => {
273
- console.log('selectedMethod changed:==================>', selectedMethod);
274
- }, [selectedMethod]);
275
-
276
- const handleNextClick = async (flowStepType: string) => {
277
- // Set the flag to indicate this is a new login/create ABHA flow
278
- setIsNewLoginOrCreateFlow(true);
279
- // Track event for clicking 'Next' on ABHA login
280
- trackAbhaEvent({
281
- name: 'abha_login_next_click',
282
- data: {
283
- flow_step_type: flowStepType,
284
- },
285
- });
286
-
287
- // Begin login/auth process
288
- setAbdmLoginInitApiStatus(LOADING_STATE.LOADING);
289
-
290
- // Assume flow is login until proven otherwise (error in init)
291
- setRegistrationType(REGISTRATION_TYPE.LOGIN);
292
-
293
- let authTxnId = '';
294
-
295
- // If login is not coming from Eka app, start ABDM auth init
296
- if (!isEkaAppLogin) {
297
- // Clear any previous auth sessions, logout is specifcally for outside the app flows
298
- // clientIds are www-eka, android -> outside the app flow.
299
- // Clear any previous auth sessions, logout is specifically for outside the app flows
300
- const logoutSuccess = await postAuthLogoutV2();
301
- trackAbhaEvent({
302
- name: logoutSuccess ? 'abha_logout_success' : 'abha_logout_failure',
303
- data: {
304
- platform: clientId,
305
- },
306
- });
307
-
308
- const { txn_id: txnId, error } = await postAuthInitV2({
309
- method: AUTH_METHOD.ABHA,
310
- });
311
-
312
- if (!txnId || error) {
313
- trackAbhaEvent({
314
- name: 'abha_auth_init_failure',
315
- data: {
316
- flow_step_type: 'init',
317
- authTxnId: authTxnId,
318
- error_message: error || 'missing_txnId_or_unknown_error',
319
- error_message_exists: !!error,
320
- txn_id_exists: !!txnId,
321
- },
322
- });
323
- setError(error?.message || 'Something went wrong. Please try again.');
324
- setAbdmLoginInitApiStatus(LOADING_STATE.REJECTED);
325
- return;
326
- }
327
- authTxnId = txnId;
328
-
329
- // Track successful auth API call
330
- trackAbhaEvent({
331
- name: 'abha_auth_init_success.',
332
- data: {
333
- flow_step_type: 'init',
334
- auth_txnId: authTxnId,
335
- },
336
- });
337
- }
338
-
339
- // Construct identifier (append domain if using ABHA address)
340
- const loginIdentifier =
341
- selectedMethod === ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS
342
- ? `${identifierValue}${isProd ? '@abdm' : '@sbx'}`
343
- : identifierValue;
344
-
345
- // ----- MOBILE LOGIN FLOW -----
346
- if (
347
- selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE ||
348
- selectedMethod === ABHA_AUTH_FLOW_METHOD.ABHA_NUMBER ||
349
- selectedMethod === ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS
350
- ) {
351
- const {
352
- txn_id: abdmTxnId,
353
- error: abdmLoginError,
354
- action: abdmLoginErrorAction,
355
- hint,
356
- } = await postAbdmLoginInit({
357
- method: selectedMethod,
358
- identifier: loginIdentifier,
359
- });
360
-
361
- setIdentityValue(loginIdentifier); // Store identity used
362
-
363
- // Track login init call
364
- trackAbhaEvent({
365
- name: 'abha_login_init_triggered',
366
- data: {
367
- flow_step_type: 'init',
368
- authTxnId: authTxnId,
369
- ndhmTxnId: abdmTxnId,
370
- method: selectedMethod,
371
- },
372
- });
373
-
374
- // ----- ABHA ADDRESS FLOW -----
375
- if (selectedMethod === ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS) {
376
- setSelectedAbhaAddress(loginIdentifier);
377
- }
378
-
379
- if (abdmLoginError || !abdmTxnId) {
380
- if (abdmLoginErrorAction?.cta?.pid === 'abha_mobile_enroll') {
381
- // Attempt fallback to registration flow
382
- updateInitStatus('mobile', LOADING_STATE.LOADING);
383
- setRegistrationType(REGISTRATION_TYPE.CREATE);
384
- const {
385
- txn_id,
386
- hint,
387
- error: abdmRegMobileError,
388
- action: abdmRegErrorAction,
389
- } = await postRegisterMobileInit({
390
- mobile_number: identifierValue,
391
- });
392
- setIdentityValue(identifierValue);
393
- setSelectedAbhaFlow('mobile');
394
-
395
- if (txn_id && hint) {
396
- // Successful fallback to registration
397
- setMobileInitResponse({
398
- authTxnId,
399
- txnId: txn_id,
400
- mobileOtpSentToHint: hint,
401
- });
402
-
403
- trackAbhaEvent({
404
- name: 'abha_mobile_registration_init_success',
405
- data: {
406
- flow_step_type: 'init',
407
- authTxnId: authTxnId,
408
- ndhmTxnId: abdmTxnId,
409
- error_message: abdmRegMobileError,
410
- error_action: abdmLoginErrorAction,
411
- },
412
- });
413
-
414
- updateInitStatus('mobile', LOADING_STATE.RESOLVED);
415
- setAbdmLoginInitApiStatus(LOADING_STATE.RESOLVED);
416
- setRegistrationType(REGISTRATION_TYPE.CREATE);
417
- setScreen(SCREEN_NAMES.ABHA_PHONE_NUMBER_VERIFICATION);
418
- return;
419
- }
420
-
421
- updateInitStatus('mobile', LOADING_STATE.REJECTED);
422
- trackAbhaEvent({
423
- name: 'abha_mobile_registration_init_failure',
424
- data: {
425
- flow_step_type: 'init',
426
- authTxnId: authTxnId,
427
- error_message: abdmRegMobileError || 'unknown_error',
428
- error_message_exists: !!abdmRegMobileError,
429
- error_action_exists: !!abdmRegErrorAction,
430
- },
431
- });
432
- if (abdmRegErrorAction) {
433
- if (abdmRegErrorAction?.cta?.pid) {
434
- return setScreen(SCREEN_NAMES.LOGIN_OR_CREATE_ABHA);
435
- }
436
- } else {
437
- setError(abdmRegMobileError || 'Something went wrong');
438
- }
439
- setError(abdmRegMobileError || 'Something went wrong. Please try again.');
440
- setAbdmLoginInitApiStatus(LOADING_STATE.REJECTED);
441
- return;
442
- }
443
- trackAbhaEvent({
444
- name: 'abha_login_init_failure',
445
- data: {
446
- flow_step_type: 'init',
447
- authTxnId: authTxnId,
448
- error_message: abdmLoginError || 'unknown_error',
449
- error_message_exists: !!abdmLoginError,
450
- error_action_exists: !!abdmLoginErrorAction,
451
- },
452
- });
453
- setError(abdmLoginError || 'Something went wrong. Please try again.');
454
- setAbdmLoginInitApiStatus(LOADING_STATE.REJECTED);
455
- return;
456
- }
457
- // Login init success
458
- trackAbhaEvent({
459
- name: 'abha_login_init_success',
460
- data: {
461
- flow_step_type: 'init',
462
- authTxnId: authTxnId,
463
- ndhmTxnId: abdmTxnId,
464
- hint: hint,
465
- },
466
- });
467
-
468
- setAadhaarInitResponse({
469
- authTxnId,
470
- txnId: abdmTxnId,
471
- aadhaarOtpSentToHint: hint || null,
472
- });
473
-
474
- setLoginIdentifierValue(loginIdentifier);
475
- setAbdmLoginInitApiStatus(LOADING_STATE.RESOLVED);
476
- setScreen(SCREEN_NAMES.VERIFY_OTP_LOGIN_WITH_ABHA);
477
- return;
478
- }
479
-
480
- // ----- AADHAAR REGISTRATION FLOW -----
481
- if (selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) {
482
- updateInitStatus('aadhaar', LOADING_STATE.LOADING);
483
- trackAbhaEvent({
484
- name: 'aadhaar_registration_init_start',
485
- data: {
486
- flow_step_type: 'init',
487
- authTxnId: authTxnId,
488
- aadhaarNumber: identifierValue,
489
- },
490
- });
491
- const {
492
- txn_id,
493
- hint,
494
- error: aadhaarError,
495
- action: errorAction,
496
- } = await postRegisterAadhaarInit({
497
- aadhaar_number: identifierValue,
498
- });
499
-
500
- setIdentityValue(identifierValue);
501
- setSelectedAbhaFlow('aadhaar');
502
-
503
- if (txn_id && hint) {
504
- setAadhaarInitResponse({
505
- authTxnId,
506
- txnId: txn_id,
507
- aadhaarOtpSentToHint: hint,
508
- });
509
-
510
- trackAbhaEvent({
511
- name: 'aadhaar_registration_init_success',
512
- data: {
513
- flow_step_type: 'verify',
514
- ndhmTxnId: txn_id,
515
- authTxnId: authTxnId,
516
- },
517
- });
518
- updateInitStatus('aadhaar', LOADING_STATE.RESOLVED);
519
- setRegistrationType(REGISTRATION_TYPE.CREATE);
520
- setAbdmLoginInitApiStatus(LOADING_STATE.RESOLVED);
521
- setScreen(SCREEN_NAMES.ABHA_OTP_AND_MOBILE);
522
- return;
523
- }
524
-
525
- trackAbhaEvent({
526
- name: 'abha_registration_init_failure',
527
- data: {
528
- error_message: aadhaarError || 'unknown_error',
529
- error_message_exists: !!aadhaarError,
530
- auth_txn_id: authTxnId,
531
- error_action: errorAction,
532
- error_action_exists: !!errorAction,
533
- },
534
- });
535
-
536
- updateInitStatus('aadhaar', LOADING_STATE.REJECTED);
537
- setAbdmLoginInitApiStatus(LOADING_STATE.REJECTED);
538
- // Error handler for Aadhaar registration failure
539
- if (errorAction || aadhaarError) {
540
- if (errorAction?.cta?.pid) {
541
- setScreen(SCREEN_NAMES.LOGIN_OR_CREATE_ABHA);
542
- } else {
543
- setError(aadhaarError || 'Something went wrong');
544
- }
545
- return;
546
- }
547
- }
548
- };
549
-
550
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
551
- const [isAbhaNumberSheetOpen, setIsAbhaNumberSheetOpen] = useState(false);
552
- const [isPhrAddressSheetOpen, setIsPhrAddressSheetOpen] = useState(false);
553
-
554
- return (
555
- <>
556
- <div className="pds2-p-16 pds2-bg-bg-01 pds2-space-y-16 pds2-text-center">
557
- <div className="pds2-flex pds2-justify-center pds2-items-center pds2-gap-16">
558
- <div className="pds2-bg-bg-white pds2-rounded-16">
559
- <img
560
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
561
- alt="abha"
562
- className="pds2-w-64 pds2-h-64"
563
- />
564
- </div>
565
- </div>
566
-
567
- <div className="Heading3Semibold pds2-text-text-black">
568
- {clientId === 'phr'
569
- ? 'Login or Create your ABHA'
570
- : isDocAppRequest
571
- ? 'Add Patient via ABHA'
572
- : 'Create your ABHA'}
573
- </div>
574
- <div className="pds2-text-text-03" style={{ marginTop: '4px' }}>
575
- {selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE
576
- ? 'Enter your Mobile Number'
577
- : selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
578
- ? 'Enter your Aadhaar Number'
579
- : selectedMethod === ABHA_AUTH_FLOW_METHOD.ABHA_NUMBER
580
- ? 'Enter your ABHA Number'
581
- : selectedMethod === ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS
582
- ? 'Enter your ABHA Address'
583
- : methodText}
584
- </div>
585
-
586
- {/* Tabs for Mobile and Aadhaar - Only show for Mobile/Aadhaar methods */}
587
- {(selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE ||
588
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) && (
589
- <div className="pds2-flex pds2-mt-4 pds2-bg-bg-02 pds2-rounded-lg pds2-overflow-hidden pds2-p-1">
590
- {/* Mobile Tab */}
591
- <button
592
- onClick={() => setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.MOBILE)}
593
- className={`pds2-flex-1 pds2-py-3 pds2-flex pds2-items-center pds2-justify-center pds2-gap-8 pds2-relative ${
594
- selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE
595
- ? 'pds2-bg-bg-white'
596
- : 'pds2-bg-bg-seperator-dark'
597
- }`}
598
- style={{
599
- clipPath:
600
- 'polygon(8px 0%, calc(100% - 8px) 0%, 100% 8px, 100% calc(100% - 8px), calc(100% - 8px) 100%, 8px 100%, 0% calc(100% - 8px), 0% 8px)',
601
- }}
602
- >
603
- <PhoneSolidIcon className="pds2-w-14 pds2-h-14 pds2-text-icon-success-02" />
604
- <span
605
- className={`pds2-text-base ${
606
- selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE
607
- ? 'pds2-font-bold pds2-text-fg-default'
608
- : 'pds2-font-normal pds2-text-fg-subtle'
609
- }`}
610
- style={
611
- selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE
612
- ? { fontWeight: 700 }
613
- : { fontWeight: 400 }
614
- }
615
- >
616
- Mobile
617
- </span>
618
- </button>
619
- {/* Aadhaar Tab */}
620
- <button
621
- onClick={() => setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER)}
622
- className={`pds2-flex-1 pds2-py-3 pds2-flex pds2-items-center pds2-justify-center pds2-gap-8 pds2-relative pds2-ml-1 ${
623
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
624
- ? 'pds2-bg-bg-white'
625
- : 'pds2-bg-bg-seperator-dark'
626
- }`}
627
- style={{
628
- clipPath:
629
- 'polygon(8px 0%, calc(100% - 8px) 0%, 100% 8px, 100% calc(100% - 8px), calc(100% - 8px) 100%, 8px 100%, 0% calc(100% - 8px), 0% 8px)',
630
- }}
631
- >
632
- <img
633
- src="https://cdn.eka.care/vagus/cm5mcdm3h00070tfs9fjkepff.webp"
634
- alt="Aadhaar"
635
- className="pds2-w-24 pds2-h-24"
636
- />
637
- <span
638
- className={`pds2-text-base ${
639
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
640
- ? 'pds2-font-bold pds2-text-fg-default'
641
- : 'pds2-font-normal pds2-text-fg-subtle'
642
- }`}
643
- style={
644
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
645
- ? { fontWeight: 700 }
646
- : { fontWeight: 400 }
647
- }
648
- >
649
- Aadhaar
650
- </span>
651
- </button>
652
- </div>
653
- )}
654
-
655
- {/* Input Field Section - Only show for Mobile/Aadhaar methods */}
656
- {(selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE ||
657
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) && (
658
- <div className="pds2-mt-16 pds2-w-full pds2-max-w-md pds2-mx-auto pds2-px-4 pds2-relative">
659
- {selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER ? (
660
- <SpacedInputComponent
661
- numberOfInputs={3}
662
- length={4}
663
- placeholder="XXXX"
664
- onSubmit={handleOnAadhaarInputComplete}
665
- setIsValid={setIsValidAadhaar}
666
- />
667
- ) : (
668
- <Pds2InputField
669
- value={identifierValue}
670
- onChange={handleIdentifierValueChange}
671
- type="tel"
672
- placeholder="Mobile Number"
673
- disabled={isMobileNonEditable}
674
- inputMode="numeric"
675
- autoFocus={true}
676
- maxLength={10}
677
- PrefixComponent={
678
- <div className="pds2-flex pds2-items-center pds2-gap-x-8 pds2-border-r pds2-border-border-brand-02 pds2-pr-24">
679
- <img
680
- src="https://cdn.eka.care/vagus/cm4mlct2900000tg98p8u967s.webp"
681
- alt="India Flag"
682
- className="pds2-w-24 pds2-h-24"
683
- />
684
- <span className="pds2-text-text-black pds2-text-sm">+91</span>
685
- </div>
686
- }
687
- />
688
- )}
689
- </div>
690
- )}
691
-
692
- {error && <div className="pds2-text-text-error Body3Regular">{error}</div>}
693
-
694
- {/* Next Button - Only show for Mobile/Aadhaar methods */}
695
- {(selectedMethod === ABHA_AUTH_FLOW_METHOD.MOBILE ||
696
- selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) && (
697
- <Pds2Button
698
- title="Next"
699
- IconComponent={() => (
700
- <ChevronDownRegularIcon className="pds2-w-16 pds2-h-16 -pds2-rotate-90 pds2-ml-8" />
701
- )}
702
- state={!isValidIdentifier || abdmLoginInitApiStatus === LOADING_STATE.LOADING ? 'disabled' : 'enabled'}
703
- isLoading={abdmLoginInitApiStatus === LOADING_STATE.LOADING}
704
- onClick={() => handleNextClick("aadhaar_or_mobile_on_click")}
705
- className="pds2-w-full"
706
- />
707
- )}
708
- </div>
709
-
710
- {/* Other Login Options Dropdown */}
711
- <div className="pds2-mt-24 pds2-mx-16 pds2-mb-48 pds2-pb-36">
712
- <div className="pds2-bg-bg-white pds2-rounded-16 pds2-border pds2-border-border-03 pds2-overflow-hidden">
713
- {/* Dropdown Header */}
714
- <button
715
- onClick={() => setIsDropdownOpen(!isDropdownOpen)}
716
- className="pds2-w-full pds2-flex pds2-items-center pds2-justify-between pds2-p-16 pds2-bg-bg-white hover:pds2-bg-bg-02 pds2-transition-colors"
717
- >
718
- <span className="pds2-text-text-03">Other login options for ABHA</span>
719
- <ChevronDownRegularIcon
720
- className={`pds2-w-16 pds2-h-16 pds2-text-text-03 pds2-transition-transform ${
721
- isDropdownOpen ? 'pds2-rotate-180' : ''
722
- }`}
723
- />
724
- </button>
725
-
726
- {/* Dropdown Content */}
727
- {isDropdownOpen && (
728
- <div>
729
- {/* Login -> ABHA Number */}
730
- <button
731
- onClick={() => {
732
- setIsDropdownOpen(false);
733
- setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.ABHA_NUMBER);
734
- setIsAbhaNumberSheetOpen(true);
735
- }}
736
- className="pds2-w-full pds2-flex pds2-items-center pds2-justify-between pds2-p-12 hover:pds2-bg-bg-02 pds2-transition-colors"
737
- >
738
- <div className="pds2-flex pds2-items-center pds2-gap-12">
739
- <div className="pds2-w-40 pds2-h-40 pds2-rounded-full pds2-bg-bg-02 pds2-flex pds2-items-center pds2-justify-center">
740
- <img
741
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
742
- alt="ABHA"
743
- className="pds2-w-24 pds2-h-24"
744
- />
745
- </div>
746
- <span className="Body1Regular pds2-text-text-black">Login with ABHA Number</span>
747
- </div>
748
- <ChevronDownRegularIcon className="pds2-w-16 pds2-h-16 -pds2-rotate-90 pds2-text-text-03" />
749
- </button>
750
-
751
- {/* Login with ABHA Address */}
752
- <button
753
- onClick={() => {
754
- setIsDropdownOpen(false);
755
- setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.PHR_ADDRESS);
756
- setIsPhrAddressSheetOpen(true);
757
- }}
758
- className="pds2-w-full pds2-flex pds2-items-center pds2-justify-between pds2-p-12 hover:pds2-bg-bg-02 pds2-transition-colors"
759
- >
760
- <div className="pds2-flex pds2-items-center pds2-gap-12">
761
- <div className="pds2-w-40 pds2-h-40 pds2-rounded-full pds2-bg-bg-02 pds2-flex pds2-items-center pds2-justify-center">
762
- <img
763
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
764
- alt="ABHA"
765
- className="pds2-w-24 pds2-h-24"
766
- />
767
- </div>
768
- <span className="Body1Regular pds2-text-text-black">Login with ABHA Address</span>
769
- </div>
770
- <ChevronDownRegularIcon className="pds2-w-16 pds2-h-16 -pds2-rotate-90 pds2-text-text-03" />
771
- </button>
772
- </div>
773
- )}
774
- </div>
775
- </div>
776
-
777
- {/* Bottom Sheet for ABHA Number */}
778
- <AbhaBottomSheet isOpen={isAbhaNumberSheetOpen} setIsOpen={setIsAbhaNumberSheetOpen}>
779
- <div className="pds2-p-24 pds2-text-center pds2-h-full pds2-flex pds2-flex-col">
780
- {/* Close button */}
781
- <div className="pds2-flex pds2-justify-end pds2-mb-16">
782
- <button
783
- onClick={() => {
784
- setIsAbhaNumberSheetOpen(false);
785
- setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.MOBILE);
786
- }}
787
- className="pds2-w-24 pds2-h-24 pds2-flex pds2-items-center pds2-justify-center pds2-text-text-03 hover:pds2-text-text-black"
788
- >
789
-
790
- </button>
791
- </div>
792
-
793
- {/* Content - flex grow to fill available space */}
794
- <div className="pds2-flex-1 pds2-flex pds2-flex-col pds2-justify-start">
795
- {/* ABHA Logo */}
796
- <div className="pds2-flex pds2-justify-center pds2-mb-16">
797
- <div className="pds2-w-64 pds2-h-64 pds2-rounded-full pds2-bg-bg-01 pds2-flex pds2-items-center pds2-justify-center">
798
- <img
799
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
800
- alt="ABHA Logo"
801
- className="pds2-w-48 pds2-h-48"
802
- />
803
- </div>
804
- </div>
805
-
806
- {/* Title and Description */}
807
- <h2 className="Heading3Semibold pds2-text-text-black">Login with ABHA Number</h2>
808
- <p className="Body2Regular pds2-text-text-03 pds2-mb-24">
809
- Enter your 14 digit ABHA Number
810
- </p>
811
-
812
- {/* Input Field */}
813
- <div className="pds2-mb-24">
814
- <Pds2InputField
815
- value={identifierValue}
816
- onChange={handleIdentifierValueChange}
817
- placeholder="00-0000-0000-0000"
818
- padding="pds2-p-18"
819
- textStyle="Body2Regular pds2-text-center pds2-text-lg"
820
- borderStyle="focus-within:pds2-border-border-brand-01"
821
- type="tel"
822
- inputMode="numeric"
823
- autoFocus={true}
824
- // className="pds2-w-full"
825
- />
826
- </div>
827
-
828
- {error && <div className="pds2-text-text-error Body3Regular">{error}</div>}
829
- {/* Next Button */}
830
- <Pds2Button
831
- title="Next"
832
- IconComponent={() => (
833
- <ChevronDownRegularIcon className="pds2-w-16 pds2-h-16 -pds2-rotate-90 pds2-ml-8" />
834
- )}
835
- state={!identifierValue || abdmLoginInitApiStatus === LOADING_STATE.LOADING ? 'disabled' : 'enabled'}
836
- onClick={() => handleNextClick("after_enter_abha_number_on_click_by_user")}
837
- className="pds2-w-full"
838
- isLoading={abdmLoginInitApiStatus === LOADING_STATE.LOADING}
839
- />
840
- </div>
841
- </div>
842
- </AbhaBottomSheet>
843
-
844
- {/* Bottom Sheet for ABHA Address */}
845
- <AbhaBottomSheet isOpen={isPhrAddressSheetOpen} setIsOpen={setIsPhrAddressSheetOpen}>
846
- <div className="pds2-p-24 pds2-text-center pds2-h-full pds2-flex pds2-flex-col">
847
- {/* Close button */}
848
- <div className="pds2-flex pds2-justify-end pds2-mb-16">
849
- <button
850
- onClick={() => {
851
- setIsPhrAddressSheetOpen(false);
852
- setAbhaAuthFlowMethod(ABHA_AUTH_FLOW_METHOD.MOBILE);
853
- }}
854
- className="pds2-w-24 pds2-h-24 pds2-flex pds2-items-center pds2-justify-center pds2-text-text-03 hover:pds2-text-text-black"
855
- >
856
-
857
- </button>
858
- </div>
859
-
860
- {/* Content - flex grow to fill available space */}
861
- <div className="pds2-flex-1 pds2-flex pds2-flex-col pds2-justify-start">
862
- {/* ABHA Logo */}
863
- <div className="pds2-flex pds2-justify-center pds2-mb-16">
864
- <div className="pds2-w-64 pds2-h-64 pds2-rounded-full pds2-bg-bg-01 pds2-flex pds2-items-center pds2-justify-center">
865
- <img
866
- src="https://cdn.eka.care/vagus/cm4ml1lwu00000tfs1okl7hs9.webp"
867
- alt="ABHA Logo"
868
- className="pds2-w-48 pds2-h-48"
869
- />
870
- </div>
871
- </div>
872
-
873
- {/* Title and Description */}
874
- <h2 className="Heading3Semibold pds2-text-text-black">Login with ABHA Address</h2>
875
- <p className="Body2Regular pds2-text-text-03 pds2-mb-24">
876
- Enter your ABHA Address below
877
- </p>
878
-
879
- {/* Input Field with suffix */}
880
- <div className="pds2-mb-24 pds2-relative">
881
- <Pds2InputField
882
- value={identifierValue}
883
- onChange={handleIdentifierValueChange}
884
- placeholder="Enter ABHA Address"
885
- inputMode="text"
886
- autoFocus={true}
887
- // className="pds2-w-full pds2-pr-64"
888
- />
889
- <div className="pds2-absolute pds2-right-16 pds2-top-16 Body1Regular pds2-text-text-03">
890
- {isProd ? '@abdm' : '@sbx'}
891
- </div>
892
- </div>
893
-
894
- {error && <div className="pds2-text-text-error Body3Regular">{error}</div>}
895
-
896
- {/* Next Button */}
897
- <Pds2Button
898
- title="Next"
899
- IconComponent={() => (
900
- <ChevronDownRegularIcon className="pds2-w-16 pds2-h-16 -pds2-rotate-90 pds2-ml-8" />
901
- )}
902
- state={!identifierValue || abdmLoginInitApiStatus === LOADING_STATE.LOADING ? 'disabled' : 'enabled'}
903
- onClick={() => handleNextClick("after_enter_abha_address_on_click_by_user")}
904
- className="pds2-w-full"
905
- isLoading={abdmLoginInitApiStatus === LOADING_STATE.LOADING}
906
- />
907
- </div>
908
- </div>
909
- </AbhaBottomSheet>
910
- </>
911
- );
912
- };
913
-
914
- export default LoginorCreateAbhaScreen;
915
-
916
- interface AbhaBottomSheetProps {
917
- isOpen: boolean;
918
- setIsOpen: (isOpen: boolean) => void;
919
- children: React.ReactNode;
920
- overlayClassName?: string;
921
- }
922
-
923
- const AbhaBottomSheet: React.FC<AbhaBottomSheetProps> = ({
924
- isOpen,
925
- setIsOpen,
926
- children,
927
- overlayClassName = 'pds2-bg-text-black pds2-bg-opacity-50',
928
- }) => {
929
- if (!isOpen) return null;
930
-
931
- return (
932
- <div className="pds2-absolute pds2-inset-0 pds2-z-50 pds2-flex pds2-items-end">
933
- {/* Overlay */}
934
- <div
935
- className={`pds2-absolute pds2-inset-0 ${overlayClassName}`}
936
- style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)' }}
937
- onClick={() => setIsOpen(false)}
938
- />
939
-
940
- {/* Bottom Sheet */}
941
- <div
942
- className="pds2-relative pds2-bg-bg-white pds2-rounded-t-24 pds2-w-full"
943
- style={{
944
- height: '75%',
945
- maxHeight: '600px',
946
- overflowY: 'auto',
947
- }}
948
- >
949
- {children}
950
- </div>
951
- </div>
952
- );
953
- };