@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.
- package/README.md +184 -0
- package/lib/api/applicationApi.d.ts +1 -0
- package/lib/api/applicationApi.js +11 -0
- package/lib/api/bankApi.d.ts +352 -0
- package/lib/api/bankApi.js +54 -0
- package/lib/api/baseApi.d.ts +8 -0
- package/lib/api/baseApi.js +456 -0
- package/lib/api/customerApi.d.ts +855 -0
- package/lib/api/customerApi.js +213 -0
- package/lib/api/fdApi.d.ts +979 -0
- package/lib/api/fdApi.js +112 -0
- package/lib/api/fdCalculatorApi.d.ts +179 -0
- package/lib/api/fdCalculatorApi.js +36 -0
- package/lib/api/index.d.ts +14 -0
- package/lib/api/index.js +45 -0
- package/lib/api/interestRateApi.d.ts +585 -0
- package/lib/api/interestRateApi.js +101 -0
- package/lib/api/kycApi.d.ts +486 -0
- package/lib/api/kycApi.js +71 -0
- package/lib/api/masterDataApi.d.ts +158 -0
- package/lib/api/masterDataApi.js +32 -0
- package/lib/api/nomineeApi.d.ts +325 -0
- package/lib/api/nomineeApi.js +46 -0
- package/lib/api/onboardingApi.d.ts +192 -0
- package/lib/api/onboardingApi.js +41 -0
- package/lib/api/panApi.d.ts +0 -0
- package/lib/api/panApi.js +23 -0
- package/lib/api/paymentApi.d.ts +325 -0
- package/lib/api/paymentApi.js +46 -0
- package/lib/api/workflowApi.d.ts +654 -0
- package/lib/api/workflowApi.js +90 -0
- package/lib/assets/images/images.d.ts +4 -0
- package/lib/assets/images/images.js +10 -0
- package/lib/components/AadhaarInput.d.ts +13 -0
- package/lib/components/AadhaarInput.js +47 -0
- package/lib/components/ActionButton.d.ts +12 -0
- package/lib/components/ActionButton.js +87 -0
- package/lib/components/ActiveFDCard.d.ts +16 -0
- package/lib/components/ActiveFDCard.js +95 -0
- package/lib/components/AmountInput.d.ts +20 -0
- package/lib/components/AmountInput.js +144 -0
- package/lib/components/CheckboxOption.d.ts +11 -0
- package/lib/components/CheckboxOption.js +41 -0
- package/lib/components/CompanyHeader.d.ts +7 -0
- package/lib/components/CompanyHeader.js +57 -0
- package/lib/components/DropdownSelector.d.ts +9 -0
- package/lib/components/DropdownSelector.js +49 -0
- package/lib/components/EmptyState.d.ts +17 -0
- package/lib/components/EmptyState.js +44 -0
- package/lib/components/ErrorDisplay.d.ts +17 -0
- package/lib/components/ErrorDisplay.js +69 -0
- package/lib/components/FAQItem.d.ts +9 -0
- package/lib/components/FAQItem.js +52 -0
- package/lib/components/FDCard.d.ts +21 -0
- package/lib/components/FDCard.js +96 -0
- package/lib/components/FormDropdown.d.ts +18 -0
- package/lib/components/FormDropdown.js +155 -0
- package/lib/components/FormSection.d.ts +14 -0
- package/lib/components/FormSection.js +38 -0
- package/lib/components/Header.d.ts +14 -0
- package/lib/components/Header.js +52 -0
- package/lib/components/IFSCSearchResultCard.d.ts +13 -0
- package/lib/components/IFSCSearchResultCard.js +70 -0
- package/lib/components/InfoBox.d.ts +8 -0
- package/lib/components/InfoBox.js +39 -0
- package/lib/components/InterestRateCard.d.ts +8 -0
- package/lib/components/InterestRateCard.js +46 -0
- package/lib/components/LoadingIndicator.d.ts +12 -0
- package/lib/components/LoadingIndicator.js +30 -0
- package/lib/components/OTPInput.d.ts +17 -0
- package/lib/components/OTPInput.js +144 -0
- package/lib/components/PaymentDetailsCard.d.ts +20 -0
- package/lib/components/PaymentDetailsCard.js +68 -0
- package/lib/components/PendingFDBottomSheet.d.ts +18 -0
- package/lib/components/PendingFDBottomSheet.js +122 -0
- package/lib/components/SafeAreaWrapper.d.ts +13 -0
- package/lib/components/SafeAreaWrapper.js +41 -0
- package/lib/components/ScreenHeader.d.ts +11 -0
- package/lib/components/ScreenHeader.js +46 -0
- package/lib/components/StatusDisplay.d.ts +15 -0
- package/lib/components/StatusDisplay.js +88 -0
- package/lib/components/TextFieldWithLabel.d.ts +46 -0
- package/lib/components/TextFieldWithLabel.js +326 -0
- package/lib/components/TrustBox.d.ts +8 -0
- package/lib/components/TrustBox.js +45 -0
- package/lib/components/ValidationErrorAlert.d.ts +23 -0
- package/lib/components/ValidationErrorAlert.js +39 -0
- package/lib/components/ValidationMessage.d.ts +9 -0
- package/lib/components/ValidationMessage.js +98 -0
- package/lib/components/index.d.ts +35 -0
- package/lib/components/index.js +64 -0
- package/lib/config/apiConfig.d.ts +34 -0
- package/lib/config/apiConfig.js +158 -0
- package/lib/config/appDataConfig.d.ts +114 -0
- package/lib/config/appDataConfig.js +264 -0
- package/lib/config/encryptionConfig.d.ts +21 -0
- package/lib/config/encryptionConfig.js +61 -0
- package/lib/config/workflowConstants.d.ts +37 -0
- package/lib/config/workflowConstants.js +38 -0
- package/lib/constants/strings/bank.d.ts +72 -0
- package/lib/constants/strings/bank.js +86 -0
- package/lib/constants/strings/base64Images.d.ts +25 -0
- package/lib/constants/strings/base64Images.js +28 -0
- package/lib/constants/strings/common.d.ts +53 -0
- package/lib/constants/strings/common.js +62 -0
- package/lib/constants/strings/employee.d.ts +61 -0
- package/lib/constants/strings/employee.js +77 -0
- package/lib/constants/strings/faq.d.ts +14 -0
- package/lib/constants/strings/faq.js +20 -0
- package/lib/constants/strings/fd.d.ts +122 -0
- package/lib/constants/strings/fd.js +151 -0
- package/lib/constants/strings/home.d.ts +49 -0
- package/lib/constants/strings/home.js +62 -0
- package/lib/constants/strings/index.d.ts +16 -0
- package/lib/constants/strings/index.js +44 -0
- package/lib/constants/strings/kyc.d.ts +80 -0
- package/lib/constants/strings/kyc.js +94 -0
- package/lib/constants/strings/nominee.d.ts +64 -0
- package/lib/constants/strings/nominee.js +81 -0
- package/lib/hooks/useAuth.d.ts +25 -0
- package/lib/hooks/useAuth.js +39 -0
- package/lib/hooks/useFDData.d.ts +11 -0
- package/lib/hooks/useFDData.js +40 -0
- package/lib/index.d.ts +69 -0
- package/lib/index.js +182 -0
- package/lib/navigation/RootNavigator.d.ts +8 -0
- package/lib/navigation/RootNavigator.js +205 -0
- package/lib/navigation/SimpleNavigator.d.ts +11 -0
- package/lib/navigation/SimpleNavigator.js +107 -0
- package/lib/navigation/helpers.d.ts +11 -0
- package/lib/navigation/helpers.js +83 -0
- package/lib/navigation/index.d.ts +15 -0
- package/lib/navigation/index.js +42 -0
- package/lib/navigation/types.d.ts +113 -0
- package/lib/navigation/types.js +2 -0
- package/lib/navigation/workflowNavigator.d.ts +22 -0
- package/lib/navigation/workflowNavigator.js +104 -0
- package/lib/providers/ApiProvider.d.ts +7 -0
- package/lib/providers/ApiProvider.js +34 -0
- package/lib/providers/MasterDataProvider.d.ts +10 -0
- package/lib/providers/MasterDataProvider.js +54 -0
- package/lib/screens/AadhaarVerification.d.ts +7 -0
- package/lib/screens/AadhaarVerification.js +627 -0
- package/lib/screens/AddBankAccount.d.ts +22 -0
- package/lib/screens/AddBankAccount.js +381 -0
- package/lib/screens/BankDetail.d.ts +16 -0
- package/lib/screens/BankDetail.js +596 -0
- package/lib/screens/BookFD.d.ts +0 -0
- package/lib/screens/BookFD.js +315 -0
- package/lib/screens/Employee.d.ts +18 -0
- package/lib/screens/Employee.js +594 -0
- package/lib/screens/FDCalculator.d.ts +18 -0
- package/lib/screens/FDCalculator.js +759 -0
- package/lib/screens/FDList.d.ts +27 -0
- package/lib/screens/FDList.js +1008 -0
- package/lib/screens/FindIFSC.d.ts +16 -0
- package/lib/screens/FindIFSC.js +248 -0
- package/lib/screens/Home.d.ts +0 -0
- package/lib/screens/Home.js +143 -0
- package/lib/screens/NomineeDetail.d.ts +17 -0
- package/lib/screens/NomineeDetail.js +592 -0
- package/lib/screens/PayNow.d.ts +14 -0
- package/lib/screens/PayNow.js +230 -0
- package/lib/screens/Payment.d.ts +11 -0
- package/lib/screens/Payment.js +191 -0
- package/lib/screens/PaymentStatus.d.ts +16 -0
- package/lib/screens/PaymentStatus.js +397 -0
- package/lib/screens/ReviewKYC.d.ts +21 -0
- package/lib/screens/ReviewKYC.js +660 -0
- package/lib/state/paymentSession.d.ts +8 -0
- package/lib/state/paymentSession.js +13 -0
- package/lib/store/fdListSelectedSlice.d.ts +21 -0
- package/lib/store/fdListSelectedSlice.js +26 -0
- package/lib/store/hooks.d.ts +8 -0
- package/lib/store/hooks.js +31 -0
- package/lib/store/index.d.ts +3 -0
- package/lib/store/index.js +8 -0
- package/lib/store/onboardingSlice.d.ts +12 -0
- package/lib/store/onboardingSlice.js +32 -0
- package/lib/store/store.d.ts +13 -0
- package/lib/store/store.js +33 -0
- package/lib/theme/ThemeContext.d.ts +210 -0
- package/lib/theme/ThemeContext.js +90 -0
- package/lib/theme/colors.d.ts +80 -0
- package/lib/theme/colors.js +85 -0
- package/lib/theme/index.d.ts +34 -0
- package/lib/theme/index.js +69 -0
- package/lib/theme/shadows.d.ts +53 -0
- package/lib/theme/shadows.js +58 -0
- package/lib/theme/typography.d.ts +134 -0
- package/lib/theme/typography.js +143 -0
- package/lib/types/dataTypes.d.ts +34 -0
- package/lib/types/dataTypes.js +2 -0
- package/lib/types/workflowTypes.d.ts +2 -0
- package/lib/types/workflowTypes.js +2 -0
- package/lib/utils/apiLogger.d.ts +48 -0
- package/lib/utils/apiLogger.js +105 -0
- package/lib/utils/encryption.d.ts +28 -0
- package/lib/utils/encryption.js +113 -0
- package/lib/utils/getFDData.d.ts +48 -0
- package/lib/utils/getFDData.js +154 -0
- package/lib/utils/globalData.d.ts +2 -0
- package/lib/utils/globalData.js +10 -0
- package/package.json +76 -0
- package/src/api/applicationApi.ts +12 -0
- package/src/api/bankApi.ts +42 -0
- package/src/api/baseApi.ts +513 -0
- package/src/api/customerApi.ts +291 -0
- package/src/api/fdApi.ts +150 -0
- package/src/api/fdCalculatorApi.ts +41 -0
- package/src/api/index.ts +29 -0
- package/src/api/interestRateApi.ts +143 -0
- package/src/api/kycApi.ts +63 -0
- package/src/api/masterDataApi.ts +34 -0
- package/src/api/nomineeApi.ts +34 -0
- package/src/api/onboardingApi.ts +64 -0
- package/src/api/panApi.ts +25 -0
- package/src/api/paymentApi.ts +34 -0
- package/src/api/workflowApi.ts +94 -0
- package/src/assets/images/arrow-filled.png +0 -0
- package/src/assets/images/arrow-left.png +0 -0
- package/src/assets/images/backicon.png +0 -0
- package/src/assets/images/calendar.png +0 -0
- package/src/assets/images/chevron-down.png +0 -0
- package/src/assets/images/chevron-down@2x.png +0 -0
- package/src/assets/images/chevron-down@3x.png +0 -0
- package/src/assets/images/images.js +8 -0
- package/src/components/AadhaarInput.tsx +91 -0
- package/src/components/ActionButton.tsx +129 -0
- package/src/components/ActiveFDCard.tsx +158 -0
- package/src/components/AmountInput.tsx +217 -0
- package/src/components/CheckboxOption.tsx +93 -0
- package/src/components/CompanyHeader.tsx +78 -0
- package/src/components/DropdownSelector.tsx +77 -0
- package/src/components/EmptyState.tsx +109 -0
- package/src/components/ErrorDisplay.tsx +135 -0
- package/src/components/FAQItem.tsx +90 -0
- package/src/components/FDCard.tsx +165 -0
- package/src/components/FormDropdown.tsx +214 -0
- package/src/components/FormSection.tsx +86 -0
- package/src/components/Header.tsx +110 -0
- package/src/components/IFSCSearchResultCard.tsx +139 -0
- package/src/components/InfoBox.tsx +55 -0
- package/src/components/InterestRateCard.tsx +77 -0
- package/src/components/LoadingIndicator.tsx +63 -0
- package/src/components/OTPInput.tsx +213 -0
- package/src/components/PaymentDetailsCard.tsx +120 -0
- package/src/components/PendingFDBottomSheet.tsx +235 -0
- package/src/components/README.md +210 -0
- package/src/components/SafeAreaWrapper.tsx +68 -0
- package/src/components/ScreenHeader.tsx +83 -0
- package/src/components/StatusDisplay.tsx +139 -0
- package/src/components/TextFieldWithLabel.tsx +502 -0
- package/src/components/TrustBox.tsx +63 -0
- package/src/components/ValidationErrorAlert.tsx +57 -0
- package/src/components/ValidationMessage.tsx +134 -0
- package/src/components/index.tsx +47 -0
- package/src/config/apiConfig.ts +217 -0
- package/src/config/appDataConfig.ts +279 -0
- package/src/config/encryptionConfig.ts +65 -0
- package/src/config/workflowConstants.ts +43 -0
- package/src/constants/strings/README.md +146 -0
- package/src/constants/strings/bank.ts +92 -0
- package/src/constants/strings/base64Images.ts +29 -0
- package/src/constants/strings/common.ts +63 -0
- package/src/constants/strings/employee.ts +85 -0
- package/src/constants/strings/faq.ts +23 -0
- package/src/constants/strings/fd.ts +172 -0
- package/src/constants/strings/home.ts +67 -0
- package/src/constants/strings/index.ts +21 -0
- package/src/constants/strings/kyc.ts +100 -0
- package/src/constants/strings/nominee.ts +90 -0
- package/src/hooks/useAuth.ts +42 -0
- package/src/hooks/useFDData.ts +48 -0
- package/src/index.tsx +173 -0
- package/src/navigation/RootNavigator.tsx +352 -0
- package/src/navigation/SimpleNavigator.tsx +107 -0
- package/src/navigation/helpers.ts +85 -0
- package/src/navigation/index.tsx +81 -0
- package/src/navigation/types.ts +124 -0
- package/src/navigation/workflowNavigator.ts +131 -0
- package/src/providers/ApiProvider.tsx +43 -0
- package/src/providers/MasterDataProvider.tsx +30 -0
- package/src/screens/AadhaarVerification.tsx +809 -0
- package/src/screens/AddBankAccount.tsx +541 -0
- package/src/screens/BankDetail.tsx +826 -0
- package/src/screens/BookFD.tsx +330 -0
- package/src/screens/Employee.tsx +822 -0
- package/src/screens/FDCalculator.tsx +987 -0
- package/src/screens/FDList.tsx +1284 -0
- package/src/screens/FindIFSC.tsx +332 -0
- package/src/screens/Home.tsx +152 -0
- package/src/screens/NomineeDetail.tsx +800 -0
- package/src/screens/PayNow.tsx +282 -0
- package/src/screens/Payment.tsx +224 -0
- package/src/screens/PaymentStatus.tsx +561 -0
- package/src/screens/ReviewKYC.tsx +956 -0
- package/src/state/paymentSession.ts +13 -0
- package/src/store/fdListSelectedSlice.ts +42 -0
- package/src/store/hooks.ts +27 -0
- package/src/store/index.ts +3 -0
- package/src/store/onboardingSlice.ts +37 -0
- package/src/store/store.ts +35 -0
- package/src/theme/ThemeContext.tsx +82 -0
- package/src/theme/colors.ts +90 -0
- package/src/theme/index.ts +64 -0
- package/src/theme/shadows.ts +61 -0
- package/src/theme/typography.ts +151 -0
- package/src/types/dataTypes.ts +37 -0
- package/src/types/env.d.ts +93 -0
- package/src/types/workflowTypes.ts +12 -0
- package/src/utils/apiLogger.ts +166 -0
- package/src/utils/encryption.ts +159 -0
- package/src/utils/getFDData.ts +175 -0
- package/src/utils/globalData.ts +7 -0
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, TouchableWithoutFeedback, BackHandler, Platform, ActivityIndicator, KeyboardAvoidingView } from 'react-native';
|
|
3
|
+
import Icon from 'react-native-vector-icons/Ionicons';
|
|
4
|
+
import SafeAreaWrapper from '../components/SafeAreaWrapper';
|
|
5
|
+
import { Header, IFSCSearchResultCard } from '../components';
|
|
6
|
+
import ActionButton from '../components/ActionButton';
|
|
7
|
+
import TextFieldWithLabel from '../components/TextFieldWithLabel';
|
|
8
|
+
import { useColors, useTypography, useTheme } from '../theme/ThemeContext';
|
|
9
|
+
import { useMasterData } from '../providers/MasterDataProvider';
|
|
10
|
+
import { getAppData, getUserInfoForAPI } from '../config/appDataConfig';
|
|
11
|
+
import { useFdBankDetailsSearchMutation, useFdBankAccountMutation } from '../api/fdApi';
|
|
12
|
+
import { usePreviousStateMutation } from '../api/workflowApi';
|
|
13
|
+
import { useGetCustomerApplicationDetailsMutation } from '../api/customerApi';
|
|
14
|
+
import { useAppSelector } from '../store';
|
|
15
|
+
import { navigate } from '../navigation/helpers';
|
|
16
|
+
import { useFocusEffect } from '@react-navigation/native';
|
|
17
|
+
import { BANK_STRINGS } from '../constants/strings/bank';
|
|
18
|
+
|
|
19
|
+
export interface BankDetailProps {
|
|
20
|
+
onGoBack?: () => void;
|
|
21
|
+
onContinue?: (data: BankData) => void;
|
|
22
|
+
onAddAccount?: () => void;
|
|
23
|
+
initialData?: Partial<BankData>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface BankData {
|
|
27
|
+
accountType: string;
|
|
28
|
+
accountNumber: string;
|
|
29
|
+
ifscCode: string;
|
|
30
|
+
bankName: string;
|
|
31
|
+
branchName: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const BankDetail: React.FC<BankDetailProps> = ({ onGoBack, onContinue, onAddAccount, initialData }) => {
|
|
36
|
+
const colors = useColors();
|
|
37
|
+
const typography = useTypography();
|
|
38
|
+
const { themeName } = useTheme();
|
|
39
|
+
const styles = createStyles(colors, typography, themeName);
|
|
40
|
+
const { masterData } = useMasterData();
|
|
41
|
+
|
|
42
|
+
// Normalize helper for arrays or CSV strings
|
|
43
|
+
const normalizeOptions = (raw: any, fallback: string[]): string[] => {
|
|
44
|
+
if (Array.isArray(raw)) return raw.map((v) => String(v)).filter(Boolean);
|
|
45
|
+
if (typeof raw === 'string' && raw.trim().length) return raw.split(',').map((v) => v.trim()).filter(Boolean);
|
|
46
|
+
return fallback;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Prefer nested data if present, memoized to avoid re-creation on each render
|
|
50
|
+
const mdRoot: any = React.useMemo(() => {
|
|
51
|
+
return (masterData as any)?.data || masterData || {};
|
|
52
|
+
}, [masterData]);
|
|
53
|
+
|
|
54
|
+
// Get account type options from master data, memoized
|
|
55
|
+
const accountTypeOptions: string[] = React.useMemo(() => {
|
|
56
|
+
const raw = mdRoot?.bankAccountType || mdRoot?.accountTypeOptions || mdRoot?.accountTypes;
|
|
57
|
+
return normalizeOptions(raw, []);
|
|
58
|
+
}, [mdRoot]);
|
|
59
|
+
|
|
60
|
+
// Get app data from global state
|
|
61
|
+
const appData = getAppData();
|
|
62
|
+
const defaultProviderId = useAppSelector((state: any) => state?.onboarding?.providerId);// Default Shriram provider ID
|
|
63
|
+
const workflowInstanceId = useAppSelector((state: any) => state?.onboarding?.workflowInstanceId);
|
|
64
|
+
const applicationId = useAppSelector((state: any) => state?.onboarding?.applicationId);
|
|
65
|
+
const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
|
|
66
|
+
const customerId = useAppSelector((state: any) => state?.onboarding?.customerId);
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
// FD Bank Details API (mutation for on-demand calls)
|
|
70
|
+
const [fdBankDetails, {
|
|
71
|
+
data: fdBankDetailsResponse,
|
|
72
|
+
error: fdBankDetailsError,
|
|
73
|
+
isLoading: isLoadingFdBankDetails,
|
|
74
|
+
}] = useFdBankDetailsSearchMutation();
|
|
75
|
+
|
|
76
|
+
// FD Bank Account API
|
|
77
|
+
const [fdBankAccount, {
|
|
78
|
+
data: fdBankAccountResponse,
|
|
79
|
+
error: fdBankAccountError,
|
|
80
|
+
isLoading: isLoadingFdBankAccount,
|
|
81
|
+
}] = useFdBankAccountMutation();
|
|
82
|
+
const [previousState] = usePreviousStateMutation();
|
|
83
|
+
|
|
84
|
+
// Customer Application Details API (called on focus)
|
|
85
|
+
const [getCustomerApplicationDetails, {
|
|
86
|
+
data: customerApplicationDetailsResponse,
|
|
87
|
+
error: customerApplicationDetailsError,
|
|
88
|
+
isLoading: isLoadingCustomerApplicationDetails,
|
|
89
|
+
}] = useGetCustomerApplicationDetailsMutation();
|
|
90
|
+
|
|
91
|
+
// Helper function to get account type display name
|
|
92
|
+
const getAccountTypeDisplay = (code: string): string => {
|
|
93
|
+
if (!code || code.trim() === '') return '';
|
|
94
|
+
switch (code) {
|
|
95
|
+
case 'SB': return 'Saving A/c';
|
|
96
|
+
case 'CA': return 'Current A/c';
|
|
97
|
+
default: return 'Saving A/c';
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Loading state for back navigation
|
|
102
|
+
const [isGoingBack, setIsGoingBack] = useState(false);
|
|
103
|
+
|
|
104
|
+
const [form, setForm] = useState<BankData>({
|
|
105
|
+
accountType: initialData?.accountType || getAccountTypeDisplay(appData?.typeOfAccount || ''),
|
|
106
|
+
accountNumber: initialData?.accountNumber || appData?.accountNo || '',
|
|
107
|
+
ifscCode: initialData?.ifscCode || appData?.ifsc || '',
|
|
108
|
+
bankName: initialData?.bankName || appData?.nameOfBank || '',
|
|
109
|
+
branchName: initialData?.branchName || '',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Ref to track last IFSC code that was used to call API (to prevent duplicate calls)
|
|
113
|
+
const lastFetchedIfscRef = useRef<string>('');
|
|
114
|
+
|
|
115
|
+
// Keep account type valid if options change after load
|
|
116
|
+
React.useEffect(() => {
|
|
117
|
+
if (form.accountType && !accountTypeOptions.includes(form.accountType)) {
|
|
118
|
+
setForm(prev => ({
|
|
119
|
+
...prev,
|
|
120
|
+
accountType: '',
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
}, [accountTypeOptions, form.accountType]);
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
// Call customer application details API when screen comes into focus
|
|
127
|
+
useFocusEffect(
|
|
128
|
+
React.useCallback(() => {
|
|
129
|
+
let isActive = true;
|
|
130
|
+
(async () => {
|
|
131
|
+
try {
|
|
132
|
+
// Only call API if we have the required IDs
|
|
133
|
+
if (!applicationId || !customerId) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const userInfo = getUserInfoForAPI();
|
|
138
|
+
const req = {
|
|
139
|
+
providerId: defaultProviderId,
|
|
140
|
+
workflowInstanceId,
|
|
141
|
+
userreferenceid: userInfo.userReferenceId,
|
|
142
|
+
applicationid: applicationId,
|
|
143
|
+
entityid: entityId,
|
|
144
|
+
// Body params
|
|
145
|
+
applicationId: applicationId,
|
|
146
|
+
customerId: customerId,
|
|
147
|
+
} as any;
|
|
148
|
+
|
|
149
|
+
const res = await getCustomerApplicationDetails(req).unwrap();
|
|
150
|
+
if (!isActive) return;
|
|
151
|
+
|
|
152
|
+
// Set form data from bank_account object in API response if available
|
|
153
|
+
if (res?.data?.bank_account) {
|
|
154
|
+
const bankData = res.data.bank_account;
|
|
155
|
+
|
|
156
|
+
setForm(prev => ({
|
|
157
|
+
...prev,
|
|
158
|
+
accountType: bankData.account_type || prev.accountType,
|
|
159
|
+
accountNumber: bankData.account_no || prev.accountNumber,
|
|
160
|
+
ifscCode: bankData.ifsc_code || prev.ifscCode,
|
|
161
|
+
bankName: bankData.bank_name || prev.bankName,
|
|
162
|
+
branchName: bankData.bank_branch || prev.branchName,
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (!isActive) return;
|
|
167
|
+
}
|
|
168
|
+
})();
|
|
169
|
+
return () => { isActive = false; };
|
|
170
|
+
}, [applicationId, customerId, defaultProviderId, workflowInstanceId, entityId, getCustomerApplicationDetails])
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const [openMenus, setOpenMenus] = useState({
|
|
174
|
+
accountType: false,
|
|
175
|
+
branchName: false,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const [fieldErrors, setFieldErrors] = useState<{ [key: string]: string }>({});
|
|
179
|
+
|
|
180
|
+
// Validation functions
|
|
181
|
+
const validateAccountNumber = (accountNumber: string): string => {
|
|
182
|
+
if (!accountNumber || accountNumber.trim().length === 0) {
|
|
183
|
+
return 'Account number is required';
|
|
184
|
+
}
|
|
185
|
+
if (accountNumber.length < 9 || accountNumber.length > 18) {
|
|
186
|
+
return 'Account number must be between 9 and 18 digits';
|
|
187
|
+
}
|
|
188
|
+
if (!/^\d+$/.test(accountNumber)) {
|
|
189
|
+
return 'Account number must contain only digits';
|
|
190
|
+
}
|
|
191
|
+
return '';
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const validateIFSC = (ifsc: string): string => {
|
|
195
|
+
if (!ifsc || ifsc.trim().length === 0) {
|
|
196
|
+
return 'IFSC code is required';
|
|
197
|
+
}
|
|
198
|
+
const ifscRegex = /^[A-Z]{4}0[A-Z0-9]{6}$/;
|
|
199
|
+
if (!ifscRegex.test(ifsc.toUpperCase())) {
|
|
200
|
+
return 'Please enter a valid IFSC code (e.g., SBIN0001234)';
|
|
201
|
+
}
|
|
202
|
+
return '';
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const validateBankName = (bankName: string): string => {
|
|
206
|
+
if (!bankName || bankName.trim().length === 0) {
|
|
207
|
+
return 'Bank name is required';
|
|
208
|
+
}
|
|
209
|
+
if (bankName.trim().length < 2) {
|
|
210
|
+
return 'Bank name must be at least 2 characters';
|
|
211
|
+
}
|
|
212
|
+
return '';
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const validateBranchName = (branchName: string): string => {
|
|
216
|
+
if (!branchName || branchName.trim().length === 0) {
|
|
217
|
+
return 'Branch name is required';
|
|
218
|
+
}
|
|
219
|
+
if (branchName.trim().length < 2) {
|
|
220
|
+
return 'Branch name must be at least 2 characters';
|
|
221
|
+
}
|
|
222
|
+
return '';
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const validateField = (field: keyof BankData, value: string): string => {
|
|
226
|
+
switch (field) {
|
|
227
|
+
case 'accountNumber':
|
|
228
|
+
return validateAccountNumber(value);
|
|
229
|
+
case 'ifscCode':
|
|
230
|
+
return validateIFSC(value);
|
|
231
|
+
case 'bankName':
|
|
232
|
+
return validateBankName(value);
|
|
233
|
+
case 'branchName':
|
|
234
|
+
return validateBranchName(value);
|
|
235
|
+
default:
|
|
236
|
+
return '';
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Function to fetch bank details when IFSC code is entered
|
|
241
|
+
const fetchBankDetails = useCallback(async (ifscCode: string) => {
|
|
242
|
+
if (!ifscCode || ifscCode.trim().length === 0) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const upperIfsc = ifscCode.trim().toUpperCase();
|
|
247
|
+
// Validate IFSC - validateIFSC returns empty string if valid, error message if invalid
|
|
248
|
+
const validationError = validateIFSC(upperIfsc);
|
|
249
|
+
if (validationError) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const fdBankDetailsRequest = {
|
|
255
|
+
providerId: defaultProviderId,
|
|
256
|
+
ifscCode: upperIfsc,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// Call the API
|
|
260
|
+
const response = await fdBankDetails(fdBankDetailsRequest).unwrap();
|
|
261
|
+
|
|
262
|
+
// Handle the actual API response structure (same as FindIFSC)
|
|
263
|
+
let bankName = '';
|
|
264
|
+
let branchName = '';
|
|
265
|
+
let ifscCodeFromApi = '';
|
|
266
|
+
|
|
267
|
+
if (response && response.data && Array.isArray(response.data) && response.data.length > 0) {
|
|
268
|
+
const bankData = response.data[0];
|
|
269
|
+
bankName = bankData.BnkDescr || '';
|
|
270
|
+
branchName = bankData.BankBranch || '';
|
|
271
|
+
ifscCodeFromApi = bankData.IfscCode || '';
|
|
272
|
+
} else if (response && response.bankName && response.branchName && response.ifscCode) {
|
|
273
|
+
// Fallback for old response format
|
|
274
|
+
bankName = response.bankName;
|
|
275
|
+
branchName = response.branchName;
|
|
276
|
+
ifscCodeFromApi = response.ifscCode;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Update form with bank details from API response
|
|
280
|
+
if (bankName || branchName || ifscCodeFromApi) {
|
|
281
|
+
setForm(prev => ({
|
|
282
|
+
...prev,
|
|
283
|
+
bankName: bankName || prev.bankName,
|
|
284
|
+
branchName: branchName || prev.branchName,
|
|
285
|
+
ifscCode: ifscCodeFromApi || prev.ifscCode,
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
// Silently handle error - don't show alert, just don't update fields
|
|
290
|
+
}
|
|
291
|
+
}, [defaultProviderId, fdBankDetails]);
|
|
292
|
+
|
|
293
|
+
const updateField = (field: keyof BankData, value: string) => {
|
|
294
|
+
// Clean input based on field type
|
|
295
|
+
let cleanedValue = value;
|
|
296
|
+
if (field === 'accountNumber') {
|
|
297
|
+
cleanedValue = value.replace(/[^0-9]/g, '').substring(0, 18);
|
|
298
|
+
} else if (field === 'ifscCode') {
|
|
299
|
+
cleanedValue = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase().substring(0, 11);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Validate field and set error
|
|
303
|
+
const error = validateField(field, cleanedValue);
|
|
304
|
+
|
|
305
|
+
// Handle IFSC code changes - clear bank and branch names when IFSC is removed, invalid, or changed
|
|
306
|
+
if (field === 'ifscCode') {
|
|
307
|
+
const upperIfsc = cleanedValue.trim().toUpperCase();
|
|
308
|
+
const validationError = validateIFSC(upperIfsc);
|
|
309
|
+
const isIfscValid = cleanedValue.length === 11 && validationError === '';
|
|
310
|
+
const previousIfsc = form.ifscCode?.trim().toUpperCase() || '';
|
|
311
|
+
const isIfscChanged = cleanedValue.trim().toUpperCase() !== previousIfsc;
|
|
312
|
+
|
|
313
|
+
// Determine if we should clear bank and branch names
|
|
314
|
+
const shouldClearBankBranch =
|
|
315
|
+
cleanedValue.length === 0 || // IFSC is removed (empty)
|
|
316
|
+
cleanedValue.length < 11 || // IFSC is incomplete
|
|
317
|
+
(cleanedValue.length === 11 && validationError !== '') || // IFSC is invalid (11 chars but fails validation)
|
|
318
|
+
(isIfscChanged && previousIfsc.length === 11 && previousIfsc === lastFetchedIfscRef.current); // IFSC changed from a previously valid one
|
|
319
|
+
|
|
320
|
+
if (shouldClearBankBranch) {
|
|
321
|
+
setForm(prev => ({
|
|
322
|
+
...prev,
|
|
323
|
+
[field]: cleanedValue,
|
|
324
|
+
bankName: '',
|
|
325
|
+
branchName: '',
|
|
326
|
+
}));
|
|
327
|
+
} else {
|
|
328
|
+
setForm(prev => ({ ...prev, [field]: cleanedValue }));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
setFieldErrors(prev => ({
|
|
332
|
+
...prev,
|
|
333
|
+
[field]: error,
|
|
334
|
+
}));
|
|
335
|
+
|
|
336
|
+
// Call API immediately when IFSC code reaches 11 characters and is valid
|
|
337
|
+
if (isIfscValid && upperIfsc !== lastFetchedIfscRef.current) {
|
|
338
|
+
lastFetchedIfscRef.current = upperIfsc;
|
|
339
|
+
// Call API immediately - don't await, let it run in background
|
|
340
|
+
fetchBankDetails(upperIfsc).catch((err) => {
|
|
341
|
+
// Reset ref on error so user can retry
|
|
342
|
+
if (lastFetchedIfscRef.current === upperIfsc) {
|
|
343
|
+
lastFetchedIfscRef.current = '';
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
} else if (cleanedValue.length < 11) {
|
|
347
|
+
// Reset ref when IFSC code is less than 11 characters
|
|
348
|
+
lastFetchedIfscRef.current = '';
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
// For other fields, just update normally
|
|
352
|
+
setForm(prev => ({ ...prev, [field]: cleanedValue }));
|
|
353
|
+
setFieldErrors(prev => ({
|
|
354
|
+
...prev,
|
|
355
|
+
[field]: error,
|
|
356
|
+
}));
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// Call API when IFSC code becomes valid (11 characters and passes validation)
|
|
361
|
+
// Also clear bank and branch names when IFSC is invalid or removed
|
|
362
|
+
useEffect(() => {
|
|
363
|
+
if (form.ifscCode && form.ifscCode.length === 11) {
|
|
364
|
+
const upperIfsc = form.ifscCode.trim().toUpperCase();
|
|
365
|
+
const validationError = validateIFSC(upperIfsc);
|
|
366
|
+
// Only call API if IFSC is valid and different from last fetched IFSC
|
|
367
|
+
if (!validationError && upperIfsc !== lastFetchedIfscRef.current) {
|
|
368
|
+
lastFetchedIfscRef.current = upperIfsc;
|
|
369
|
+
fetchBankDetails(upperIfsc);
|
|
370
|
+
} else if (validationError) {
|
|
371
|
+
// IFSC is invalid - clear bank and branch names
|
|
372
|
+
setForm(prev => ({
|
|
373
|
+
...prev,
|
|
374
|
+
bankName: '',
|
|
375
|
+
branchName: '',
|
|
376
|
+
}));
|
|
377
|
+
lastFetchedIfscRef.current = '';
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
// IFSC code is removed or less than 11 characters - clear bank and branch names
|
|
381
|
+
if (form.bankName || form.branchName) {
|
|
382
|
+
setForm(prev => ({
|
|
383
|
+
...prev,
|
|
384
|
+
bankName: '',
|
|
385
|
+
branchName: '',
|
|
386
|
+
}));
|
|
387
|
+
}
|
|
388
|
+
// Reset ref when IFSC code is not 11 characters
|
|
389
|
+
lastFetchedIfscRef.current = '';
|
|
390
|
+
}
|
|
391
|
+
}, [form.ifscCode, fetchBankDetails]);
|
|
392
|
+
|
|
393
|
+
const toggleMenu = (key: keyof typeof openMenus) => {
|
|
394
|
+
setOpenMenus(prev => ({ ...prev, [key]: !prev[key] }));
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const closeAllMenus = () => {
|
|
398
|
+
setOpenMenus({
|
|
399
|
+
accountType: false,
|
|
400
|
+
branchName: false,
|
|
401
|
+
});
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// Render error message for a field
|
|
405
|
+
const renderFieldError = (field: keyof BankData) => {
|
|
406
|
+
const error = fieldErrors[field];
|
|
407
|
+
if (!error) return null;
|
|
408
|
+
|
|
409
|
+
return (
|
|
410
|
+
<View style={styles.errorContainer}>
|
|
411
|
+
{Platform.OS === 'android' && (
|
|
412
|
+
<Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
|
|
413
|
+
)}
|
|
414
|
+
<Text style={styles.errorText}>{error}</Text>
|
|
415
|
+
</View>
|
|
416
|
+
);
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
// Mask account number to show first 4 digits and rest as X
|
|
420
|
+
const formatAccountNumber = (accountNumber: string): string => {
|
|
421
|
+
if (!accountNumber) return '';
|
|
422
|
+
if (accountNumber.length <= 4) return accountNumber;
|
|
423
|
+
const firstFour = accountNumber.substring(0, 4);
|
|
424
|
+
const masked = 'X'.repeat(Math.min(accountNumber.length - 4, 12));
|
|
425
|
+
return `${firstFour} ${masked}`;
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// Validate all form fields (for submission)
|
|
429
|
+
const validateForm = (): boolean => {
|
|
430
|
+
const errors: { [key: string]: string } = {};
|
|
431
|
+
|
|
432
|
+
// Validate account type
|
|
433
|
+
if (!form.accountType || form.accountType.trim() === '') {
|
|
434
|
+
errors.accountType = 'Account type is required';
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Validate account number
|
|
438
|
+
const accountNumberError = validateAccountNumber(form.accountNumber);
|
|
439
|
+
if (accountNumberError) errors.accountNumber = accountNumberError;
|
|
440
|
+
|
|
441
|
+
// Validate IFSC code
|
|
442
|
+
const ifscError = validateIFSC(form.ifscCode);
|
|
443
|
+
if (ifscError) errors.ifscCode = ifscError;
|
|
444
|
+
|
|
445
|
+
// Validate bank name
|
|
446
|
+
const bankNameError = validateBankName(form.bankName);
|
|
447
|
+
if (bankNameError) errors.bankName = bankNameError;
|
|
448
|
+
|
|
449
|
+
// Validate branch name
|
|
450
|
+
const branchNameError = validateBranchName(form.branchName);
|
|
451
|
+
if (branchNameError) errors.branchName = branchNameError;
|
|
452
|
+
|
|
453
|
+
setFieldErrors(errors);
|
|
454
|
+
return Object.keys(errors).length === 0;
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// Check if form is valid without setting errors (for button state)
|
|
458
|
+
const isFormValid = (): boolean => {
|
|
459
|
+
// Check account type
|
|
460
|
+
if (!form.accountType || form.accountType.trim() === '') {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Check account number
|
|
465
|
+
if (!form.accountNumber || form.accountNumber.trim() === '') {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
if (form.accountNumber.length < 9 || form.accountNumber.length > 18) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
if (!/^\d+$/.test(form.accountNumber)) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Check IFSC code
|
|
476
|
+
if (!form.ifscCode || form.ifscCode.trim() === '') {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
const ifscRegex = /^[A-Z]{4}0[A-Z0-9]{6}$/;
|
|
480
|
+
if (!ifscRegex.test(form.ifscCode.toUpperCase())) {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Check bank name
|
|
485
|
+
if (!form.bankName || form.bankName.trim() === '') {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
if (form.bankName.trim().length < 2) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Check branch name
|
|
493
|
+
if (!form.branchName || form.branchName.trim() === '') {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
if (form.branchName.trim().length < 2) {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return true;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
const renderDropdown = (
|
|
504
|
+
label: string,
|
|
505
|
+
value: string,
|
|
506
|
+
field: keyof BankData,
|
|
507
|
+
options: string[],
|
|
508
|
+
menuKey: keyof typeof openMenus,
|
|
509
|
+
placeholder: string = 'Select option',
|
|
510
|
+
editable: boolean = true,
|
|
511
|
+
) => (
|
|
512
|
+
<View>
|
|
513
|
+
<TextFieldWithLabel
|
|
514
|
+
label={label}
|
|
515
|
+
value={value}
|
|
516
|
+
onChangeText={(text) => updateField(field, text)}
|
|
517
|
+
variant="dropdown"
|
|
518
|
+
options={options}
|
|
519
|
+
isDropdownOpen={openMenus[menuKey]}
|
|
520
|
+
onDropdownToggle={() => toggleMenu(menuKey)}
|
|
521
|
+
onDropdownSelect={(option) => {
|
|
522
|
+
updateField(field, option);
|
|
523
|
+
setOpenMenus(prev => ({ ...prev, [menuKey]: false }));
|
|
524
|
+
}}
|
|
525
|
+
placeholder={placeholder}
|
|
526
|
+
editable={editable}
|
|
527
|
+
/>
|
|
528
|
+
{openMenus[menuKey] && editable && (
|
|
529
|
+
<View style={styles.inlineMenu}>
|
|
530
|
+
{options.map((option) => (
|
|
531
|
+
<TouchableOpacity
|
|
532
|
+
key={option}
|
|
533
|
+
style={styles.modalOption}
|
|
534
|
+
onPress={() => {
|
|
535
|
+
updateField(field, option);
|
|
536
|
+
setOpenMenus(prev => ({ ...prev, [menuKey]: false }));
|
|
537
|
+
}}
|
|
538
|
+
>
|
|
539
|
+
<Text style={styles.modalOptionText}>{option}</Text>
|
|
540
|
+
</TouchableOpacity>
|
|
541
|
+
))}
|
|
542
|
+
</View>
|
|
543
|
+
)}
|
|
544
|
+
</View>
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
const handleContinue = async () => {
|
|
548
|
+
// Validate form before submitting
|
|
549
|
+
if (!validateForm()) {
|
|
550
|
+
Alert.alert(
|
|
551
|
+
'Validation Error',
|
|
552
|
+
'Please fix all errors before continuing.',
|
|
553
|
+
[{ text: 'OK' }]
|
|
554
|
+
);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
try {
|
|
559
|
+
|
|
560
|
+
// Prepare the API request
|
|
561
|
+
const fdBankAccountRequest = {
|
|
562
|
+
// Headers
|
|
563
|
+
providerId: defaultProviderId,
|
|
564
|
+
workflowInstanceId,
|
|
565
|
+
userreferenceid: appData?.userReferenceId,
|
|
566
|
+
applicationid: applicationId,
|
|
567
|
+
entityid: entityId,
|
|
568
|
+
// Body (entityid should NOT be in body, only in headers)
|
|
569
|
+
accountType: form.accountType,
|
|
570
|
+
accountNumber: form.accountNumber,
|
|
571
|
+
ifscCode: form.ifscCode.toUpperCase(), // Ensure IFSC is uppercase for API
|
|
572
|
+
bankName: form.bankName,
|
|
573
|
+
branchName: form.branchName,
|
|
574
|
+
customerId: customerId,
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
const response = await fdBankAccount(fdBankAccountRequest).unwrap();
|
|
578
|
+
|
|
579
|
+
// Call the original onContinue callback with form data
|
|
580
|
+
onContinue?.(form);
|
|
581
|
+
|
|
582
|
+
} catch (error) {
|
|
583
|
+
|
|
584
|
+
// Show error message to user
|
|
585
|
+
Alert.alert(
|
|
586
|
+
BANK_STRINGS.BANK_VERIFICATION_FAILED,
|
|
587
|
+
BANK_STRINGS.BANK_ACCOUNT_ADDED_FAILED,
|
|
588
|
+
[{ text: 'OK' }]
|
|
589
|
+
);
|
|
590
|
+
|
|
591
|
+
// Do not call onContinue on failure - stay on current screen
|
|
592
|
+
// User can retry or correct their information
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
// Handler for back button (used by both header and hardware back button)
|
|
597
|
+
const handleBackPress = async () => {
|
|
598
|
+
setIsGoingBack(true);
|
|
599
|
+
try {
|
|
600
|
+
await previousState({
|
|
601
|
+
providerId: defaultProviderId,
|
|
602
|
+
workflowInstanceId,
|
|
603
|
+
userreferenceid: appData?.userReferenceId,
|
|
604
|
+
applicationid: applicationId,
|
|
605
|
+
entityid: entityId,
|
|
606
|
+
});
|
|
607
|
+
} catch (e) {
|
|
608
|
+
// Handle error silently
|
|
609
|
+
} finally {
|
|
610
|
+
setIsGoingBack(false);
|
|
611
|
+
// onGoBack?.();
|
|
612
|
+
navigate('NomineeDetail');
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
// Handle Android hardware back button
|
|
617
|
+
useEffect(() => {
|
|
618
|
+
if (Platform.OS !== 'android') return;
|
|
619
|
+
|
|
620
|
+
const onHardwareBackPress = () => {
|
|
621
|
+
handleBackPress();
|
|
622
|
+
return true; // Prevent default behavior
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
const backHandler = BackHandler.addEventListener(
|
|
626
|
+
'hardwareBackPress',
|
|
627
|
+
onHardwareBackPress
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
return () => backHandler.remove();
|
|
631
|
+
}, [defaultProviderId, workflowInstanceId, applicationId, entityId, appData?.userReferenceId]);
|
|
632
|
+
|
|
633
|
+
return (
|
|
634
|
+
<SafeAreaWrapper
|
|
635
|
+
includeTop={false}
|
|
636
|
+
bottomPadding={25}
|
|
637
|
+
statusBarColor="#000000"
|
|
638
|
+
statusBarStyle="light-content"
|
|
639
|
+
>
|
|
640
|
+
<Header
|
|
641
|
+
title={BANK_STRINGS.BANK_DETAILS_TITLE}
|
|
642
|
+
onBackPress={handleBackPress}
|
|
643
|
+
backgroundColor={colors.primary}
|
|
644
|
+
/>
|
|
645
|
+
|
|
646
|
+
<KeyboardAvoidingView
|
|
647
|
+
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
|
648
|
+
style={styles.keyboardAvoidingView}
|
|
649
|
+
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 0}
|
|
650
|
+
>
|
|
651
|
+
<ScrollView
|
|
652
|
+
style={styles.container}
|
|
653
|
+
showsVerticalScrollIndicator={false}
|
|
654
|
+
keyboardShouldPersistTaps="handled"
|
|
655
|
+
contentContainerStyle={styles.scrollContent}
|
|
656
|
+
scrollEnabled={!isLoadingFdBankAccount}
|
|
657
|
+
>
|
|
658
|
+
<TouchableWithoutFeedback onPress={isLoadingFdBankAccount ? undefined : closeAllMenus}>
|
|
659
|
+
<View>
|
|
660
|
+
<View>
|
|
661
|
+
{renderDropdown(
|
|
662
|
+
BANK_STRINGS.ACCOUNT_TYPE_LABEL,
|
|
663
|
+
form.accountType,
|
|
664
|
+
'accountType',
|
|
665
|
+
accountTypeOptions,
|
|
666
|
+
'accountType',
|
|
667
|
+
'Select option',
|
|
668
|
+
true // Always editable - user can change account type
|
|
669
|
+
)}
|
|
670
|
+
{renderFieldError('accountType')}
|
|
671
|
+
</View>
|
|
672
|
+
|
|
673
|
+
<View>
|
|
674
|
+
<TextFieldWithLabel
|
|
675
|
+
label={BANK_STRINGS.ACCOUNT_NUMBER_LABEL}
|
|
676
|
+
value={!appData?.accountNo || appData.accountNo.trim() === '' ? form.accountNumber : formatAccountNumber(form.accountNumber)}
|
|
677
|
+
onChangeText={(text) => updateField('accountNumber', text)}
|
|
678
|
+
onFocus={() => { closeAllMenus(); }}
|
|
679
|
+
placeholder={BANK_STRINGS.ACCOUNT_NUMBER_PLACEHOLDER}
|
|
680
|
+
variant="numeric"
|
|
681
|
+
keyboardType="numeric"
|
|
682
|
+
maxLength={18}
|
|
683
|
+
editable={!appData?.accountNo || appData.accountNo.trim() === ''}
|
|
684
|
+
/>
|
|
685
|
+
{renderFieldError('accountNumber')}
|
|
686
|
+
</View>
|
|
687
|
+
|
|
688
|
+
<View>
|
|
689
|
+
<TextFieldWithLabel
|
|
690
|
+
label={BANK_STRINGS.IFSC_CODE_LABEL}
|
|
691
|
+
value={form.ifscCode}
|
|
692
|
+
onChangeText={(text) => updateField('ifscCode', text)}
|
|
693
|
+
onFocus={() => { closeAllMenus(); }}
|
|
694
|
+
placeholder={BANK_STRINGS.IFSC_CODE_PLACEHOLDER}
|
|
695
|
+
variant="text"
|
|
696
|
+
maxLength={11}
|
|
697
|
+
autoCapitalize="characters"
|
|
698
|
+
editable={!appData?.ifsc || appData.ifsc.trim() === ''}
|
|
699
|
+
/>
|
|
700
|
+
{renderFieldError('ifscCode')}
|
|
701
|
+
</View>
|
|
702
|
+
|
|
703
|
+
<View>
|
|
704
|
+
<TextFieldWithLabel
|
|
705
|
+
label={BANK_STRINGS.BANK_NAME_LABEL}
|
|
706
|
+
value={form.bankName}
|
|
707
|
+
onChangeText={(text) => updateField('bankName', text)}
|
|
708
|
+
onFocus={() => { closeAllMenus(); }}
|
|
709
|
+
placeholder={BANK_STRINGS.BANK_NAME_PLACEHOLDER}
|
|
710
|
+
variant="text"
|
|
711
|
+
editable={false}
|
|
712
|
+
inputStyle={{ color: '#000000' }}
|
|
713
|
+
/>
|
|
714
|
+
{renderFieldError('bankName')}
|
|
715
|
+
</View>
|
|
716
|
+
|
|
717
|
+
<View>
|
|
718
|
+
<TextFieldWithLabel
|
|
719
|
+
label={BANK_STRINGS.BRANCH_NAME_LABEL}
|
|
720
|
+
value={form.branchName}
|
|
721
|
+
onChangeText={(text) => updateField('branchName', text)}
|
|
722
|
+
onFocus={() => { closeAllMenus(); }}
|
|
723
|
+
placeholder={BANK_STRINGS.BRANCH_NAME_PLACEHOLDER}
|
|
724
|
+
variant="text"
|
|
725
|
+
editable={false}
|
|
726
|
+
inputStyle={{ color: '#000000' }}
|
|
727
|
+
/>
|
|
728
|
+
{renderFieldError('branchName')}
|
|
729
|
+
</View>
|
|
730
|
+
|
|
731
|
+
<TouchableOpacity style={styles.addAccountButton} onPress={onAddAccount}>
|
|
732
|
+
<Text style={styles.addAccountText}>{BANK_STRINGS.ADD_BANK_BUTTON}</Text>
|
|
733
|
+
</TouchableOpacity>
|
|
734
|
+
|
|
735
|
+
<ActionButton
|
|
736
|
+
title="Continue"
|
|
737
|
+
onPress={handleContinue}
|
|
738
|
+
disabled={isLoadingFdBankAccount || !isFormValid()}
|
|
739
|
+
loading={isLoadingFdBankAccount}
|
|
740
|
+
/>
|
|
741
|
+
</View>
|
|
742
|
+
</TouchableWithoutFeedback>
|
|
743
|
+
</ScrollView>
|
|
744
|
+
</KeyboardAvoidingView>
|
|
745
|
+
{/* Overlay to disable screen interactions during API call */}
|
|
746
|
+
{isLoadingFdBankAccount && (
|
|
747
|
+
<View style={styles.loadingOverlay} pointerEvents="auto">
|
|
748
|
+
</View>
|
|
749
|
+
)}
|
|
750
|
+
{/* Loading overlay for back navigation */}
|
|
751
|
+
{isGoingBack && (
|
|
752
|
+
<View style={styles.loadingOverlay} pointerEvents="auto">
|
|
753
|
+
<ActivityIndicator size="large" color={colors.primary} />
|
|
754
|
+
</View>
|
|
755
|
+
)}
|
|
756
|
+
</SafeAreaWrapper>
|
|
757
|
+
);
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
const createStyles = (colors: any, typography: any, themeName: string) => StyleSheet.create({
|
|
761
|
+
keyboardAvoidingView: {
|
|
762
|
+
flex: 1,
|
|
763
|
+
},
|
|
764
|
+
container: {
|
|
765
|
+
flex: 1,
|
|
766
|
+
paddingHorizontal: 16,
|
|
767
|
+
paddingTop: 20,
|
|
768
|
+
},
|
|
769
|
+
scrollContent: {
|
|
770
|
+
flexGrow: 1,
|
|
771
|
+
},
|
|
772
|
+
inlineMenu: {
|
|
773
|
+
backgroundColor: themeName === 'dark' ? colors.inputBackground : colors.background,
|
|
774
|
+
borderWidth: themeName === 'dark' ? 1 : 0.5,
|
|
775
|
+
borderColor: themeName === 'dark' ? '#ffffff' : 'rgba(0,0,0,0.2)',
|
|
776
|
+
borderRadius: 8,
|
|
777
|
+
marginTop: -20,
|
|
778
|
+
marginBottom: 10,
|
|
779
|
+
paddingHorizontal: 12,
|
|
780
|
+
paddingVertical: 6,
|
|
781
|
+
},
|
|
782
|
+
modalOption: {
|
|
783
|
+
paddingVertical: 14,
|
|
784
|
+
},
|
|
785
|
+
modalOptionText: {
|
|
786
|
+
...typography.styles.bodyLarge,
|
|
787
|
+
color: colors.text,
|
|
788
|
+
},
|
|
789
|
+
addAccountButton: {
|
|
790
|
+
alignItems: 'center',
|
|
791
|
+
paddingVertical: 16,
|
|
792
|
+
marginBottom: 20,
|
|
793
|
+
},
|
|
794
|
+
addAccountText: {
|
|
795
|
+
...typography.styles.bodyLarge,
|
|
796
|
+
color: colors.primary,
|
|
797
|
+
},
|
|
798
|
+
errorContainer: {
|
|
799
|
+
flexDirection: 'row',
|
|
800
|
+
alignItems: 'center',
|
|
801
|
+
marginTop: -20,
|
|
802
|
+
marginBottom: 20,
|
|
803
|
+
},
|
|
804
|
+
errorIcon: {
|
|
805
|
+
marginRight: 6,
|
|
806
|
+
},
|
|
807
|
+
errorText: {
|
|
808
|
+
fontSize: 12,
|
|
809
|
+
color: colors.error || '#FF0000',
|
|
810
|
+
flex: 1,
|
|
811
|
+
},
|
|
812
|
+
loadingOverlay: {
|
|
813
|
+
position: 'absolute',
|
|
814
|
+
top: 0,
|
|
815
|
+
left: 0,
|
|
816
|
+
right: 0,
|
|
817
|
+
bottom: 0,
|
|
818
|
+
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
819
|
+
justifyContent: 'center',
|
|
820
|
+
alignItems: 'center',
|
|
821
|
+
zIndex: 1000,
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
export default BankDetail;
|
|
826
|
+
|