@finspringinnovations/fdsdk 0.0.1

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 (315) hide show
  1. package/README.md +184 -0
  2. package/lib/api/applicationApi.d.ts +1 -0
  3. package/lib/api/applicationApi.js +11 -0
  4. package/lib/api/bankApi.d.ts +352 -0
  5. package/lib/api/bankApi.js +54 -0
  6. package/lib/api/baseApi.d.ts +8 -0
  7. package/lib/api/baseApi.js +456 -0
  8. package/lib/api/customerApi.d.ts +855 -0
  9. package/lib/api/customerApi.js +213 -0
  10. package/lib/api/fdApi.d.ts +979 -0
  11. package/lib/api/fdApi.js +112 -0
  12. package/lib/api/fdCalculatorApi.d.ts +179 -0
  13. package/lib/api/fdCalculatorApi.js +36 -0
  14. package/lib/api/index.d.ts +14 -0
  15. package/lib/api/index.js +45 -0
  16. package/lib/api/interestRateApi.d.ts +585 -0
  17. package/lib/api/interestRateApi.js +101 -0
  18. package/lib/api/kycApi.d.ts +486 -0
  19. package/lib/api/kycApi.js +71 -0
  20. package/lib/api/masterDataApi.d.ts +158 -0
  21. package/lib/api/masterDataApi.js +32 -0
  22. package/lib/api/nomineeApi.d.ts +325 -0
  23. package/lib/api/nomineeApi.js +46 -0
  24. package/lib/api/onboardingApi.d.ts +192 -0
  25. package/lib/api/onboardingApi.js +41 -0
  26. package/lib/api/panApi.d.ts +0 -0
  27. package/lib/api/panApi.js +23 -0
  28. package/lib/api/paymentApi.d.ts +325 -0
  29. package/lib/api/paymentApi.js +46 -0
  30. package/lib/api/workflowApi.d.ts +654 -0
  31. package/lib/api/workflowApi.js +90 -0
  32. package/lib/assets/images/images.d.ts +4 -0
  33. package/lib/assets/images/images.js +10 -0
  34. package/lib/components/AadhaarInput.d.ts +13 -0
  35. package/lib/components/AadhaarInput.js +47 -0
  36. package/lib/components/ActionButton.d.ts +12 -0
  37. package/lib/components/ActionButton.js +87 -0
  38. package/lib/components/ActiveFDCard.d.ts +16 -0
  39. package/lib/components/ActiveFDCard.js +95 -0
  40. package/lib/components/AmountInput.d.ts +20 -0
  41. package/lib/components/AmountInput.js +144 -0
  42. package/lib/components/CheckboxOption.d.ts +11 -0
  43. package/lib/components/CheckboxOption.js +41 -0
  44. package/lib/components/CompanyHeader.d.ts +7 -0
  45. package/lib/components/CompanyHeader.js +57 -0
  46. package/lib/components/DropdownSelector.d.ts +9 -0
  47. package/lib/components/DropdownSelector.js +49 -0
  48. package/lib/components/EmptyState.d.ts +17 -0
  49. package/lib/components/EmptyState.js +44 -0
  50. package/lib/components/ErrorDisplay.d.ts +17 -0
  51. package/lib/components/ErrorDisplay.js +69 -0
  52. package/lib/components/FAQItem.d.ts +9 -0
  53. package/lib/components/FAQItem.js +52 -0
  54. package/lib/components/FDCard.d.ts +21 -0
  55. package/lib/components/FDCard.js +96 -0
  56. package/lib/components/FormDropdown.d.ts +18 -0
  57. package/lib/components/FormDropdown.js +155 -0
  58. package/lib/components/FormSection.d.ts +14 -0
  59. package/lib/components/FormSection.js +38 -0
  60. package/lib/components/Header.d.ts +14 -0
  61. package/lib/components/Header.js +52 -0
  62. package/lib/components/IFSCSearchResultCard.d.ts +13 -0
  63. package/lib/components/IFSCSearchResultCard.js +70 -0
  64. package/lib/components/InfoBox.d.ts +8 -0
  65. package/lib/components/InfoBox.js +39 -0
  66. package/lib/components/InterestRateCard.d.ts +8 -0
  67. package/lib/components/InterestRateCard.js +46 -0
  68. package/lib/components/LoadingIndicator.d.ts +12 -0
  69. package/lib/components/LoadingIndicator.js +30 -0
  70. package/lib/components/OTPInput.d.ts +17 -0
  71. package/lib/components/OTPInput.js +144 -0
  72. package/lib/components/PaymentDetailsCard.d.ts +20 -0
  73. package/lib/components/PaymentDetailsCard.js +68 -0
  74. package/lib/components/PendingFDBottomSheet.d.ts +18 -0
  75. package/lib/components/PendingFDBottomSheet.js +122 -0
  76. package/lib/components/SafeAreaWrapper.d.ts +13 -0
  77. package/lib/components/SafeAreaWrapper.js +41 -0
  78. package/lib/components/ScreenHeader.d.ts +11 -0
  79. package/lib/components/ScreenHeader.js +46 -0
  80. package/lib/components/StatusDisplay.d.ts +15 -0
  81. package/lib/components/StatusDisplay.js +88 -0
  82. package/lib/components/TextFieldWithLabel.d.ts +46 -0
  83. package/lib/components/TextFieldWithLabel.js +326 -0
  84. package/lib/components/TrustBox.d.ts +8 -0
  85. package/lib/components/TrustBox.js +45 -0
  86. package/lib/components/ValidationErrorAlert.d.ts +23 -0
  87. package/lib/components/ValidationErrorAlert.js +39 -0
  88. package/lib/components/ValidationMessage.d.ts +9 -0
  89. package/lib/components/ValidationMessage.js +98 -0
  90. package/lib/components/index.d.ts +35 -0
  91. package/lib/components/index.js +64 -0
  92. package/lib/config/apiConfig.d.ts +34 -0
  93. package/lib/config/apiConfig.js +158 -0
  94. package/lib/config/appDataConfig.d.ts +114 -0
  95. package/lib/config/appDataConfig.js +264 -0
  96. package/lib/config/encryptionConfig.d.ts +21 -0
  97. package/lib/config/encryptionConfig.js +61 -0
  98. package/lib/config/workflowConstants.d.ts +37 -0
  99. package/lib/config/workflowConstants.js +38 -0
  100. package/lib/constants/strings/bank.d.ts +72 -0
  101. package/lib/constants/strings/bank.js +86 -0
  102. package/lib/constants/strings/base64Images.d.ts +25 -0
  103. package/lib/constants/strings/base64Images.js +28 -0
  104. package/lib/constants/strings/common.d.ts +53 -0
  105. package/lib/constants/strings/common.js +62 -0
  106. package/lib/constants/strings/employee.d.ts +61 -0
  107. package/lib/constants/strings/employee.js +77 -0
  108. package/lib/constants/strings/faq.d.ts +14 -0
  109. package/lib/constants/strings/faq.js +20 -0
  110. package/lib/constants/strings/fd.d.ts +122 -0
  111. package/lib/constants/strings/fd.js +151 -0
  112. package/lib/constants/strings/home.d.ts +49 -0
  113. package/lib/constants/strings/home.js +62 -0
  114. package/lib/constants/strings/index.d.ts +16 -0
  115. package/lib/constants/strings/index.js +44 -0
  116. package/lib/constants/strings/kyc.d.ts +80 -0
  117. package/lib/constants/strings/kyc.js +94 -0
  118. package/lib/constants/strings/nominee.d.ts +64 -0
  119. package/lib/constants/strings/nominee.js +81 -0
  120. package/lib/hooks/useAuth.d.ts +25 -0
  121. package/lib/hooks/useAuth.js +39 -0
  122. package/lib/hooks/useFDData.d.ts +11 -0
  123. package/lib/hooks/useFDData.js +40 -0
  124. package/lib/index.d.ts +69 -0
  125. package/lib/index.js +182 -0
  126. package/lib/navigation/RootNavigator.d.ts +8 -0
  127. package/lib/navigation/RootNavigator.js +205 -0
  128. package/lib/navigation/SimpleNavigator.d.ts +11 -0
  129. package/lib/navigation/SimpleNavigator.js +107 -0
  130. package/lib/navigation/helpers.d.ts +11 -0
  131. package/lib/navigation/helpers.js +83 -0
  132. package/lib/navigation/index.d.ts +15 -0
  133. package/lib/navigation/index.js +42 -0
  134. package/lib/navigation/types.d.ts +113 -0
  135. package/lib/navigation/types.js +2 -0
  136. package/lib/navigation/workflowNavigator.d.ts +22 -0
  137. package/lib/navigation/workflowNavigator.js +104 -0
  138. package/lib/providers/ApiProvider.d.ts +7 -0
  139. package/lib/providers/ApiProvider.js +34 -0
  140. package/lib/providers/MasterDataProvider.d.ts +10 -0
  141. package/lib/providers/MasterDataProvider.js +54 -0
  142. package/lib/screens/AadhaarVerification.d.ts +7 -0
  143. package/lib/screens/AadhaarVerification.js +627 -0
  144. package/lib/screens/AddBankAccount.d.ts +22 -0
  145. package/lib/screens/AddBankAccount.js +381 -0
  146. package/lib/screens/BankDetail.d.ts +16 -0
  147. package/lib/screens/BankDetail.js +596 -0
  148. package/lib/screens/BookFD.d.ts +0 -0
  149. package/lib/screens/BookFD.js +315 -0
  150. package/lib/screens/Employee.d.ts +18 -0
  151. package/lib/screens/Employee.js +594 -0
  152. package/lib/screens/FDCalculator.d.ts +18 -0
  153. package/lib/screens/FDCalculator.js +759 -0
  154. package/lib/screens/FDList.d.ts +27 -0
  155. package/lib/screens/FDList.js +1008 -0
  156. package/lib/screens/FindIFSC.d.ts +16 -0
  157. package/lib/screens/FindIFSC.js +248 -0
  158. package/lib/screens/Home.d.ts +0 -0
  159. package/lib/screens/Home.js +143 -0
  160. package/lib/screens/NomineeDetail.d.ts +17 -0
  161. package/lib/screens/NomineeDetail.js +592 -0
  162. package/lib/screens/PayNow.d.ts +14 -0
  163. package/lib/screens/PayNow.js +230 -0
  164. package/lib/screens/Payment.d.ts +11 -0
  165. package/lib/screens/Payment.js +191 -0
  166. package/lib/screens/PaymentStatus.d.ts +16 -0
  167. package/lib/screens/PaymentStatus.js +397 -0
  168. package/lib/screens/ReviewKYC.d.ts +21 -0
  169. package/lib/screens/ReviewKYC.js +660 -0
  170. package/lib/state/paymentSession.d.ts +8 -0
  171. package/lib/state/paymentSession.js +13 -0
  172. package/lib/store/fdListSelectedSlice.d.ts +21 -0
  173. package/lib/store/fdListSelectedSlice.js +26 -0
  174. package/lib/store/hooks.d.ts +8 -0
  175. package/lib/store/hooks.js +31 -0
  176. package/lib/store/index.d.ts +3 -0
  177. package/lib/store/index.js +8 -0
  178. package/lib/store/onboardingSlice.d.ts +12 -0
  179. package/lib/store/onboardingSlice.js +32 -0
  180. package/lib/store/store.d.ts +13 -0
  181. package/lib/store/store.js +33 -0
  182. package/lib/theme/ThemeContext.d.ts +210 -0
  183. package/lib/theme/ThemeContext.js +90 -0
  184. package/lib/theme/colors.d.ts +80 -0
  185. package/lib/theme/colors.js +85 -0
  186. package/lib/theme/index.d.ts +34 -0
  187. package/lib/theme/index.js +69 -0
  188. package/lib/theme/shadows.d.ts +53 -0
  189. package/lib/theme/shadows.js +58 -0
  190. package/lib/theme/typography.d.ts +134 -0
  191. package/lib/theme/typography.js +143 -0
  192. package/lib/types/dataTypes.d.ts +34 -0
  193. package/lib/types/dataTypes.js +2 -0
  194. package/lib/types/workflowTypes.d.ts +2 -0
  195. package/lib/types/workflowTypes.js +2 -0
  196. package/lib/utils/apiLogger.d.ts +48 -0
  197. package/lib/utils/apiLogger.js +105 -0
  198. package/lib/utils/encryption.d.ts +28 -0
  199. package/lib/utils/encryption.js +113 -0
  200. package/lib/utils/getFDData.d.ts +48 -0
  201. package/lib/utils/getFDData.js +154 -0
  202. package/lib/utils/globalData.d.ts +2 -0
  203. package/lib/utils/globalData.js +10 -0
  204. package/package.json +76 -0
  205. package/src/api/applicationApi.ts +12 -0
  206. package/src/api/bankApi.ts +42 -0
  207. package/src/api/baseApi.ts +513 -0
  208. package/src/api/customerApi.ts +291 -0
  209. package/src/api/fdApi.ts +150 -0
  210. package/src/api/fdCalculatorApi.ts +41 -0
  211. package/src/api/index.ts +29 -0
  212. package/src/api/interestRateApi.ts +143 -0
  213. package/src/api/kycApi.ts +63 -0
  214. package/src/api/masterDataApi.ts +34 -0
  215. package/src/api/nomineeApi.ts +34 -0
  216. package/src/api/onboardingApi.ts +64 -0
  217. package/src/api/panApi.ts +25 -0
  218. package/src/api/paymentApi.ts +34 -0
  219. package/src/api/workflowApi.ts +94 -0
  220. package/src/assets/images/arrow-filled.png +0 -0
  221. package/src/assets/images/arrow-left.png +0 -0
  222. package/src/assets/images/backicon.png +0 -0
  223. package/src/assets/images/calendar.png +0 -0
  224. package/src/assets/images/chevron-down.png +0 -0
  225. package/src/assets/images/chevron-down@2x.png +0 -0
  226. package/src/assets/images/chevron-down@3x.png +0 -0
  227. package/src/assets/images/images.js +8 -0
  228. package/src/components/AadhaarInput.tsx +91 -0
  229. package/src/components/ActionButton.tsx +129 -0
  230. package/src/components/ActiveFDCard.tsx +158 -0
  231. package/src/components/AmountInput.tsx +217 -0
  232. package/src/components/CheckboxOption.tsx +93 -0
  233. package/src/components/CompanyHeader.tsx +78 -0
  234. package/src/components/DropdownSelector.tsx +77 -0
  235. package/src/components/EmptyState.tsx +109 -0
  236. package/src/components/ErrorDisplay.tsx +135 -0
  237. package/src/components/FAQItem.tsx +90 -0
  238. package/src/components/FDCard.tsx +165 -0
  239. package/src/components/FormDropdown.tsx +214 -0
  240. package/src/components/FormSection.tsx +86 -0
  241. package/src/components/Header.tsx +110 -0
  242. package/src/components/IFSCSearchResultCard.tsx +139 -0
  243. package/src/components/InfoBox.tsx +55 -0
  244. package/src/components/InterestRateCard.tsx +77 -0
  245. package/src/components/LoadingIndicator.tsx +63 -0
  246. package/src/components/OTPInput.tsx +213 -0
  247. package/src/components/PaymentDetailsCard.tsx +120 -0
  248. package/src/components/PendingFDBottomSheet.tsx +235 -0
  249. package/src/components/README.md +210 -0
  250. package/src/components/SafeAreaWrapper.tsx +68 -0
  251. package/src/components/ScreenHeader.tsx +83 -0
  252. package/src/components/StatusDisplay.tsx +139 -0
  253. package/src/components/TextFieldWithLabel.tsx +502 -0
  254. package/src/components/TrustBox.tsx +63 -0
  255. package/src/components/ValidationErrorAlert.tsx +57 -0
  256. package/src/components/ValidationMessage.tsx +134 -0
  257. package/src/components/index.tsx +47 -0
  258. package/src/config/apiConfig.ts +217 -0
  259. package/src/config/appDataConfig.ts +279 -0
  260. package/src/config/encryptionConfig.ts +65 -0
  261. package/src/config/workflowConstants.ts +43 -0
  262. package/src/constants/strings/README.md +146 -0
  263. package/src/constants/strings/bank.ts +92 -0
  264. package/src/constants/strings/base64Images.ts +29 -0
  265. package/src/constants/strings/common.ts +63 -0
  266. package/src/constants/strings/employee.ts +85 -0
  267. package/src/constants/strings/faq.ts +23 -0
  268. package/src/constants/strings/fd.ts +172 -0
  269. package/src/constants/strings/home.ts +67 -0
  270. package/src/constants/strings/index.ts +21 -0
  271. package/src/constants/strings/kyc.ts +100 -0
  272. package/src/constants/strings/nominee.ts +90 -0
  273. package/src/hooks/useAuth.ts +42 -0
  274. package/src/hooks/useFDData.ts +48 -0
  275. package/src/index.tsx +173 -0
  276. package/src/navigation/RootNavigator.tsx +352 -0
  277. package/src/navigation/SimpleNavigator.tsx +107 -0
  278. package/src/navigation/helpers.ts +85 -0
  279. package/src/navigation/index.tsx +81 -0
  280. package/src/navigation/types.ts +124 -0
  281. package/src/navigation/workflowNavigator.ts +131 -0
  282. package/src/providers/ApiProvider.tsx +43 -0
  283. package/src/providers/MasterDataProvider.tsx +30 -0
  284. package/src/screens/AadhaarVerification.tsx +809 -0
  285. package/src/screens/AddBankAccount.tsx +541 -0
  286. package/src/screens/BankDetail.tsx +826 -0
  287. package/src/screens/BookFD.tsx +330 -0
  288. package/src/screens/Employee.tsx +822 -0
  289. package/src/screens/FDCalculator.tsx +987 -0
  290. package/src/screens/FDList.tsx +1284 -0
  291. package/src/screens/FindIFSC.tsx +332 -0
  292. package/src/screens/Home.tsx +152 -0
  293. package/src/screens/NomineeDetail.tsx +800 -0
  294. package/src/screens/PayNow.tsx +282 -0
  295. package/src/screens/Payment.tsx +224 -0
  296. package/src/screens/PaymentStatus.tsx +561 -0
  297. package/src/screens/ReviewKYC.tsx +956 -0
  298. package/src/state/paymentSession.ts +13 -0
  299. package/src/store/fdListSelectedSlice.ts +42 -0
  300. package/src/store/hooks.ts +27 -0
  301. package/src/store/index.ts +3 -0
  302. package/src/store/onboardingSlice.ts +37 -0
  303. package/src/store/store.ts +35 -0
  304. package/src/theme/ThemeContext.tsx +82 -0
  305. package/src/theme/colors.ts +90 -0
  306. package/src/theme/index.ts +64 -0
  307. package/src/theme/shadows.ts +61 -0
  308. package/src/theme/typography.ts +151 -0
  309. package/src/types/dataTypes.ts +37 -0
  310. package/src/types/env.d.ts +93 -0
  311. package/src/types/workflowTypes.ts +12 -0
  312. package/src/utils/apiLogger.ts +166 -0
  313. package/src/utils/encryption.ts +159 -0
  314. package/src/utils/getFDData.ts +175 -0
  315. package/src/utils/globalData.ts +7 -0
@@ -0,0 +1,541 @@
1
+
2
+ import React, { useState, useRef, useEffect } from 'react';
3
+ import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, Image, TouchableWithoutFeedback, TextInput, KeyboardAvoidingView, Platform, BackHandler } from 'react-native';
4
+ import Icon from 'react-native-vector-icons/Ionicons';
5
+ import SafeAreaWrapper from '../components/SafeAreaWrapper';
6
+ import { Header, IFSCSearchResultCard } from '../components';
7
+ import ActionButton from '../components/ActionButton';
8
+ import TextFieldWithLabel from '../components/TextFieldWithLabel';
9
+ import { useColors, useTypography, useTheme } from '../theme/ThemeContext';
10
+ import { useMasterData } from '../providers/MasterDataProvider';
11
+ import { useFdBankAccountMutation } from '../api/fdApi';
12
+ import { useAppSelector } from '../store';
13
+ import { getUserInfoForAPI } from '../config/appDataConfig';
14
+ import { navigate } from '../navigation/helpers';
15
+ import { BANK_STRINGS } from '../constants/strings/bank';
16
+ import { COMMON_STRINGS } from '../constants/strings/common';
17
+ import { base64Images } from '../constants/strings/base64Images';
18
+
19
+ export interface AddBankAccountProps {
20
+ onGoBack?: () => void;
21
+ onContinue?: (data: AddBankAccountData) => void;
22
+ onFindIFSC?: () => void;
23
+ initialData?: Partial<AddBankAccountData>;
24
+ selectedIFSC?: IFSCData;
25
+ }
26
+
27
+ export interface IFSCData {
28
+ bankName: string;
29
+ branchName: string;
30
+ ifscCode: string;
31
+ bankShortDesc?: string;
32
+ bankCode?: string;
33
+ customerBankPk?: string;
34
+ }
35
+
36
+ export interface AddBankAccountData {
37
+ accountType: string;
38
+ accountNumber: string;
39
+ }
40
+
41
+ const defaultAccountTypeOptions = ['Saving', 'Current'];
42
+
43
+ const AddBankAccount: React.FC<AddBankAccountProps> = ({ onGoBack, onContinue, onFindIFSC, initialData, selectedIFSC }) => {
44
+
45
+ const colors = useColors();
46
+ const typography = useTypography();
47
+ const { themeName } = useTheme();
48
+ const styles = createStyles(colors, typography, themeName);
49
+ const workflowInstanceId = useAppSelector((state: any) => state?.onboarding?.workflowInstanceId);
50
+ const applicationId = useAppSelector((state: any) => state?.onboarding?.applicationId);
51
+ const customerId = useAppSelector((state: any) => state?.onboarding?.customerId);
52
+ const { masterData } = useMasterData();
53
+
54
+ // Get providerId from app data or use default
55
+ const defaultProviderId = useAppSelector((state: any) => state?.onboarding?.providerId);// Default Shriram provider ID
56
+
57
+
58
+ // FD Bank Account API
59
+ const [fdBankAccount, {
60
+ data: fdBankAccountResponse,
61
+ error: fdBankAccountError,
62
+ isLoading: isLoadingFDBankAccount,
63
+ }] = useFdBankAccountMutation();
64
+
65
+ // Normalize helper for arrays or CSV strings
66
+ const normalizeOptions = (raw: any, fallback: string[]): string[] => {
67
+ if (Array.isArray(raw)) return raw.map((v) => String(v)).filter(Boolean);
68
+ if (typeof raw === 'string' && raw.trim().length) return raw.split(',').map((v) => v.trim()).filter(Boolean);
69
+ return fallback;
70
+ };
71
+
72
+ // Prefer nested data if present, memoized to avoid re-creation on each render
73
+ const mdRoot: any = React.useMemo(() => {
74
+ return (masterData as any)?.data || masterData || {};
75
+ }, [masterData]);
76
+
77
+ // Get account type options from master data with fallback, memoized
78
+ const accountTypeOptions: string[] = React.useMemo(() => {
79
+ const raw = mdRoot?.bankAccountType || mdRoot?.accountTypeOptions || mdRoot?.accountTypes;
80
+ return normalizeOptions(raw, defaultAccountTypeOptions);
81
+ }, [mdRoot]);
82
+
83
+ const [form, setForm] = useState<AddBankAccountData>({
84
+ accountType: initialData?.accountType || '',
85
+ accountNumber: initialData?.accountNumber || '',
86
+ });
87
+
88
+ // Keep account type valid if options change after load
89
+ React.useEffect(() => {
90
+ setForm(prev => ({
91
+ ...prev,
92
+ accountType: accountTypeOptions.includes(prev.accountType) ? prev.accountType : '',
93
+ }));
94
+ }, [accountTypeOptions]);
95
+
96
+ // Track which fields have been touched by the user
97
+ const [touchedFields, setTouchedFields] = useState<{
98
+ accountType: boolean;
99
+ accountNumber: boolean;
100
+ }>({
101
+ accountType: false,
102
+ accountNumber: false,
103
+ });
104
+
105
+ // Show errors only for touched fields
106
+ React.useEffect(() => {
107
+ // Validate account type only if it has been touched
108
+ if (touchedFields.accountType && !form.accountType.trim()) {
109
+ setErrors(prev => ({ ...prev, accountType: BANK_STRINGS.ACCOUNT_TYPE_REQUIRED }));
110
+ } else if (touchedFields.accountType && form.accountType.trim()) {
111
+ setErrors(prev => ({ ...prev, accountType: undefined }));
112
+ }
113
+
114
+ // Validate account number if it has content and has been touched
115
+ if (touchedFields.accountNumber && form.accountNumber.trim() && !isAccountNumberValid(form.accountNumber)) {
116
+ setErrors(prev => ({ ...prev, accountNumber: BANK_STRINGS.INVALID_ACCOUNT_NUMBER }));
117
+ } else if (touchedFields.accountNumber && form.accountNumber.trim() && isAccountNumberValid(form.accountNumber)) {
118
+ setErrors(prev => ({ ...prev, accountNumber: undefined }));
119
+ }
120
+ }, [form.accountType, form.accountNumber, touchedFields]);
121
+
122
+ const [errors, setErrors] = useState<{
123
+ accountType?: string;
124
+ accountNumber?: string;
125
+ }>({});
126
+
127
+ const [openMenus, setOpenMenus] = useState({
128
+ accountType: false,
129
+ });
130
+
131
+ // Ref for account number text input to blur when dropdown is opened
132
+ const accountNumberRef = useRef<TextInput>(null);
133
+ // Ref for ScrollView to enable auto-scroll when input is focused
134
+ const scrollViewRef = useRef<ScrollView>(null);
135
+
136
+ const updateField = (field: keyof AddBankAccountData, value: string) => {
137
+ setForm(prev => ({ ...prev, [field]: value }));
138
+
139
+ // Mark field as touched when user interacts with it
140
+ setTouchedFields(prev => ({ ...prev, [field]: true }));
141
+ };
142
+
143
+ const toggleMenu = (key: keyof typeof openMenus) => {
144
+ // Remove focus from account number field when dropdown is opened
145
+ accountNumberRef.current?.blur();
146
+
147
+ // Mark field as touched when user opens dropdown
148
+ if (key === 'accountType') {
149
+ setTouchedFields(prev => ({ ...prev, accountType: true }));
150
+ }
151
+
152
+ setOpenMenus(prev => ({
153
+ accountType: key === 'accountType' ? !prev.accountType : false,
154
+ }));
155
+ };
156
+
157
+ const closeAllMenus = () => setOpenMenus({ accountType: false });
158
+
159
+ // FD bank account API status monitored
160
+
161
+ // Pure validation (does not update state)
162
+ const isAccountNumberValid = (accountNumber: string): boolean => {
163
+ const cleaned = accountNumber.replace(/\s/g, '');
164
+ if (!cleaned) return false;
165
+ if (!/^\d{9,18}$/.test(cleaned)) return false;
166
+ return true;
167
+ };
168
+
169
+ // Validation and set error
170
+ const validateAccountNumber = (accountNumber: string): boolean => {
171
+ const valid = isAccountNumberValid(accountNumber);
172
+ if (!valid) {
173
+ setErrors(prev => ({ ...prev, accountNumber: BANK_STRINGS.INVALID_ACCOUNT_NUMBER }));
174
+ } else {
175
+ setErrors(prev => ({ ...prev, accountNumber: undefined }));
176
+ }
177
+ return valid;
178
+ };
179
+
180
+
181
+ const handleAccountNumberBlur = () => {
182
+ if (form.accountNumber) {
183
+ validateAccountNumber(form.accountNumber);
184
+ }
185
+ };
186
+
187
+
188
+ const renderDropdown = (
189
+ label: string,
190
+ value: string,
191
+ field: keyof AddBankAccountData,
192
+ options: string[],
193
+ menuKey: keyof typeof openMenus,
194
+ ) => (
195
+ <View>
196
+ <TextFieldWithLabel
197
+ label={label}
198
+ value={value}
199
+ onChangeText={(text) => updateField(field, text)}
200
+ variant="dropdown"
201
+ options={options}
202
+ isDropdownOpen={openMenus[menuKey]}
203
+ onDropdownToggle={() => toggleMenu(menuKey)}
204
+ onDropdownSelect={(option) => {
205
+ closeAllMenus();
206
+ updateField(field, option);
207
+ setOpenMenus(prev => ({ ...prev, [menuKey]: false }));
208
+ }}
209
+ placeholder={BANK_STRINGS.ACCOUNT_TYPE_PLACEHOLDER}
210
+ />
211
+ {errors[field] && !openMenus[menuKey] && (
212
+ <View style={styles.errorContainer}>
213
+ {Platform.OS === 'android' && (
214
+ <Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
215
+ )}
216
+ <Text style={styles.errorText}>{errors[field]}</Text>
217
+ </View>
218
+ )}
219
+ {openMenus[menuKey] && (
220
+ <View style={styles.inlineMenu}>
221
+ {options.map((option) => (
222
+ <TouchableOpacity
223
+ key={option}
224
+ style={styles.modalOption}
225
+ onPress={() => {
226
+ closeAllMenus();
227
+ updateField(field, option);
228
+ setOpenMenus(prev => ({ ...prev, [menuKey]: false }));
229
+ }}
230
+ >
231
+ <Text style={styles.modalOptionText}>{option}</Text>
232
+ </TouchableOpacity>
233
+ ))}
234
+ </View>
235
+ )}
236
+ </View>
237
+ );
238
+
239
+ // Validation function to check if all required fields are filled (pure, no setErrors)
240
+ const isFormValid = (): boolean => {
241
+ const isAccountTypeValid = !!form.accountType;
242
+ const isAccountNumberValidVal = isAccountNumberValid(form.accountNumber);
243
+ const isIFSCSelected = !!selectedIFSC;
244
+ return isAccountTypeValid && isAccountNumberValidVal && isIFSCSelected;
245
+ };
246
+
247
+ const handleContinue = async () => {
248
+ // Mark all fields as touched when validating form
249
+ setTouchedFields({
250
+ accountType: true,
251
+ accountNumber: true,
252
+ });
253
+
254
+ // Validate all fields and set errors if needed
255
+ let valid = true;
256
+ if (!form.accountType) {
257
+ setErrors(prev => ({ ...prev, accountType: BANK_STRINGS.ACCOUNT_TYPE_REQUIRED }));
258
+ valid = false;
259
+ }
260
+ if (!isAccountNumberValid(form.accountNumber)) {
261
+ setErrors(prev => ({ ...prev, accountNumber: BANK_STRINGS.INVALID_ACCOUNT_NUMBER }));
262
+ valid = false;
263
+ }
264
+ if (!valid) {
265
+ Alert.alert(COMMON_STRINGS.REQUIRED_FIELD, COMMON_STRINGS.FILL_REQUIRED_FIELDS);
266
+ return;
267
+ }
268
+
269
+ // Check if IFSC data is available
270
+ if (!selectedIFSC) {
271
+ Alert.alert(COMMON_STRINGS.REQUIRED_FIELD, BANK_STRINGS.IFSC_CODE_REQUIRED);
272
+ return;
273
+ }
274
+
275
+ try {
276
+ // Get user info from app data
277
+ const userInfo = getUserInfoForAPI();
278
+
279
+ if (!customerId) {
280
+ Alert.alert(COMMON_STRINGS.ERROR, 'Customer ID not found. Please try again.');
281
+ return;
282
+ }
283
+
284
+ // Prepare FD bank account request data with required parameters
285
+ const fdBankAccountRequest = {
286
+ providerId: defaultProviderId,
287
+ workflowInstanceId: workflowInstanceId,
288
+ userreferenceid: userInfo.userReferenceId,
289
+ applicationid: applicationId,
290
+ accountType: form.accountType,
291
+ accountNumber: form.accountNumber,
292
+ ifscCode: selectedIFSC.ifscCode,
293
+ bankName: selectedIFSC.bankName,
294
+ branchName: selectedIFSC.branchName,
295
+ customerId: customerId,
296
+ };
297
+
298
+ const response = await fdBankAccount(fdBankAccountRequest).unwrap();
299
+
300
+ // Navigate to PayNow screen after successful API call
301
+ navigate('PayNow');
302
+ } catch (error) {
303
+
304
+ // Show error message to user and stay on current screen
305
+ Alert.alert(COMMON_STRINGS.ERROR, BANK_STRINGS.BANK_ACCOUNT_ADDED_FAILED);
306
+ }
307
+ };
308
+
309
+ // Handler for back button (used by both header and hardware back button)
310
+ const handleBackPress = () => {
311
+ navigate('BankDetail');
312
+ };
313
+
314
+ // Handle Android hardware back button
315
+ useEffect(() => {
316
+ if (Platform.OS !== 'android') return;
317
+
318
+ const onHardwareBackPress = () => {
319
+ handleBackPress();
320
+ return true; // Prevent default behavior
321
+ };
322
+
323
+ const backHandler = BackHandler.addEventListener(
324
+ 'hardwareBackPress',
325
+ onHardwareBackPress
326
+ );
327
+
328
+ return () => backHandler.remove();
329
+ }, []);
330
+
331
+ return (
332
+ <SafeAreaWrapper
333
+ includeTop={false}
334
+ bottomPadding={25}
335
+ statusBarColor="#000000"
336
+ statusBarStyle="light-content"
337
+ >
338
+ <Header
339
+ title={BANK_STRINGS.ADD_BANK_ACCOUNT_TITLE}
340
+ onBackPress={handleBackPress}
341
+ backgroundColor={colors.primary}
342
+ />
343
+
344
+ <KeyboardAvoidingView
345
+ style={{ flex: 1 }}
346
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
347
+ keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 0}
348
+ >
349
+ <ScrollView
350
+ ref={scrollViewRef}
351
+ style={styles.scrollContent}
352
+ showsVerticalScrollIndicator={false}
353
+ keyboardShouldPersistTaps="handled"
354
+ onScrollBeginDrag={closeAllMenus}
355
+ contentContainerStyle={styles.scrollContentContainer}
356
+ scrollEnabled={!isLoadingFDBankAccount}
357
+ >
358
+ <TouchableWithoutFeedback onPress={isLoadingFDBankAccount ? undefined : closeAllMenus}>
359
+ <View>
360
+ {renderDropdown(BANK_STRINGS.ACCOUNT_TYPE_LABEL, form.accountType, 'accountType', accountTypeOptions, 'accountType')}
361
+
362
+ <View>
363
+ <TextFieldWithLabel
364
+ label={BANK_STRINGS.ACCOUNT_NUMBER_LABEL}
365
+ value={form.accountNumber}
366
+ onChangeText={(text) => {
367
+ // Allow only numbers
368
+ const cleaned = text.replace(/\D/g, '');
369
+ updateField('accountNumber', cleaned);
370
+ }}
371
+ onFocus={() => {
372
+ closeAllMenus();
373
+ setTouchedFields(prev => ({ ...prev, accountNumber: true }));
374
+ // Scroll to input when focused to keep it visible above keyboard
375
+ setTimeout(() => {
376
+ scrollViewRef.current?.scrollToEnd({ animated: true });
377
+ }, 300);
378
+ }}
379
+ textInputRef={accountNumberRef}
380
+ placeholder={BANK_STRINGS.ACCOUNT_NUMBER_PLACEHOLDER}
381
+ variant="numeric"
382
+ keyboardType="numeric"
383
+ maxLength={18}
384
+ />
385
+ {errors.accountNumber && (
386
+ <View style={styles.errorContainer}>
387
+ {Platform.OS === 'android' && (
388
+ <Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
389
+ )}
390
+ <Text style={styles.errorText}>{errors.accountNumber}</Text>
391
+ </View>
392
+ )}
393
+ </View>
394
+
395
+ <View>
396
+ <Text style={styles.ifscLabel}>{BANK_STRINGS.IFSC_CODE_LABEL} (Required)</Text>
397
+ {(() => {
398
+ return null;
399
+ })()}
400
+ {selectedIFSC ? (
401
+ <IFSCSearchResultCard
402
+ bankName={selectedIFSC.bankName}
403
+ branchName={selectedIFSC.branchName}
404
+ ifscCode={selectedIFSC.ifscCode}
405
+ bankShortDesc={selectedIFSC.bankShortDesc}
406
+ bankCode={selectedIFSC.bankCode}
407
+ onSelect={onFindIFSC || (() => { })}
408
+ buttonTitle="Change"
409
+ />
410
+ ) : (
411
+ <TouchableOpacity style={styles.findIFSCButton} onPress={() => { closeAllMenus(); onFindIFSC?.(); }}>
412
+ <View style={styles.findIFSCContainer}>
413
+ <Image source={{ uri: base64Images.search }} style={styles.searchIcon} />
414
+ <Text style={styles.findIFSCText}>{BANK_STRINGS.FIND_IFSC_BUTTON}</Text>
415
+ </View>
416
+ </TouchableOpacity>
417
+ )}
418
+ </View>
419
+
420
+ </View>
421
+ </TouchableWithoutFeedback>
422
+ </ScrollView>
423
+ </KeyboardAvoidingView>
424
+
425
+ <View style={styles.footer}>
426
+ <ActionButton
427
+ title={COMMON_STRINGS.CONTINUE}
428
+ onPress={handleContinue}
429
+ disabled={isLoadingFDBankAccount || !isFormValid()}
430
+ loading={isLoadingFDBankAccount}
431
+ />
432
+ </View>
433
+ {/* Overlay to disable screen interactions during API call */}
434
+ {isLoadingFDBankAccount && (
435
+ <View style={styles.loadingOverlay} pointerEvents="auto">
436
+ </View>
437
+ )}
438
+ </SafeAreaWrapper>
439
+ );
440
+ };
441
+
442
+ const createStyles = (colors: any, typography: any, themeName: string) => StyleSheet.create({
443
+ scrollContent: {
444
+ flex: 1,
445
+ paddingHorizontal: 16,
446
+ paddingTop: 20,
447
+ },
448
+ scrollContentContainer: {
449
+ flexGrow: 1,
450
+ paddingBottom: 200,
451
+ },
452
+ footer: {
453
+ position: 'absolute',
454
+ bottom: 0,
455
+ left: 0,
456
+ right: 0,
457
+ backgroundColor: colors.background,
458
+ paddingHorizontal: 16,
459
+ paddingTop: 16,
460
+ paddingBottom: 25,
461
+ },
462
+ inlineMenu: {
463
+ backgroundColor: themeName === 'dark' ? colors.inputBackground : colors.background,
464
+ borderWidth: themeName === 'dark' ? 1 : 0.5,
465
+ borderColor: themeName === 'dark' ? '#ffffff' : 'rgba(0,0,0,0.2)',
466
+ borderRadius: 8,
467
+ marginTop: -20,
468
+ marginBottom: 10,
469
+ paddingHorizontal: 12,
470
+ paddingVertical: 6,
471
+ },
472
+ modalOption: {
473
+ paddingVertical: 14,
474
+ },
475
+ modalOptionText: {
476
+ ...typography.styles.bodyLarge,
477
+ color: colors.text,
478
+ },
479
+ ifscLabel: {
480
+ ...typography.styles.bodySmall,
481
+ color: colors.textLight,
482
+ marginBottom: 8,
483
+ },
484
+ findIFSCButton: {
485
+ marginBottom: 10,
486
+ },
487
+ findIFSCContainer: {
488
+ flexDirection: 'row',
489
+ alignItems: 'flex-start',
490
+ justifyContent: 'flex-start',
491
+ },
492
+ searchIcon: {
493
+ width: 14,
494
+ height: 14,
495
+ marginRight: 4,
496
+ marginTop: 2,
497
+ tintColor: colors.primary,
498
+ },
499
+ findIFSCText: {
500
+ ...typography.styles.bodyMedium,
501
+ color: colors.primary,
502
+ },
503
+ debugButton: {
504
+ paddingHorizontal: 16,
505
+ paddingVertical: 12,
506
+ borderRadius: 8,
507
+ marginBottom: 16,
508
+ alignItems: 'center',
509
+ },
510
+ debugButtonText: {
511
+ ...typography.styles.bodyMedium,
512
+ fontWeight: '600',
513
+ },
514
+ errorContainer: {
515
+ flexDirection: 'row',
516
+ alignItems: 'center',
517
+ marginTop: -20,
518
+ marginBottom: 20,
519
+ },
520
+ errorIcon: {
521
+ marginRight: 6,
522
+ },
523
+ errorText: {
524
+ fontSize: 12,
525
+ color: colors.error || '#FF0000',
526
+ flex: 1,
527
+ },
528
+ loadingOverlay: {
529
+ position: 'absolute',
530
+ top: 0,
531
+ left: 0,
532
+ right: 0,
533
+ bottom: 0,
534
+ backgroundColor: 'rgba(0, 0, 0, 0.3)',
535
+ zIndex: 1000,
536
+ },
537
+ });
538
+
539
+ export default AddBankAccount;
540
+
541
+