@eka-care/abha-stg 0.0.40 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +3 -0
- package/.eslintrc +29 -0
- package/.prettierrc +7 -0
- package/.turbo/daemon/da13e0828a6aedf8-turbo.log.2025-10-30 +0 -0
- package/{dist/index.html → index.html} +1 -2
- package/package/styles/pds2/border.ts +69 -0
- package/package/styles/pds2/colors.ts +70 -0
- package/package/styles/pds2/spacing.ts +1007 -0
- package/package/tailwind/tailwind.config.ts +124 -0
- package/package.json +9 -8
- package/postcss.config.js +6 -0
- package/scripts/build-purged-css.cjs +70 -0
- package/src/App.css +0 -0
- package/src/App.tsx +43 -0
- package/src/api-queries/aorta-go/v3/get-profile-patient.ts +32 -0
- package/src/api-queries/aorta-go/v3/get-profiles-phr-user.ts +26 -0
- package/src/api-queries/aorta-go/v3/post-auth-init-v2.ts +34 -0
- package/src/api-queries/aorta-go/v3/post-auth-logout-v2.ts +32 -0
- package/src/api-queries/aorta-go/v3/post-auth-verify-v2.ts +38 -0
- package/src/api-queries/aorta-go/v3/post-profile-switch.ts +39 -0
- package/src/api-queries/ndhm/get-abdm-register-suggest.ts +37 -0
- package/src/api-queries/ndhm/get-pincode-details.ts +28 -0
- package/src/api-queries/ndhm/post-abdm-login-init.ts +37 -0
- package/src/api-queries/ndhm/post-abdm-login-phr.ts +37 -0
- package/src/api-queries/ndhm/post-abdm-login-verify.ts +37 -0
- package/src/api-queries/ndhm/post-abdm-profile-eka-link-phr.ts +40 -0
- package/src/api-queries/ndhm/post-abdm-profile-eka.ts +66 -0
- package/src/api-queries/ndhm/post-abdm-register-abha-number-create-phr.ts +37 -0
- package/src/api-queries/ndhm/post-abdm-register-mobile-create-phr.ts +66 -0
- package/src/api-queries/ndhm/post-abdm-register-mobile-resend-otp.ts +32 -0
- package/src/api-queries/ndhm/post-abdm-register-mobile-verify.ts +38 -0
- package/src/api-queries/ndhm/post-abdm-register-phr-check.ts +34 -0
- package/src/api-queries/ndhm/post-register-aadhaar-create-phr.ts +37 -0
- package/src/api-queries/ndhm/post-register-aadhaar-init.ts +34 -0
- package/src/api-queries/ndhm/post-register-aadhaar-mobile-resend-otp.ts +34 -0
- package/src/api-queries/ndhm/post-register-aadhaar-mobile-verify.ts +37 -0
- package/src/api-queries/ndhm/post-register-aadhaar-resend-otp.ts +34 -0
- package/src/api-queries/ndhm/post-register-aadhaar-verify.ts +40 -0
- package/src/api-queries/ndhm/post-register-mobile-init.ts +34 -0
- package/src/api-queries/use-get-profiles-patient.ts +12 -0
- package/src/api-queries/use-get-profiles-phr-user.ts +28 -0
- package/src/api-queries/use-post-abdm-login-verify-v1.ts +26 -0
- package/src/api-queries/use-post-auth-verify-v2.ts +50 -0
- package/src/api-queries/use-post-profile-switch.ts +58 -0
- package/src/api-queries/use-post-register-mobile-create-phr.ts +39 -0
- package/src/api-queries/user-post-abdm-profile-login-phr.ts +26 -0
- package/src/assets/Success.json +1 -0
- package/src/assets/react.svg +1 -0
- package/src/atoms/button/custom-button.tsx +32 -0
- package/src/atoms/button/index.tsx +40 -0
- package/src/atoms/button/types.d.ts +31 -0
- package/src/atoms/header.tsx +25 -0
- package/src/atoms/input-field/index.tsx +63 -0
- package/src/atoms/input-field/patient-input-field.tsx +16 -0
- package/src/atoms/input-field/types.ts +24 -0
- package/src/atoms/pds2-otp-input/index.tsx +35 -0
- package/src/atoms/pds2-otp-input/types.d.ts +3 -0
- package/src/atoms/single-input-chip/index.tsx +32 -0
- package/src/atoms/single-input-chip/types.ts +6 -0
- package/src/atoms/spinner.tsx +33 -0
- package/src/atoms/text-separator.tsx +11 -0
- package/src/atoms/ui/spinner.tsx +75 -0
- package/src/constants/constants.ts +376 -0
- package/src/fetch-client/index.ts +164 -0
- package/src/index.css +152 -0
- package/src/main.tsx +374 -0
- package/src/molecules/abha/bottom-sheet/bottom-sheet-wrapper.tsx +40 -0
- package/src/molecules/abha/bottom-sheet/index.tsx +66 -0
- package/src/molecules/abha/spaced-input-component.tsx +168 -0
- package/src/molecules/copyright-year.tsx +16 -0
- package/src/molecules/exit-popup/index.tsx +101 -0
- package/src/molecules/pds2-otp-component/index.tsx +147 -0
- package/src/organisms/abha/abha-header.tsx +25 -0
- package/src/organisms/abha/abha-stepper.tsx +83 -0
- package/src/organisms/abha/error-bottom-sheet.tsx +27 -0
- package/src/organisms/abha/otp-card.tsx +99 -0
- package/src/organisms/abha/verification-status.tsx +30 -0
- package/src/organisms/choose-language/choose-language.tsx +53 -0
- package/src/organisms/choose-language/types.ts +10 -0
- package/src/organisms/screen-switcher/screen-switcher.tsx +80 -0
- package/src/routes/abha-aadhaar-verification-status-screen.tsx +246 -0
- package/src/routes/abha-created-screen.tsx +45 -0
- package/src/routes/abha-login-otp-verify-screen.tsx +519 -0
- package/src/routes/abha-mobile-linking-status-screen.tsx +267 -0
- package/src/routes/abha-otp-and-mobile-screen.tsx +435 -0
- package/src/routes/abha-phone-number-verification-screen.tsx +388 -0
- package/src/routes/create-abha-address-screen.tsx +928 -0
- package/src/routes/create-abha-with-aadhaar-screen.tsx +986 -0
- package/src/routes/create-eka-profile-screen.tsx +831 -0
- package/src/routes/get-all-profiles-screen.tsx +161 -0
- package/src/routes/login-or-create-abha-address-screen.tsx +1056 -0
- package/src/routes/login-with-abha-screen.tsx +454 -0
- package/src/routes/select-abha-from-list-screen.tsx +792 -0
- package/src/routes/select-eka-profile-screen.tsx +446 -0
- package/src/routes/utils/trackAbhaEvent.ts +41 -0
- package/src/stores/auth-abha-store/index.ts +152 -0
- package/src/stores/auth-abha-store/types.ts +217 -0
- package/src/utils/mock-auth-response.ts +29 -0
- package/src/utils/send-event-utils.ts +76 -0
- package/src/utils/validations.ts +89 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.ts +9 -0
- package/tsconfig.json +25 -0
- package/tsconfig.node.json +10 -0
- package/tsconfig.node.tsbuildinfo +1 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vite.config.d.ts +2 -0
- package/vite.config.js +45 -0
- package/vite.config.ts +50 -0
- package/dist/sdk/abha/css/abha.css +0 -1
- package/dist/sdk/abha/js/abha.js +0 -146
- /package/{dist → public}/images/adhaar.webp +0 -0
- /package/{dist → public}/images/at-the-rate.webp +0 -0
- /package/{dist → public}/images/avatar.webp +0 -0
- /package/{dist → public}/images/ayushman-bharat.webp +0 -0
- /package/{dist → public}/images/circle-checkmark.webp +0 -0
- /package/{dist → public}/images/link-abha.webp +0 -0
- /package/{dist → public}/images/national-authority.webp +0 -0
- /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
|
+
};
|