@finspringinnovations/fixeddepositsdk 1.0.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 (311) hide show
  1. package/README.md +128 -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 +6 -0
  7. package/lib/api/baseApi.js +406 -0
  8. package/lib/api/customerApi.d.ts +855 -0
  9. package/lib/api/customerApi.js +241 -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 +35 -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 +6 -0
  33. package/lib/assets/images/images.js +12 -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 +18 -0
  39. package/lib/components/ActiveFDCard.js +116 -0
  40. package/lib/components/AmountInput.d.ts +20 -0
  41. package/lib/components/AmountInput.js +142 -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 +59 -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 +23 -0
  55. package/lib/components/FDCard.js +116 -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 +19 -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 +46 -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 +159 -0
  95. package/lib/config/appDataConfig.js +310 -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 +62 -0
  99. package/lib/config/workflowConstants.js +63 -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 +26 -0
  103. package/lib/constants/strings/base64Images.js +29 -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 +48 -0
  125. package/lib/index.js +161 -0
  126. package/lib/navigation/RootNavigator.d.ts +9 -0
  127. package/lib/navigation/RootNavigator.js +459 -0
  128. package/lib/navigation/SimpleNavigator.d.ts +11 -0
  129. package/lib/navigation/SimpleNavigator.js +114 -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 +17 -0
  133. package/lib/navigation/index.js +42 -0
  134. package/lib/navigation/types.d.ts +139 -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 +16 -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/Employee.d.ts +18 -0
  149. package/lib/screens/Employee.js +594 -0
  150. package/lib/screens/FDCalculator.d.ts +18 -0
  151. package/lib/screens/FDCalculator.js +767 -0
  152. package/lib/screens/FDList.d.ts +28 -0
  153. package/lib/screens/FDList.js +1853 -0
  154. package/lib/screens/FindIFSC.d.ts +16 -0
  155. package/lib/screens/FindIFSC.js +248 -0
  156. package/lib/screens/NomineeDetail.d.ts +17 -0
  157. package/lib/screens/NomineeDetail.js +592 -0
  158. package/lib/screens/PayNow.d.ts +14 -0
  159. package/lib/screens/PayNow.js +230 -0
  160. package/lib/screens/Payment.d.ts +11 -0
  161. package/lib/screens/Payment.js +191 -0
  162. package/lib/screens/PaymentStatus.d.ts +16 -0
  163. package/lib/screens/PaymentStatus.js +431 -0
  164. package/lib/screens/ReviewKYC.d.ts +23 -0
  165. package/lib/screens/ReviewKYC.js +727 -0
  166. package/lib/state/paymentSession.d.ts +8 -0
  167. package/lib/state/paymentSession.js +13 -0
  168. package/lib/store/fdListSelectedSlice.d.ts +21 -0
  169. package/lib/store/fdListSelectedSlice.js +26 -0
  170. package/lib/store/hooks.d.ts +8 -0
  171. package/lib/store/hooks.js +8 -0
  172. package/lib/store/index.d.ts +3 -0
  173. package/lib/store/index.js +8 -0
  174. package/lib/store/onboardingSlice.d.ts +12 -0
  175. package/lib/store/onboardingSlice.js +32 -0
  176. package/lib/store/store.d.ts +13 -0
  177. package/lib/store/store.js +27 -0
  178. package/lib/theme/ThemeContext.d.ts +210 -0
  179. package/lib/theme/ThemeContext.js +92 -0
  180. package/lib/theme/colors.d.ts +80 -0
  181. package/lib/theme/colors.js +85 -0
  182. package/lib/theme/index.d.ts +35 -0
  183. package/lib/theme/index.js +78 -0
  184. package/lib/theme/shadows.d.ts +53 -0
  185. package/lib/theme/shadows.js +58 -0
  186. package/lib/theme/typography.d.ts +134 -0
  187. package/lib/theme/typography.js +143 -0
  188. package/lib/types/dataTypes.d.ts +34 -0
  189. package/lib/types/dataTypes.js +2 -0
  190. package/lib/types/workflowTypes.d.ts +2 -0
  191. package/lib/types/workflowTypes.js +2 -0
  192. package/lib/utils/apiLogger.d.ts +48 -0
  193. package/lib/utils/apiLogger.js +105 -0
  194. package/lib/utils/encryption.d.ts +28 -0
  195. package/lib/utils/encryption.js +113 -0
  196. package/lib/utils/getFDData.d.ts +48 -0
  197. package/lib/utils/getFDData.js +145 -0
  198. package/lib/utils/globalData.d.ts +2 -0
  199. package/lib/utils/globalData.js +10 -0
  200. package/package.json +51 -0
  201. package/src/api/applicationApi.ts +12 -0
  202. package/src/api/bankApi.ts +42 -0
  203. package/src/api/baseApi.ts +463 -0
  204. package/src/api/customerApi.ts +324 -0
  205. package/src/api/fdApi.ts +150 -0
  206. package/src/api/fdCalculatorApi.ts +41 -0
  207. package/src/api/index.ts +29 -0
  208. package/src/api/interestRateApi.ts +143 -0
  209. package/src/api/kycApi.ts +63 -0
  210. package/src/api/masterDataApi.ts +37 -0
  211. package/src/api/nomineeApi.ts +34 -0
  212. package/src/api/onboardingApi.ts +64 -0
  213. package/src/api/panApi.ts +25 -0
  214. package/src/api/paymentApi.ts +34 -0
  215. package/src/api/workflowApi.ts +94 -0
  216. package/src/assets/images/Mahindra.png +0 -0
  217. package/src/assets/images/arrow-filled.png +0 -0
  218. package/src/assets/images/arrow-left.png +0 -0
  219. package/src/assets/images/backicon.png +0 -0
  220. package/src/assets/images/calendar.png +0 -0
  221. package/src/assets/images/chevron-down.png +0 -0
  222. package/src/assets/images/chevron-down@2x.png +0 -0
  223. package/src/assets/images/chevron-down@3x.png +0 -0
  224. package/src/assets/images/images.js +10 -0
  225. package/src/assets/images/shriram_logo.png +0 -0
  226. package/src/components/AadhaarInput.tsx +91 -0
  227. package/src/components/ActionButton.tsx +129 -0
  228. package/src/components/ActiveFDCard.tsx +188 -0
  229. package/src/components/AmountInput.tsx +217 -0
  230. package/src/components/CheckboxOption.tsx +93 -0
  231. package/src/components/CompanyHeader.tsx +80 -0
  232. package/src/components/DropdownSelector.tsx +77 -0
  233. package/src/components/EmptyState.tsx +109 -0
  234. package/src/components/ErrorDisplay.tsx +135 -0
  235. package/src/components/FAQItem.tsx +90 -0
  236. package/src/components/FDCard.tsx +186 -0
  237. package/src/components/FormDropdown.tsx +214 -0
  238. package/src/components/FormSection.tsx +86 -0
  239. package/src/components/Header.tsx +110 -0
  240. package/src/components/IFSCSearchResultCard.tsx +139 -0
  241. package/src/components/InfoBox.tsx +55 -0
  242. package/src/components/InterestRateCard.tsx +77 -0
  243. package/src/components/LoadingIndicator.tsx +63 -0
  244. package/src/components/OTPInput.tsx +213 -0
  245. package/src/components/PaymentDetailsCard.tsx +120 -0
  246. package/src/components/PendingFDBottomSheet.tsx +237 -0
  247. package/src/components/README.md +210 -0
  248. package/src/components/SafeAreaWrapper.tsx +68 -0
  249. package/src/components/ScreenHeader.tsx +83 -0
  250. package/src/components/StatusDisplay.tsx +139 -0
  251. package/src/components/TextFieldWithLabel.tsx +502 -0
  252. package/src/components/TrustBox.tsx +63 -0
  253. package/src/components/ValidationErrorAlert.tsx +57 -0
  254. package/src/components/ValidationMessage.tsx +134 -0
  255. package/src/components/index.tsx +47 -0
  256. package/src/config/apiConfig.ts +217 -0
  257. package/src/config/appDataConfig.ts +358 -0
  258. package/src/config/encryptionConfig.ts +65 -0
  259. package/src/config/workflowConstants.ts +70 -0
  260. package/src/constants/strings/README.md +146 -0
  261. package/src/constants/strings/bank.ts +92 -0
  262. package/src/constants/strings/base64Images.ts +31 -0
  263. package/src/constants/strings/common.ts +63 -0
  264. package/src/constants/strings/employee.ts +85 -0
  265. package/src/constants/strings/faq.ts +23 -0
  266. package/src/constants/strings/fd.ts +172 -0
  267. package/src/constants/strings/home.ts +67 -0
  268. package/src/constants/strings/index.ts +21 -0
  269. package/src/constants/strings/kyc.ts +100 -0
  270. package/src/constants/strings/nominee.ts +90 -0
  271. package/src/hooks/useAuth.ts +42 -0
  272. package/src/hooks/useFDData.ts +48 -0
  273. package/src/index.tsx +139 -0
  274. package/src/navigation/RootNavigator.tsx +687 -0
  275. package/src/navigation/SimpleNavigator.tsx +123 -0
  276. package/src/navigation/helpers.ts +85 -0
  277. package/src/navigation/index.tsx +84 -0
  278. package/src/navigation/types.ts +146 -0
  279. package/src/navigation/workflowNavigator.ts +131 -0
  280. package/src/providers/ApiProvider.tsx +23 -0
  281. package/src/providers/MasterDataProvider.tsx +30 -0
  282. package/src/screens/AadhaarVerification.tsx +809 -0
  283. package/src/screens/AddBankAccount.tsx +541 -0
  284. package/src/screens/BankDetail.tsx +826 -0
  285. package/src/screens/Employee.tsx +822 -0
  286. package/src/screens/FDCalculator.tsx +1002 -0
  287. package/src/screens/FDList.tsx +2199 -0
  288. package/src/screens/FindIFSC.tsx +332 -0
  289. package/src/screens/NomineeDetail.tsx +800 -0
  290. package/src/screens/PayNow.tsx +282 -0
  291. package/src/screens/Payment.tsx +224 -0
  292. package/src/screens/PaymentStatus.tsx +595 -0
  293. package/src/screens/ReviewKYC.tsx +1062 -0
  294. package/src/state/paymentSession.ts +13 -0
  295. package/src/store/fdListSelectedSlice.ts +42 -0
  296. package/src/store/hooks.ts +6 -0
  297. package/src/store/index.ts +3 -0
  298. package/src/store/onboardingSlice.ts +37 -0
  299. package/src/store/store.ts +27 -0
  300. package/src/theme/ThemeContext.tsx +84 -0
  301. package/src/theme/colors.ts +90 -0
  302. package/src/theme/index.ts +85 -0
  303. package/src/theme/shadows.ts +61 -0
  304. package/src/theme/typography.ts +151 -0
  305. package/src/types/dataTypes.ts +37 -0
  306. package/src/types/env.d.ts +93 -0
  307. package/src/types/workflowTypes.ts +12 -0
  308. package/src/utils/apiLogger.ts +166 -0
  309. package/src/utils/encryption.ts +159 -0
  310. package/src/utils/getFDData.ts +165 -0
  311. package/src/utils/globalData.ts +7 -0
@@ -0,0 +1,1062 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { useRoute } from '@react-navigation/native';
3
+ import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, Image, TouchableWithoutFeedback, Keyboard, TextInput, BackHandler, Platform, ActivityIndicator, KeyboardAvoidingView } from 'react-native';
4
+ import Icon from 'react-native-vector-icons/Ionicons';
5
+ import SafeAreaWrapper from '../components/SafeAreaWrapper';
6
+ import { Header, DropdownSelector } from '../components';
7
+ import ActionButton from '../components/ActionButton';
8
+ import TextFieldWithLabel from '../components/TextFieldWithLabel';
9
+ import { useColors, useTypography, useTheme } from '../theme/ThemeContext';
10
+ import { usePreviousStateMutation } from '../api/workflowApi';
11
+ import { getAppData, getUserInfoForAPI } from '../config/appDataConfig';
12
+ import { useMasterData } from '../providers/MasterDataProvider';
13
+ import { navigate } from '../navigation/helpers';
14
+ import { useAppSelector } from '../store';
15
+ import { useGetCustomerApplicationDetailsMutation } from '../api/customerApi';
16
+ import { usePanRapidNoMutation } from '../api/kycApi';
17
+ import { getGlobalData } from '../utils/globalData';
18
+ import { base64Images } from '../constants/strings/base64Images';
19
+
20
+
21
+ export interface ReviewKYCProps {
22
+ onGoBack?: () => void;
23
+ onContinue?: (kycData: KYCData) => void;
24
+ initialData?: Partial<KYCData>;
25
+ }
26
+
27
+ export interface KYCData {
28
+ panCard: string; // Maps to appData.panNumber (required from main app)
29
+ dateOfBirth: string; // Maps to appData.dob (formatted from YYYY-MM-DD to DD/MM/YYYY for display)
30
+ maritalStatus: string; // Maps to appData.maritalStatus (uses full values like Married/Unmarried/Other)
31
+ kycRelation: string; // Relationship of the applicant for KYC purposes
32
+ kycRelationName: string; // Name corresponding to the selected KYC relation
33
+ area: string; // Maps to appData.area
34
+ city: string; // Maps to appData.city
35
+ addressLine1: string; // Maps to appData.address
36
+ addressLine2: string; // Maps to appData.area (secondary address line)
37
+ pincode: string; // Maps to appData.pinCode
38
+ state: string; // Maps to appData.state
39
+ country: string; // Maps to appData.country
40
+ useExistingAddress: boolean; // User preference for address usage
41
+ }
42
+
43
+ const ReviewKYC: React.FC<ReviewKYCProps> = ({
44
+ onGoBack,
45
+ onContinue,
46
+ initialData,
47
+ }) => {
48
+ const route = useRoute<any>();
49
+ const fdDataFromRoute = route?.params?.fdData;
50
+
51
+ // Route params processed
52
+
53
+ const colors = useColors();
54
+ const typography = useTypography();
55
+ const { themeName } = useTheme();
56
+ const styles = createStyles(colors, typography, themeName);
57
+
58
+ // Previous State API
59
+ const [previousState] = usePreviousStateMutation();
60
+ const { masterData, setMasterData } = useMasterData();
61
+ const workflowInstanceId = useAppSelector((state: any) => state?.onboarding?.workflowInstanceId);
62
+ const applicationId = useAppSelector((state: any) => state?.onboarding?.applicationId);
63
+ const customerId = useAppSelector((state: any) => state?.onboarding?.customerId);
64
+ const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
65
+ const wfStatus = useAppSelector((state: any) => state?.onboarding?.wfStatus);
66
+
67
+
68
+ // Customer Application Details API
69
+ const [getCustomerApplicationDetails, {
70
+ data: customerApplicationDetails,
71
+ error: customerApplicationDetailsError,
72
+ isLoading: isLoadingCustomerApplicationDetails,
73
+ }] = useGetCustomerApplicationDetailsMutation();
74
+
75
+ // PAN Rapid API
76
+ const [panRapidNo, {
77
+ data: panRapidResponse,
78
+ error: panRapidError,
79
+ isLoading: isLoadingPanRapid,
80
+ }] = usePanRapidNoMutation();
81
+
82
+ // Get providerId from app data or use default
83
+ const appData = getAppData();
84
+ const defaultProviderId = useAppSelector((state: any) => state?.onboarding?.providerId);// Default FD provider ID
85
+
86
+ // Use master data from global state if available
87
+ const effectiveMasterData = masterData;
88
+
89
+ // Call customer application details API on component mount
90
+ React.useEffect(() => {
91
+
92
+ // Ensure IDs are available from onboarding before calling API
93
+ if (!applicationId || !customerId) {
94
+ return;
95
+ }
96
+
97
+ // Use async/await for better error handling
98
+ const callAPI = async () => {
99
+ try {
100
+
101
+ // Add timeout to detect if API call is hanging
102
+ const timeoutPromise = new Promise((_, reject) => {
103
+ setTimeout(() => reject(new Error('API call timeout after 60 seconds')), 60000);
104
+ });
105
+
106
+ // Get user info from app data
107
+ const userInfo = getUserInfoForAPI();
108
+
109
+ const apiPromise = getCustomerApplicationDetails({
110
+ providerId: defaultProviderId,
111
+ applicationId: applicationId,
112
+ customerId: customerId,
113
+ workflowInstanceId: workflowInstanceId,
114
+ userreferenceid: userInfo.userReferenceId,
115
+ applicationid: applicationId,
116
+ entityid: entityId,
117
+ }).unwrap();
118
+
119
+ const response = await Promise.race([apiPromise, timeoutPromise]);
120
+ } catch (error) {
121
+ // Handle error silently or implement proper error handling
122
+ }
123
+ };
124
+
125
+ callAPI();
126
+ }, [applicationId, customerId, workflowInstanceId]);
127
+
128
+ // Update form data when API response is received
129
+ React.useEffect(() => {
130
+ if (customerApplicationDetails?.data) {
131
+ const apiData = customerApplicationDetails.data;
132
+
133
+ // Check if KYC details exist in the response
134
+ if (apiData.kyc_details && Array.isArray(apiData.kyc_details) && apiData.kyc_details.length > 0) {
135
+
136
+ // Use the first KYC detail (assuming there's one primary KYC record)
137
+ const kycDetail = apiData.kyc_details[0];
138
+
139
+ setKycData(prev => ({
140
+ ...prev,
141
+ // Map KYC detail fields to form fields - API data takes priority
142
+ panCard: kycDetail.panNumber || prev.panCard,
143
+ dateOfBirth: kycDetail.dob ? formatDateForDisplay(kycDetail.dob) : prev.dateOfBirth,
144
+ maritalStatus: kycDetail.maritalStatus || prev.maritalStatus,
145
+ kycRelation: kycDetail.kycRelation || kycDetail.KYCRelation || kycDetail.kycrelation || prev.kycRelation,
146
+ kycRelationName: kycDetail.kycRelationName || kycDetail.KYCRelationName || kycDetail.kycrelationname || prev.kycRelationName,
147
+ area: kycDetail.area || prev.area,
148
+ city: kycDetail.city || prev.city,
149
+ addressLine1: kycDetail.addressLine1 || kycDetail.address || prev.addressLine1,
150
+ addressLine2: kycDetail.addressLine2 || prev.addressLine2,
151
+ pincode: kycDetail.pincode || prev.pincode,
152
+ state: kycDetail.state || prev.state,
153
+ country: kycDetail.country || prev.country,
154
+ }));
155
+ }
156
+
157
+ // Also check for customer data in the response for marital status and other fields
158
+ if (apiData.customer) {
159
+ setKycData(prev => ({
160
+ ...prev,
161
+ maritalStatus: apiData.customer.marital_status || prev.maritalStatus,
162
+ dateOfBirth: apiData.customer.dob ? formatDateForDisplay(apiData.customer.dob) : prev.dateOfBirth,
163
+ kycRelation: apiData.customer.kycRelation || apiData.customer.KYCRelation || apiData.customer.kycrelation || prev.kycRelation,
164
+ kycRelationName: apiData.customer.kycRelationName || apiData.customer.KYCRelationName || apiData.customer.kycrelationname || prev.kycRelationName,
165
+ }));
166
+ }
167
+
168
+ // Check for address data in the response
169
+ if (apiData.address) {
170
+ setKycData(prev => ({
171
+ ...prev,
172
+ area: apiData.address.area || prev.area,
173
+ city: apiData.address.city || prev.city,
174
+ addressLine1: apiData.address.line1 || prev.addressLine1,
175
+ addressLine2: apiData.address.line2 || prev.addressLine2,
176
+ pincode: apiData.address.pincode || prev.pincode,
177
+ state: apiData.address.state || prev.state,
178
+ country: apiData.address.country || prev.country,
179
+ }));
180
+ }
181
+ }
182
+ }, [customerApplicationDetails]);
183
+
184
+ // App data is already loaded above
185
+
186
+ // Helper function to format date from YYYY-MM-DD to DD/MM/YYYY
187
+ const formatDateForDisplay = (dateString: string): string => {
188
+ if (!dateString) return '';
189
+ const [year, month, day] = dateString.split('-');
190
+ return `${day}/${month}/${year}`;
191
+ };
192
+
193
+ // Marital status is now used as-is from API without any code conversion
194
+
195
+ // App data processed
196
+
197
+ // API status monitoring complete
198
+
199
+ const initialKycRelation =
200
+ initialData?.kycRelation ??
201
+ (initialData as any)?.KYCRelation ??
202
+ (appData as any)?.kycRelation ??
203
+ (appData as any)?.KYCRelation ??
204
+ '';
205
+
206
+ const [kycData, setKycData] = useState<KYCData>({
207
+ panCard: initialData?.panCard || appData?.panNumber || '',
208
+ dateOfBirth: initialData?.dateOfBirth || formatDateForDisplay(appData?.dob || ''),
209
+ maritalStatus: initialData?.maritalStatus || appData?.maritalStatus || '', // Keep empty to show placeholder
210
+ kycRelation: initialKycRelation, // Keep empty to show placeholder
211
+ kycRelationName: (initialData as any)?.kycRelationName || (appData as any)?.kycRelationName || '',
212
+ area: initialData?.area || appData?.area || '',
213
+ city: initialData?.city || appData?.city || '',
214
+ addressLine1: initialData?.addressLine1 || appData?.address || '',
215
+ addressLine2: initialData?.addressLine2 || appData?.area || '', // Use area as address line 2
216
+ pincode: initialData?.pincode || appData?.pinCode || '',
217
+ state: initialData?.state || appData?.state || '',
218
+ country: initialData?.country || appData?.country || '',
219
+ useExistingAddress: initialData?.useExistingAddress ?? false,
220
+ });
221
+
222
+ // Error states for each field
223
+ const [fieldErrors, setFieldErrors] = useState<{ [key: string]: string }>({});
224
+
225
+ // State to track marital status dropdown visibility
226
+ const [showMaritalStatusMenu, setShowMaritalStatusMenu] = useState(false);
227
+ const [isGoingBack, setIsGoingBack] = useState(false);
228
+
229
+ //State to track KYC relation dropdown visibility
230
+ const [showKYCRelationMenu, setShowKYCRelationMenu] = useState(false);
231
+
232
+ // Ref to track currently focused text input
233
+ const focusedTextInputRef = useRef<TextInput | null>(null);
234
+
235
+ // Refs for each text field
236
+ const panCardRef = useRef<TextInput>(null);
237
+ const dateOfBirthRef = useRef<TextInput>(null);
238
+ const kycRelationNameRef = useRef<TextInput>(null);
239
+ const areaRef = useRef<TextInput>(null);
240
+ const cityRef = useRef<TextInput>(null);
241
+ const addressLine1Ref = useRef<TextInput>(null);
242
+ const addressLine2Ref = useRef<TextInput>(null);
243
+ const pincodeRef = useRef<TextInput>(null);
244
+ const stateRef = useRef<TextInput>(null);
245
+ const countryRef = useRef<TextInput>(null);
246
+
247
+ // Function to close dropdown when other fields are focused
248
+ const closeDropdown = () => {
249
+ setShowMaritalStatusMenu(false);
250
+ setShowKYCRelationMenu(false);
251
+ };
252
+
253
+ // Function to blur currently focused text input
254
+ const blurFocusedTextInput = () => {
255
+ if (focusedTextInputRef.current) {
256
+ focusedTextInputRef.current.blur();
257
+ focusedTextInputRef.current = null;
258
+ }
259
+ };
260
+
261
+ // Function to handle focus and store ref
262
+ const handleFieldFocus = (ref: React.RefObject<TextInput>) => {
263
+ // Blur any previously focused field
264
+ blurFocusedTextInput();
265
+ // Store the new focused field ref
266
+ focusedTextInputRef.current = ref.current;
267
+ // Close dropdown
268
+ closeDropdown();
269
+ };
270
+
271
+ // Add keyboard event listener to close dropdown when keyboard appears
272
+ useEffect(() => {
273
+ const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
274
+ closeDropdown();
275
+ });
276
+
277
+ return () => {
278
+ keyboardDidShowListener?.remove();
279
+ };
280
+ }, []);
281
+
282
+ // Get marital status options from master data with fallback
283
+ const maritalStatusOptions: string[] = React.useMemo(() => {
284
+ try {
285
+ const src = (effectiveMasterData as any)?.data || effectiveMasterData || {};
286
+ const raw = src?.maritalStatusOptions ||
287
+ src?.maritalStatusList ||
288
+ src?.maritalStatus ||
289
+ src?.maritalOptions;
290
+
291
+ if (Array.isArray(raw) && raw.length) {
292
+ return raw.map((v: any) => String(v)).filter(Boolean);
293
+ }
294
+ if (typeof raw === 'string' && raw.trim().length) {
295
+ return raw.split(',').map((v: string) => v.trim()).filter(Boolean);
296
+ }
297
+
298
+ // Fallback defaults
299
+ return ['Married', 'Unmarried', 'Other'];
300
+ } catch (e) {
301
+ return ['Married', 'Unmarried', 'Other'];
302
+ }
303
+ }, [effectiveMasterData]);
304
+ const kycRelationOptions: string[] = React.useMemo(() => {
305
+ try {
306
+ const src = (effectiveMasterData as any)?.data || effectiveMasterData || {};
307
+ const raw = src?.KYCRelation ||
308
+ src?.KYCRelation ||
309
+ src?.KYCRelation ||
310
+ src?.KYCRelation;
311
+
312
+ if (Array.isArray(raw) && raw.length) {
313
+ return raw.map((v: any) => String(v)).filter(Boolean);
314
+ }
315
+ if (typeof raw === 'string' && raw.trim().length) {
316
+ return raw.split(',').map((v: string) => v.trim()).filter(Boolean);
317
+ }
318
+
319
+ // Fallback defaults
320
+ return ['Father', 'Mother', 'Spouse'];
321
+ } catch (e) {
322
+ return ['Father', 'Mother', 'Spouse'];
323
+ }
324
+ }, [effectiveMasterData]);
325
+
326
+ // Do not auto-select a default marital status; keep empty to show placeholder when not provided by main app or API
327
+
328
+ // Validate individual field and set error
329
+ const validateField = (field: keyof KYCData, value: string): string => {
330
+ if (!value || value.trim().length === 0) {
331
+ // Use "District" for area field
332
+ if (field === 'area') {
333
+ return 'District is required';
334
+ }
335
+ if (field === 'kycRelation') {
336
+ return 'KYC relation is required';
337
+ }
338
+ if (field === 'kycRelationName') {
339
+ return 'KYC relation name is required';
340
+ }
341
+ return `${field.charAt(0).toUpperCase() + field.slice(1)} is required`;
342
+ }
343
+
344
+ // Minimum 2 characters validation for text fields (excluding PAN, pincode, dateOfBirth, maritalStatus)
345
+ const textFields = ['kycRelationName', 'area', 'city', 'addressLine1', 'addressLine2', 'state', 'country'];
346
+ if (textFields.includes(field)) {
347
+ if (value.trim().length < 2) {
348
+ // Use "Address" for addressLine1 and addressLine2
349
+ if (field === 'addressLine1' || field === 'addressLine2') {
350
+ return 'Address must be at least 2 characters';
351
+ } else if (field === 'area') {
352
+ return 'District must be at least 2 characters';
353
+ }
354
+ return `${field.charAt(0).toUpperCase() + field.slice(1)} must be at least 2 characters`;
355
+ }
356
+ }
357
+
358
+ // Special validation for PAN Card
359
+ if (field === 'panCard') {
360
+ const panRegex = /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/;
361
+ const upperValue = value.toUpperCase();
362
+ if (!panRegex.test(upperValue)) {
363
+ return 'Please enter a valid PAN (e.g., ABCDE1234F)';
364
+ }
365
+ }
366
+
367
+ // Special validation for pincode
368
+ if (field === 'pincode') {
369
+ if (!validatePincode(value)) {
370
+ return 'Please enter a valid 6-digit pincode (should not start with 0)';
371
+ }
372
+ }
373
+
374
+ return '';
375
+ };
376
+
377
+ // Render error message for a field
378
+ const renderFieldError = (field: keyof KYCData) => {
379
+ const error = fieldErrors[field];
380
+ if (!error) return null;
381
+
382
+ return (
383
+ <View style={styles.errorContainer}>
384
+ {Platform.OS === 'android' && (
385
+ <Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
386
+ )}
387
+ <Text style={styles.errorText}>{error}</Text>
388
+ </View>
389
+ );
390
+ };
391
+
392
+ // Enhanced field validation functions
393
+ const validateAndCleanText = (text: string, field: keyof KYCData): string => {
394
+ let cleanedText = text;
395
+
396
+ // Apply field-specific validation
397
+ switch (field) {
398
+ case 'panCard':
399
+ // Only allow alphanumeric, limit to 10 characters
400
+ // Don't uppercase here to prevent cursor jumping - let autoCapitalize handle display
401
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9]/g, '').substring(0, 10);
402
+ break;
403
+ case 'area':
404
+ // Allow only letters, numbers, spaces; collapse spaces; limit length
405
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9 ]/g, '').replace(/\s+/g, ' ').substring(0, 50);
406
+ break;
407
+ case 'city':
408
+ // Allow only letters, numbers, spaces; collapse spaces; limit length
409
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9 ]/g, '').replace(/\s+/g, ' ').substring(0, 30);
410
+ break;
411
+ case 'addressLine1':
412
+ case 'addressLine2':
413
+ // Allow letters, numbers, spaces, and common address special characters (comma, period, hyphen, slash, hash, parentheses, apostrophe, quotes)
414
+ // Collapse multiple spaces to single space; limit length
415
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9 ,./()#'"-]/g, '').replace(/\s+/g, ' ').substring(0, 100);
416
+ break;
417
+ case 'pincode':
418
+ // Only allow digits and limit to 6 characters
419
+ cleanedText = cleanedText.replace(/[^0-9]/g, '').substring(0, 6);
420
+ break;
421
+ case 'kycRelationName':
422
+ cleanedText = cleanedText.replace(/[^a-zA-Z ]/g, '').replace(/\s+/g, ' ').substring(0, 50);
423
+ break;
424
+ case 'state':
425
+ // Allow only letters, numbers, spaces; collapse spaces; limit length
426
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9 ]/g, '').replace(/\s+/g, ' ').substring(0, 40);
427
+ break;
428
+ case 'country':
429
+ // Allow only letters, numbers, spaces; collapse spaces; limit length
430
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9 ]/g, '').replace(/\s+/g, ' ').substring(0, 40);
431
+ break;
432
+ default:
433
+ // Default: allow only letters, numbers, spaces
434
+ cleanedText = cleanedText.replace(/[^a-zA-Z0-9 ]/g, '').replace(/\s+/g, ' ');
435
+ break;
436
+ }
437
+
438
+ return cleanedText;
439
+ };
440
+
441
+ const validatePincode = (pincode: string): boolean => {
442
+ // Must be exactly 6 digits
443
+ if (pincode.length !== 6) return false;
444
+
445
+ // Must be all digits
446
+ if (!/^\d{6}$/.test(pincode)) return false;
447
+
448
+ // Basic pincode validation (first digit should be 1-9, not 0)
449
+ if (pincode.startsWith('0')) return false;
450
+
451
+ return true;
452
+ };
453
+
454
+ const updateField = (field: keyof KYCData, value: string | boolean) => {
455
+
456
+ // Apply validation and cleaning for text fields
457
+ let processedValue = value;
458
+ if (typeof value === 'string' && field !== 'useExistingAddress') {
459
+ processedValue = validateAndCleanText(value, field);
460
+ }
461
+
462
+ setKycData(prev => {
463
+ const newData = {
464
+ ...prev,
465
+ [field]: processedValue
466
+ };
467
+
468
+ // Log checkbox state changes
469
+ if (field === 'useExistingAddress') {
470
+ // Checkbox state changed
471
+ }
472
+
473
+ return newData;
474
+ });
475
+
476
+ // Validate field and set error
477
+ if (typeof processedValue === 'string') {
478
+ const error = validateField(field, processedValue);
479
+ setFieldErrors(prev => ({
480
+ ...prev,
481
+ [field]: error,
482
+ }));
483
+ }
484
+ };
485
+
486
+ // Helper function to format date from DD/MM/YYYY back to YYYY-MM-DD
487
+ const formatDateForAPI = (dateString: string): string => {
488
+ if (!dateString) return '';
489
+ const [day, month, year] = dateString.split('/');
490
+ return `${year}-${month}-${day}`;
491
+ };
492
+
493
+ // Pass-through marital status: use the exact value from master data (no S/M/D mapping)
494
+ const getMaritalStatusCode = (display: string): string => {
495
+ return display || '';
496
+ };
497
+
498
+ // Validation function to check if all required fields are filled and valid
499
+ const validateForm = (): boolean => {
500
+ const requiredFields = [
501
+ kycData.panCard,
502
+ kycData.dateOfBirth,
503
+ kycData.maritalStatus,
504
+ kycData.kycRelation,
505
+ kycData.kycRelationName,
506
+ kycData.area,
507
+ kycData.city,
508
+ kycData.addressLine1,
509
+ kycData.pincode,
510
+ kycData.state,
511
+ kycData.country,
512
+ ];
513
+
514
+ // Check if all required fields are filled
515
+ const allFieldsFilled = requiredFields.every(field => field && field.trim().length > 0);
516
+
517
+ // Check minimum 2 characters for text fields (only if field is filled)
518
+ const textFields = {
519
+ kycRelationName: kycData.kycRelationName,
520
+ area: kycData.area,
521
+ city: kycData.city,
522
+ addressLine1: kycData.addressLine1,
523
+ state: kycData.state,
524
+ country: kycData.country,
525
+ };
526
+ const allTextFieldsValid = Object.values(textFields).every(field => {
527
+ // If field is empty, it's already checked by allFieldsFilled
528
+ // If field has value, it must be at least 2 characters
529
+ return !field || field.trim().length === 0 || field.trim().length >= 2;
530
+ });
531
+
532
+ // Additional validation for pincode
533
+ const isPincodeValid = validatePincode(kycData.pincode);
534
+
535
+ return allFieldsFilled && allTextFieldsValid && isPincodeValid;
536
+ };
537
+
538
+ const handleContinue = async () => {
539
+ console.log('following is the provider ID', defaultProviderId)
540
+ // try {
541
+
542
+ // // Validate all required fields
543
+ // if (!validateForm()) {
544
+ // // Check specifically for pincode validation
545
+ // if (!validatePincode(kycData.pincode)) {
546
+ // Alert.alert('Invalid Pincode', 'Please enter a valid 6-digit pincode (should not start with 0).');
547
+ // } else {
548
+ // Alert.alert('Required Fields', 'Please fill in all required fields before continuing.');
549
+ // }
550
+ // return;
551
+ // }
552
+
553
+ // // Convert the display format back to API format before sending
554
+ // const apiFormattedData = {
555
+ // ...kycData,
556
+ // dateOfBirth: formatDateForAPI(kycData.dateOfBirth),
557
+ // maritalStatus: getMaritalStatusCode(kycData.maritalStatus),
558
+ // kycRelation: kycData.kycRelation,
559
+ // kycRelationName: kycData.kycRelationName,
560
+ // };
561
+
562
+
563
+ // // Get user info from app data
564
+ // const userInfo = getUserInfoForAPI();
565
+
566
+ // // Call PAN rapid API (body fields from text fields/dropdowns)
567
+ // const panRapidRequest = {
568
+ // // headers via panApi: provider/workflowInstanceId/userreferenceid/applicationid
569
+ // providerId: defaultProviderId,
570
+ // workflowInstanceId, // from store
571
+ // userreferenceid: userInfo.userReferenceId,
572
+ // applicationid: applicationId,
573
+
574
+ // // required body params
575
+ // customerId: customerId,
576
+ // applicationId: applicationId,
577
+ // maritalStatus: getMaritalStatusCode(kycData.maritalStatus),
578
+ // kycRelation: kycData.kycRelation,
579
+ // kycRelationName: kycData.kycRelationName,
580
+ // area: kycData.area,
581
+ // addressLine1: kycData.addressLine1,
582
+ // addressLine2: kycData.addressLine2, // Added missing addressLine2 field
583
+ // city: kycData.city,
584
+ // state: kycData.state,
585
+ // country: kycData.country,
586
+ // pincode: kycData.pincode,
587
+ // panNo: kycData.panCard.toUpperCase(), // Uppercase PAN before sending to API
588
+ // mobileNo: userInfo.mobileNumber,
589
+ // addressConsentGiven: !!kycData.useExistingAddress,
590
+ // };
591
+
592
+
593
+ // const panResponse = await panRapidNo(panRapidRequest).unwrap();
594
+
595
+ // // Normalize payload (API returns data as array of one element)
596
+ // const payload: any = Array.isArray((panResponse as any)?.data)
597
+ // ? (panResponse as any).data[0]
598
+ // : (panResponse as any)?.data ?? (panResponse as any);
599
+
600
+ // // Extract fields with tolerant casing/locations
601
+ // const panRapidNumber = payload?.panRapidNumber ?? payload?.panrapidnumber ?? (panResponse as any)?.panRapidNumber ?? (panResponse as any)?.panrapidnumber ?? null;
602
+
603
+ // // Check demographicInfoSaved gate
604
+ // const demographicInfoSaved = payload?.demographicInfoSaved ?? (panResponse as any)?.demographicInfoSaved;
605
+
606
+ // if (!demographicInfoSaved) {
607
+ // Alert.alert('Action required', 'Your demographic information could not be saved. Please review the details and try again.');
608
+ // return;
609
+ // }
610
+ // const data = getGlobalData();
611
+ // // Decide next screen based on panrapidnumber existence
612
+ // if (panRapidNumber && data.completeFDData) {
613
+ // navigate('PayNow', { fdData: fdDataFromRoute });
614
+ // } else if (panRapidNumber) {
615
+ // navigate('Employee');
616
+ // } else {
617
+ // navigate('AadhaarVerification', { fdData: fdDataFromRoute });
618
+ // }
619
+
620
+ // // Do not trigger onContinue here; navigation is handled above
621
+
622
+ // } catch (error) {
623
+ // // Show error message to user
624
+ // Alert.alert(
625
+ // 'PAN Verification Failed',
626
+ // 'Unable to verify your PAN details. Please check your information and try again.',
627
+ // [{ text: 'OK' }]
628
+ // );
629
+
630
+ // // Do not navigate on failure - stay on current screen
631
+ // // User can retry or correct their information
632
+ // }
633
+ };
634
+
635
+ const renderInputField = (
636
+ label: string,
637
+ value: string,
638
+ field: keyof KYCData,
639
+ placeholder?: string,
640
+ editable: boolean = true,
641
+ variant: 'text' | 'numeric' | 'email' = 'text',
642
+ maxLength?: number,
643
+ textInputRef?: React.RefObject<TextInput>
644
+ ) => (
645
+ <View>
646
+ <TextFieldWithLabel
647
+ label={label}
648
+ value={value}
649
+ onChangeText={(text) => updateField(field, text)}
650
+ placeholder={placeholder}
651
+ editable={editable}
652
+ variant={variant}
653
+ maxLength={maxLength}
654
+ keyboardType={variant === 'numeric' ? 'numeric' : variant === 'email' ? 'email-address' : 'default'}
655
+ autoCapitalize={variant === 'email' ? 'none' : 'words'}
656
+ onFocus={() => textInputRef && handleFieldFocus(textInputRef)}
657
+ textInputRef={textInputRef}
658
+ returnKeyType="done"
659
+ onSubmitEditing={() => {
660
+ if (textInputRef?.current) {
661
+ textInputRef.current.blur();
662
+ }
663
+ Keyboard.dismiss();
664
+ }}
665
+ />
666
+ {renderFieldError(field)}
667
+ </View>
668
+ );
669
+
670
+ const renderMaritalStatusDropdown = () => {
671
+ return (
672
+ <View>
673
+ <TextFieldWithLabel
674
+ label="Marital Status"
675
+ value={kycData.maritalStatus}
676
+ onChangeText={(text) => updateField('maritalStatus', text)}
677
+ variant="dropdown"
678
+ options={maritalStatusOptions}
679
+ isDropdownOpen={showMaritalStatusMenu}
680
+ onDropdownToggle={() => {
681
+ // Blur any focused text field when dropdown is opened
682
+ blurFocusedTextInput();
683
+ setShowKYCRelationMenu(false);
684
+ setShowMaritalStatusMenu(prev => !prev);
685
+ }}
686
+ onDropdownSelect={(option) => {
687
+ setShowMaritalStatusMenu(false);
688
+ updateField('maritalStatus', option);
689
+ }}
690
+ placeholder="Select Marital Status"
691
+ editable={true}
692
+ />
693
+ {showMaritalStatusMenu && (
694
+ <View style={styles.inlineMenu}>
695
+ {maritalStatusOptions.map((option: string) => (
696
+ <TouchableOpacity
697
+ key={option}
698
+ style={styles.modalOption}
699
+ onPress={() => {
700
+ setShowMaritalStatusMenu(false);
701
+ updateField('maritalStatus', option);
702
+ }}
703
+ >
704
+ <Text style={styles.modalOptionText}>{option}</Text>
705
+ </TouchableOpacity>
706
+ ))}
707
+ </View>
708
+ )}
709
+ {renderFieldError('maritalStatus')}
710
+ </View>
711
+ );
712
+ };
713
+ const renderKycRelationDropDown = () => {
714
+ return (
715
+ <View>
716
+ <TextFieldWithLabel
717
+ label="KYC Relation"
718
+ value={kycData.kycRelation}
719
+ onChangeText={(text) => updateField('kycRelation', text)}
720
+ variant="dropdown"
721
+ options={kycRelationOptions}
722
+ isDropdownOpen={showKYCRelationMenu}
723
+ onDropdownToggle={() => {
724
+ // Blur any focused text field when dropdown is opened
725
+ blurFocusedTextInput();
726
+ setShowMaritalStatusMenu(false);
727
+ setShowKYCRelationMenu(prev => !prev);
728
+ }}
729
+ onDropdownSelect={(option) => {
730
+ setShowKYCRelationMenu(false);
731
+ updateField('kycRelation', option);
732
+ }}
733
+ placeholder="Select KYC Relation"
734
+ editable={true}
735
+ />
736
+ {showKYCRelationMenu && (
737
+ <View style={styles.inlineMenu}>
738
+ {kycRelationOptions.map((option: string) => (
739
+ <TouchableOpacity
740
+ key={option}
741
+ style={styles.modalOption}
742
+ onPress={() => {
743
+ setShowKYCRelationMenu(false);
744
+ updateField('kycRelation', option);
745
+ }}
746
+ >
747
+ <Text style={styles.modalOptionText}>{option}</Text>
748
+ </TouchableOpacity>
749
+ ))}
750
+ </View>
751
+ )}
752
+ {renderFieldError('kycRelation')}
753
+ </View>
754
+ );
755
+ };
756
+
757
+ const renderDateField = (
758
+ label: string,
759
+ value: string,
760
+ field: keyof KYCData,
761
+ editable: boolean = true,
762
+ textInputRef?: React.RefObject<TextInput>
763
+ ) => (
764
+ <View>
765
+ <TextFieldWithLabel
766
+ label={label}
767
+ value={value}
768
+ onChangeText={(text) => updateField(field, text)}
769
+ variant="date"
770
+ placeholder="DD/MM/YYYY"
771
+ maxLength={10}
772
+ dateFormat="DD/MM/YYYY"
773
+ editable={editable}
774
+ onFocus={() => textInputRef && handleFieldFocus(textInputRef)}
775
+ textInputRef={textInputRef}
776
+ onDatePress={() => {
777
+ // TODO: Implement date picker if needed
778
+ }}
779
+ returnKeyType="done"
780
+ onSubmitEditing={() => {
781
+ if (textInputRef?.current) {
782
+ textInputRef.current.blur();
783
+ }
784
+ Keyboard.dismiss();
785
+ }}
786
+ />
787
+ {renderFieldError(field)}
788
+ </View>
789
+ );
790
+
791
+ // Handler for back button (used by both header and hardware back button)
792
+ const handleBackPress = async () => {
793
+ setIsGoingBack(true);
794
+ try {
795
+ const userInfo = getUserInfoForAPI();
796
+ await previousState({
797
+ providerId: defaultProviderId,
798
+ workflowInstanceId,
799
+ userreferenceid: userInfo.userReferenceId,
800
+ applicationid: applicationId,
801
+ entityid: entityId,
802
+ });
803
+ } catch (e) {
804
+ // Handle error silently
805
+ } finally {
806
+ setIsGoingBack(false);
807
+ //onGoBack?.();
808
+ navigate('FDCalculator');
809
+ }
810
+ };
811
+
812
+ // Handle Android hardware back button
813
+ useEffect(() => {
814
+ if (Platform.OS !== 'android') return;
815
+
816
+ const onHardwareBackPress = () => {
817
+ handleBackPress();
818
+ return true; // Prevent default behavior
819
+ };
820
+
821
+ const backHandler = BackHandler.addEventListener(
822
+ 'hardwareBackPress',
823
+ onHardwareBackPress
824
+ );
825
+
826
+ return () => backHandler.remove();
827
+ }, [defaultProviderId, workflowInstanceId, applicationId, entityId]);
828
+
829
+ return (
830
+ <SafeAreaWrapper
831
+ includeTop={false}
832
+ bottomPadding={25}
833
+ statusBarColor="#000000"
834
+ statusBarStyle="light-content"
835
+ >
836
+ <Header
837
+ title="Review KYC"
838
+ onBackPress={handleBackPress}
839
+ backgroundColor={colors.primary}
840
+ />
841
+
842
+ <KeyboardAvoidingView
843
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
844
+ style={styles.keyboardAvoidingView}
845
+ keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 0}
846
+ >
847
+ <ScrollView
848
+ style={styles.container}
849
+ showsVerticalScrollIndicator={false}
850
+ scrollEnabled={!isLoadingPanRapid}
851
+ keyboardShouldPersistTaps="handled"
852
+ contentContainerStyle={styles.scrollContent}
853
+ >
854
+ <TouchableWithoutFeedback onPress={isLoadingPanRapid ? undefined : closeDropdown}>
855
+ <View>
856
+ <View>
857
+ <TextFieldWithLabel
858
+ label="PAN Card"
859
+ value={kycData.panCard}
860
+ onChangeText={(text) => updateField('panCard', text)}
861
+ placeholder="Enter PAN Card"
862
+ editable={false}
863
+ variant="text"
864
+ maxLength={10}
865
+ keyboardType="default"
866
+ autoCapitalize="characters"
867
+ onFocus={() => handleFieldFocus(panCardRef)}
868
+ textInputRef={panCardRef}
869
+ returnKeyType="done"
870
+ onSubmitEditing={() => {
871
+ if (panCardRef?.current) {
872
+ panCardRef.current.blur();
873
+ }
874
+ Keyboard.dismiss();
875
+ }}
876
+ />
877
+ {renderFieldError('panCard')}
878
+ </View>
879
+
880
+ {renderDateField('Date of Birth', kycData.dateOfBirth, 'dateOfBirth', false, dateOfBirthRef)}
881
+
882
+ {renderMaritalStatusDropdown()}
883
+
884
+ {renderKycRelationDropDown()}
885
+
886
+ {renderInputField('KYC Relation Name', kycData.kycRelationName, 'kycRelationName', 'Enter KYC Relation Name', true, 'text', 50, kycRelationNameRef)}
887
+
888
+ {renderInputField('District', kycData.area, 'area', 'Enter District', true, 'text', 50, areaRef)}
889
+
890
+ {renderInputField('City', kycData.city, 'city', 'Enter City', true, 'text', 30, cityRef)}
891
+
892
+ {renderInputField('Address line 1', kycData.addressLine1, 'addressLine1', 'Enter Address Line 1', true, 'text', 100, addressLine1Ref)}
893
+
894
+ {renderInputField('Address line 2', kycData.addressLine2, 'addressLine2', 'Enter Address Line 2', true, 'text', 100, addressLine2Ref)}
895
+
896
+ {renderInputField('Pincode', kycData.pincode, 'pincode', 'Enter Pincode', true, 'numeric', 6, pincodeRef)}
897
+
898
+ {renderInputField('State', kycData.state, 'state', 'Enter State', true, 'text', undefined, stateRef)}
899
+
900
+ {renderInputField('Country', kycData.country, 'country', 'Enter Country', true, 'text', undefined, countryRef)}
901
+
902
+ <View style={styles.checkboxContainer}>
903
+ <TouchableOpacity
904
+ style={styles.checkbox}
905
+ onPress={() => updateField('useExistingAddress', !kycData.useExistingAddress)}
906
+ >
907
+ <View style={[
908
+ styles.checkboxBox,
909
+ kycData.useExistingAddress && styles.checkboxChecked
910
+ ]}>
911
+ {kycData.useExistingAddress ? (
912
+ <Image
913
+ source={{ uri: (themeName === 'dark') ? base64Images.checkBoxDark : base64Images.filledCheckBox }}
914
+ resizeMode="cover"
915
+ width={20}
916
+ height={20}
917
+ />
918
+ ) : (
919
+ (themeName === 'dark') ? (
920
+ <Image
921
+ source={{ uri: base64Images.unCheckBoxDark }}
922
+ resizeMode="cover"
923
+ width={20}
924
+ height={20}
925
+ />
926
+ ) : null
927
+ )}
928
+ </View>
929
+ </TouchableOpacity>
930
+ <Text style={styles.checkboxText}>
931
+ For existing customers, we'll use the address from our records. For new customers, the address from your Aadhar card will be used. To update, please raise a service request with valid address proof.
932
+ </Text>
933
+ </View>
934
+
935
+
936
+ </View>
937
+ </TouchableWithoutFeedback>
938
+ </ScrollView>
939
+ </KeyboardAvoidingView>
940
+ <ActionButton
941
+ title="Continue"
942
+ onPress={handleContinue}
943
+ disabled={!kycData.useExistingAddress || isLoadingPanRapid || !validateForm()}
944
+ loading={isLoadingPanRapid}
945
+ />
946
+ {/* Overlay to disable screen interactions during API call */}
947
+ {isLoadingPanRapid && (
948
+ <View style={styles.loadingOverlay} pointerEvents="auto">
949
+ </View>
950
+ )}
951
+ {/* Loading overlay for back navigation */}
952
+ {isGoingBack && (
953
+ <View style={styles.loadingOverlay} pointerEvents="auto">
954
+ <ActivityIndicator size="large" color={colors.primary} />
955
+ </View>
956
+ )}
957
+ </SafeAreaWrapper>
958
+ );
959
+ };
960
+
961
+ const createStyles = (colors: any, typography: any, themeName?: string) => StyleSheet.create({
962
+ keyboardAvoidingView: {
963
+ flex: 1,
964
+ },
965
+ container: {
966
+ flex: 1,
967
+ paddingHorizontal: 16,
968
+ paddingTop: 20,
969
+ },
970
+ scrollContent: {
971
+ flexGrow: 1,
972
+ },
973
+ checkboxContainer: {
974
+ flexDirection: 'row',
975
+ alignItems: 'flex-start',
976
+ marginBottom: 40,
977
+ paddingHorizontal: 4,
978
+ marginTop: 16,
979
+ },
980
+ checkbox: {
981
+ marginRight: 12,
982
+ marginTop: 2,
983
+ },
984
+ checkboxBox: {
985
+ width: 20,
986
+ height: 20,
987
+ borderWidth: 2,
988
+ borderColor: themeName === 'dark' ? colors.tabSelected : colors.primary,
989
+ borderRadius: 4,
990
+ alignItems: 'center',
991
+ justifyContent: 'center',
992
+ backgroundColor: 'white',
993
+ },
994
+ checkboxChecked: {
995
+ // backgroundColor: colors.primary,
996
+ },
997
+ checkboxText: {
998
+ ...typography.styles.bodySmall,
999
+ color: colors.textLight,
1000
+ flex: 1,
1001
+ lineHeight: 18,
1002
+ },
1003
+ inlineMenu: {
1004
+ backgroundColor: themeName === 'dark' ? colors.inputBackground : colors.background,
1005
+ borderWidth: themeName === 'dark' ? 1 : 0.5,
1006
+ borderColor: themeName === 'dark' ? '#ffffff' : 'rgba(0,0,0,0.2)',
1007
+ borderRadius: 8,
1008
+ marginTop: -20,
1009
+ marginBottom: 10,
1010
+ paddingHorizontal: 12,
1011
+ paddingVertical: 6,
1012
+ },
1013
+ modalOption: {
1014
+ paddingVertical: 14,
1015
+ },
1016
+ modalOptionText: {
1017
+ ...typography.styles.bodyLarge,
1018
+ color: colors.text,
1019
+ },
1020
+ debugButtonsContainer: {
1021
+ marginBottom: 16,
1022
+ },
1023
+ debugButton: {
1024
+ paddingHorizontal: 16,
1025
+ paddingVertical: 12,
1026
+ borderRadius: 8,
1027
+ marginBottom: 8,
1028
+ alignItems: 'center',
1029
+ },
1030
+ debugButtonText: {
1031
+ ...typography.styles.bodyMedium,
1032
+ fontWeight: '600',
1033
+ },
1034
+ errorContainer: {
1035
+ flexDirection: 'row',
1036
+ alignItems: 'center',
1037
+ marginTop: -20,
1038
+ marginBottom: 20,
1039
+ },
1040
+ errorIcon: {
1041
+ marginRight: 6,
1042
+ },
1043
+ errorText: {
1044
+ fontSize: 12,
1045
+ color: colors.error || '#FF0000',
1046
+ fontWeight: '500',
1047
+ flex: 1,
1048
+ },
1049
+ loadingOverlay: {
1050
+ position: 'absolute',
1051
+ top: 0,
1052
+ left: 0,
1053
+ right: 0,
1054
+ bottom: 0,
1055
+ backgroundColor: 'rgba(0, 0, 0, 0.3)',
1056
+ justifyContent: 'center',
1057
+ alignItems: 'center',
1058
+ zIndex: 1000,
1059
+ },
1060
+ });
1061
+
1062
+ export default ReviewKYC;