saafe-redirection-flow 2.0.0 → 2.2.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/aa-redirection-1607251826.zip +0 -0
  3. package/docs/features/account-discovery.md +803 -0
  4. package/docs/features/authentication.md +583 -0
  5. package/docs/features/consent-management.md +740 -0
  6. package/docs/features/index.md +206 -0
  7. package/docs/features/navigation-routing.md +846 -0
  8. package/docs/features/overview.md +554 -0
  9. package/docs/features/theming-internationalization.md +982 -0
  10. package/docs/index.md +1 -1
  11. package/package.json +1 -1
  12. package/src/components/AutoDiscoveryLoader.tsx +29 -0
  13. package/src/components/LinkedAccountTypeAccordion.tsx +154 -0
  14. package/src/components/alert/alert.tsx +10 -4
  15. package/src/components/modal/HelpModal.tsx +122 -0
  16. package/src/components/session/SessionTimer.tsx +20 -33
  17. package/src/components/title/AppBar.tsx +1 -1
  18. package/src/components/ui/bottom-sheet.tsx +1 -1
  19. package/src/components/ui/frosted-panel.tsx +0 -2
  20. package/src/components/ui/otp-input.tsx +38 -6
  21. package/src/hooks/use-account-discovery.ts +13 -6
  22. package/src/hooks/use-auto-discovery.ts +226 -0
  23. package/src/index.css +3 -0
  24. package/src/pages/accounts/AccountsToProceed.tsx +598 -59
  25. package/src/pages/accounts/Discover.tsx +127 -9
  26. package/src/pages/accounts/DiscoverAccount.tsx +195 -42
  27. package/src/pages/accounts/LinkSelectedAccounts.tsx +15 -9
  28. package/src/pages/accounts/OldUser.tsx +184 -79
  29. package/src/pages/accounts/link-accounts.tsx +19 -11
  30. package/src/pages/consent/ReviewConsent.tsx +19 -10
  31. package/src/pages/consent/rejected.tsx +17 -8
  32. package/src/pages/consent/success.tsx +125 -76
  33. package/src/services/api/account.service.ts +2 -2
  34. package/src/store/fip.store.ts +74 -28
  35. package/src/store/redirect.store.ts +19 -0
  36. package/src/utils/auto-discovery.ts +126 -0
  37. package/src/utils/toast-helpers.ts +5 -0
  38. package/stage-aa-2506251021.zip +0 -0
@@ -6,14 +6,20 @@ import { useLocation, useParams } from "react-router-dom";
6
6
  import AccountsToProceed from "./AccountsToProceed";
7
7
  import LinkSelectedAccounts from "./LinkSelectedAccounts";
8
8
  import DiscoverAccount from "./DiscoverAccount";
9
+
9
10
  import { useFipStore } from "@/store/fip.store";
11
+ import { useRedirectStore } from "@/store/redirect.store";
10
12
  import { useEffect } from "react";
13
+ import { useNavigate } from "react-router-dom";
14
+ import { isAutoDiscoveryEnabled, getAutoDiscoveryFipIds } from "@/utils/auto-discovery";
11
15
 
12
16
  const Discover = () => {
13
17
  const { category } = useParams();
14
18
  const location = useLocation();
15
19
  const path = location.pathname.split('/').pop() || '';
16
- const { activeCategory, setActiveCategory, categories } = useFipStore();
20
+ const navigate = useNavigate();
21
+ const { activeCategory, setActiveCategory, categories, groupedFips, setSelectedFips } = useFipStore();
22
+ const { decodedInfo } = useRedirectStore();
17
23
 
18
24
  // For step navigation in the sidebar - detect category from path
19
25
  useEffect(() => {
@@ -37,19 +43,131 @@ const Discover = () => {
37
43
  }
38
44
  }, [path, category, categories, setActiveCategory, location.state]);
39
45
 
46
+ // Handle auto discovery logic
47
+ useEffect(() => {
48
+ // Only run auto discovery logic on category pages (not flow pages)
49
+ const flowPaths = ['discovery', 'link', 'discover-account'];
50
+ const isFlowPath = flowPaths.includes(path);
51
+
52
+ console.log('Auto Discovery Debug:', {
53
+ path,
54
+ isFlowPath,
55
+ activeCategory,
56
+ hasDecodedInfo: !!decodedInfo,
57
+ otherAppCustomization: decodedInfo?.customization?.otherAppCustomization,
58
+ fipId: decodedInfo?.fipId,
59
+ locationPathname: location.pathname,
60
+ groupedFipsKeys: Object.keys(groupedFips || {}),
61
+ groupedFipsEmpty: !groupedFips || Object.keys(groupedFips).length === 0,
62
+ categoriesLoaded: categories.length > 0
63
+ });
64
+
65
+ // Guard clauses to prevent unnecessary execution
66
+ if (isFlowPath || !activeCategory || !decodedInfo) {
67
+ console.log('Auto Discovery: Early return due to guard clauses', {
68
+ isFlowPath,
69
+ activeCategory,
70
+ hasDecodedInfo: !!decodedInfo
71
+ });
72
+ return;
73
+ }
74
+
75
+ // Check if groupedFips is loaded
76
+ if (!groupedFips || Object.keys(groupedFips).length === 0) {
77
+ console.log('Auto Discovery: groupedFips not loaded yet, waiting...');
78
+ return;
79
+ }
80
+
81
+ // Additional guard: only run for supported auto discovery categories
82
+ const supportedCategories = ['INVESTMENTS', 'GST', 'INSURANCE'];
83
+ if (!supportedCategories.includes(activeCategory.toUpperCase())) {
84
+ console.log('Auto Discovery: Category not supported:', activeCategory);
85
+ return;
86
+ }
87
+
88
+ const autoDiscoveryEnabled = isAutoDiscoveryEnabled(
89
+ activeCategory,
90
+ decodedInfo?.customization?.otherAppCustomization
91
+ );
92
+
93
+ console.log('Auto Discovery: Enabled?', autoDiscoveryEnabled, 'for category:', activeCategory);
94
+
95
+ if (autoDiscoveryEnabled) {
96
+ // Get FIP IDs for auto discovery
97
+ const fipIds = getAutoDiscoveryFipIds(
98
+ activeCategory,
99
+ decodedInfo?.fipId,
100
+ groupedFips
101
+ );
102
+
103
+ console.log('Auto Discovery: FIP IDs:', fipIds, 'groupedFips keys:', Object.keys(groupedFips || {}));
104
+
105
+ if (fipIds.length > 0) {
106
+ // Additional guard: check if we're already navigating or have navigated
107
+ if (location.pathname === '/link-accounts/discovery') {
108
+ console.log('Auto Discovery: Already on discovery page, skipping navigation');
109
+ return;
110
+ }
111
+
112
+ console.log('Auto Discovery: Navigating to discovery with FIPs:', fipIds);
113
+
114
+ // Set selected FIPs in the store
115
+ setSelectedFips(activeCategory, fipIds);
116
+
117
+ // IMPORTANT: Also populate identifiers in the store for manual discovery hooks to use
118
+ // This mirrors the logic from link-accounts.tsx handleNext function
119
+ const { fips, setIdentifiers, selectedMobileNumber } = useFipStore.getState();
120
+ const identifiersList: { type: string; value: string | undefined; category: string }[] = [];
121
+
122
+ fips
123
+ .filter(fip => fipIds.includes(fip.id))
124
+ .forEach(fip => {
125
+ fip.Identifiers?.forEach(identifier => {
126
+ if (!identifiersList.find(i => i.type === identifier.type)) {
127
+ const value =
128
+ identifier.type === 'PAN'
129
+ ? decodedInfo?.pan || undefined
130
+ : identifier.type === 'MOBILE'
131
+ ? selectedMobileNumber || decodedInfo?.phoneNumber || undefined
132
+ : identifier.type === 'DOB'
133
+ ? decodedInfo?.dob || undefined
134
+ : undefined;
135
+ identifiersList.push({ type: identifier.type, value, category: identifier.category });
136
+ }
137
+ });
138
+ });
139
+
140
+ console.log('Auto Discovery: Setting identifiers in store:', identifiersList);
141
+ setIdentifiers(identifiersList);
142
+
143
+ // Navigate to discovery page
144
+ navigate('/link-accounts/discovery', {
145
+ state: {
146
+ category: activeCategory,
147
+ selectedFips: fipIds,
148
+ isAutoDiscovery: true
149
+ },
150
+ replace: true // Use replace to avoid back button issues
151
+ });
152
+ } else {
153
+ console.log('Auto Discovery: No FIP IDs found, staying on FIP listing');
154
+ }
155
+ }
156
+ }, [activeCategory, path, decodedInfo?.customization?.otherAppCustomization, decodedInfo?.fipId, location.pathname, groupedFips, categories]);
157
+
40
158
  const getCurrentStep = (newPath: string) => {
41
159
  // Flow paths
42
160
  switch (newPath || path) {
43
161
  case 'discovery':
44
162
  case 'proceed':
45
163
  return <AccountsToProceed
46
- state={location.state as { category: string; selectedFips: string[] }}
164
+ state={location.state as { category: string; selectedFips: string[]; isAutoDiscovery?: boolean }}
47
165
  currentCategory={activeCategory}
48
- />;
49
-
50
- case 'link':
166
+ />;
167
+
168
+ case 'link':
51
169
  return <LinkSelectedAccounts
52
- state={location.state as { category: string; selectedFips: string[] }}
170
+ state={location.state as { category: string; selectedFips: string[]; selectedAccounts: string[]; signature?: string }}
53
171
  currentCategory={activeCategory}
54
172
  />;
55
173
 
@@ -60,15 +178,15 @@ const Discover = () => {
60
178
  />;
61
179
 
62
180
  default:
63
- // If we're on a category path or any other path, show FIP listing
64
- // This handles all category paths like /link-accounts/banks, /link-accounts/investment etc.
181
+ // Default: show FIP listing (manual flow)
182
+ // Auto discovery logic is now handled in useEffect above
65
183
  return <LinkAccounts />;
66
184
  }
67
185
  }
68
186
 
69
187
  return (
70
188
  <FrostedLayout>
71
- {getCurrentStep()}
189
+ {getCurrentStep(path)}
72
190
  </FrostedLayout>
73
191
  )
74
192
  }
@@ -18,7 +18,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'
18
18
  import { accountService } from '@/services/api'
19
19
  import { useMediaQuery } from '@/hooks/use-media-query'
20
20
  import { useFipStore } from '@/store/fip.store'
21
- import logo from '../../assets/brand/saafe-logo.svg'
22
21
  import { z } from 'zod'
23
22
  import { Calendar } from '@/components/ui/calendar'
24
23
  import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
@@ -36,10 +35,22 @@ import { useSetPageTitle } from '@/hooks/use-page-title'
36
35
  import { useRedirectStore } from '@/store/redirect.store'
37
36
  import { BottomSheet } from '@/components/ui/bottom-sheet'
38
37
 
38
+ interface ApiError extends Error {
39
+ response?: {
40
+ data?: {
41
+ errorCode?: string
42
+ errorMsg?: string
43
+ }
44
+ }
45
+ }
46
+
39
47
  interface DiscoverAccountProps {
40
48
  state?: {
41
49
  category: string
42
50
  selectedFips?: string[]
51
+ fromOldUser?: boolean
52
+ fromDiscoverMore?: boolean
53
+ fromAutoDiscovery?: boolean
43
54
  }
44
55
  currentCategory?: string | null
45
56
  }
@@ -107,7 +118,7 @@ const AddNumberModalContent = ({ showModal, setShowModal, t, addNewNoQuery, hand
107
118
  onSuccess: () => {
108
119
  handleAddNumber(inputValue.number)
109
120
  },
110
- onError: (error: Error) => {
121
+ onError: (error: ApiError) => {
111
122
  // console.error(error)
112
123
  setInputValue({ number: inputValue.number, error: error.response?.data?.errorCode || 'Something went wrong' });
113
124
  }
@@ -145,7 +156,44 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
145
156
  AADHAAR: null
146
157
  })
147
158
  const [isPopoverOpen, setIsPopoverOpen] = useState(false)
148
- const [showAlert, setShowAlert] = useState(true)
159
+ // const [showAlert, setShowAlert] = useState(true)
160
+
161
+ // Utility function to parse various date formats
162
+ const parseDateFromDecodedInfo = (dateString: string | null): Date | null => {
163
+ if (!dateString) return null
164
+
165
+ try {
166
+ // Handle URL-encoded date string
167
+ const decodedDateString = decodeURIComponent(dateString)
168
+
169
+ // Try parsing as ISO string first (handles formats like "1999-12-09T18:30:00.000Z")
170
+ let parsedDate = new Date(decodedDateString)
171
+
172
+ // If that fails, try other common formats
173
+ if (isNaN(parsedDate.getTime())) {
174
+ // Try DD/MM/YYYY format
175
+ if (decodedDateString.includes('/')) {
176
+ const [day, month, year] = decodedDateString.split('/')
177
+ parsedDate = new Date(parseInt(year), parseInt(month) - 1, parseInt(day))
178
+ }
179
+ // Try YYYY-MM-DD format
180
+ else if (decodedDateString.includes('-') && decodedDateString.length === 10) {
181
+ parsedDate = new Date(decodedDateString + 'T00:00:00.000Z')
182
+ }
183
+ }
184
+
185
+ // Validate the parsed date
186
+ if (isNaN(parsedDate.getTime())) {
187
+ console.warn('Could not parse date:', dateString)
188
+ return null
189
+ }
190
+
191
+ return parsedDate
192
+ } catch (error) {
193
+ console.warn('Error parsing date:', error)
194
+ return null
195
+ }
196
+ }
149
197
 
150
198
  // Format category name for display
151
199
  const formatCategoryName = (name: string) => {
@@ -159,7 +207,8 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
159
207
  title: t('addNewMobileNumber'),
160
208
  content: null as React.ReactNode,
161
209
  number: '',
162
- otp: null as string | null
210
+ otp: null as string | null,
211
+ error: ''
163
212
  })
164
213
 
165
214
  // Detect mobile screens
@@ -189,7 +238,7 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
189
238
  getMobileNumbersQuery.refetch()
190
239
  setShowModal(old => ({ ...old, otp: null, error: '' }))
191
240
  },
192
- onError: error => {
241
+ onError: (error: ApiError) => {
193
242
  setShowModal(old => ({ ...old, otp: null, error: error.response?.data?.errorCode || 'Something went wrong' }))
194
243
  }
195
244
  })
@@ -209,10 +258,11 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
209
258
  title: 'Add new mobile number',
210
259
  content: null,
211
260
  number: '',
212
- otp: null
261
+ otp: null,
262
+ error: ''
213
263
  })
214
264
  },
215
- onError: error => {
265
+ onError: (error: ApiError) => {
216
266
  setShowModal(old => ({ ...old, otp: null, error: error.response?.data?.errorCode || 'Something went wrong' }))
217
267
  // console.error(error)
218
268
  }
@@ -257,13 +307,64 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
257
307
  ...result[mobileIndex],
258
308
  value: selectedMobileNumber
259
309
  })
260
- navigate('/link-accounts/discovery', {
261
- state: {
262
- category,
263
- selectedFips: state?.selectedFips,
264
- fromDiscovery: true
265
- }
310
+
311
+ // Update identifiers in FIP store
312
+ setIdentifiers(result)
313
+
314
+ // Also update PAN and DOB in redirect store for API calls
315
+ const { updateIdentifiers } = useRedirectStore.getState()
316
+ const panIdentifier = result.find(i => i.type === 'PAN')
317
+ const dobIdentifier = result.find(i => i.type === 'DOB')
318
+
319
+ updateIdentifiers(
320
+ panIdentifier?.value || undefined,
321
+ dobIdentifier?.value || undefined
322
+ )
323
+
324
+ console.log('DiscoverAccount: Updated identifiers in both stores', {
325
+ pan: panIdentifier?.value,
326
+ dob: dobIdentifier?.value
266
327
  })
328
+
329
+ // Check if we came from different sources and redirect accordingly
330
+ if (state?.fromOldUser) {
331
+ // Redirect back to old user page
332
+ navigate('/link-accounts/old-user', {
333
+ state: {
334
+ category,
335
+ selectedFips: state?.selectedFips,
336
+ fromDiscovery: true
337
+ }
338
+ })
339
+ } else if (state?.fromAutoDiscovery) {
340
+ // Redirect back to auto discovery page
341
+ navigate('/link-accounts/discovery', {
342
+ state: {
343
+ category,
344
+ selectedFips: state?.selectedFips,
345
+ isAutoDiscovery: true, // Important: preserve auto discovery flag
346
+ fromDiscovery: true
347
+ }
348
+ })
349
+ } else if (state?.fromDiscoverMore) {
350
+ // Redirect back to AccountsToProceed page
351
+ navigate('/link-accounts/discovery', {
352
+ state: {
353
+ category,
354
+ selectedFips: state?.selectedFips,
355
+ fromDiscovery: true
356
+ }
357
+ })
358
+ } else {
359
+ // Normal flow - go to discovery page
360
+ navigate('/link-accounts/discovery', {
361
+ state: {
362
+ category,
363
+ selectedFips: state?.selectedFips,
364
+ fromDiscovery: true
365
+ }
366
+ })
367
+ }
267
368
  }
268
369
 
269
370
  const handleCancel = () => {
@@ -308,7 +409,7 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
308
409
  <Modal
309
410
  title={showModal.title}
310
411
  open={showModal.isOpen}
311
- className='w-[380px]'
412
+ className='w-[450px]'
312
413
  onOpenChange={open =>
313
414
  !open &&
314
415
  setShowModal({
@@ -330,13 +431,14 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
330
431
  title=''
331
432
  editable={true}
332
433
  mobileNumber={showModal.number}
434
+ eyeClassName="translate-x-2"
333
435
  onResend={() => {
334
436
  setShowModal(old => ({ ...old, otp: null, error: '' }))
335
437
  addNewNoQuery.mutate(undefined, {
336
438
  onSuccess: () => {
337
439
  setShowModal(old => ({ ...old, otp: null, error: '' }))
338
440
  },
339
- onError: (error: Error) => {
441
+ onError: (error: ApiError) => {
340
442
  setShowModal(old => ({ ...old, otp: null, error: error.response?.data?.errorMsg || 'Something went wrong' }))
341
443
  // console.error(error)
342
444
  }
@@ -366,10 +468,32 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
366
468
  );
367
469
  };
368
470
 
471
+ // Auto-fill DOB from decodedInfo when identifiers are set
472
+ useEffect(() => {
473
+ if (decodedInfo?.dob && identifiers?.find(i => i.type === 'DOB')) {
474
+ const parsedDate = parseDateFromDecodedInfo(decodedInfo.dob)
475
+
476
+ if (parsedDate) {
477
+ const dobIdentifier = identifiers.find(i => i.type === 'DOB')
478
+ if (dobIdentifier && !dobIdentifier.value) {
479
+ const result = [...identifiers]
480
+ const dobIndex = result.findIndex(i => i.type === 'DOB')
481
+ if (dobIndex !== -1) {
482
+ result[dobIndex] = {
483
+ ...dobIdentifier,
484
+ value: parsedDate.toLocaleDateString('en-CA') // YYYY-MM-DD format
485
+ }
486
+ setIdentifiers(result)
487
+ }
488
+ }
489
+ }
490
+ }
491
+ }, [decodedInfo?.dob, identifiers, setIdentifiers])
492
+
369
493
  return (
370
494
  <div>
371
495
  <div className='flex flex-col gap-1 w-full md:px-14 px-0 gap-2 md:mt-6 mt-0'>
372
- {showAlert &&
496
+ {/* {showAlert &&
373
497
  <div className='mb-4'>
374
498
  <AlertComp
375
499
  icon={
@@ -389,7 +513,7 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
389
513
  }
390
514
  />
391
515
  </div>
392
- }
516
+ } */}
393
517
  <div className='flex items-center justify-between gap-2'>
394
518
  <p className='text-md md:text-2xl font-semibold text-black dark:text-white'>
395
519
  {t('keywords.Discover') +
@@ -476,15 +600,30 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
476
600
  <div className='flex flex-col gap-1 md:w-[50%] w-full gap-2'>
477
601
  <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
478
602
  <PopoverTrigger asChild>
479
- <div className='flex h-[56px] w-full items-center justify-between rounded-md border bg-white border-gray-200 dark:border-gray-700 dark:bg-input/30 px-3 py-2 text-consent-primary dark:border-gray-700'>
603
+ {/* */}
604
+ <div
605
+ className={`flex h-[56px] w-full items-center justify-between rounded-md border bg-white border-gray-200 dark:border-gray-700 dark:bg-input/30 px-3 py-2 text-muted-foreground dark:border-gray-700 cursor-pointer`}
606
+ >
480
607
  {identifiers?.find(i => i.type === 'DOB')?.value ? (
481
- <span>{new Date(identifiers.find(i => i.type === 'DOB')?.value || '').toLocaleDateString('en-IN', { year: 'numeric', month: 'long', day: 'numeric' })}</span>
608
+ <span>
609
+ {
610
+ (() => {
611
+ const dobString = identifiers.find(i => i.type === 'DOB')?.value || '';
612
+ const [day, month, year] = dobString.split('/');
613
+ const dob = new Date(Number(year), Number(month) - 1, Number(day));
614
+ return dob.toLocaleDateString('en-IN', {
615
+ year: 'numeric',
616
+ month: 'long',
617
+ day: 'numeric'
618
+ });
619
+ })()
620
+ }
621
+ </span>
482
622
  ) : (
483
623
  <span className='text-muted-foreground'>Pick a date</span>
484
624
  )}
485
- <CalendarIcon className='h-4 w-4 opacity-50' />
625
+ <CalendarIcon className={`h-4 w-4 ${decodedInfo?.dob ? 'opacity-30' : 'opacity-50'}`} />
486
626
  </div>
487
-
488
627
  </PopoverTrigger>
489
628
  <PopoverContent className='w-auto p-0' align='start'>
490
629
  <Calendar
@@ -529,16 +668,22 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
529
668
  selected={identifiers?.find(i => i.type === 'DOB')?.value ? new Date(identifiers.find(i => i.type === 'DOB')?.value || '') : undefined}
530
669
  onSelect={(date) => {
531
670
  if (date) {
671
+ const dateValue = date.toLocaleString().split(',')[0]
532
672
  const result = [...identifiers]
533
673
  result.splice(
534
674
  result.findIndex(i => i.type === 'DOB'),
535
675
  1,
536
676
  {
537
677
  ...identifiers?.find(i => i.type === 'DOB'),
538
- value: date.toLocaleString().split(',')[0]
678
+ value: dateValue
539
679
  }
540
680
  )
541
681
  setIdentifiers(result)
682
+
683
+ // Also update redirect store immediately
684
+ const { updateIdentifiers } = useRedirectStore.getState()
685
+ updateIdentifiers(undefined, dateValue || undefined)
686
+
542
687
  setIsPopoverOpen(false)
543
688
  }
544
689
  }}
@@ -557,21 +702,27 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
557
702
  type='text'
558
703
  className={`h-[56px] bg-white border-gray-200 dark:border-gray-700 text-consent-primary text-md ${validationError.PAN ? 'border-red-500' : ''}`}
559
704
  placeholder={`Enter PAN`}
560
- value={identifiers?.find(i => i.type === 'PAN')?.value}
561
- readOnly={decodedInfo?.pan ? true : false}
705
+ value={identifiers?.find(i => i.type === 'PAN')?.value || ''}
706
+ // readOnly={decodedInfo?.pan ? true : false}
562
707
  onChange={e => {
563
708
  setValidationError(prev => ({ ...prev, PAN: null }))
564
709
  const panValue = e.target.value.replace(/[^A-Za-z0-9]/g, '').toUpperCase()
710
+
711
+ // Update identifiers array more safely
565
712
  const result = [...identifiers]
566
- result.splice(
567
- result.findIndex(i => i.type === 'PAN'),
568
- 1,
569
- {
570
- ...identifiers?.find(i => i.type === 'PAN'),
713
+ const panIndex = result.findIndex(i => i.type === 'PAN')
714
+
715
+ if (panIndex !== -1) {
716
+ result[panIndex] = {
717
+ ...result[panIndex],
571
718
  value: panValue
572
719
  }
573
- )
574
- setIdentifiers(result)
720
+ setIdentifiers(result)
721
+
722
+ // Also update redirect store immediately
723
+ const { updateIdentifiers } = useRedirectStore.getState()
724
+ updateIdentifiers(panValue || undefined, undefined)
725
+ }
575
726
 
576
727
  // Only validate when input reaches max length
577
728
  if (panValue.length >= 10) {
@@ -601,20 +752,22 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
601
752
  className={`h-[56px] bg-white border-gray-200 dark:border-gray-700 text-consent-primary text-md ${validationError.AADHAAR ? 'border-red-500' : ''}`}
602
753
  placeholder={`Enter AADHAAR`}
603
754
  readOnly={decodedInfo?.aadhaar ? true : false}
604
- value={identifiers?.find(i => i.type === 'AADHAAR')?.value}
755
+ value={identifiers?.find(i => i.type === 'AADHAAR')?.value || ''}
605
756
  onChange={e => {
606
757
  setValidationError(prev => ({ ...prev, AADHAAR: null }))
607
758
  const aadhaarValue = e.target.value.replace(/[^0-9]/g, '')
759
+
760
+ // Update identifiers array more safely
608
761
  const result = [...identifiers]
609
- result.splice(
610
- result.findIndex(i => i.type === 'AADHAAR'),
611
- 1,
612
- {
613
- ...identifiers?.find(i => i.type === 'AADHAAR'),
762
+ const aadhaarIndex = result.findIndex(i => i.type === 'AADHAAR')
763
+
764
+ if (aadhaarIndex !== -1) {
765
+ result[aadhaarIndex] = {
766
+ ...result[aadhaarIndex],
614
767
  value: aadhaarValue
615
768
  }
616
- )
617
- setIdentifiers(result)
769
+ setIdentifiers(result)
770
+ }
618
771
 
619
772
  // Only validate when input reaches max length
620
773
  if (aadhaarValue.length >= 12) {
@@ -710,13 +863,14 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
710
863
  title=''
711
864
  editable={true}
712
865
  mobileNumber={showModal.number}
866
+ eyeClassName="translate-x-2"
713
867
  onResend={() => {
714
868
  setShowModal(old => ({ ...old, otp: null, error: '' }))
715
869
  addNewNoQuery.mutate(undefined, {
716
870
  onSuccess: () => {
717
871
  setShowModal(old => ({ ...old, otp: null, error: '' }))
718
872
  },
719
- onError: (error: Error) => {
873
+ onError: (error: ApiError) => {
720
874
  setShowModal(old => ({ ...old, otp: null, error: error.response?.data?.errorMsg || 'Something went wrong' }))
721
875
  // console.error(error)
722
876
  }
@@ -743,8 +897,7 @@ const DiscoverAccount = ({ state, currentCategory }: DiscoverAccountProps) => {
743
897
  </AnimatedButton>
744
898
  </div> : showModal.content}
745
899
  </BottomSheet>
746
-
747
- </div >
900
+ </div>
748
901
  )
749
902
  }
750
903
 
@@ -8,7 +8,7 @@ import { Repeat } from 'lucide-react'
8
8
  import { Button } from '@/components/ui/button'
9
9
  import { MobileFooter } from '@/components/ui/mobile-footer'
10
10
  import WebFooter from '@/components/ui/web-footer'
11
- import { useFipStore } from '@/store/fip.store'
11
+ import { useFipStore, DiscoveredAccount } from '@/store/fip.store'
12
12
  import { Collapsible, CollapsibleContent } from '@/components/ui/collapsible'
13
13
  import { Input } from '@/components/ui/input'
14
14
  import { useMutation } from '@tanstack/react-query'
@@ -117,8 +117,11 @@ const SuccessAnimation = ({
117
117
  interface Account {
118
118
  id: string;
119
119
  fipId: string;
120
+ fipName: string;
121
+ signature: string;
120
122
  accounts: string;
121
123
  otp: string;
124
+ DiscoveredAccounts?: DiscoveredAccount[];
122
125
  }
123
126
 
124
127
  interface LinkSelectedAccountsProps {
@@ -157,13 +160,12 @@ const LinkSelectedAccounts = ({
157
160
  const {
158
161
  selectedAccountToLink,
159
162
  selectedMobileNumber,
160
- signature,
161
163
  accountsStatusArray,
162
164
  setAccountsStatusArray
163
165
  } = useFipStore()
164
166
 
165
167
  const sendBankOTPQuery = useMutation({
166
- mutationFn: ({ fipId, accounts }: { fipId: string; accounts: any[] }) =>
168
+ mutationFn: ({ fipId, accounts, signature }: { fipId: string; accounts: DiscoveredAccount[]; signature: string }) =>
167
169
  accountService.sendBankOTP({
168
170
  signature: signature || '',
169
171
  FipId: fipId || '',
@@ -236,9 +238,10 @@ const LinkSelectedAccounts = ({
236
238
  ) {
237
239
  sendBankOTPQuery.mutate({
238
240
  fipId: selectedAccountToLink[nextIndex].fipId,
239
- accounts: selectedAccountToLink[nextIndex]?.['DiscoveredAccounts']
241
+ accounts: selectedAccountToLink[nextIndex]?.DiscoveredAccounts || [],
242
+ signature: selectedAccountToLink[nextIndex]?.signature || ''
240
243
  })
241
- setIsExpanded({ item: selectedAccountToLink[nextIndex], expanded: true })
244
+ setIsExpanded({ item: { ...selectedAccountToLink[nextIndex], accounts: '', otp: '' }, expanded: true })
242
245
  } else {
243
246
  if (type != 'retry') { setIsExpanded({ item: null, expanded: false }) }
244
247
  }
@@ -313,10 +316,11 @@ const LinkSelectedAccounts = ({
313
316
  if (accountsStatusArray?.length) {
314
317
  handleNextActiveAccount()
315
318
  } else {
316
- setIsExpanded({ item: selectedAccountToLink[0], expanded: true })
319
+ setIsExpanded({ item: { ...selectedAccountToLink[0], accounts: '', otp: '' }, expanded: true })
317
320
  sendBankOTPQuery.mutate({
318
321
  fipId: selectedAccountToLink[0].fipId,
319
- accounts: selectedAccountToLink[0]?.['DiscoveredAccounts']
322
+ accounts: selectedAccountToLink[0]?.DiscoveredAccounts || [],
323
+ signature: selectedAccountToLink[0]?.signature || ''
320
324
  })
321
325
  }
322
326
  }
@@ -443,7 +447,8 @@ const LinkSelectedAccounts = ({
443
447
  ) {
444
448
  sendBankOTPQuery.mutate({
445
449
  fipId: account.fipId,
446
- accounts: account?.['DiscoveredAccounts']
450
+ accounts: account?.DiscoveredAccounts || [],
451
+ signature: account?.signature || ''
447
452
  })
448
453
  }
449
454
  setIsExpanded({
@@ -555,7 +560,8 @@ const LinkSelectedAccounts = ({
555
560
  onClick={() => {
556
561
  sendBankOTPQuery.mutate({
557
562
  fipId: account.fipId,
558
- accounts: account?.['DiscoveredAccounts']
563
+ accounts: account?.DiscoveredAccounts || [],
564
+ signature: account?.signature || ''
559
565
  })
560
566
  setOTPResent(true)
561
567
  }}