@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,987 @@
|
|
|
1
|
+
// FDCalculator.tsx
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Text,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
ScrollView,
|
|
9
|
+
ActivityIndicator,
|
|
10
|
+
Image,
|
|
11
|
+
Platform,
|
|
12
|
+
BackHandler,
|
|
13
|
+
Keyboard,
|
|
14
|
+
} from 'react-native';
|
|
15
|
+
import Icon from 'react-native-vector-icons/Ionicons';
|
|
16
|
+
import SafeAreaWrapper from '../components/SafeAreaWrapper';
|
|
17
|
+
import {
|
|
18
|
+
CompanyHeader,
|
|
19
|
+
AmountInput,
|
|
20
|
+
DropdownSelector,
|
|
21
|
+
InterestRateCard,
|
|
22
|
+
CheckboxOption,
|
|
23
|
+
InfoBox,
|
|
24
|
+
TrustBox,
|
|
25
|
+
FAQItem,
|
|
26
|
+
} from '../components';
|
|
27
|
+
import { useTypography, useColors, useTheme } from '../theme/ThemeContext';
|
|
28
|
+
import { useMasterData } from '../providers/MasterDataProvider';
|
|
29
|
+
import { useCalculateFDMutation } from '../api/fdCalculatorApi';
|
|
30
|
+
import { useGetInterestRatesMutation } from '../api/interestRateApi';
|
|
31
|
+
import { useStartOnboardingMutation } from '../api/onboardingApi';
|
|
32
|
+
import { useGetMasterDataQuery } from '../api/masterDataApi';
|
|
33
|
+
import { getAppData } from '../config/appDataConfig';
|
|
34
|
+
import { useAppSelector, useAppDispatch } from '../store';
|
|
35
|
+
// import { setFDCalculationData } from '../store/fdCalculationSlice';
|
|
36
|
+
import { setFDListSelected } from '../store/fdListSelectedSlice';
|
|
37
|
+
import { navigate } from '../navigation/helpers';
|
|
38
|
+
import { COMMON_STRINGS, FD_STRINGS, FAQ_STRINGS } from '../constants/strings';
|
|
39
|
+
import { base64Images } from '../constants/strings/base64Images';
|
|
40
|
+
|
|
41
|
+
export interface FDCalculatorProps {
|
|
42
|
+
onGoBack?: () => void;
|
|
43
|
+
onNavigateToReviewKYC?: () => void;
|
|
44
|
+
fdData?: {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
accountNumber: string;
|
|
48
|
+
roi: string;
|
|
49
|
+
tenure: string;
|
|
50
|
+
amount: number;
|
|
51
|
+
maturityDate: string;
|
|
52
|
+
status: 'active' | 'matured' | 'pending';
|
|
53
|
+
creditRating: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const FDCalculator: React.FC<FDCalculatorProps> = ({ onGoBack, onNavigateToReviewKYC, fdData }) => {
|
|
58
|
+
const typography = useTypography();
|
|
59
|
+
const colors = useColors();
|
|
60
|
+
const { themeName } = useTheme();
|
|
61
|
+
const styles = React.useMemo(() => createStyles(typography, colors, themeName), [typography, colors, themeName]);
|
|
62
|
+
const { masterData, setMasterData } = useMasterData();
|
|
63
|
+
|
|
64
|
+
// Get FD data from Redux as fallback if not passed as props
|
|
65
|
+
const fdListSelectedData = useAppSelector((state: any) => state?.fdListSelected);
|
|
66
|
+
const effectiveFdData = fdData || fdListSelectedData;
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
const [amount, setAmount] = useState('');
|
|
70
|
+
const [seniorCitizen, setSeniorCitizen] = useState(false);
|
|
71
|
+
const [taxResident, setTaxResident] = useState(true);
|
|
72
|
+
const [autoRenewal, setAutoRenewal] = useState(false);
|
|
73
|
+
const [expandedIndex, setExpandedIndex] = useState<number | null>(null);
|
|
74
|
+
const [calculationResult, setCalculationResult] = useState<any>(null);
|
|
75
|
+
const [debounceTimer, setDebounceTimer] = useState<NodeJS.Timeout | null>(null);
|
|
76
|
+
const [amountError, setAmountError] = useState<string>('');
|
|
77
|
+
const [taxResidentError, setTaxResidentError] = useState<string>('');
|
|
78
|
+
const [isAmountEditing, setIsAmountEditing] = useState<boolean>(false);
|
|
79
|
+
|
|
80
|
+
// Calculate age from DOB and set senior citizen status
|
|
81
|
+
const calculateAgeAndSetSeniorCitizen = React.useCallback((dob: string) => {
|
|
82
|
+
if (!dob) return;
|
|
83
|
+
|
|
84
|
+
const today = new Date();
|
|
85
|
+
const birthDate = new Date(dob);
|
|
86
|
+
let age = today.getFullYear() - birthDate.getFullYear();
|
|
87
|
+
const monthDiff = today.getMonth() - birthDate.getMonth();
|
|
88
|
+
|
|
89
|
+
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
|
90
|
+
age--;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setSeniorCitizen(age >= 60);
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
// Interest payout dropdown state - will be updated after master data is loaded
|
|
97
|
+
const [payoutValue, setPayoutValue] = useState<string>('');
|
|
98
|
+
const [showPayoutModal, setShowPayoutModal] = useState<boolean>(false);
|
|
99
|
+
|
|
100
|
+
// Map dropdown values to API values
|
|
101
|
+
const mapPayoutToAPI = (dropdownValue: string): string => {
|
|
102
|
+
const mapping: { [key: string]: string } = {
|
|
103
|
+
'On Maturity': 'On Maturity',
|
|
104
|
+
'Monthly': 'Monthly',
|
|
105
|
+
'Quarterly': 'Quarterly',
|
|
106
|
+
'Yearly': 'Yearly',
|
|
107
|
+
'Half-Yearly': 'Half-Yearly',
|
|
108
|
+
};
|
|
109
|
+
return mapping[dropdownValue] || '';
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Check senior citizen status on component mount
|
|
113
|
+
React.useEffect(() => {
|
|
114
|
+
try {
|
|
115
|
+
const appData = getAppData();
|
|
116
|
+
if (appData?.dob) {
|
|
117
|
+
calculateAgeAndSetSeniorCitizen(appData.dob);
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
// Handle error silently
|
|
121
|
+
}
|
|
122
|
+
}, [calculateAgeAndSetSeniorCitizen]);
|
|
123
|
+
|
|
124
|
+
// Interest rates for Tenure options (real API)
|
|
125
|
+
const [getInterestRates, { data: interestRates }] = useGetInterestRatesMutation();
|
|
126
|
+
React.useEffect(() => {
|
|
127
|
+
try {
|
|
128
|
+
getInterestRates({});
|
|
129
|
+
} catch (e) {
|
|
130
|
+
// Handle error silently
|
|
131
|
+
}
|
|
132
|
+
}, [getInterestRates]);
|
|
133
|
+
|
|
134
|
+
// Fallback: Load master data if not available from global state
|
|
135
|
+
const defaultProviderId = useAppSelector((state: any) => state?.onboarding?.providerId);// Default Shriram provider ID
|
|
136
|
+
// Default Shriram provider ID
|
|
137
|
+
|
|
138
|
+
const { data: fallbackMasterData, isLoading: isLoadingFallback, error: fallbackError, refetch: refetchMasterData } = useGetMasterDataQuery(
|
|
139
|
+
{ providerId: defaultProviderId }, // Use default provider ID
|
|
140
|
+
{ skip: !!masterData } // Skip if master data is already available
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Use fallback master data if global master data is not available
|
|
144
|
+
// Store only the data parameter after stringifying instead of complete response
|
|
145
|
+
const effectiveMasterData = React.useMemo(() => {
|
|
146
|
+
const sourceData = masterData || fallbackMasterData;
|
|
147
|
+
if (!sourceData) return null;
|
|
148
|
+
|
|
149
|
+
// If sourceData has a data property, extract and stringify it
|
|
150
|
+
if (sourceData.data) {
|
|
151
|
+
return JSON.stringify(sourceData.data);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// If sourceData is already the data object, stringify it
|
|
155
|
+
return JSON.stringify(sourceData);
|
|
156
|
+
}, [masterData, fallbackMasterData]);
|
|
157
|
+
|
|
158
|
+
// Default payout options as fallback
|
|
159
|
+
// const defaultPayoutOptions = ['Maturity', 'Monthly eee', 'Quarterly', 'Half-Yearly', 'Yearly'];
|
|
160
|
+
|
|
161
|
+
const payoutOptions: string[] = React.useMemo(() => {
|
|
162
|
+
try {
|
|
163
|
+
const parsedData = JSON.parse(effectiveMasterData || '{}');
|
|
164
|
+
// If master data gives a single value instead of an array
|
|
165
|
+
const rawValue = parsedData?.interestPayoutTerm;
|
|
166
|
+
|
|
167
|
+
if (!rawValue) return [];
|
|
168
|
+
|
|
169
|
+
// Handle both array and string types
|
|
170
|
+
if (Array.isArray(rawValue)) {
|
|
171
|
+
return rawValue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// If it's a comma-separated string or a single string
|
|
175
|
+
if (typeof rawValue === 'string') {
|
|
176
|
+
// e.g. "Maturity,Monthly,Quarterly" → ['Maturity', 'Monthly', 'Quarterly']
|
|
177
|
+
return rawValue.split(',').map(v => v.trim());
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return [];
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
}, [effectiveMasterData]);
|
|
185
|
+
|
|
186
|
+
// Store fallback master data in global state if it becomes available
|
|
187
|
+
React.useEffect(() => {
|
|
188
|
+
if (fallbackMasterData && !masterData) {
|
|
189
|
+
setMasterData(fallbackMasterData);
|
|
190
|
+
}
|
|
191
|
+
}, [fallbackMasterData, masterData, setMasterData]);
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
// Update payout value when master data becomes available
|
|
196
|
+
React.useEffect(() => {
|
|
197
|
+
if (payoutOptions.length > 0 && !payoutValue) {
|
|
198
|
+
// Set "On Maturity" as default if available, otherwise use first option
|
|
199
|
+
const defaultOption = payoutOptions.find(option => option === 'On Maturity') || payoutOptions[0];
|
|
200
|
+
setPayoutValue(defaultOption);
|
|
201
|
+
}
|
|
202
|
+
}, [payoutOptions]);
|
|
203
|
+
|
|
204
|
+
React.useEffect(() => {
|
|
205
|
+
if (amount && payoutValue) {
|
|
206
|
+
// Only call if amount is valid
|
|
207
|
+
const numericValue = parseInt(amount.replace(/,/g, ''), 10);
|
|
208
|
+
if (numericValue >= 5000 && numericValue <= 50000000 && numericValue % 1000 === 0) {
|
|
209
|
+
handleCalculateFD(amount, payoutValue);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}, [payoutValue]);
|
|
213
|
+
// Master data processing complete
|
|
214
|
+
|
|
215
|
+
// FD Calculator API
|
|
216
|
+
const [calculateFD, { isLoading: isCalculating }] = useCalculateFDMutation();
|
|
217
|
+
|
|
218
|
+
// Onboarding API
|
|
219
|
+
const [startOnboarding, { isLoading: isOnboarding }] = useStartOnboardingMutation();
|
|
220
|
+
const [isBooking, setIsBooking] = React.useState(false);
|
|
221
|
+
const dispatch = useAppDispatch();
|
|
222
|
+
const { setOnboardingIds } = require('../store/onboardingSlice');
|
|
223
|
+
|
|
224
|
+
const tenureOptions: string[] = React.useMemo(() => {
|
|
225
|
+
const months: number[] = [];
|
|
226
|
+
const sdr = interestRates?.data?.sdrScheme || [];
|
|
227
|
+
const fdr = interestRates?.data?.fdrScheme || [];
|
|
228
|
+
sdr.forEach((r: any) => { if (typeof r?.perdMonth === 'number') months.push(r.perdMonth); });
|
|
229
|
+
fdr.forEach((r: any) => { if (typeof r?.perdMonth === 'number') months.push(r.perdMonth); });
|
|
230
|
+
const unique = Array.from(new Set(months)).sort((a, b) => a - b);
|
|
231
|
+
return unique.map(m => `${m} Months`);
|
|
232
|
+
}, [interestRates]);
|
|
233
|
+
|
|
234
|
+
const [tenureValue, setTenureValue] = useState<string>('');
|
|
235
|
+
React.useEffect(() => {
|
|
236
|
+
if (tenureOptions.length > 0) {
|
|
237
|
+
// If effectiveFdData has tenure, use it; otherwise use first option
|
|
238
|
+
if (effectiveFdData?.tenure) {
|
|
239
|
+
// Check if the effectiveFdData tenure exists in tenureOptions
|
|
240
|
+
const matchingTenure = tenureOptions.find(option => option === effectiveFdData.tenure);
|
|
241
|
+
setTenureValue(matchingTenure || effectiveFdData.tenure);
|
|
242
|
+
} else {
|
|
243
|
+
setTenureValue(tenureOptions[0]);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}, [tenureOptions, effectiveFdData?.tenure]);
|
|
247
|
+
const [showTenureMenu, setShowTenureMenu] = useState<boolean>(false);
|
|
248
|
+
|
|
249
|
+
// Function to close all dropdown menus
|
|
250
|
+
const closeAllMenus = () => {
|
|
251
|
+
setShowTenureMenu(false);
|
|
252
|
+
setShowPayoutModal(false);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Function to call FD calculator API
|
|
256
|
+
const handleCalculateFD = React.useCallback(async (currentAmount?: string, selectedPayout?: string) => {
|
|
257
|
+
const payoutToUse = selectedPayout || payoutValue;
|
|
258
|
+
const amountToUse = currentAmount || amount; // ✅ use latest if provided
|
|
259
|
+
|
|
260
|
+
if (!amountToUse || !payoutToUse) return;
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
const amountValue = parseFloat(amountToUse.replace(/,/g, ''));
|
|
264
|
+
const tenureMonths = parseInt(tenureValue.replace(' Months', ''));
|
|
265
|
+
|
|
266
|
+
if (isNaN(amountValue) || isNaN(tenureMonths) || amountValue <= 0 || tenureMonths <= 0) return;
|
|
267
|
+
|
|
268
|
+
const sdr = interestRates?.data?.sdrScheme || [];
|
|
269
|
+
const fdr = interestRates?.data?.fdrScheme || [];
|
|
270
|
+
const firstRate = sdr[0] || fdr[0];
|
|
271
|
+
const providerId = firstRate?.providerId;
|
|
272
|
+
|
|
273
|
+
const appData = getAppData();
|
|
274
|
+
const userDob = appData?.dob || '1990-01-01';
|
|
275
|
+
const isWomenDepositor = appData?.gender === 'F';
|
|
276
|
+
|
|
277
|
+
const requestData = {
|
|
278
|
+
principalAmount: amountValue,
|
|
279
|
+
tenureInMonths: tenureMonths,
|
|
280
|
+
dob: userDob,
|
|
281
|
+
isWomenDepositor,
|
|
282
|
+
investmentType: payoutToUse === 'On Maturity' ? 'SDR' : 'FDR',
|
|
283
|
+
providerId,
|
|
284
|
+
interestPayout: payoutToUse,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const result = await calculateFD(requestData).unwrap();
|
|
288
|
+
setCalculationResult(result);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
// FD calculation failed
|
|
291
|
+
} finally {
|
|
292
|
+
setIsAmountEditing(false);
|
|
293
|
+
}
|
|
294
|
+
}, [amount, tenureValue, payoutValue, calculateFD, interestRates]);
|
|
295
|
+
|
|
296
|
+
// Debounced amount change handler
|
|
297
|
+
const handleAmountChange = React.useCallback((text: string) => {
|
|
298
|
+
setIsAmountEditing(true);
|
|
299
|
+
// Step 1: Always remove commas first
|
|
300
|
+
const unformatted = text.replace(/,/g, '');
|
|
301
|
+
|
|
302
|
+
// Step 2: Allow only numbers
|
|
303
|
+
let cleanedText = unformatted.replace(/[^0-9]/g, '');
|
|
304
|
+
if (cleanedText.length > 1 && cleanedText.startsWith('0')) {
|
|
305
|
+
cleanedText = cleanedText.replace(/^0+/, '');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Step 3: Stop if greater than 5 crores
|
|
309
|
+
const numericValue = parseInt(cleanedText || '0', 10);
|
|
310
|
+
if (numericValue > 50000000) return;
|
|
311
|
+
|
|
312
|
+
// Step 4: Update state with raw digits (not formatted)
|
|
313
|
+
setAmount(cleanedText);
|
|
314
|
+
|
|
315
|
+
// Step 5: Validate
|
|
316
|
+
if (!cleanedText) {
|
|
317
|
+
setAmountError('');
|
|
318
|
+
setIsAmountEditing(false);
|
|
319
|
+
}
|
|
320
|
+
else if (numericValue < 5000) setAmountError(FD_STRINGS.MINIMUM_AMOUNT_ERROR);
|
|
321
|
+
else if (numericValue % 1000 !== 0) setAmountError(FD_STRINGS.AMOUNT_MULTIPLES_ERROR);
|
|
322
|
+
else setAmountError('');
|
|
323
|
+
|
|
324
|
+
// Step 6: Clear previous debounce timer
|
|
325
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
326
|
+
|
|
327
|
+
// Step 7: Debounced API call
|
|
328
|
+
const isValidLocal = numericValue >= 5000 && numericValue <= 50000000 && numericValue % 1000 === 0;
|
|
329
|
+
if (cleanedText && isValidLocal && payoutValue) {
|
|
330
|
+
const newTimer = setTimeout(() => {
|
|
331
|
+
// Pass latest cleanedText directly to avoid stale state
|
|
332
|
+
handleCalculateFD(cleanedText);
|
|
333
|
+
}, 1000);
|
|
334
|
+
setDebounceTimer(newTimer);
|
|
335
|
+
}
|
|
336
|
+
}, [debounceTimer, handleCalculateFD, payoutValue]);
|
|
337
|
+
|
|
338
|
+
// Function to call onboarding API
|
|
339
|
+
const handleStartOnboarding = React.useCallback(async (selectedPayout?: string) => {
|
|
340
|
+
if (isBooking) return;
|
|
341
|
+
setIsBooking(true);
|
|
342
|
+
const payoutToUse = selectedPayout || payoutValue;
|
|
343
|
+
try {
|
|
344
|
+
// Check if required fields are filled
|
|
345
|
+
if (!amount || !tenureValue) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const amountValue = parseFloat(amount.replace(/,/g, ''));
|
|
350
|
+
const tenureMonths = parseInt(tenureValue.replace(' Months', ''));
|
|
351
|
+
|
|
352
|
+
if (isNaN(amountValue) || isNaN(tenureMonths) || amountValue <= 0 || tenureMonths <= 0) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Check minimum amount requirement
|
|
357
|
+
if (amountValue < 5000) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Get providerId from interest rates data
|
|
362
|
+
const sdr = interestRates?.data?.sdrScheme || [];
|
|
363
|
+
const fdr = interestRates?.data?.fdrScheme || [];
|
|
364
|
+
const firstRate = sdr[0] || fdr[0];
|
|
365
|
+
const providerId = firstRate?.providerId;
|
|
366
|
+
|
|
367
|
+
// Get user data for all required fields
|
|
368
|
+
const appData = getAppData();
|
|
369
|
+
const userDob = appData?.dob || '1990-01-01';
|
|
370
|
+
const isWomenDepositor = appData?.gender === 'F';
|
|
371
|
+
|
|
372
|
+
// Get calculated values from API response based on investment type
|
|
373
|
+
const investmentType = payoutValue === 'On Maturity' ? 'SDR' : 'FDR';
|
|
374
|
+
const calcData = investmentType === 'SDR'
|
|
375
|
+
? calculationResult?.data?.sdrCalc?.[0]
|
|
376
|
+
: calculationResult?.data?.fdrCalc?.[0];
|
|
377
|
+
const interestRate = calcData?.wRoi;
|
|
378
|
+
const maturityAmount = calcData?.maturityAmount;
|
|
379
|
+
|
|
380
|
+
// Calculate maturity date
|
|
381
|
+
const maturityDate = new Date();
|
|
382
|
+
maturityDate.setMonth(maturityDate.getMonth() + tenureMonths);
|
|
383
|
+
const formattedMaturityDate = maturityDate.toISOString().split('T')[0];
|
|
384
|
+
|
|
385
|
+
const onboardingData = {
|
|
386
|
+
// User personal details
|
|
387
|
+
mobile: appData?.mobNo || '',
|
|
388
|
+
prefix: appData?.gender === 'M' ? 'Mr.' : (appData?.gender === 'F' ? 'Ms.' : 'Mr.'),
|
|
389
|
+
fullName: appData?.name || '',
|
|
390
|
+
firstName: appData?.name?.split(' ')[0] || '',
|
|
391
|
+
lastName: appData?.name?.split(' ').slice(1).join(' ') || '',
|
|
392
|
+
userReferenceId: appData?.id || '',
|
|
393
|
+
dob: userDob,
|
|
394
|
+
email: appData?.email || '',
|
|
395
|
+
gender: appData?.gender === 'M' ? 'Male' : (appData?.gender === 'F' ? 'Female' : 'Male'),
|
|
396
|
+
|
|
397
|
+
// FD details
|
|
398
|
+
autoRenewal: autoRenewal,
|
|
399
|
+
investmentAmount: amountValue,
|
|
400
|
+
tenureInMonths: tenureMonths,
|
|
401
|
+
interestPayoutTerm: payoutToUse,
|
|
402
|
+
interestRate: interestRate,
|
|
403
|
+
maturityDate: formattedMaturityDate,
|
|
404
|
+
maturityAmount: Math.round(maturityAmount),
|
|
405
|
+
|
|
406
|
+
// Additional fields
|
|
407
|
+
principalAmount: amountValue,
|
|
408
|
+
isWomenDepositor: isWomenDepositor,
|
|
409
|
+
investmentType: payoutToUse === 'On Maturity' ? 'SDR' : 'FDR',
|
|
410
|
+
providerId: providerId,
|
|
411
|
+
eventNotifyUrl: appData?.eventNotifyUrl,
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const result = await startOnboarding(onboardingData).unwrap();
|
|
415
|
+
|
|
416
|
+
// Store FD calculation data directly into FDListSelected for PayNow screen
|
|
417
|
+
try {
|
|
418
|
+
const fdListSelectedData = {
|
|
419
|
+
id: effectiveFdData?.id || '',
|
|
420
|
+
providerId: providerId || '',
|
|
421
|
+
name: effectiveFdData?.name || '',
|
|
422
|
+
accountNumber: '',
|
|
423
|
+
roi: effectiveFdData?.roi || '',
|
|
424
|
+
tenure: tenureValue,
|
|
425
|
+
amount: parseInt(amount) || 0,
|
|
426
|
+
maturityDate: '',
|
|
427
|
+
status: 'pending' as const,
|
|
428
|
+
creditRating: effectiveFdData?.creditRating || 'NA',
|
|
429
|
+
companyName: effectiveFdData?.name || '',
|
|
430
|
+
fdRate: effectiveFdData?.roi || '',
|
|
431
|
+
interestPayout: payoutToUse,
|
|
432
|
+
};
|
|
433
|
+
dispatch(setFDListSelected(fdListSelectedData as any));
|
|
434
|
+
} catch (e) {
|
|
435
|
+
// Handle error silently
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Persist onboarding identifiers globally for subsequent API calls
|
|
439
|
+
try {
|
|
440
|
+
const ids = {
|
|
441
|
+
workflowInstanceId: result?.data?.workflowInstanceId,
|
|
442
|
+
applicationId: result?.data?.applicationId,
|
|
443
|
+
entityid: result?.data?.entityid,
|
|
444
|
+
customerId: result?.data?.customerId,
|
|
445
|
+
fdId: result?.data?.fdId,
|
|
446
|
+
};
|
|
447
|
+
if (dispatch && setOnboardingIds) {
|
|
448
|
+
dispatch(setOnboardingIds(ids));
|
|
449
|
+
} else {
|
|
450
|
+
// Dispatch or setOnboardingIds unavailable
|
|
451
|
+
}
|
|
452
|
+
} catch (e) {
|
|
453
|
+
// Handle error silently
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Navigate to ReviewKYC after successful onboarding
|
|
457
|
+
if (result.status === 'success' && onNavigateToReviewKYC) {
|
|
458
|
+
onNavigateToReviewKYC();
|
|
459
|
+
}
|
|
460
|
+
} catch (error) {
|
|
461
|
+
// Handle error silently
|
|
462
|
+
} finally {
|
|
463
|
+
setIsBooking(false);
|
|
464
|
+
}
|
|
465
|
+
}, [amount, tenureValue, interestRates, startOnboarding, onNavigateToReviewKYC, isBooking, payoutValue, calculationResult, autoRenewal]);
|
|
466
|
+
|
|
467
|
+
// Cleanup timer on unmount
|
|
468
|
+
React.useEffect(() => {
|
|
469
|
+
return () => {
|
|
470
|
+
if (debounceTimer) {
|
|
471
|
+
clearTimeout(debounceTimer);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}, [debounceTimer]);
|
|
475
|
+
|
|
476
|
+
// Derived validation state for amount input
|
|
477
|
+
const isAmountValid = React.useMemo(() => {
|
|
478
|
+
const amountValue = parseFloat(amount.replace(/,/g, ''));
|
|
479
|
+
return !!amount && !isNaN(amountValue) && amountValue >= 5000 && amountValue <= 50000000 && amountValue % 1000 === 0;
|
|
480
|
+
}, [amount]);
|
|
481
|
+
|
|
482
|
+
// Derived validation state for payout selection
|
|
483
|
+
const isPayoutValid = React.useMemo(() => {
|
|
484
|
+
return !!payoutValue && payoutValue.trim() !== '';
|
|
485
|
+
}, [payoutValue]);
|
|
486
|
+
|
|
487
|
+
// Handle tax resident checkbox change
|
|
488
|
+
const handleTaxResidentChange = () => {
|
|
489
|
+
const newValue = !taxResident;
|
|
490
|
+
setTaxResident(newValue);
|
|
491
|
+
|
|
492
|
+
// Show error if unchecked
|
|
493
|
+
if (!newValue) {
|
|
494
|
+
setTaxResidentError(FD_STRINGS.TAX_RESIDENT_ERROR);
|
|
495
|
+
} else {
|
|
496
|
+
setTaxResidentError('');
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// Extract FAQ data from master data API response
|
|
501
|
+
const faqData: { title: string; description: string }[] = React.useMemo(() => {
|
|
502
|
+
try {
|
|
503
|
+
const parsedData = JSON.parse(effectiveMasterData || '{}');
|
|
504
|
+
|
|
505
|
+
// Check if master data contains FAQ information (exact field name from API response)
|
|
506
|
+
const masterDataFaq = parsedData?.Faq || parsedData?.faq || parsedData?.faqData || parsedData?.frequentlyAskedQuestions;
|
|
507
|
+
|
|
508
|
+
if (masterDataFaq && Array.isArray(masterDataFaq) && masterDataFaq.length > 0) {
|
|
509
|
+
return masterDataFaq.map((faq: any) => ({
|
|
510
|
+
title: faq.title || faq.question || faq.q || '',
|
|
511
|
+
description: faq.description || faq.answer || faq.a || ''
|
|
512
|
+
})).filter((faq: any) => faq.title && faq.description);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Fallback to hardcoded FAQ strings if master data doesn't contain FAQ
|
|
516
|
+
return [
|
|
517
|
+
{
|
|
518
|
+
title: FAQ_STRINGS.FAQ_WITHDRAWAL_QUESTION,
|
|
519
|
+
description: FAQ_STRINGS.FAQ_WITHDRAWAL_ANSWER,
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
title: FAQ_STRINGS.FAQ_CREDIT_QUESTION,
|
|
523
|
+
description: FAQ_STRINGS.FAQ_CREDIT_ANSWER
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
title: FAQ_STRINGS.FAQ_TAX_EXEMPTION_QUESTION,
|
|
527
|
+
description: FAQ_STRINGS.FAQ_TAX_EXEMPTION_ANSWER
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
title: FAQ_STRINGS.FAQ_CUMULATIVE_QUESTION,
|
|
531
|
+
description: FAQ_STRINGS.FAQ_CUMULATIVE_ANSWER
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
title: FAQ_STRINGS.FAQ_OPENING_TIME_QUESTION,
|
|
535
|
+
description: FAQ_STRINGS.FAQ_OPENING_TIME_ANSWER
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
title: FAQ_STRINGS.FAQ_TDS_AVOIDANCE_QUESTION,
|
|
539
|
+
description: FAQ_STRINGS.FAQ_TDS_AVOIDANCE_ANSWER
|
|
540
|
+
},
|
|
541
|
+
];
|
|
542
|
+
} catch (error) {
|
|
543
|
+
// Return fallback FAQ data on error
|
|
544
|
+
return [
|
|
545
|
+
{
|
|
546
|
+
title: FAQ_STRINGS.FAQ_WITHDRAWAL_QUESTION,
|
|
547
|
+
description: FAQ_STRINGS.FAQ_WITHDRAWAL_ANSWER,
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
title: FAQ_STRINGS.FAQ_CREDIT_QUESTION,
|
|
551
|
+
description: FAQ_STRINGS.FAQ_CREDIT_ANSWER
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
title: FAQ_STRINGS.FAQ_TAX_EXEMPTION_QUESTION,
|
|
555
|
+
description: FAQ_STRINGS.FAQ_TAX_EXEMPTION_ANSWER
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
title: FAQ_STRINGS.FAQ_CUMULATIVE_QUESTION,
|
|
559
|
+
description: FAQ_STRINGS.FAQ_CUMULATIVE_ANSWER
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
title: FAQ_STRINGS.FAQ_OPENING_TIME_QUESTION,
|
|
563
|
+
description: FAQ_STRINGS.FAQ_OPENING_TIME_ANSWER
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
title: FAQ_STRINGS.FAQ_TDS_AVOIDANCE_QUESTION,
|
|
567
|
+
description: FAQ_STRINGS.FAQ_TDS_AVOIDANCE_ANSWER
|
|
568
|
+
},
|
|
569
|
+
];
|
|
570
|
+
}
|
|
571
|
+
}, [effectiveMasterData]);
|
|
572
|
+
|
|
573
|
+
// Handle Android hardware back button - use same navigation as header back button
|
|
574
|
+
useEffect(() => {
|
|
575
|
+
if (Platform.OS !== 'android') return;
|
|
576
|
+
|
|
577
|
+
const onHardwareBackPress = () => {
|
|
578
|
+
navigate('FDList'); // Same as header back button
|
|
579
|
+
return true; // Prevent default behavior
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
const backHandler = BackHandler.addEventListener(
|
|
583
|
+
'hardwareBackPress',
|
|
584
|
+
onHardwareBackPress
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
return () => backHandler.remove();
|
|
588
|
+
}, []);
|
|
589
|
+
|
|
590
|
+
return (
|
|
591
|
+
<SafeAreaWrapper
|
|
592
|
+
includeTop={false}
|
|
593
|
+
bottomPadding={25}
|
|
594
|
+
statusBarColor="#000000"
|
|
595
|
+
statusBarStyle="light-content"
|
|
596
|
+
>
|
|
597
|
+
{/* Header */}
|
|
598
|
+
<View style={styles.header}>
|
|
599
|
+
<TouchableOpacity onPress={() => navigate('FDList')} style={styles.backButton}>
|
|
600
|
+
<Image
|
|
601
|
+
source={{ uri: base64Images.backArrow }}
|
|
602
|
+
style={[styles.backIcon, { tintColor: themeName === 'dark' ? colors.headerText : undefined }]}
|
|
603
|
+
resizeMode="contain"
|
|
604
|
+
width={24}
|
|
605
|
+
height={24}
|
|
606
|
+
|
|
607
|
+
/>
|
|
608
|
+
</TouchableOpacity>
|
|
609
|
+
</View>
|
|
610
|
+
|
|
611
|
+
<View style={{ flex: 1, justifyContent: 'space-between' }}>
|
|
612
|
+
<ScrollView
|
|
613
|
+
style={styles.scrollContainer}
|
|
614
|
+
contentContainerStyle={styles.scrollContent}
|
|
615
|
+
showsVerticalScrollIndicator={false}
|
|
616
|
+
onScrollBeginDrag={closeAllMenus}
|
|
617
|
+
scrollEnabled={!(isOnboarding || isBooking)}
|
|
618
|
+
keyboardShouldPersistTaps="handled"
|
|
619
|
+
bounces={true}
|
|
620
|
+
alwaysBounceVertical={true}
|
|
621
|
+
>
|
|
622
|
+
{/* Company Header */}
|
|
623
|
+
<CompanyHeader
|
|
624
|
+
companyName={effectiveFdData?.name || ''}
|
|
625
|
+
rating={effectiveFdData?.creditRating || 'AA+'}
|
|
626
|
+
/>
|
|
627
|
+
|
|
628
|
+
{/* Amount Input */}
|
|
629
|
+
<AmountInput
|
|
630
|
+
label={FD_STRINGS.INVESTMENT_AMOUNT_LABEL}
|
|
631
|
+
value={amount}
|
|
632
|
+
onChangeText={handleAmountChange}
|
|
633
|
+
onFocus={closeAllMenus}
|
|
634
|
+
placeholder={FD_STRINGS.AMOUNT_PLACEHOLDER}
|
|
635
|
+
noteText={FD_STRINGS.AMOUNT_NOTE}
|
|
636
|
+
minMaxText={FD_STRINGS.AMOUNT_MIN_MAX}
|
|
637
|
+
errorMessage={amountError}
|
|
638
|
+
/>
|
|
639
|
+
|
|
640
|
+
{/* Tenure Selector */}
|
|
641
|
+
<DropdownSelector
|
|
642
|
+
label={FD_STRINGS.TENURE_LABEL}
|
|
643
|
+
value={tenureValue || COMMON_STRINGS.SELECT}
|
|
644
|
+
onPress={() => {
|
|
645
|
+
Keyboard.dismiss();
|
|
646
|
+
closeAllMenus();
|
|
647
|
+
setShowTenureMenu(prev => !prev);
|
|
648
|
+
}}
|
|
649
|
+
/>
|
|
650
|
+
{showTenureMenu && (
|
|
651
|
+
<View style={styles.inlineMenu}>
|
|
652
|
+
{(tenureOptions.length > 0 ? tenureOptions : [FD_STRINGS.TENURE_12_MONTHS, FD_STRINGS.TENURE_24_MONTHS, FD_STRINGS.TENURE_36_MONTHS]).map((option) => (
|
|
653
|
+
<TouchableOpacity
|
|
654
|
+
key={option}
|
|
655
|
+
style={styles.modalOption}
|
|
656
|
+
onPress={() => {
|
|
657
|
+
setTenureValue(option);
|
|
658
|
+
setShowTenureMenu(false);
|
|
659
|
+
// Call API after dropdown value changes
|
|
660
|
+
setTimeout(() => handleCalculateFD(), 100);
|
|
661
|
+
}}
|
|
662
|
+
>
|
|
663
|
+
<Text style={styles.modalOptionText}>{option}</Text>
|
|
664
|
+
</TouchableOpacity>
|
|
665
|
+
))}
|
|
666
|
+
</View>
|
|
667
|
+
)}
|
|
668
|
+
|
|
669
|
+
{/* Interest Payout Selector */}
|
|
670
|
+
<DropdownSelector
|
|
671
|
+
label={FD_STRINGS.INTEREST_PAYOUT_TERM_LABEL}
|
|
672
|
+
value={payoutValue}
|
|
673
|
+
onPress={() => {
|
|
674
|
+
Keyboard.dismiss();
|
|
675
|
+
closeAllMenus();
|
|
676
|
+
setShowPayoutModal(prev => !prev);
|
|
677
|
+
}}
|
|
678
|
+
placeholder={FD_STRINGS.PAYOUT_MONTHLY}
|
|
679
|
+
/>
|
|
680
|
+
{showPayoutModal && (
|
|
681
|
+
<View style={styles.inlineMenu}>
|
|
682
|
+
{payoutOptions
|
|
683
|
+
.filter((v, i, a) => !!v && a.indexOf(v) === i)
|
|
684
|
+
.map((option) => (
|
|
685
|
+
<TouchableOpacity
|
|
686
|
+
key={option}
|
|
687
|
+
style={styles.modalOption}
|
|
688
|
+
onPress={() => {
|
|
689
|
+
setPayoutValue(option);
|
|
690
|
+
setShowPayoutModal(false);
|
|
691
|
+
handleCalculateFD(amount, option);
|
|
692
|
+
// Pass the selected option directly to avoid stale state
|
|
693
|
+
// setTimeout(() => handleCalculateFD(option), 100);
|
|
694
|
+
}}
|
|
695
|
+
>
|
|
696
|
+
<Text style={styles.modalOptionText}>{option}</Text>
|
|
697
|
+
</TouchableOpacity>
|
|
698
|
+
))}
|
|
699
|
+
</View>
|
|
700
|
+
)}
|
|
701
|
+
|
|
702
|
+
{/* Interest Rate Card */}
|
|
703
|
+
{isCalculating && (
|
|
704
|
+
<View style={styles.loadingContainer}>
|
|
705
|
+
<ActivityIndicator size="small" color={colors.primary} />
|
|
706
|
+
<Text style={styles.loadingText}>{COMMON_STRINGS.PROCESSING}</Text>
|
|
707
|
+
</View>
|
|
708
|
+
)}
|
|
709
|
+
<InterestRateCard
|
|
710
|
+
interestRate={(() => {
|
|
711
|
+
const data = calculationResult?.data;
|
|
712
|
+
const investmentType = payoutValue === 'On Maturity' ? 'SDR' : 'FDR';
|
|
713
|
+
const calcData = investmentType === 'SDR'
|
|
714
|
+
? data?.sdrCalc?.[0]
|
|
715
|
+
: data?.fdrCalc?.[0];
|
|
716
|
+
const wroi = calcData?.wRoi || data?.wroi || data?.interestRate || data?.rate;
|
|
717
|
+
return wroi ? `${Number(wroi).toFixed(1)}% p.a.` : "";
|
|
718
|
+
})()}
|
|
719
|
+
maturityAmount={(() => {
|
|
720
|
+
const data = calculationResult?.data;
|
|
721
|
+
const investmentType = payoutValue === 'On Maturity' ? 'SDR' : 'FDR';
|
|
722
|
+
const calcData = investmentType === 'SDR'
|
|
723
|
+
? data?.sdrCalc?.[0]
|
|
724
|
+
: data?.fdrCalc?.[0];
|
|
725
|
+
const maturityAmount = calcData?.maturityAmount || data?.maturityAmount || data?.totalAmount || data?.finalAmount || data?.amount;
|
|
726
|
+
return maturityAmount ? `₹${maturityAmount.toLocaleString()}` : "";
|
|
727
|
+
})()}
|
|
728
|
+
>
|
|
729
|
+
<CheckboxOption
|
|
730
|
+
label={FD_STRINGS.SENIOR_CITIZEN_BENEFIT}
|
|
731
|
+
checked={seniorCitizen}
|
|
732
|
+
onPress={() => setSeniorCitizen(!seniorCitizen)}
|
|
733
|
+
numberOfLines={1}
|
|
734
|
+
containerStyle={{ marginTop: 12 }}
|
|
735
|
+
disabled={true}
|
|
736
|
+
/>
|
|
737
|
+
</InterestRateCard>
|
|
738
|
+
|
|
739
|
+
{/* Tax Resident Checkbox */}
|
|
740
|
+
<View style={[styles.checkboxCard, !taxResident && styles.checkboxCardError]}>
|
|
741
|
+
<CheckboxOption
|
|
742
|
+
label={FD_STRINGS.TAX_RESIDENT_CONFIRMATION}
|
|
743
|
+
checked={taxResident}
|
|
744
|
+
onPress={handleTaxResidentChange}
|
|
745
|
+
/>
|
|
746
|
+
</View>
|
|
747
|
+
{taxResidentError && (
|
|
748
|
+
<View style={styles.errorContainer}>
|
|
749
|
+
{Platform.OS === 'android' && (
|
|
750
|
+
<Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
|
|
751
|
+
)}
|
|
752
|
+
<Text style={styles.errorText}>{taxResidentError}</Text>
|
|
753
|
+
</View>
|
|
754
|
+
)}
|
|
755
|
+
|
|
756
|
+
{/* Auto Renewal Checkbox */}
|
|
757
|
+
<View style={styles.checkboxCard}>
|
|
758
|
+
<CheckboxOption
|
|
759
|
+
label={FD_STRINGS.MATURITY_AUTO_RENEWAL}
|
|
760
|
+
checked={autoRenewal}
|
|
761
|
+
onPress={() => setAutoRenewal(!autoRenewal)}
|
|
762
|
+
/>
|
|
763
|
+
</View>
|
|
764
|
+
|
|
765
|
+
{/* Info Box with nonStock icon before withdrawal text */}
|
|
766
|
+
<InfoBox message={FD_STRINGS.WITHDRAWAL_INFO} containerStyle={styles.infoBoxCard} showNonStockIcon={true} />
|
|
767
|
+
|
|
768
|
+
{/* Safety & Trust */}
|
|
769
|
+
<Text style={styles.sectionTitle}>{FD_STRINGS.SAFETY_TRUST_TITLE}</Text>
|
|
770
|
+
<View style={styles.trustRow}>
|
|
771
|
+
<TrustBox title1={FD_STRINGS.TRUSTED_BY} title2={FD_STRINGS.CRORES_INDIANS} />
|
|
772
|
+
<TrustBox title1={FD_STRINGS.AAA_RATING} title2={FD_STRINGS.RATING} style={{ marginLeft: 10 }} />
|
|
773
|
+
</View>
|
|
774
|
+
|
|
775
|
+
{/* FAQ Section */}
|
|
776
|
+
<Text style={styles.sectionTitle}>{FD_STRINGS.FAQ_TITLE}</Text>
|
|
777
|
+
{faqData.map((item, index) => (
|
|
778
|
+
<FAQItem
|
|
779
|
+
key={index}
|
|
780
|
+
question={item.title}
|
|
781
|
+
answer={item.description}
|
|
782
|
+
isExpanded={expandedIndex === index}
|
|
783
|
+
onToggle={() => setExpandedIndex(expandedIndex === index ? null : index)}
|
|
784
|
+
/>
|
|
785
|
+
))}
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
</ScrollView>
|
|
789
|
+
{/* Start FD Button */}
|
|
790
|
+
<TouchableOpacity
|
|
791
|
+
style={[
|
|
792
|
+
styles.startButton,
|
|
793
|
+
(!taxResident || isOnboarding || isBooking || !isAmountValid || !isPayoutValid || isCalculating || isAmountEditing) ? styles.startButtonDisabled : null
|
|
794
|
+
]}
|
|
795
|
+
disabled={!taxResident || isOnboarding || isBooking || !isAmountValid || !isPayoutValid || isCalculating || isAmountEditing}
|
|
796
|
+
activeOpacity={(!taxResident || isOnboarding || isBooking || !isAmountValid || !isPayoutValid || isCalculating || isAmountEditing) ? 1 : 0.7}
|
|
797
|
+
onPress={() => {
|
|
798
|
+
if (taxResident && !isOnboarding && !isBooking && isAmountValid && isPayoutValid && !isCalculating && !isAmountEditing) {
|
|
799
|
+
handleStartOnboarding(payoutValue);
|
|
800
|
+
}
|
|
801
|
+
}}
|
|
802
|
+
>
|
|
803
|
+
{(isOnboarding || isBooking) ? (
|
|
804
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
|
|
805
|
+
<ActivityIndicator size="small" color={themeName === 'dark' ? colors.buttonTextColor : colors.background} style={{ marginRight: 8 }} />
|
|
806
|
+
<Text style={[
|
|
807
|
+
styles.startButtonText,
|
|
808
|
+
(!taxResident || isOnboarding || isBooking || !isAmountValid || !isPayoutValid || isCalculating || isAmountEditing) ? styles.startButtonTextDisabled : null
|
|
809
|
+
]}>
|
|
810
|
+
{COMMON_STRINGS.PROCESSING}
|
|
811
|
+
</Text>
|
|
812
|
+
</View>
|
|
813
|
+
) : (
|
|
814
|
+
<Text style={[
|
|
815
|
+
styles.startButtonText,
|
|
816
|
+
(!taxResident || isOnboarding || isBooking || !isAmountValid || !isPayoutValid || isCalculating || isAmountEditing) ? styles.startButtonTextDisabled : null
|
|
817
|
+
]}>
|
|
818
|
+
{FD_STRINGS.BOOK_FD_BUTTON}
|
|
819
|
+
</Text>
|
|
820
|
+
)}
|
|
821
|
+
</TouchableOpacity>
|
|
822
|
+
</View>
|
|
823
|
+
{/* Overlay to disable screen interactions during API call */}
|
|
824
|
+
{
|
|
825
|
+
(isOnboarding || isBooking) && (
|
|
826
|
+
<View style={styles.loadingOverlay} pointerEvents="auto">
|
|
827
|
+
</View>
|
|
828
|
+
)
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
{/* Inline dropdown renders just under the field; closes on selection */}
|
|
832
|
+
</SafeAreaWrapper >
|
|
833
|
+
);
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
export default FDCalculator;
|
|
837
|
+
|
|
838
|
+
const isAndroid15OrHigher = Platform.OS === "android" && Platform.Version >= 15;
|
|
839
|
+
const createStyles = (typography: any, colors: any, themeName: string) => StyleSheet.create({
|
|
840
|
+
header: {
|
|
841
|
+
flexDirection: 'row',
|
|
842
|
+
justifyContent: 'flex-start',
|
|
843
|
+
alignItems: 'center',
|
|
844
|
+
paddingHorizontal: 16,
|
|
845
|
+
paddingTop: Platform.OS === 'ios' ? 40 : 20,
|
|
846
|
+
paddingBottom: 10,
|
|
847
|
+
backgroundColor: colors.background,
|
|
848
|
+
},
|
|
849
|
+
backIcon: {
|
|
850
|
+
// Icon styling handled by Ionicons component
|
|
851
|
+
width: 24,
|
|
852
|
+
height: 24,
|
|
853
|
+
resizeMode: 'contain',
|
|
854
|
+
// backgroundColor: "red",
|
|
855
|
+
},
|
|
856
|
+
backButton: {
|
|
857
|
+
padding: 8,
|
|
858
|
+
marginTop: isAndroid15OrHigher ? 10 : 0,
|
|
859
|
+
},
|
|
860
|
+
scrollContainer: {
|
|
861
|
+
flex: 1,
|
|
862
|
+
},
|
|
863
|
+
scrollContent: {
|
|
864
|
+
paddingHorizontal: 16,
|
|
865
|
+
paddingBottom: 40,
|
|
866
|
+
},
|
|
867
|
+
checkboxCard: {
|
|
868
|
+
backgroundColor: themeName === 'dark' ? colors.inputBackground : 'rgba(0,235,180,0.1)',
|
|
869
|
+
padding: 12,
|
|
870
|
+
borderRadius: 4,
|
|
871
|
+
marginTop: 16,
|
|
872
|
+
},
|
|
873
|
+
infoBoxCard: {
|
|
874
|
+
backgroundColor: themeName === 'dark' ? colors.inputBackground : 'rgba(0,235,180,0.1)',
|
|
875
|
+
padding: 16,
|
|
876
|
+
borderRadius: 4,
|
|
877
|
+
marginTop: 16,
|
|
878
|
+
},
|
|
879
|
+
sectionTitle: {
|
|
880
|
+
...typography.styles.bodyMedium,
|
|
881
|
+
fontWeight: typography.fontWeight.semiBold,
|
|
882
|
+
marginTop: 25,
|
|
883
|
+
marginBottom: 8,
|
|
884
|
+
color: colors.text,
|
|
885
|
+
fontSize: 16,
|
|
886
|
+
},
|
|
887
|
+
trustRow: {
|
|
888
|
+
flexDirection: 'row',
|
|
889
|
+
justifyContent: 'space-between',
|
|
890
|
+
marginTop: 10,
|
|
891
|
+
},
|
|
892
|
+
startButtonWrapper: {
|
|
893
|
+
position: 'relative',
|
|
894
|
+
},
|
|
895
|
+
startButton: {
|
|
896
|
+
backgroundColor: themeName === 'dark' ? colors.buttonBackground : colors.headerBg,
|
|
897
|
+
paddingVertical: themeName === 'dark' ? 1 : 20,
|
|
898
|
+
paddingHorizontal: 20,
|
|
899
|
+
borderRadius: themeName === 'dark' ? 10 : 30,
|
|
900
|
+
marginTop: 30,
|
|
901
|
+
alignItems: 'center',
|
|
902
|
+
justifyContent: 'center',
|
|
903
|
+
height: themeName === 'dark' ? 50 : 56,
|
|
904
|
+
width: '90%',
|
|
905
|
+
alignSelf: 'center',
|
|
906
|
+
},
|
|
907
|
+
startButtonDisabled: {
|
|
908
|
+
backgroundColor: '#909090',
|
|
909
|
+
color: '#ffffff',
|
|
910
|
+
},
|
|
911
|
+
startButtonText: {
|
|
912
|
+
...typography.styles.button,
|
|
913
|
+
color: themeName === 'dark' ? colors.buttonTextColor : colors.background,
|
|
914
|
+
lineHeight: themeName === 'dark' ? 24 : typography.styles.button.lineHeight,
|
|
915
|
+
fontSize: 16,
|
|
916
|
+
},
|
|
917
|
+
startButtonTextDisabled: {
|
|
918
|
+
color: themeName === 'dark' ? "#ffffff" : colors.tabSelected,
|
|
919
|
+
},
|
|
920
|
+
inlineMenu: {
|
|
921
|
+
backgroundColor: themeName === 'dark' ? colors.inputBackground : colors.background,
|
|
922
|
+
borderWidth: themeName === 'dark' ? 1 : 0.5,
|
|
923
|
+
borderColor: themeName === 'dark' ? '#ffffff' : 'rgba(0,0,0,0.2)',
|
|
924
|
+
borderRadius: 8,
|
|
925
|
+
marginTop: 6,
|
|
926
|
+
paddingHorizontal: 12,
|
|
927
|
+
paddingVertical: 6,
|
|
928
|
+
},
|
|
929
|
+
modalOption: {
|
|
930
|
+
paddingVertical: 14,
|
|
931
|
+
},
|
|
932
|
+
modalOptionText: {
|
|
933
|
+
...typography.styles.bodyLarge,
|
|
934
|
+
color: colors.text,
|
|
935
|
+
fontSize: 16,
|
|
936
|
+
placeholderTextColor: '#9ca9b0',
|
|
937
|
+
},
|
|
938
|
+
|
|
939
|
+
loadingContainer: {
|
|
940
|
+
flexDirection: 'row',
|
|
941
|
+
alignItems: 'center',
|
|
942
|
+
justifyContent: 'center',
|
|
943
|
+
paddingVertical: 12,
|
|
944
|
+
fontSize: 14,
|
|
945
|
+
marginTop: 16,
|
|
946
|
+
},
|
|
947
|
+
loadingText: {
|
|
948
|
+
...typography.styles.bodyMedium,
|
|
949
|
+
color: colors.textLight,
|
|
950
|
+
marginLeft: 8,
|
|
951
|
+
},
|
|
952
|
+
overlayAboveInterestRate: {
|
|
953
|
+
position: 'absolute',
|
|
954
|
+
top: 0,
|
|
955
|
+
left: 0,
|
|
956
|
+
right: 0,
|
|
957
|
+
height: 20,
|
|
958
|
+
backgroundColor: 'rgba(128, 128, 128, 0.3)', // Light gray translucent overlay
|
|
959
|
+
zIndex: 1,
|
|
960
|
+
},
|
|
961
|
+
errorContainer: {
|
|
962
|
+
flexDirection: 'row',
|
|
963
|
+
alignItems: 'center',
|
|
964
|
+
marginTop: 8,
|
|
965
|
+
},
|
|
966
|
+
errorIcon: {
|
|
967
|
+
marginRight: 6,
|
|
968
|
+
},
|
|
969
|
+
errorText: {
|
|
970
|
+
fontSize: 14,
|
|
971
|
+
color: colors.error || '#FF0000',
|
|
972
|
+
fontWeight: '500',
|
|
973
|
+
flex: 1,
|
|
974
|
+
},
|
|
975
|
+
checkboxCardError: {
|
|
976
|
+
backgroundColor: 'rgba(255, 0, 0, 0.08)', // Red with same opacity as the original green
|
|
977
|
+
},
|
|
978
|
+
loadingOverlay: {
|
|
979
|
+
position: 'absolute',
|
|
980
|
+
top: 0,
|
|
981
|
+
left: 0,
|
|
982
|
+
right: 0,
|
|
983
|
+
bottom: 0,
|
|
984
|
+
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
985
|
+
zIndex: 1000,
|
|
986
|
+
},
|
|
987
|
+
});
|