@eka-care/abha-stg 0.1.34 → 0.1.35

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 (116) hide show
  1. package/README.md +369 -101
  2. package/{dist/index.html → index.html} +1 -2
  3. package/package/styles/pds2/border.ts +69 -0
  4. package/package/styles/pds2/colors.ts +70 -0
  5. package/package/styles/pds2/spacing.ts +1007 -0
  6. package/package/tailwind/tailwind.config.ts +124 -0
  7. package/package.json +9 -8
  8. package/postcss.config.js +6 -0
  9. package/scripts/build-purged-css.cjs +70 -0
  10. package/src/App.css +0 -0
  11. package/src/App.tsx +43 -0
  12. package/src/api-queries/aorta-go/v3/get-profile-patient.ts +32 -0
  13. package/src/api-queries/aorta-go/v3/get-profiles-phr-user.ts +26 -0
  14. package/src/api-queries/aorta-go/v3/post-auth-init-v2.ts +34 -0
  15. package/src/api-queries/aorta-go/v3/post-auth-logout-v2.ts +32 -0
  16. package/src/api-queries/aorta-go/v3/post-auth-verify-v2.ts +38 -0
  17. package/src/api-queries/aorta-go/v3/post-profile-switch.ts +39 -0
  18. package/src/api-queries/ndhm/get-abdm-register-suggest.ts +37 -0
  19. package/src/api-queries/ndhm/get-pincode-details.ts +28 -0
  20. package/src/api-queries/ndhm/post-abdm-login-init.ts +37 -0
  21. package/src/api-queries/ndhm/post-abdm-login-phr.ts +37 -0
  22. package/src/api-queries/ndhm/post-abdm-login-verify.ts +37 -0
  23. package/src/api-queries/ndhm/post-abdm-profile-eka-link-phr.ts +40 -0
  24. package/src/api-queries/ndhm/post-abdm-profile-eka.ts +66 -0
  25. package/src/api-queries/ndhm/post-abdm-register-abha-number-create-phr.ts +37 -0
  26. package/src/api-queries/ndhm/post-abdm-register-mobile-create-phr.ts +66 -0
  27. package/src/api-queries/ndhm/post-abdm-register-mobile-resend-otp.ts +32 -0
  28. package/src/api-queries/ndhm/post-abdm-register-mobile-verify.ts +38 -0
  29. package/src/api-queries/ndhm/post-abdm-register-phr-check.ts +34 -0
  30. package/src/api-queries/ndhm/post-register-aadhaar-create-phr.ts +37 -0
  31. package/src/api-queries/ndhm/post-register-aadhaar-init.ts +34 -0
  32. package/src/api-queries/ndhm/post-register-aadhaar-mobile-resend-otp.ts +34 -0
  33. package/src/api-queries/ndhm/post-register-aadhaar-mobile-verify.ts +37 -0
  34. package/src/api-queries/ndhm/post-register-aadhaar-resend-otp.ts +34 -0
  35. package/src/api-queries/ndhm/post-register-aadhaar-verify.ts +40 -0
  36. package/src/api-queries/ndhm/post-register-mobile-init.ts +34 -0
  37. package/src/api-queries/use-get-profiles-patient.ts +12 -0
  38. package/src/api-queries/use-get-profiles-phr-user.ts +28 -0
  39. package/src/api-queries/use-post-abdm-login-verify-v1.ts +26 -0
  40. package/src/api-queries/use-post-auth-verify-v2.ts +50 -0
  41. package/src/api-queries/use-post-profile-switch.ts +58 -0
  42. package/src/api-queries/use-post-register-mobile-create-phr.ts +39 -0
  43. package/src/api-queries/user-post-abdm-profile-login-phr.ts +26 -0
  44. package/src/assets/Success.json +1 -0
  45. package/src/assets/react.svg +1 -0
  46. package/src/atoms/button/custom-button.tsx +32 -0
  47. package/src/atoms/button/index.tsx +40 -0
  48. package/src/atoms/button/types.d.ts +31 -0
  49. package/src/atoms/header.tsx +25 -0
  50. package/src/atoms/input-field/index.tsx +63 -0
  51. package/src/atoms/input-field/patient-input-field.tsx +16 -0
  52. package/src/atoms/input-field/types.ts +24 -0
  53. package/src/atoms/pds2-otp-input/index.tsx +35 -0
  54. package/src/atoms/pds2-otp-input/types.d.ts +3 -0
  55. package/src/atoms/single-input-chip/index.tsx +32 -0
  56. package/src/atoms/single-input-chip/types.ts +6 -0
  57. package/src/atoms/spinner.tsx +33 -0
  58. package/src/atoms/text-separator.tsx +11 -0
  59. package/src/atoms/ui/spinner.tsx +75 -0
  60. package/src/constants/constants.ts +376 -0
  61. package/src/fetch-client/index.ts +164 -0
  62. package/src/index.css +152 -0
  63. package/src/main.tsx +374 -0
  64. package/src/molecules/abha/bottom-sheet/bottom-sheet-wrapper.tsx +40 -0
  65. package/src/molecules/abha/bottom-sheet/index.tsx +66 -0
  66. package/src/molecules/abha/spaced-input-component.tsx +168 -0
  67. package/src/molecules/copyright-year.tsx +16 -0
  68. package/src/molecules/exit-popup/index.tsx +101 -0
  69. package/src/molecules/pds2-otp-component/index.tsx +147 -0
  70. package/src/organisms/abha/abha-header.tsx +25 -0
  71. package/src/organisms/abha/abha-stepper.tsx +83 -0
  72. package/src/organisms/abha/error-bottom-sheet.tsx +27 -0
  73. package/src/organisms/abha/otp-card.tsx +99 -0
  74. package/src/organisms/abha/verification-status.tsx +30 -0
  75. package/src/organisms/choose-language/choose-language.tsx +53 -0
  76. package/src/organisms/choose-language/types.ts +10 -0
  77. package/src/organisms/screen-switcher/screen-switcher.tsx +80 -0
  78. package/src/routes/abha-aadhaar-verification-status-screen.tsx +246 -0
  79. package/src/routes/abha-created-screen.tsx +45 -0
  80. package/src/routes/abha-login-otp-verify-screen.tsx +519 -0
  81. package/src/routes/abha-mobile-linking-status-screen.tsx +267 -0
  82. package/src/routes/abha-otp-and-mobile-screen.tsx +435 -0
  83. package/src/routes/abha-phone-number-verification-screen.tsx +388 -0
  84. package/src/routes/create-abha-address-screen.tsx +928 -0
  85. package/src/routes/create-abha-with-aadhaar-screen.tsx +986 -0
  86. package/src/routes/create-eka-profile-screen.tsx +831 -0
  87. package/src/routes/get-all-profiles-screen.tsx +161 -0
  88. package/src/routes/login-or-create-abha-address-screen.tsx +1056 -0
  89. package/src/routes/login-with-abha-screen.tsx +454 -0
  90. package/src/routes/select-abha-from-list-screen.tsx +792 -0
  91. package/src/routes/select-eka-profile-screen.tsx +446 -0
  92. package/src/routes/utils/trackAbhaEvent.ts +41 -0
  93. package/src/stores/auth-abha-store/index.ts +152 -0
  94. package/src/stores/auth-abha-store/types.ts +217 -0
  95. package/src/utils/mock-auth-response.ts +29 -0
  96. package/src/utils/send-event-utils.ts +76 -0
  97. package/src/utils/validations.ts +89 -0
  98. package/src/vite-env.d.ts +1 -0
  99. package/tailwind.config.ts +9 -0
  100. package/tsconfig.json +25 -0
  101. package/tsconfig.node.json +10 -0
  102. package/tsconfig.node.tsbuildinfo +1 -0
  103. package/tsconfig.tsbuildinfo +1 -0
  104. package/vite.config.d.ts +2 -0
  105. package/vite.config.js +30 -0
  106. package/vite.config.ts +35 -0
  107. package/dist/sdk/abha/css/abha.css +0 -1
  108. package/dist/sdk/abha/js/abha.js +0 -146
  109. /package/{dist → public}/images/adhaar.webp +0 -0
  110. /package/{dist → public}/images/at-the-rate.webp +0 -0
  111. /package/{dist → public}/images/avatar.webp +0 -0
  112. /package/{dist → public}/images/ayushman-bharat.webp +0 -0
  113. /package/{dist → public}/images/circle-checkmark.webp +0 -0
  114. /package/{dist → public}/images/link-abha.webp +0 -0
  115. /package/{dist → public}/images/national-authority.webp +0 -0
  116. /package/{dist → public}/images/three-dots.webp +0 -0
@@ -0,0 +1,267 @@
1
+ import { ABHA_V3_SKIP_STATES, GET_EXTRA_HEADERS, setIndividualEnv, TProfileRecord } from '../constants/constants';
2
+
3
+ import { useEffect, useState, useRef } from 'react';
4
+ import { onAbhaSuccess, unMount } from '../main';
5
+ import AbhaVerificationStatus from '../organisms/abha/verification-status';
6
+ import useAuthAbhaStore from '../stores/auth-abha-store';
7
+ import { SCREEN_NAMES } from '../stores/auth-abha-store/types';
8
+
9
+ import { getMockAuthVerifyResponse } from '../utils/mock-auth-response';
10
+ import handleSendEvent from '../utils/send-event-utils';
11
+ import getProfilesPatient from '../api-queries/aorta-go/v3/get-profile-patient';
12
+ import postAuthVerifyV2 from '../api-queries/aorta-go/v3/post-auth-verify-v2';
13
+
14
+ const AbhaMobileLinkingStatusScreen = () => {
15
+ const aadhaarVerificationSkipStateStatus = useAuthAbhaStore(
16
+ (state) => state.aadhaarVerificationSkipStateStatus
17
+ );
18
+ const authTxnId = useAuthAbhaStore((state) => state.authTxnId);
19
+ const ekaSmallToken = useAuthAbhaStore((state) => state.ekaSmallToken);
20
+ const oid = useAuthAbhaStore((state) => state.oid);
21
+ const setScreen = useAuthAbhaStore((state) => state.setScreen);
22
+ const [loadingStatus, setLoadingStatus] = useState<boolean>(true);
23
+ const setEkaProfileInfo = useAuthAbhaStore((state) => state.setEkaProfileInfo);
24
+ const clientId = useAuthAbhaStore((state) => state.clientId);
25
+ const isEkaAppLogin = useAuthAbhaStore((state) => state.isEkaAppLogin);
26
+ const ekaProfileInfo = useAuthAbhaStore((state) => state.ekaProfileInfo);
27
+ const validGenders = ['M', 'F', 'O', 'U'] as const;
28
+ const hasApiTriggered = useRef(false);
29
+ const isNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.isNewLoginOrCreateFlow);
30
+ const txnId = useAuthAbhaStore((state) => state.txnId);
31
+ const extra_headers = GET_EXTRA_HEADERS();
32
+
33
+ // Analytics event tracker
34
+ const trackAbhaEvent = ({ name, data = {} }: { name: string; data?: Record<string, any> }) => {
35
+ const baseProps = {
36
+ login_platform: clientId,
37
+ is_eka_app_login: isEkaAppLogin ? 'true' : 'false',
38
+ is_new_login_or_create_flow: isNewLoginOrCreateFlow ? 'true' : 'false',
39
+ txn_id: txnId || 'missing txnId',
40
+ oid: extra_headers?.['X-User-ID'] ? 'true' : 'false',
41
+ access_token: extra_headers?.['auth'] ? 'true' : 'false',
42
+ };
43
+
44
+ const eventData = {
45
+ ...baseProps,
46
+ ...data,
47
+ };
48
+
49
+ handleSendEvent({
50
+ eventName: name,
51
+ eventData,
52
+ });
53
+
54
+ window.curio?.pushToMixpanel?.(name, eventData);
55
+ };
56
+
57
+ useEffect(() => {
58
+ // Start a 500ms artificial loading timeout
59
+ const p1 = new Promise((resolve) => {
60
+ setTimeout(() => {
61
+ resolve(setLoadingStatus(false));
62
+ }, 500);
63
+ });
64
+
65
+ // Track the page view for successful mobile verification
66
+ trackAbhaEvent({
67
+ name: 'page_view',
68
+ data: {
69
+ page_view: 'mobile_verified_successful',
70
+ platform: clientId,
71
+ },
72
+ });
73
+ // Main logic after artificial loading
74
+ async function dummyLoadingEffect() {
75
+ await p1;
76
+
77
+ setTimeout(async () => {
78
+ // Trigger logic only if skip state is ABHA_CREATE or ABHA_END
79
+ if (
80
+ // here the status will be abha create, in mobile flow
81
+ // then redirect the user to get all profiles screen.
82
+ aadhaarVerificationSkipStateStatus === ABHA_V3_SKIP_STATES.ABHA_CREATE ||
83
+ aadhaarVerificationSkipStateStatus === ABHA_V3_SKIP_STATES.ABHA_END
84
+ ) {
85
+
86
+ trackAbhaEvent({
87
+ name: 'abha_create_mobile_initiate',
88
+ data: {
89
+ platform: clientId,
90
+ oid_received : oid,
91
+ txn_id : txnId,
92
+ skip_state : aadhaarVerificationSkipStateStatus,
93
+ },
94
+ });
95
+
96
+ // If X-User-ID exists and API not yet triggered, fetch profile and store Eka info
97
+ if (oid && !hasApiTriggered.current) {
98
+ // Only call API if extraHeaders is NOT present
99
+ const profile = await getProfilesPatient();
100
+ hasApiTriggered.current = true;
101
+ if (profile) {
102
+ setEkaProfileInfo({
103
+ date_of_birth: profile.dob as string,
104
+ firstname: profile.fn,
105
+ lastname: profile.ln as string,
106
+ pincode: '',
107
+ gender: profile.gen as string,
108
+ oid: profile?.oid,
109
+ middlename: profile?.mn,
110
+ abha_address: profile?.['health-ids']?.[0],
111
+ abha_number: profile?.abha_number,
112
+ });
113
+ }
114
+ }
115
+
116
+ // handling for ABHA_END if OID is present
117
+ if (
118
+ isEkaAppLogin &&
119
+ aadhaarVerificationSkipStateStatus === ABHA_V3_SKIP_STATES.ABHA_END
120
+ ) {
121
+ // here if the oid is present , then call auth verify and unmount the sdk
122
+ if (oid) {
123
+ const gender = validGenders.includes(ekaProfileInfo?.gender as any)
124
+ ? (ekaProfileInfo?.gender as 'M' | 'F' | 'O' | 'U')
125
+ : undefined;
126
+
127
+ const authProfile: TProfileRecord = {
128
+ oid: ekaProfileInfo?.oid || '',
129
+ fln: ekaProfileInfo?.name || '',
130
+ dob: ekaProfileInfo?.date_of_birth,
131
+ gen: gender,
132
+ mobile: ekaProfileInfo?.mobile,
133
+ at: '',
134
+ fn: ekaProfileInfo?.firstname || '',
135
+ mn: ekaProfileInfo?.middlename || '',
136
+ ln: ekaProfileInfo?.lastname || '',
137
+ 'health-ids': ekaProfileInfo?.abha_address
138
+ ? [ekaProfileInfo.abha_address]
139
+ : undefined,
140
+ abha_number: ekaProfileInfo?.abha_number || '',
141
+ };
142
+
143
+ trackAbhaEvent({
144
+ name: 'abha_mobile_linking_success',
145
+ data: {
146
+ type: 'unmount',
147
+ isEkaAppLogin: isEkaAppLogin,
148
+ skip_state: aadhaarVerificationSkipStateStatus,
149
+ },
150
+ });
151
+ const authResponse = getMockAuthVerifyResponse(authProfile);
152
+ // Handle SDK callback or fallback to JS
153
+ if (window.EkaAbha && window.EkaAbha.onAbhaSuccess) {
154
+ window.EkaAbha?.onAbhaSuccess(JSON.stringify({ response: authResponse }));
155
+ return;
156
+ }
157
+ // @ts-ignore
158
+ onAbhaSuccess({ response: authResponse });
159
+ unMount();
160
+ return;
161
+ }
162
+ }
163
+ // If app login and ABHA_CREATE, redirect to create Eka profile
164
+ if (
165
+ isEkaAppLogin &&
166
+ aadhaarVerificationSkipStateStatus === ABHA_V3_SKIP_STATES.ABHA_CREATE
167
+ ) {
168
+ // since the flow is inside the app, and the skip_state is not abha end, then redirect to create eka profile
169
+ trackAbhaEvent({
170
+ name: 'navigate_to_screen',
171
+ data: {
172
+ destination: 'create_eka_profile',
173
+ reason: 'abha_create_from_mobile_flow',
174
+ },
175
+ });
176
+ setScreen(SCREEN_NAMES.CREATE_EKA_PROFILE);
177
+ return;
178
+ }
179
+ // Check for missing tokens and track error if any missing
180
+ if (!authTxnId || !ekaSmallToken) {
181
+ trackAbhaEvent({
182
+ name: 'authTxnId_or_minToken_not_found',
183
+ data: {
184
+ platform: clientId,
185
+ type: 'error',
186
+ auth_txnId: authTxnId || 'missing_authTxnId',
187
+ auth_txnId_exists: !!authTxnId,
188
+ ekaSmallToken_exists: !!ekaSmallToken,
189
+ },
190
+ });
191
+ return;
192
+ }
193
+ // Call verify API
194
+ const verifyResponse = await postAuthVerifyV2({
195
+ txn_id: authTxnId,
196
+ token: ekaSmallToken,
197
+ });
198
+ // Store token in headers
199
+ if (verifyResponse.data) {
200
+ setIndividualEnv({
201
+ extraHeaders: {
202
+ auth: verifyResponse.data?.tokens.sess,
203
+ },
204
+ });
205
+
206
+ // If ABHA_END, finish login with onAbhaSuccess if OID is present
207
+ if (aadhaarVerificationSkipStateStatus === ABHA_V3_SKIP_STATES.ABHA_END) {
208
+ if (oid) {
209
+ // for ios specific handling
210
+ if (window.EkaAbha && window.EkaAbha.onAbhaSuccess) {
211
+ window.EkaAbha?.onAbhaSuccess(JSON.stringify({ response: verifyResponse }));
212
+ return;
213
+ }
214
+ // @ts-ignore
215
+ onAbhaSuccess({ response: verifyResponse });
216
+ unMount();
217
+ return;
218
+ }
219
+ // Fallback if OID is not present
220
+ setIndividualEnv({
221
+ extraHeaders: {
222
+ auth: verifyResponse.data?.tokens.sess,
223
+ },
224
+ });
225
+ trackAbhaEvent({
226
+ name: 'navigate_to_screen',
227
+ data: {
228
+ destination: 'get_all_profiles',
229
+ reason: 'abha_end_with_no_oid',
230
+ },
231
+ });
232
+ setScreen(SCREEN_NAMES.GET_ALL_PROFILES);
233
+ return;
234
+ }
235
+ setIndividualEnv({
236
+ extraHeaders: {
237
+ auth: verifyResponse.data?.tokens.sess,
238
+ },
239
+ });
240
+ // Default case for verified session → GET ALL PROFILES
241
+ trackAbhaEvent({
242
+ name: 'navigate_to_screen',
243
+ data: {
244
+ destination: 'get_all_profiles',
245
+ reason: 'auth_verify_success',
246
+ },
247
+ });
248
+ setScreen(SCREEN_NAMES.GET_ALL_PROFILES);
249
+ return;
250
+ }
251
+ } else {
252
+ }
253
+ }, 2000);
254
+ }
255
+ dummyLoadingEffect();
256
+ }, []);
257
+
258
+ return (
259
+ <AbhaVerificationStatus
260
+ loading={loadingStatus}
261
+ loadingText="Verifying..."
262
+ successText="Successfully linked mobile number with ABHA!"
263
+ />
264
+ );
265
+ };
266
+
267
+ export default AbhaMobileLinkingStatusScreen;
@@ -0,0 +1,435 @@
1
+ import {
2
+ ArrowLeftRegularIcon,
3
+ CircleInfoRegularIcon,
4
+ EkaIcon,
5
+ PhoneSolidIcon,
6
+ } from '@eka-care/icons';
7
+ import { LOADING_STATE, ABHA_AUTH_FLOW_METHOD, GET_EXTRA_HEADERS } from '../constants/constants';
8
+ import React, { useEffect, useRef, useState } from 'react';
9
+ import Pds2Button from '../atoms/button';
10
+ import AbhaHeader from '../organisms/abha/abha-header';
11
+ import AbhaErrorBottomSheet from '../organisms/abha/error-bottom-sheet';
12
+ import AbhaOtpCard from '../organisms/abha/otp-card';
13
+ import useAuthAbhaStore from '../stores/auth-abha-store';
14
+ import { SCREEN_NAMES } from '../stores/auth-abha-store/types';
15
+ import { CustomCheckBox } from './create-abha-with-aadhaar-screen';
16
+ import AbhaStepper from '../organisms/abha/abha-stepper';
17
+ import handleSendEvent from '../utils/send-event-utils';
18
+ import postRegisterAadhaarResendOtp from '../api-queries/ndhm/post-register-aadhaar-resend-otp';
19
+ import postRegisterAadhaarVerify from '../api-queries/ndhm/post-register-aadhaar-verify';
20
+
21
+ const AbhaOtpAndMobileScreen = () => {
22
+ const setAbhaAddressList = useAuthAbhaStore((state) => state.setAbhaAddressList);
23
+ const setScreen = useAuthAbhaStore((state) => state.setScreen);
24
+
25
+ const txnId = useAuthAbhaStore((state) => state.txnId);
26
+ const setTxnId = useAuthAbhaStore((state) => state.setTxnId);
27
+
28
+ const aadhaarOtpSentToHint = useAuthAbhaStore((state) => state.aadhaarOtpSentToHint);
29
+ const setAadhaarVerificationSkipStateStatus = useAuthAbhaStore(
30
+ (state) => state.setAadhaarVerificationSkipStateStatus
31
+ );
32
+ const setEkaSmallToken = useAuthAbhaStore((state) => state.setEkaSmallToken);
33
+ const setOid = useAuthAbhaStore((state) => state.setOid);
34
+ const clearAbhaAuthStore = useAuthAbhaStore((state) => state.clearAbhaAuthStore);
35
+ const setBottomsheetErrorInfo = useAuthAbhaStore((state) => state.setBottomsheetErrorInfo);
36
+ const goBackLoginScreen = useAuthAbhaStore((state) => state.goBackLoginScreen);
37
+
38
+ const [otp, setOtp] = useState('');
39
+ const [isOtpValid, setIsOtpValid] = useState(false);
40
+ const [mobileNumber, setMobileNumber] = useState('');
41
+
42
+ const [error, setError] = useState<string | null>(null);
43
+
44
+ const [isHealthLockerChecked, setIsHealthLockerChecked] = useState(true);
45
+ const [isLinkHealthDataChecked, setIsLinkHealthDataChecked] = useState(true);
46
+
47
+ const [aadhaarVerifyApiStatus, setAadhaarVerifyApiStatus] = useState<LOADING_STATE>(
48
+ LOADING_STATE.IDLE
49
+ );
50
+ const setSelectedAbhaAddress = useAuthAbhaStore((state) => state.setSelectedAbhaAddress);
51
+ const initAbhaAppMobileNumber = useAuthAbhaStore((state) => state.initAbhaAppMobileNumber);
52
+ const setEkaProfileInfo = useAuthAbhaStore((state) => state.setEkaProfileInfo);
53
+ const clientId = useAuthAbhaStore((state) => state.clientId);
54
+ const isEkaAppLogin = useAuthAbhaStore((state) => state.isEkaAppLogin);
55
+ const isNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.isNewLoginOrCreateFlow);
56
+ const extra_headers = GET_EXTRA_HEADERS();
57
+
58
+ const selectedMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
59
+
60
+ // Analytics event tracker
61
+ const trackAbhaEvent = ({ name, data = {} }: { name: string; data?: Record<string, any> }) => {
62
+ const baseProps = {
63
+ login_platform: clientId,
64
+ is_eka_app_login: isEkaAppLogin ? 'true' : 'false',
65
+ is_new_login_or_create_flow: isNewLoginOrCreateFlow ? 'true' : 'false',
66
+ txn_id: txnId || 'missing txnId',
67
+ oid: extra_headers?.['X-User-ID'] ? 'true' : 'false',
68
+ access_token: extra_headers?.['auth'] ? 'true' : 'false',
69
+ flow: selectedMethod ?? ""
70
+ };
71
+
72
+ const eventData = {
73
+ ...baseProps,
74
+ ...data,
75
+ };
76
+
77
+ handleSendEvent({
78
+ eventName: name,
79
+ eventData,
80
+ });
81
+
82
+ window.curio?.pushToMixpanel?.(name, eventData);
83
+ };
84
+
85
+ useEffect(() => {
86
+ if (initAbhaAppMobileNumber) {
87
+ setMobileNumber(initAbhaAppMobileNumber);
88
+ }
89
+ }, [initAbhaAppMobileNumber]);
90
+
91
+ const handleOtpCompletion = ({ otp }: { otp: string }) => {
92
+ trackAbhaEvent({
93
+ name: 'abha_aadhaar_otp_enter_clicks',
94
+ data: {
95
+ page_view: 'aadhaar_verification',
96
+ platform: clientId,
97
+ otp_entered: true,
98
+ },
99
+ });
100
+ setOtp(otp);
101
+ };
102
+
103
+ const handleMobileNumberChange = ({
104
+ mobileNumber: newMobileNumber,
105
+ }: {
106
+ mobileNumber: string;
107
+ }) => {
108
+ setMobileNumber(newMobileNumber);
109
+
110
+ trackAbhaEvent({
111
+ name: 'abha_aadhaar_mobile_otp_enter',
112
+ data: {
113
+ page_view: 'aadhaar_verification',
114
+ platform: clientId
115
+ },
116
+ });
117
+ };
118
+
119
+ const handleResendOtpClick = async () => {
120
+ if (!txnId) {
121
+ trackAbhaEvent({
122
+ name: 'aadhaar_otp_resend_clicked_no_txnId',
123
+ data: {
124
+ platform: clientId,
125
+ txn_id: txnId || 'missing_txnId',
126
+ txn_id_exists: !!txnId
127
+ },
128
+ });
129
+ return;
130
+ }
131
+
132
+ const {
133
+ txn_id,
134
+ error: resendOtpError,
135
+ action: errorAction,
136
+ } = await postRegisterAadhaarResendOtp({ txn_id: txnId });
137
+
138
+ if (!txn_id) {
139
+ trackAbhaEvent({
140
+ name: 'aadhaar_otp_resend_failed',
141
+ data: {
142
+ platform: clientId,
143
+ reason: resendOtpError || 'no_txn_id',
144
+ reason_exists: !!resendOtpError,
145
+ },
146
+ });
147
+ setError(resendOtpError || 'Something went wrong, please try again');
148
+ if (errorAction) {
149
+ setBottomsheetErrorInfo(errorAction);
150
+ }
151
+ return;
152
+ }
153
+
154
+ trackAbhaEvent({
155
+ name: 'aadhaar_otp_resend_success',
156
+ data: {
157
+ platform: clientId,
158
+ txn_id: txn_id,
159
+ },
160
+ });
161
+
162
+ // Update the txnId in the store with the new one
163
+ setTxnId(txn_id);
164
+ };
165
+
166
+ const handleVerifyClick = async () => {
167
+ if (!txnId) {
168
+ trackAbhaEvent({
169
+ name: 'aadhaar_otp_verification_no_txnId',
170
+ data: {
171
+ platform: clientId,
172
+ type: 'verify',
173
+ txn_id: txnId || 'missing_txnId',
174
+ txn_id_exists: !!txnId,
175
+ },
176
+ });
177
+ return;
178
+ }
179
+
180
+ trackAbhaEvent({
181
+ name: 'abha_aadhaar_otp_verify_submitted',
182
+ data: {
183
+ platform: clientId,
184
+ type: 'verify',
185
+ },
186
+ });
187
+
188
+ setAadhaarVerifyApiStatus(LOADING_STATE.LOADING);
189
+ const {
190
+ txn_id,
191
+ skip_state,
192
+ profile,
193
+ eka,
194
+ error,
195
+ abha_profiles,
196
+ action: errorAction,
197
+ } = await postRegisterAadhaarVerify({
198
+ otp,
199
+ mobile: mobileNumber,
200
+ txn_id: txnId,
201
+ });
202
+
203
+ if (!txn_id || !skip_state) {
204
+ trackAbhaEvent({
205
+ name: 'aadhaar_otp_verification_failed',
206
+ data: {
207
+ platform: clientId,
208
+ reason: error || 'missing_txn_id_or_skip_state',
209
+ txn_id_exists: !!txn_id,
210
+ skip_state_exists: !!skip_state,
211
+ },
212
+ });
213
+ setAadhaarVerifyApiStatus(LOADING_STATE.REJECTED);
214
+ setError(error || 'Something went wrong, please try again');
215
+ if (errorAction) {
216
+ setBottomsheetErrorInfo(errorAction);
217
+ }
218
+ return;
219
+ }
220
+
221
+ trackAbhaEvent({
222
+ name: 'aadhaar_otp_verification_success',
223
+ data: {
224
+ platform: clientId,
225
+ skip_state,
226
+ oid: eka?.oid,
227
+ },
228
+ });
229
+
230
+ setAadhaarVerifyApiStatus(LOADING_STATE.RESOLVED);
231
+ setAadhaarVerificationSkipStateStatus(skip_state);
232
+ if (eka?.min_token) {
233
+ setEkaSmallToken(eka.min_token);
234
+ }
235
+
236
+ if (profile && profile.abha_address) {
237
+ setSelectedAbhaAddress(profile.abha_address);
238
+ }
239
+
240
+ if (eka?.oid) {
241
+ setOid(eka.oid);
242
+ }
243
+
244
+ // in HMIS case, when we are trying to create a new patient,
245
+ // then oid will not be present in the headers.
246
+ // but if the abha address is created elsewhere,
247
+ // server will send the oid in the response.
248
+
249
+ if (profile) {
250
+ setEkaProfileInfo({
251
+ date_of_birth: `${profile.year_of_birth}-${String(profile.month_of_birth).padStart(2, '0')}-${String(profile.day_of_birth).padStart(2, '0')}`,
252
+ firstname: profile.first_name as string,
253
+ lastname: profile.last_name as string,
254
+ pincode: profile.pincode as string,
255
+ gender: profile.gender as string,
256
+ name: (profile.first_name + ' ' + profile.last_name) as string,
257
+ mobile: profile.mobile,
258
+ oid: eka?.oid,
259
+ abha_address: profile.abha_address,
260
+ abha_number: profile.abha_number,
261
+ });
262
+ }
263
+
264
+
265
+ trackAbhaEvent({
266
+ name: 'abha_aadhaar_otp_verification_success',
267
+ data: {
268
+ platform: clientId,
269
+ skip_state,
270
+ oid: eka?.oid,
271
+ },
272
+ });
273
+
274
+ if(abha_profiles){
275
+ setAbhaAddressList(abha_profiles);
276
+ }
277
+ setScreen(SCREEN_NAMES.AADHAAR_VERIFICATION_STATUS);
278
+ // setScreen(SCREEN_NAMES.SELECT_ABHA_FROM_LIST);
279
+ return;
280
+
281
+ };
282
+
283
+ const handleErrorBottomsheetButtonClick = () => {
284
+ setScreen(SCREEN_NAMES.CREATE_ABHA_WITH_AADHAAR);
285
+ const isAppLogin = useAuthAbhaStore.getState().isEkaAppLogin;
286
+ clearAbhaAuthStore();
287
+ useAuthAbhaStore.setState({ isEkaAppLogin: isAppLogin });
288
+ };
289
+
290
+ const isButtonValid =
291
+ isOtpValid && mobileNumber.length === 10 && isHealthLockerChecked && isLinkHealthDataChecked;
292
+
293
+ return (
294
+ <div className="pds2-flex pds2-flex-col pds2-w-full pds2-h-full pds2-bg-bg-01">
295
+ <AbhaHeader
296
+ prefixIcon={
297
+ <button
298
+ className="pds2-w-24 pds2-h-24 pds2-rounded-full pds2-flex pds2-items-center pds2-justify-center ripple"
299
+ onClick={goBackLoginScreen}
300
+ >
301
+ <ArrowLeftRegularIcon className="" />
302
+ </button>
303
+ }
304
+ title="Create ABHA"
305
+ suffixIcon={<EkaIcon className="pds2-w-20 pds2-h-20" />}
306
+ className="pds2-border-b-1 pds2-border-bg-seperator-dark"
307
+ />
308
+
309
+ <AbhaStepper/>
310
+ <div className="pds2-px-16 pds2-pb-16 pds2-space-y-12 pds2-overflow-y-auto pds2-flex-1 pds2-bg-bg-01">
311
+ <AbhaOtpCard
312
+ otpSentToText={
313
+ aadhaarOtpSentToHint || 'Enter OTP sent on mobile number linked with your Aadhaar'
314
+ }
315
+ onOtpCompletion={handleOtpCompletion}
316
+ onResendOtpClick={handleResendOtpClick}
317
+ setIsValid={setIsOtpValid}
318
+ error={error}
319
+ />
320
+ <EnterMobileNumberCard
321
+ mobileNumber={mobileNumber}
322
+ onMobileNumberChange={handleMobileNumberChange}
323
+ isOtpValid={isOtpValid}
324
+ onKeyDown={({ key }) => {
325
+ key === "Enter" && handleVerifyClick();
326
+ }}
327
+ />
328
+ <div className="pds2-space-y-8">
329
+ <CustomCheckBox
330
+ id="health-locker"
331
+ label="Allow Eka Care to create ABHA locker and link health data"
332
+ isCheckboxChecked={isHealthLockerChecked}
333
+ onCheckboxChange={(isChecked) => {
334
+ setIsHealthLockerChecked(isChecked);
335
+ }}
336
+ />
337
+ </div>
338
+ </div>
339
+
340
+ <div className="pds2-p-16 pds2-sticky pds2-bottom-0 pds2-bg-bg-white pds2-w-full pds2-border pds2-border-border-brand-02">
341
+ <Pds2Button
342
+ title="Verify"
343
+ state={(!isButtonValid || aadhaarVerifyApiStatus === LOADING_STATE.LOADING )? 'disabled' : 'enabled'}
344
+ className="pds2-w-full"
345
+ onClick={handleVerifyClick}
346
+ isLoading={aadhaarVerifyApiStatus === LOADING_STATE.LOADING}
347
+ />
348
+ </div>
349
+ <AbhaErrorBottomSheet onSubmitClick={handleErrorBottomsheetButtonClick} />
350
+ </div>
351
+ );
352
+ };
353
+
354
+ export default AbhaOtpAndMobileScreen;
355
+
356
+ const EnterMobileNumberCard = ({
357
+ mobileNumber,
358
+ onMobileNumberChange,
359
+ isOtpValid,
360
+ onKeyDown,
361
+ }: {
362
+ mobileNumber: string;
363
+ onMobileNumberChange: (params: { mobileNumber: string }) => void;
364
+ isOtpValid: boolean;
365
+ onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
366
+ }) => {
367
+ const mobileRef = useRef<HTMLInputElement>(null);
368
+ useEffect(() => {
369
+ if (mobileRef.current && isOtpValid) mobileRef.current.focus();
370
+ }, [isOtpValid]);
371
+
372
+ const selectedMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
373
+ const initAbhaAppMobileNumber = useAuthAbhaStore((state) => state.initAbhaAppMobileNumber);
374
+
375
+ const isMobileNonEditable =
376
+ selectedMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER && !!initAbhaAppMobileNumber;
377
+
378
+ if (initAbhaAppMobileNumber) {
379
+ mobileNumber = initAbhaAppMobileNumber;
380
+ }
381
+
382
+ return (
383
+ <CustomCardLayout>
384
+ <div className="pds2-flex pds2-items-center pds2-space-x-16 pds2-w-full">
385
+ <div className="Body1Regular pds2-text-text-01 pds2-flex-1">
386
+ Enter your mobile number to link your ABHA{' '}
387
+ <sup className="pds2-text-text-error Body3Semibold">*</sup>
388
+ </div>
389
+ <PhoneSolidIcon className="pds2-w-48 pds2-h-48 pds2-text-icon-success-02 pds2-p-6" />
390
+ </div>
391
+ <label className="pds2-relative pds2-border focus-within:pds2-border-border-brand-01 pds2-border-border-03 pds2-rounded-12">
392
+ <span className="Body1Regular pds2-absolute pds2-left-16 pds2-top-1/2 pds2-transform pds2--translate-y-1/2 pds2-text-text-01">
393
+ {'+91 -'}
394
+ </span>
395
+ <input
396
+ ref={mobileRef}
397
+ placeholder="Mobile Number"
398
+ type="tel"
399
+ value={mobileNumber}
400
+ disabled={isMobileNonEditable}
401
+ onPaste={(e) => {
402
+ e.preventDefault();
403
+ const value = e.clipboardData.getData('text').replace(/[^0-9]/g, '');
404
+ onMobileNumberChange({ mobileNumber: value.slice(-10) });
405
+ }}
406
+ onChange={(e) => {
407
+ if (e.target.value.length > 10) return;
408
+ const value = e.target.value.replace(/[^0-9]/g, '');
409
+ onMobileNumberChange({ mobileNumber: value.slice(-10) });
410
+ }}
411
+ maxLength={10}
412
+ className="Body1Regular pds2-w-full pds2-pl-60 pds2-pr-12 pds2-py-12 pds2-rounded-12 pds2-outline-none"
413
+ onKeyDown={onKeyDown}
414
+ />
415
+ </label>
416
+ <div className="pds2-flex pds2-items-center pds2-space-x-8 pds2-text-text-03"></div>
417
+ </CustomCardLayout>
418
+ );
419
+ };
420
+
421
+ export const CustomCardLayout = ({
422
+ children,
423
+ className = 'pds2-space-y-12',
424
+ }: {
425
+ children: React.ReactNode;
426
+ className?: string;
427
+ }) => {
428
+ return (
429
+ <div
430
+ className={`pds2-flex pds2-flex-col pds2-w-full pds2-p-16 pds2-rounded-16 pds2-bg-bg-white ${className}`}
431
+ >
432
+ {children}
433
+ </div>
434
+ );
435
+ };