@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,777 +0,0 @@
1
- import { ArrowLeftRegularIcon } from '@elixir/icons';
2
- import { ABHA_AUTH_FLOW_METHOD, ABHA_V3_SKIP_STATES, LOADING_STATE } from '@elixir/types';
3
- import { useEffect, useMemo, useState } from 'react';
4
- import Pds2Button from '../atoms/button';
5
- import Pds2Header from '../atoms/header';
6
- import Pds2InputField from '../atoms/input-field';
7
- import Pds2SingleInputChip from '../atoms/single-input-chip';
8
- import useAuthAbhaStore from '../stores/auth-abha-store';
9
- import { SCREEN_NAMES } from '../stores/auth-abha-store/types';
10
- import { TVerifyToken } from '../api-queries/use-post-auth-verify-v2';
11
- import AbhaErrorBottomSheet from '../organisms/abha/error-bottom-sheet';
12
- import { TCachedQueryPhrResponse } from '../api-queries/use-post-register-mobile-create-phr';
13
- import { postAbdmProfileEka, getPincodeDetails } from 'apis';
14
- import { queryClient } from '../App';
15
- import usePostProfileSwitch from '../api-queries/use-post-profile-switch';
16
- import ExitPopup from '../molecules/exit-popup';
17
- import { handleSendEvent } from '@elixir/utils';
18
- import { GET_EXTRA_HEADERS } from 'apis';
19
-
20
- const CreateEkaProfileScreen = () => {
21
- const screen = useAuthAbhaStore((state) => state.screen);
22
- const selectedAbhaAddress = useAuthAbhaStore((state) => state.selectedAbhaAddress);
23
- const setBottomsheetErrorInfo = useAuthAbhaStore((state) => state.setBottomsheetErrorInfo);
24
- const clearAbhaAuthStore = useAuthAbhaStore((state) => state.clearAbhaAuthStore);
25
- const goBackLoginScreen = useAuthAbhaStore((state) => state.goBackLoginScreen);
26
- const [isLoading, setIsLoading] = useState<LOADING_STATE>(LOADING_STATE.IDLE);
27
- const [profileData, setProfileData] = useState<TProfileData>({
28
- firstname: '',
29
- lastname: '',
30
- date_of_birth: '',
31
- pincode: '',
32
- gender: '',
33
- });
34
- const [error, setError] = useState<TProfileDataError>({
35
- firstname: '',
36
- lastname: '',
37
- date_of_birth: '',
38
- pincode: '',
39
- gender: '',
40
- });
41
- const [createProfileError, setCreateProfileError] = useState<string | null>(null);
42
- const { mutateAsync: postProfileSwitchMutate } = usePostProfileSwitch();
43
- const [isExitPopupOpen, setIsExitPopupOpen] = useState<boolean>(false);
44
- const ekaProfileInfo = useAuthAbhaStore((state) => state.ekaProfileInfo);
45
- const setEkaProfileInfo = useAuthAbhaStore((state) => state.setEkaProfileInfo);
46
- const setScreen = useAuthAbhaStore((state) => state.setScreen);
47
- const topScreen = screen[screen.length - 1];
48
- const aadhaarVerificationSkipStateStatus = useAuthAbhaStore(
49
- (state) => state.aadhaarVerificationSkipStateStatus
50
- );
51
-
52
- // const authVerifyV2Response = queryClient.getQueryData<TVerifyToken>(['authVerifyV2Response']);
53
- const cachedProfilePhrResponse = queryClient.getQueryData<TCachedQueryPhrResponse>([
54
- 'abdmProfilePhrResponse',
55
- ]);
56
-
57
- const selectedFlowMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
58
- const [profilePatient, setprofilePatient] = useState<TProfileData>({
59
- firstname: '',
60
- lastname: '',
61
- date_of_birth: '',
62
- pincode: '',
63
- gender: '',
64
- });
65
-
66
- const isDocAppRequest = useAuthAbhaStore((state) => state.isDocAppRequest);
67
- const clientId = useAuthAbhaStore((state) => state.clientId);
68
- const isEkaAppLogin = useAuthAbhaStore((state) => state.isEkaAppLogin);
69
- const isNewLoginOrCreateFlow = useAuthAbhaStore((state) => state.isNewLoginOrCreateFlow);
70
- const txnId = useAuthAbhaStore((state) => state.txnId);
71
- const extra_headers = GET_EXTRA_HEADERS();
72
- const [pincodeApiError, setPincodeApiError] = useState<string | null>(null);
73
- const selectedMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
74
-
75
- const trackAbhaEvent = ({ name, data = {} }: { name: string; data?: Record<string, any> }) => {
76
- const baseProps = {
77
- login_platform: clientId,
78
- is_eka_app_login: isEkaAppLogin ? 'true' : 'false',
79
- is_new_login_or_create_flow: isNewLoginOrCreateFlow ? 'true' : 'false',
80
- txn_id: txnId || 'missing txnId',
81
- oid: extra_headers?.['X-User-ID'] ? 'true' : 'false',
82
- access_token: extra_headers?.['auth'] ? 'true' : 'false',
83
- flow: selectedMethod ?? ""
84
- };
85
-
86
- const eventData = {
87
- ...baseProps,
88
- ...data,
89
- };
90
-
91
- handleSendEvent({
92
- eventName: name,
93
- eventData,
94
- });
95
-
96
- window.curio?.pushToMixpanel?.(name, eventData);
97
- };
98
-
99
- // Run on component mount or when clientId changes
100
- useEffect(() => {
101
- // Track "create profile screen" page view
102
- trackAbhaEvent({
103
- name: 'page_view',
104
- data: {
105
- page_view: 'create_profile_screen',
106
- },
107
- });
108
- }, [clientId]);
109
-
110
- // Run on component mount to set status bar color
111
- useEffect(() => {
112
- // Change status bar to light gray
113
- if (window.EkaAbha?.changeStatusBarColor) {
114
- window.EkaAbha.changeStatusBarColor('#F2F4F7');
115
- return () => {
116
- // Cleanup: reset color to white on unmount
117
- if (window.EkaAbha?.changeStatusBarColor) window?.EkaAbha?.changeStatusBarColor('#FFFFFF');
118
- };
119
- }
120
- }, []); // Run only once on mount
121
-
122
- useEffect(() => {
123
- // If PHR data is available, use it to prefill form
124
- if (cachedProfilePhrResponse) {
125
- const {
126
- first_name,
127
- last_name,
128
- gender,
129
- pincode,
130
- day_of_birth,
131
- month_of_birth,
132
- year_of_birth,
133
- } = cachedProfilePhrResponse;
134
-
135
- const correctedDay = day_of_birth === 0 ? 1 : day_of_birth;
136
- const correctedMonth = month_of_birth === 0 ? 1 : month_of_birth;
137
-
138
- const dateOfBirth = `${year_of_birth}-${String(correctedMonth).padStart(2, '0')}-${String(correctedDay).padStart(2, '0')}`;
139
-
140
- trackAbhaEvent({
141
- name: 'profile_data_set_from_phr_cache',
142
- data: {
143
- source: 'phr_cache',
144
- date_of_birth: dateOfBirth,
145
- firstname: first_name ?? 'missing',
146
- lastname: last_name ?? 'missing',
147
- gender: gender ?? 'missing',
148
- pincode: pincode ?? 'missing',
149
- dob_day: day_of_birth ?? 'missing',
150
- dob_month: month_of_birth ?? 'missing',
151
- dob_year: year_of_birth ?? 'missing',
152
- flow: selectedMethod ?? ""
153
- },
154
- });
155
-
156
- // Set profile data with properly formatted date
157
- setProfileData({
158
- firstname: first_name,
159
- lastname: last_name,
160
- gender: gender,
161
- pincode: pincode,
162
- date_of_birth: dateOfBirth,
163
- });
164
- return;
165
- }
166
-
167
- // Fallback: use Eka profile info if available
168
- if (ekaProfileInfo) {
169
-
170
- let year = '1983';
171
- let month = '01';
172
- let day = '01';
173
-
174
- if (ekaProfileInfo.date_of_birth) {
175
- const parts = ekaProfileInfo.date_of_birth.split('-');
176
- year = parts[0];
177
- month = parts[1] === '00' || !parts[1] ? '01' : parts[1];
178
- day = parts[2] === '00' || !parts[2] ? '01' : parts[2];
179
- }
180
-
181
- const normalizedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
182
-
183
- setProfileData({
184
- firstname: ekaProfileInfo.firstname,
185
- lastname: ekaProfileInfo.lastname,
186
- gender: ekaProfileInfo.gender,
187
- pincode: ekaProfileInfo.pincode,
188
- date_of_birth: normalizedDate,
189
- oid: ekaProfileInfo.oid,
190
- });
191
-
192
- trackAbhaEvent({
193
- name: 'profile_data_set_from_eka_profile',
194
- data: {
195
- source: 'eka_profile',
196
- date_of_birth: ekaProfileInfo?.date_of_birth ?? 'missing',
197
- firstname: ekaProfileInfo?.firstname ?? 'missing',
198
- lastname: ekaProfileInfo?.lastname ?? 'missing',
199
- gender: ekaProfileInfo?.gender ?? 'missing',
200
- pincode: ekaProfileInfo?.pincode ?? 'missing',
201
- oid: ekaProfileInfo?.oid ?? 'missing',
202
- },
203
- });
204
- }
205
- }, [cachedProfilePhrResponse, ekaProfileInfo]);
206
-
207
- // Determine if "Create Profile" button should be enabled
208
- const buttonState = useMemo(() => {
209
- if (
210
- profileData.firstname &&
211
- !error.firstname &&
212
- profileData.date_of_birth &&
213
- !error.date_of_birth &&
214
- profileData.pincode &&
215
- !error.pincode &&
216
- profileData.gender &&
217
- !error.gender
218
- )
219
- return true;
220
- else return false;
221
- }, [profileData, error]);
222
-
223
- // Handle click on "Create Profile" button
224
- const handleCreateProfileClick = async () => {
225
- // Track button click
226
- trackAbhaEvent({
227
- name: 'create_profile_screen_clicks',
228
- data: {
229
- type: 'create_profile',
230
- },
231
- });
232
-
233
- // Set loading state before navigation or API call
234
- setIsLoading(LOADING_STATE.LOADING);
235
-
236
- // Flow 1: Only creating Eka profile
237
- if (topScreen === SCREEN_NAMES.CREATE_EKA_PROFILE) {
238
- // If creating Eka profile, move to next screen to create ABHA address
239
- trackAbhaEvent({
240
- name: 'navigate_to_create_abha_address_screen',
241
- data: {
242
- type: 'next',
243
- pincode_entered: profileData?.pincode ?? 'unknown',
244
- eka_profile_info_pincode: ekaProfileInfo?.pincode ?? 'unknown',
245
- flow_type: selectedFlowMethod || 'unknown_method',
246
- },
247
- });
248
-
249
- if (selectedFlowMethod === ABHA_AUTH_FLOW_METHOD.MOBILE) {
250
- const data = await getPincodeDetails({
251
- pincode: Number(profileData.pincode),
252
- });
253
-
254
- if (data?.error) {
255
- // Display error to user
256
- setPincodeApiError(data?.error ? 'Invalid Pincode' : null);
257
- setIsLoading(LOADING_STATE.REJECTED);
258
- trackAbhaEvent({
259
- name: 'pincode_api_failed',
260
- data: {
261
- type: 'error',
262
- error: data?.error,
263
- },
264
- });
265
- return;
266
- }
267
-
268
- trackAbhaEvent({
269
- name: 'pincode_api_success',
270
- data: {
271
- type: 'verify',
272
- pincode_received: !!data.pincode,
273
- txn_id: txnId,
274
- },
275
- });
276
-
277
- if (data?.pincode) {
278
- setCreateProfileError(null);
279
- setEkaProfileInfo(profileData);
280
- trackAbhaEvent({
281
- name: 'eka_profile_info_set',
282
- data: {
283
- firstname: profileData?.firstname,
284
- lastname: profileData?.lastname,
285
- gender: profileData?.gender,
286
- pincode: profileData?.pincode,
287
- date_of_birth: profileData?.date_of_birth,
288
- },
289
- });
290
- setScreen(SCREEN_NAMES.CREATE_ABHA_ADDRESS);
291
- return;
292
- }
293
-
294
- trackAbhaEvent({
295
- name: 'no_action_on_pincode',
296
- data: {
297
- type: 'verify',
298
- pincode_entered: !!data.pincode,
299
- txn_id: txnId,
300
- },
301
- });
302
-
303
- return;
304
- } else if (selectedFlowMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER) {
305
- setEkaProfileInfo(profileData);
306
- trackAbhaEvent({
307
- name: 'eka_profile_info_set',
308
- data: {
309
- firstname: profileData?.firstname,
310
- lastname: profileData?.lastname,
311
- gender: profileData?.gender,
312
- pincode: profileData?.pincode,
313
- date_of_birth: profileData?.date_of_birth,
314
- },
315
- });
316
- setScreen(SCREEN_NAMES.CREATE_ABHA_ADDRESS);
317
- return;
318
- }
319
- }
320
-
321
- // Flow 2: Creating both PHR and Eka profile
322
- if (topScreen === SCREEN_NAMES.CREATE_PHR_EKA_PROFILE) {
323
- // Abort if ABHA address is missing
324
- if (!selectedAbhaAddress) {
325
- trackAbhaEvent({
326
- name: 'abha_create_eka_profile_abha_address_missing',
327
- data: {
328
- platform: clientId,
329
- },
330
- });
331
- return;
332
- }
333
- // Split date of birth string into day, month, year
334
- const [year, month, day] = profileData.date_of_birth
335
- ? profileData?.date_of_birth?.split('-')
336
- : ['', '', ''];
337
-
338
- // Construct profile data payload for ABDM API
339
- const profileEkaData = {
340
- abha_address: selectedAbhaAddress,
341
- day_of_birth: parseInt(day),
342
- first_name: profileData.firstname,
343
- gender: profileData.gender,
344
- last_name: profileData.lastname || '',
345
- month_of_birth: parseInt(month),
346
- pincode: profileData.pincode,
347
- year_of_birth: parseInt(year),
348
- };
349
-
350
- trackAbhaEvent({
351
- name: 'profile_eka_process_started',
352
- data: {
353
- platform: clientId,
354
- date_of_birth: profileData?.date_of_birth || null,
355
- dob_day: day || null,
356
- dob_month: month || null,
357
- dob_year: year || null,
358
- },
359
- });
360
-
361
- // Call API to create Eka profile with PHR
362
- const {
363
- error: phrError,
364
- eka,
365
- action: errorAction,
366
- } = await postAbdmProfileEka({ ...profileEkaData });
367
-
368
- // If an actionable error is returned (e.g. show bottom sheet)
369
- if (errorAction) {
370
- trackAbhaEvent({
371
- name: 'profile_eka_process_failed',
372
- data: {
373
- platform: clientId,
374
- error_message: errorAction?.cta?.title || 'unknown_error',
375
- error_message_exists: !!errorAction?.cta?.title,
376
- },
377
- });
378
- setBottomsheetErrorInfo(errorAction);
379
- return;
380
- }
381
-
382
- // If API fails or returns invalid Eka profile
383
- if (phrError || !eka || !eka.oid) {
384
- trackAbhaEvent({
385
- name: 'profile_process_failed',
386
- data: {
387
- platform: clientId,
388
- error_message: phrError || 'Unknown error',
389
- eka_oid: eka?.oid || 'missing',
390
- eka_exists: !!eka,
391
- date_of_birth: profileData?.date_of_birth || 'missing',
392
- dob_day: day || 'missing',
393
- dob_month: month || 'missing',
394
- dob_year: year || 'missing',
395
- parsed_date_valid: Boolean(parseInt(day) && parseInt(month) && parseInt(year)),
396
- firstname: profileData?.firstname || 'missing',
397
- gender: profileData?.gender || 'missing',
398
- pincode: profileData?.pincode || 'missing',
399
- },
400
- });
401
- setIsLoading(LOADING_STATE.REJECTED);
402
- setCreateProfileError(phrError || 'Something went wrong. Please try again.');
403
- return;
404
- }
405
-
406
- trackAbhaEvent({
407
- name: 'profile_eka_process_success',
408
- data: {
409
- platform: clientId,
410
- eka: eka,
411
- },
412
- });
413
-
414
- trackAbhaEvent({
415
- name: 'profile_switch_process_started',
416
- data: {
417
- platform: clientId,
418
- error_message: phrError,
419
- eka: eka,
420
- },
421
- });
422
-
423
- // Switch to newly created Eka profile
424
- const profileSwitchResponse = await postProfileSwitchMutate({
425
- oid: eka.oid,
426
- });
427
-
428
- // If profile switch fails
429
- if (profileSwitchResponse.error) {
430
- trackAbhaEvent({
431
- name: 'profile_switch_process_failed',
432
- data: {
433
- platform: clientId,
434
- error_message: profileSwitchResponse.error || 'Something went wrong, please try again',
435
- error_message_exists: !!profileSwitchResponse.error,
436
- },
437
- });
438
- setIsLoading(LOADING_STATE.REJECTED);
439
- setCreateProfileError(
440
- profileSwitchResponse.error?.message || 'Something went wrong, please try again'
441
- );
442
- return;
443
- }
444
-
445
- trackAbhaEvent({
446
- name: 'profile_switch_process_success',
447
- data: {
448
- platform: clientId,
449
- eka: eka,
450
- },
451
- });
452
-
453
- // Profile switch success
454
- setIsLoading(LOADING_STATE.RESOLVED);
455
- return;
456
- }
457
- };
458
-
459
- const handleErrorBottomsheetButtonClick = () => {
460
- goBackLoginScreen();
461
- const isAppLogin = useAuthAbhaStore.getState().isEkaAppLogin;
462
- clearAbhaAuthStore();
463
- useAuthAbhaStore.setState({ isEkaAppLogin: isAppLogin });
464
- };
465
-
466
- return (
467
- <div className="pds2-w-full pds2-flex pds2-flex-col pds2-bg-bg-01" style={{ height: '80vh' }}>
468
- <Pds2Header
469
- title=""
470
- prefixIcon={
471
- <button
472
- className="pds2-w-24 pds2-h-24 pds2-rounded-full pds2-flex pds2-items-center pds2-justify-center ripple"
473
- onClick={() => setIsExitPopupOpen(true)}
474
- >
475
- <ArrowLeftRegularIcon className="" />
476
- </button>
477
- }
478
- className="pds2-bg-bg-01"
479
- />
480
- <div className="pds2-flex pds2-flex-col pds2-flex-1 pds2-p-8">
481
- <div className="pds2-flex pds2-items-center pds2-justify-between">
482
- <div className="pds2-space-y-2 pds2-text-text-01">
483
- {isDocAppRequest ? (
484
- <div className="Heading4Semibold">Create ABHA Profile</div>
485
- ) : (
486
- <>
487
- <div className="Heading4Semibold">Create your</div>
488
- <div className="Heading2Semibold">Eka Profile</div>
489
- </>
490
- )}
491
- </div>
492
- {/* <div className="pds2-relative">
493
- <img src="/images/avatar.webp" alt="avatar" className="pds2-w-96 pds2-h-96" />
494
- <button className="pds2-flex pds2-items-center pds2-space-x-4 pds2-text-text-brand pds2-px-8 pds2-py-4 pds2-border-1 pds2-border-border-brand-01 pds2-rounded-8 pds2-bg-bg-white pds2-absolute -pds2-bottom-12 pds2-right-6">
495
- <CameraSolidIcon className="pds2-w-14 pds2-h-14" />
496
- <div className="Label1Semibold pds2-min-w-max">Add photo</div>
497
- </button>
498
- </div> */}
499
- </div>
500
- <UserDetailsForm
501
- profileData={profileData}
502
- setProfileData={setProfileData}
503
- error={error}
504
- setError={setError}
505
- pincodeApiError={pincodeApiError}
506
- />
507
- </div>
508
- {createProfileError && (
509
- <div className="pds2-p-16 pds2-text-text-error pds2-text-center">{createProfileError}</div>
510
- )}
511
- <div className="pds2-sticky pds2-bottom-0 pds2-bg-bg-white pds2-w-full">
512
- {selectedAbhaAddress &&
513
- aadhaarVerificationSkipStateStatus === ABHA_V3_SKIP_STATES.ABHA_END ? (
514
- <div className="pds2-flex pds2-items-center pds2-justify-between pds2-w-full pds2-px-16 pds2-py-6 pds2-bg-border-brand-02">
515
- <div className="">
516
- <span className="pds2-text-text-03 Body2Regular">Creating for: </span>
517
- <span className="pds2-text-text-01 Body2Semibold">{selectedAbhaAddress}</span>
518
- </div>
519
- <button
520
- onClick={goBackLoginScreen}
521
- className="Body2Semibold pds2-text-text-brand pds2-rounded-full ripple pds2-px-8 pds2-py-2"
522
- >
523
- Change
524
- </button>
525
- </div>
526
- ) : null}
527
- <div className="pds2-p-16 pds2-w-full">
528
- <Pds2Button
529
- className="pds2-w-full"
530
- title="Create Profile"
531
- state={isLoading === LOADING_STATE.LOADING ? 'disabled' : 'enabled'}
532
- onClick={handleCreateProfileClick}
533
- isLoading={isLoading === LOADING_STATE.LOADING}
534
- />
535
- </div>
536
- </div>
537
- <AbhaErrorBottomSheet onSubmitClick={handleErrorBottomsheetButtonClick} />
538
- <ExitPopup open={isExitPopupOpen} setOpen={setIsExitPopupOpen} />
539
- </div>
540
- );
541
- };
542
- export default CreateEkaProfileScreen;
543
-
544
- const genders = [
545
- { id: 'M', name: 'Male' },
546
- { id: 'F', name: 'Female' },
547
- { id: 'O', name: 'Other' },
548
- ];
549
-
550
- type TProfileData = {
551
- firstname: string;
552
- lastname: string;
553
- date_of_birth: string;
554
- pincode: string;
555
- gender: string;
556
- oid?: string;
557
- };
558
-
559
- interface TProfileDataError extends TProfileData {}
560
-
561
- const UserDetailsForm = ({
562
- profileData,
563
- setProfileData,
564
- error,
565
- setError,
566
- pincodeApiError,
567
- }: {
568
- profileData: TProfileData;
569
- setProfileData: (val: TProfileData) => void;
570
- error: TProfileDataError;
571
- setError: (val: TProfileDataError) => void;
572
- pincodeApiError?: string | null;
573
- }) => {
574
- const handleInputChange = ({
575
- event,
576
- name,
577
- }: {
578
- event: React.ChangeEvent<HTMLInputElement>;
579
- name: string;
580
- }) => {
581
- const value = event.target.value;
582
- let errorMsg = '';
583
- switch (name) {
584
- case 'firstname':
585
- if (!value || value.length < 0) errorMsg = 'This field is required';
586
- else errorMsg = '';
587
- break;
588
- case 'lastname':
589
- if (!value || value.length < 0) errorMsg = 'This field is required';
590
- else errorMsg = '';
591
- break;
592
- case 'pincode':
593
- if (!value || isNaN(Number(value)) || value.length != 6)
594
- errorMsg = 'Pincode must consist of exactly 6 digits';
595
- else errorMsg = '';
596
- break;
597
- case 'date_of_birth':
598
- if (!value || value > new Date().toISOString().split('T')[0])
599
- errorMsg = 'Date of Birth is invalid';
600
- else errorMsg = '';
601
- break;
602
- default:
603
- break;
604
- }
605
-
606
- setError({
607
- ...error,
608
- [name]: errorMsg,
609
- });
610
-
611
- setProfileData({
612
- ...profileData,
613
- [name]: value,
614
- });
615
- };
616
-
617
- const handleGenderChange = (value: string) => {
618
- setProfileData({
619
- ...profileData,
620
- gender: value,
621
- });
622
- setError({
623
- ...error,
624
- gender: '',
625
- });
626
- };
627
-
628
- const isPincodeFieldErrorToBeShown = (profileData: any, ekaProfileInfo: any): boolean => {
629
- // if ekaProfileInfo already has a pincode, skip the validation
630
- if (ekaProfileInfo?.pincode) {
631
- return false;
632
- }
633
-
634
- // Validate if firstName, gender, and date_of_birth are filled in profileData
635
- const isProfileDataComplete =
636
- (profileData.firstname ?? '').trim() !== '' &&
637
- (profileData.gender ?? '').trim() !== '' &&
638
- (profileData.date_of_birth ?? '').trim() !== '';
639
-
640
- // If profileData is incomplete, skip pincode error check
641
- if (!isProfileDataComplete) {
642
- return false;
643
- }
644
-
645
- // Check if pincode is empty or invalid (check length and numeric)
646
- if (!profileData.pincode || (profileData.pincode + '').length !== 6) {
647
- return true; // Show error if pincode is missing or invalid
648
- }
649
-
650
- return false;
651
- };
652
-
653
- const ekaProfileInfo = useAuthAbhaStore((state) => state.ekaProfileInfo);
654
- const selectedFlowMethod = useAuthAbhaStore((state) => state.abhaAuthFlowMethod);
655
-
656
- return (
657
- <form className="pds2-flex pds2-flex-col pds2-space-y-32">
658
- <label className="pds2-space-y-8">
659
- <div className="Body3Medium pds2-text-text-04">
660
- Your name
661
- <sup className="pds2-text-text-error Body3Semibold">*</sup>
662
- </div>
663
- <div className="pds2-flex pds2-items-center pds2-gap-8">
664
- <Pds2InputField
665
- textColor="pds2-text-text-01"
666
- padding="pds2-px-16 pds2-py-12"
667
- borderRadius="pds2-rounded-12"
668
- borderStyle="focus-within:pds2-ring-2 focus-within:pds2-ring-border-brand-01 focus-within:pds2-ring-offset-2"
669
- placeholder="Firstname"
670
- value={profileData.firstname}
671
- onChange={(e) => {
672
- handleInputChange({ event: e, name: 'firstname' });
673
- }}
674
- autoCapitalize="on"
675
- disabled={
676
- !!ekaProfileInfo?.firstname &&
677
- selectedFlowMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
678
- }
679
- />
680
- <Pds2InputField
681
- textColor="pds2-text-text-01"
682
- padding="pds2-px-16 pds2-py-12"
683
- borderRadius="pds2-rounded-12"
684
- borderStyle="focus-within:pds2-ring-2 focus-within:pds2-ring-border-brand-01 focus-within:pds2-ring-offset-2"
685
- placeholder="Lastname"
686
- value={profileData.lastname}
687
- onChange={(e) => {
688
- handleInputChange({ event: e, name: 'lastname' });
689
- }}
690
- autoCapitalize="on"
691
- disabled={
692
- !!ekaProfileInfo?.lastname &&
693
- selectedFlowMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
694
- }
695
- />
696
- </div>
697
- </label>
698
-
699
- <div className="pds2-space-y-8">
700
- <div className="Body3Medium pds2-text-text-04">
701
- Gender
702
- <sup className="pds2-text-text-error Body3Semibold">*</sup>
703
- </div>
704
- <div className="pds2-flex pds2-gap-16">
705
- {genders.map((item, index) => {
706
- return (
707
- <div key={index}>
708
- <Pds2SingleInputChip
709
- isSelected={item.id === profileData.gender}
710
- title={item.name}
711
- onSelect={() => {
712
- handleGenderChange(item.id);
713
- }}
714
- />
715
- </div>
716
- );
717
- })}
718
- </div>
719
- </div>
720
-
721
- <Pds2InputField
722
- label="Date of Birth"
723
- isMandatory={true}
724
- textColor="pds2-text-text-01"
725
- padding="pds2-px-16 pds2-py-12"
726
- borderRadius="pds2-rounded-12"
727
- borderStyle="focus-within:pds2-ring-2 focus-within:pds2-ring-border-brand-01 focus-within:pds2-ring-offset-2"
728
- value={profileData.date_of_birth}
729
- disabled={
730
- !!ekaProfileInfo?.date_of_birth &&
731
- selectedFlowMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
732
- }
733
- onChange={(e) => {
734
- handleInputChange({ event: e, name: 'date_of_birth' });
735
- }}
736
- type="date"
737
- maxDate={new Date().toISOString().split('T')[0]}
738
- />
739
-
740
- <div className="pds2-flex pds2-flex-col pds2-space-y-4">
741
- <Pds2InputField
742
- label="Pincode"
743
- isMandatory={true}
744
- textColor="pds2-text-text-01"
745
- padding="pds2-px-16 pds2-py-12"
746
- borderRadius="pds2-rounded-12"
747
- borderStyle={
748
- isPincodeFieldErrorToBeShown(profileData, ekaProfileInfo) || pincodeApiError
749
- ? 'pds2-border-1 pds2-border-text-error'
750
- : ''
751
- }
752
- value={profileData.pincode}
753
- placeholder="Enter Pincode"
754
- disabled={
755
- !!ekaProfileInfo?.pincode && selectedFlowMethod === ABHA_AUTH_FLOW_METHOD.AADHAR_NUMBER
756
- }
757
- onChange={(e) => {
758
- if (e.target.value.length > 6) return;
759
- handleInputChange({ event: e, name: 'pincode' });
760
- }}
761
- type="number"
762
- error={
763
- isPincodeFieldErrorToBeShown(profileData, ekaProfileInfo) ? 'Pincode is required' : ''
764
- }
765
- textStyle={
766
- isPincodeFieldErrorToBeShown(profileData, ekaProfileInfo) || pincodeApiError
767
- ? 'placeholder:pds2-text-text-error'
768
- : 'placeholder:pds2-text-text-04'
769
- }
770
- />
771
- {pincodeApiError && (
772
- <div className="Body3Medium pds2-text-text-error pds2-mt-4">{pincodeApiError}</div>
773
- )}
774
- </div>
775
- </form>
776
- );
777
- };