@finspringinnovations/fdsdk 0.0.3 → 0.0.5
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/lib/api/baseApi.js +17 -6
- package/lib/api/masterDataApi.js +21 -1
- package/lib/api/workflowApi.js +46 -1
- package/lib/assets/images/images.d.ts +1 -0
- package/lib/assets/images/images.js +1 -0
- package/lib/components/FDCard.js +9 -0
- package/lib/hooks/usePaymentSSE.d.ts +7 -1
- package/lib/hooks/usePaymentSSE.js +101 -12
- package/lib/navigation/RootNavigator.d.ts +1 -0
- package/lib/navigation/RootNavigator.js +12 -4
- package/lib/navigation/index.d.ts +1 -0
- package/lib/navigation/index.js +2 -2
- package/lib/screens/AadhaarVerification.js +2 -2
- package/lib/screens/FDCalculator.d.ts +1 -0
- package/lib/screens/FDCalculator.js +11 -4
- package/lib/screens/FDList.js +37 -64
- package/lib/screens/Payment.js +42 -28
- package/lib/screens/PaymentStatus.js +24 -26
- package/lib/screens/ReviewKYC.js +45 -97
- package/package.json +1 -1
- package/src/api/baseApi.ts +19 -6
- package/src/api/masterDataApi.ts +21 -3
- package/src/api/workflowApi.ts +50 -1
- package/src/assets/images/images.js +1 -0
- package/src/assets/images/shriram.png +0 -0
- package/src/components/FDCard.tsx +15 -0
- package/src/hooks/usePaymentSSE.ts +109 -15
- package/src/navigation/RootNavigator.tsx +12 -3
- package/src/navigation/index.tsx +3 -1
- package/src/screens/AadhaarVerification.tsx +2 -2
- package/src/screens/FDCalculator.tsx +12 -4
- package/src/screens/FDList.tsx +37 -76
- package/src/screens/Payment.tsx +45 -35
- package/src/screens/PaymentStatus.tsx +25 -40
- package/src/screens/ReviewKYC.tsx +94 -170
package/lib/screens/FDList.js
CHANGED
|
@@ -46,7 +46,6 @@ const customerApi_1 = require("../api/customerApi");
|
|
|
46
46
|
const masterDataApi_1 = require("../api/masterDataApi");
|
|
47
47
|
const MasterDataProvider_1 = require("../providers/MasterDataProvider");
|
|
48
48
|
const workflowApi_1 = require("../api/workflowApi");
|
|
49
|
-
const fdApi_1 = require("../api/fdApi");
|
|
50
49
|
const SafeAreaWrapper_1 = __importDefault(require("../components/SafeAreaWrapper"));
|
|
51
50
|
const appDataConfig_1 = require("../config/appDataConfig");
|
|
52
51
|
const helpers_1 = require("../navigation/helpers");
|
|
@@ -75,15 +74,8 @@ const FDList = ({ onGoBack, onSelectFD, onNavigateToFDCalculator, customStyles =
|
|
|
75
74
|
const [getInterestRates, { data: interestRates, error: interestRatesError, isLoading: isLoadingRates, }] = (0, interestRateApi_1.useGetInterestRatesMutation)();
|
|
76
75
|
const [getCustomerApplications, { data: customerApplications, error: customerApplicationsError, isLoading: isLoadingApplications, }] = (0, customerApi_1.useGetCustomerApplicationsMutation)();
|
|
77
76
|
const [terminateWorkflow, { data: terminateWorkflowData, error: terminateWorkflowError, isLoading: isTerminatingWorkflow, }] = (0, workflowApi_1.useTerminateWorkflowMutation)();
|
|
78
|
-
// Payment Reverse Feed API
|
|
79
|
-
const [paymentReverseFeed, { data: paymentReverseFeedResponse, error: paymentReverseFeedError, isLoading: isLoadingPaymentReverseFeed, }] = (0, fdApi_1.usePaymentReverseFeedMutation)();
|
|
80
77
|
const styles = createStyles(colors, typography, spacing, themeName);
|
|
81
78
|
const { setMasterData } = (0, MasterDataProvider_1.useMasterData)();
|
|
82
|
-
// Redux selectors for workflow IDs
|
|
83
|
-
const workflowInstanceId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.workflowInstanceId; });
|
|
84
|
-
const applicationId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.applicationId; });
|
|
85
|
-
const entityId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.entityid; });
|
|
86
|
-
const providerId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.providerId; });
|
|
87
79
|
// Helper function to check if customer applications is empty
|
|
88
80
|
const isCustomerApplicationsEmpty = () => {
|
|
89
81
|
if (!customerApplications) {
|
|
@@ -179,7 +171,12 @@ const FDList = ({ onGoBack, onSelectFD, onNavigateToFDCalculator, customStyles =
|
|
|
179
171
|
return interestRates.data.fdrScheme[0].providerId;
|
|
180
172
|
return defaultProviderId; // Use default if no rates data yet
|
|
181
173
|
}, [interestRates]);
|
|
182
|
-
const { data: masterData, isLoading: isLoadingMaster } = (0, masterDataApi_1.useGetMasterDataQuery)({ providerId: inferredProviderId }, {
|
|
174
|
+
const { data: masterData, isLoading: isLoadingMaster } = (0, masterDataApi_1.useGetMasterDataQuery)({ providerId: inferredProviderId }, {
|
|
175
|
+
skip: !inferredProviderId,
|
|
176
|
+
refetchOnMountOrArgChange: true,
|
|
177
|
+
refetchOnFocus: true,
|
|
178
|
+
refetchOnReconnect: true,
|
|
179
|
+
});
|
|
183
180
|
// Only render once all three API calls have completed (success or error)
|
|
184
181
|
// Show loading initially until all APIs have completed
|
|
185
182
|
const isAllDataReady = react_1.default.useMemo(() => {
|
|
@@ -413,25 +410,34 @@ const FDList = ({ onGoBack, onSelectFD, onNavigateToFDCalculator, customStyles =
|
|
|
413
410
|
// Customer applications loaded successfully
|
|
414
411
|
// Persist onboarding identifiers globally for subsequent API calls (like FDCalculator)
|
|
415
412
|
try {
|
|
416
|
-
// Extract workflow parameters from response
|
|
413
|
+
// Extract workflow parameters from response (support array / data[] / applications[])
|
|
417
414
|
const responseData = (customerApplications === null || customerApplications === void 0 ? void 0 : customerApplications.data) || customerApplications;
|
|
418
|
-
let
|
|
419
|
-
// Prefer the application with wf_status === 'Active'
|
|
415
|
+
let applicationsData = [];
|
|
420
416
|
if (Array.isArray(responseData)) {
|
|
421
|
-
|
|
417
|
+
applicationsData = responseData;
|
|
418
|
+
}
|
|
419
|
+
else if ((responseData === null || responseData === void 0 ? void 0 : responseData.applications) && Array.isArray(responseData.applications)) {
|
|
420
|
+
applicationsData = responseData.applications;
|
|
421
|
+
}
|
|
422
|
+
else if (Array.isArray(customerApplications === null || customerApplications === void 0 ? void 0 : customerApplications.applications)) {
|
|
423
|
+
applicationsData = customerApplications.applications;
|
|
424
|
+
}
|
|
425
|
+
let applicationData = applicationsData.length > 0 ? applicationsData[0] : (Array.isArray(responseData) ? responseData[0] : responseData);
|
|
426
|
+
// Prefer the application with wf_status === 'Active'
|
|
427
|
+
if (applicationsData.length > 0) {
|
|
428
|
+
const activeOnly = applicationsData.find((app) => {
|
|
422
429
|
const status = (app.wf_status || app.status || '').toString();
|
|
423
430
|
return status === 'Active';
|
|
424
431
|
});
|
|
425
432
|
if (activeOnly)
|
|
426
433
|
applicationData = activeOnly;
|
|
427
434
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
+
// Set completed flag robustly for downstream ReviewKYC/Aadhaar flow decisions
|
|
436
|
+
completeFDData = applicationsData.find((app) => {
|
|
437
|
+
const status = (app.wf_status || app.status || '').toString().toLowerCase();
|
|
438
|
+
return status === 'completed';
|
|
439
|
+
});
|
|
440
|
+
(0, globalData_1.setGlobalData)({ completeFDData: !!completeFDData });
|
|
435
441
|
if (applicationData) {
|
|
436
442
|
const ids = {
|
|
437
443
|
workflowInstanceId: applicationData.workflow_instance_id,
|
|
@@ -460,7 +466,6 @@ const FDList = ({ onGoBack, onSelectFD, onNavigateToFDCalculator, customStyles =
|
|
|
460
466
|
}, [customerApplications, dispatch]);
|
|
461
467
|
// Unified handler: behave like bottom sheet Continue flow
|
|
462
468
|
const handlePendingFDContinue = async () => {
|
|
463
|
-
var _a;
|
|
464
469
|
// Persist active FD data to store for use across screens
|
|
465
470
|
try {
|
|
466
471
|
if (activeFD) {
|
|
@@ -516,50 +521,18 @@ const FDList = ({ onGoBack, onSelectFD, onNavigateToFDCalculator, customStyles =
|
|
|
516
521
|
catch (error) {
|
|
517
522
|
// Handle error silently
|
|
518
523
|
}
|
|
519
|
-
// If current state is payment and transactionId is available,
|
|
524
|
+
// If current state is payment and transactionId is available,
|
|
525
|
+
// open PaymentStatus and let SSE (/events) drive status updates.
|
|
520
526
|
if (currentState === workflowConstants_1.WORKFLOW_STATES.PAYMENT && transactionId) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
applicationid: applicationId,
|
|
531
|
-
entityid: entityId,
|
|
532
|
-
// Body
|
|
533
|
-
transactionId: transactionId,
|
|
534
|
-
};
|
|
535
|
-
const response = await paymentReverseFeed(paymentReverseFeedRequest).unwrap();
|
|
536
|
-
// Handle the response based on payment status
|
|
537
|
-
const paymentStatus = (((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.paymentStatus) || '').toLowerCase();
|
|
538
|
-
const statusParam = paymentStatus === 'success' ? 'success' : paymentStatus === 'failed' ? 'failed' : 'pending';
|
|
539
|
-
// Build fdData for display
|
|
540
|
-
const fdDataParam = activeFD ? {
|
|
541
|
-
companyName: activeFD.name,
|
|
542
|
-
amount: Number(activeFD.invested) || 0,
|
|
543
|
-
fdRate: `${activeFD.returns}% p.a.`,
|
|
544
|
-
tenure: activeFD.maturityDate ? `${activeFD.maturityDate}` : '-',
|
|
545
|
-
interestPayout: activeFD.interestPayout || 'Yearly',
|
|
546
|
-
} : undefined;
|
|
547
|
-
(0, helpers_1.navigate)('PaymentStatus', { status: statusParam, transactionId, fdData: fdDataParam });
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
catch (error) {
|
|
551
|
-
// Handle error silently
|
|
552
|
-
// On error, navigate with pending status as fallback
|
|
553
|
-
const fdDataParam = activeFD ? {
|
|
554
|
-
companyName: activeFD.name,
|
|
555
|
-
amount: Number(activeFD.invested) || 0,
|
|
556
|
-
fdRate: `${activeFD.returns}% p.a.`,
|
|
557
|
-
tenure: activeFD.maturityDate ? `${activeFD.maturityDate}` : '-',
|
|
558
|
-
interestPayout: activeFD.interestPayout || 'Yearly',
|
|
559
|
-
} : undefined;
|
|
560
|
-
(0, helpers_1.navigate)('PaymentStatus', { status: 'pending', transactionId, fdData: fdDataParam });
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
527
|
+
const fdDataParam = activeFD ? {
|
|
528
|
+
companyName: activeFD.name,
|
|
529
|
+
amount: Number(activeFD.invested) || 0,
|
|
530
|
+
fdRate: `${activeFD.returns}% p.a.`,
|
|
531
|
+
tenure: activeFD.maturityDate ? `${activeFD.maturityDate}` : '-',
|
|
532
|
+
interestPayout: activeFD.interestPayout || 'Yearly',
|
|
533
|
+
} : undefined;
|
|
534
|
+
(0, helpers_1.navigate)('PaymentStatus', { status: 'pending', transactionId, fdData: fdDataParam });
|
|
535
|
+
return;
|
|
563
536
|
}
|
|
564
537
|
// Use workflow navigation based on current state (non-payment states or no transactionId)
|
|
565
538
|
if (currentState && Object.values(workflowConstants_1.WORKFLOW_STATES).includes(currentState)) {
|
package/lib/screens/Payment.js
CHANGED
|
@@ -43,34 +43,22 @@ const SafeAreaWrapper_1 = __importDefault(require("../components/SafeAreaWrapper
|
|
|
43
43
|
const ThemeContext_1 = require("../theme/ThemeContext");
|
|
44
44
|
const encryption_1 = require("../utils/encryption");
|
|
45
45
|
const encryptionConfig_1 = require("../config/encryptionConfig");
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const usePaymentStatusTimer_1 = require("../hooks/usePaymentStatusTimer");
|
|
46
|
+
const store_1 = require("../store");
|
|
47
|
+
const usePaymentSSE_1 = require("../hooks/usePaymentSSE");
|
|
49
48
|
const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPending, paymentUrl, successUrl = 'payment/success', failureUrl = 'payment/failure', }) => {
|
|
50
49
|
const colors = (0, ThemeContext_1.useColors)();
|
|
51
50
|
const styles = createStyles(colors);
|
|
52
51
|
const webViewRef = (0, react_1.useRef)(null);
|
|
53
52
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
else if (status === 'failed') {
|
|
64
|
-
onPaymentFailure === null || onPaymentFailure === void 0 ? void 0 : onPaymentFailure(response);
|
|
65
|
-
}
|
|
66
|
-
else if (status === 'pending') {
|
|
67
|
-
onPaymentPending === null || onPaymentPending === void 0 ? void 0 : onPaymentPending(response);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
(0, native_1.useFocusEffect)(react_1.default.useCallback(() => {
|
|
72
|
-
startTimer();
|
|
73
|
-
}, [startTimer, stopTimer]));
|
|
53
|
+
const applicationId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.applicationId; });
|
|
54
|
+
const workflowInstanceId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.workflowInstanceId; });
|
|
55
|
+
const entityId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.entityid; });
|
|
56
|
+
const providerId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.providerId; });
|
|
57
|
+
const { start: startPaymentSSE, stop: stopPaymentSSE } = (0, usePaymentSSE_1.usePaymentSSE)();
|
|
58
|
+
const onSuccessRef = (0, react_1.useRef)(onPaymentSuccess);
|
|
59
|
+
const onFailureRef = (0, react_1.useRef)(onPaymentFailure);
|
|
60
|
+
onSuccessRef.current = onPaymentSuccess;
|
|
61
|
+
onFailureRef.current = onPaymentFailure;
|
|
74
62
|
const handleNavigationStateChange = async (navState) => {
|
|
75
63
|
const { url } = navState;
|
|
76
64
|
if (url.includes('payment/status')) {
|
|
@@ -92,6 +80,37 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
|
|
|
92
80
|
const handleLoadEnd = () => {
|
|
93
81
|
setLoading(false);
|
|
94
82
|
};
|
|
83
|
+
// SSE: listen for payment status while user is on Payment WebView (same as web integration)
|
|
84
|
+
(0, react_1.useEffect)(() => {
|
|
85
|
+
if (!applicationId || !(paymentUrl === null || paymentUrl === void 0 ? void 0 : paymentUrl.trim()))
|
|
86
|
+
return;
|
|
87
|
+
startPaymentSSE(applicationId, {
|
|
88
|
+
onPaymentStatus: (status, payload) => {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
const normalized = String(status || '').toUpperCase();
|
|
91
|
+
if (normalized === 'SUCCESS') {
|
|
92
|
+
stopPaymentSSE();
|
|
93
|
+
(_a = onSuccessRef.current) === null || _a === void 0 ? void 0 : _a.call(onSuccessRef, payload);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (normalized === 'FAILED') {
|
|
97
|
+
stopPaymentSSE();
|
|
98
|
+
(_b = onFailureRef.current) === null || _b === void 0 ? void 0 : _b.call(onFailureRef, payload);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
onError: () => {
|
|
102
|
+
if (__DEV__)
|
|
103
|
+
console.warn('[Payment] SSE connection error');
|
|
104
|
+
},
|
|
105
|
+
onConnected: () => {
|
|
106
|
+
if (__DEV__)
|
|
107
|
+
console.log('[Payment] SSE connected for payment status');
|
|
108
|
+
},
|
|
109
|
+
}, { workflowInstanceId, applicationId, entityid: entityId, providerId });
|
|
110
|
+
return () => {
|
|
111
|
+
stopPaymentSSE();
|
|
112
|
+
};
|
|
113
|
+
}, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId, startPaymentSSE, stopPaymentSSE]);
|
|
95
114
|
const handleMessage = async (event) => {
|
|
96
115
|
var _a, _b, _c;
|
|
97
116
|
try {
|
|
@@ -130,13 +149,9 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
|
|
|
130
149
|
// Check payment status in data
|
|
131
150
|
const paymentStatus = (_c = (_b = response.data) === null || _b === void 0 ? void 0 : _b.paymentStatus) === null || _c === void 0 ? void 0 : _c.toLowerCase();
|
|
132
151
|
if (paymentStatus === 'success') {
|
|
133
|
-
currentStatusRef.current = "success";
|
|
134
|
-
stopTimer();
|
|
135
152
|
onPaymentSuccess === null || onPaymentSuccess === void 0 ? void 0 : onPaymentSuccess(response);
|
|
136
153
|
}
|
|
137
154
|
else if (paymentStatus === 'failed') {
|
|
138
|
-
currentStatusRef.current = "failed";
|
|
139
|
-
stopTimer();
|
|
140
155
|
onPaymentFailure === null || onPaymentFailure === void 0 ? void 0 : onPaymentFailure(response);
|
|
141
156
|
}
|
|
142
157
|
else {
|
|
@@ -144,7 +159,6 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
|
|
|
144
159
|
}
|
|
145
160
|
}
|
|
146
161
|
else {
|
|
147
|
-
currentStatusRef.current = "pending";
|
|
148
162
|
onPaymentPending === null || onPaymentPending === void 0 ? void 0 : onPaymentPending(response);
|
|
149
163
|
}
|
|
150
164
|
setLoading(false);
|
|
@@ -53,8 +53,7 @@ const paymentSession_1 = require("../state/paymentSession");
|
|
|
53
53
|
const native_1 = require("@react-navigation/native");
|
|
54
54
|
const bank_1 = require("../constants/strings/bank");
|
|
55
55
|
const common_1 = require("../constants/strings/common");
|
|
56
|
-
const
|
|
57
|
-
const usePaymentStatusTimer_1 = require("../hooks/usePaymentStatusTimer");
|
|
56
|
+
const usePaymentSSE_1 = require("../hooks/usePaymentSSE");
|
|
58
57
|
const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) => {
|
|
59
58
|
var _a;
|
|
60
59
|
const colors = (0, ThemeContext_1.useColors)();
|
|
@@ -75,18 +74,7 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
|
|
|
75
74
|
const applicationId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.applicationId; });
|
|
76
75
|
const entityId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.entityid; });
|
|
77
76
|
const providerId = (0, store_1.useAppSelector)((state) => { var _a; return (_a = state === null || state === void 0 ? void 0 : state.onboarding) === null || _a === void 0 ? void 0 : _a.providerId; });
|
|
78
|
-
const {
|
|
79
|
-
transactionId: finalTransactionId,
|
|
80
|
-
overrides: {
|
|
81
|
-
providerId,
|
|
82
|
-
workflowInstanceId,
|
|
83
|
-
applicationid: applicationId,
|
|
84
|
-
entityid: entityId,
|
|
85
|
-
},
|
|
86
|
-
onStatusUpdate: (nextStatus) => {
|
|
87
|
-
setCurrentStatus(nextStatus);
|
|
88
|
-
},
|
|
89
|
-
});
|
|
77
|
+
const { start: startPaymentSSE, stop: stopPaymentSSE } = (0, usePaymentSSE_1.usePaymentSSE)();
|
|
90
78
|
// Payment Retry API
|
|
91
79
|
const [paymentRetry, { data: paymentRetryResponse, error: paymentRetryError, isLoading: isLoadingPaymentRetry, }] = (0, fdApi_1.usePaymentRetryMutation)();
|
|
92
80
|
// Get Customer Applications API
|
|
@@ -111,19 +99,31 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
|
|
|
111
99
|
return amount.toLocaleString('en-IN');
|
|
112
100
|
};
|
|
113
101
|
(0, react_1.useEffect)(() => {
|
|
114
|
-
if (currentStatus
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
else {
|
|
118
|
-
stopTimer();
|
|
102
|
+
if (currentStatus !== 'pending' || !applicationId) {
|
|
103
|
+
stopPaymentSSE();
|
|
104
|
+
return;
|
|
119
105
|
}
|
|
106
|
+
startPaymentSSE(applicationId, {
|
|
107
|
+
onPaymentStatus: (status) => {
|
|
108
|
+
const normalized = String(status || '').toUpperCase();
|
|
109
|
+
if (normalized === 'SUCCESS') {
|
|
110
|
+
setCurrentStatus('success');
|
|
111
|
+
stopPaymentSSE();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (normalized === 'FAILED') {
|
|
115
|
+
setCurrentStatus('failed');
|
|
116
|
+
stopPaymentSSE();
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
onError: () => {
|
|
120
|
+
// keep pending state; stream can be restarted on re-render
|
|
121
|
+
},
|
|
122
|
+
});
|
|
120
123
|
return () => {
|
|
121
|
-
|
|
124
|
+
stopPaymentSSE();
|
|
122
125
|
};
|
|
123
|
-
}, [currentStatus,
|
|
124
|
-
const handlePaymentReverseFeed = async () => {
|
|
125
|
-
await triggerStatusCheck();
|
|
126
|
-
};
|
|
126
|
+
}, [applicationId, currentStatus, startPaymentSSE, stopPaymentSSE]);
|
|
127
127
|
// Handle payment retry when status is failed
|
|
128
128
|
const handlePaymentRetry = async () => {
|
|
129
129
|
var _a;
|
|
@@ -167,8 +167,6 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
|
|
|
167
167
|
try {
|
|
168
168
|
// Get user info from app data
|
|
169
169
|
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
170
|
-
// Get API configuration
|
|
171
|
-
const apiConfig = (0, apiConfig_1.getApiConfig)();
|
|
172
170
|
// Prepare request payload
|
|
173
171
|
const requestPayload = {
|
|
174
172
|
userReferenceId: userInfo.id
|
package/lib/screens/ReviewKYC.js
CHANGED
|
@@ -162,7 +162,6 @@ const ReviewKYC = ({ onGoBack, onContinue, initialData, }) => {
|
|
|
162
162
|
const [fieldErrors, setFieldErrors] = (0, react_1.useState)({});
|
|
163
163
|
// State to track marital status dropdown visibility
|
|
164
164
|
const [showMaritalStatusMenu, setShowMaritalStatusMenu] = (0, react_1.useState)(false);
|
|
165
|
-
const [isGoingBack, setIsGoingBack] = (0, react_1.useState)(false);
|
|
166
165
|
// Ref to track currently focused text input
|
|
167
166
|
const focusedTextInputRef = (0, react_1.useRef)(null);
|
|
168
167
|
// Refs for each text field
|
|
@@ -229,23 +228,12 @@ const ReviewKYC = ({ onGoBack, onContinue, initialData, }) => {
|
|
|
229
228
|
// Validate individual field and set error
|
|
230
229
|
const validateField = (field, value) => {
|
|
231
230
|
if (!value || value.trim().length === 0) {
|
|
232
|
-
// Use "District" for area field
|
|
233
|
-
if (field === 'area') {
|
|
234
|
-
return 'District is required';
|
|
235
|
-
}
|
|
236
231
|
return `${field.charAt(0).toUpperCase() + field.slice(1)} is required`;
|
|
237
232
|
}
|
|
238
233
|
// Minimum 2 characters validation for text fields (excluding PAN, pincode, dateOfBirth, maritalStatus)
|
|
239
234
|
const textFields = ['area', 'city', 'addressLine1', 'addressLine2', 'state', 'country'];
|
|
240
235
|
if (textFields.includes(field)) {
|
|
241
236
|
if (value.trim().length < 2) {
|
|
242
|
-
// Use "Address" for addressLine1 and addressLine2
|
|
243
|
-
if (field === 'addressLine1' || field === 'addressLine2') {
|
|
244
|
-
return 'Address must be at least 2 characters';
|
|
245
|
-
}
|
|
246
|
-
else if (field === 'area') {
|
|
247
|
-
return 'District must be at least 2 characters';
|
|
248
|
-
}
|
|
249
237
|
return `${field.charAt(0).toUpperCase() + field.slice(1)} must be at least 2 characters`;
|
|
250
238
|
}
|
|
251
239
|
}
|
|
@@ -271,7 +259,7 @@ const ReviewKYC = ({ onGoBack, onContinue, initialData, }) => {
|
|
|
271
259
|
if (!error)
|
|
272
260
|
return null;
|
|
273
261
|
return (react_1.default.createElement(react_native_1.View, { style: styles.errorContainer },
|
|
274
|
-
|
|
262
|
+
react_1.default.createElement(Ionicons_1.default, { name: "warning", size: 16, color: colors.error || '#FF0000', style: styles.errorIcon }),
|
|
275
263
|
react_1.default.createElement(react_native_1.Text, { style: styles.errorText }, error)));
|
|
276
264
|
};
|
|
277
265
|
// Enhanced field validation functions
|
|
@@ -446,6 +434,7 @@ const ReviewKYC = ({ onGoBack, onContinue, initialData, }) => {
|
|
|
446
434
|
return;
|
|
447
435
|
}
|
|
448
436
|
const data = (0, globalData_1.getGlobalData)();
|
|
437
|
+
console.log('panRapidNumber global data check', data, panRapidNumber);
|
|
449
438
|
// Decide next screen based on panrapidnumber existence
|
|
450
439
|
if (panRapidNumber && data.completeFDData) {
|
|
451
440
|
(0, helpers_1.navigate)('PayNow', { fdData: fdDataFromRoute });
|
|
@@ -466,12 +455,7 @@ const ReviewKYC = ({ onGoBack, onContinue, initialData, }) => {
|
|
|
466
455
|
}
|
|
467
456
|
};
|
|
468
457
|
const renderInputField = (label, value, field, placeholder, editable = true, variant = 'text', maxLength, textInputRef) => (react_1.default.createElement(react_native_1.View, null,
|
|
469
|
-
react_1.default.createElement(TextFieldWithLabel_1.default, { label: label, value: value, onChangeText: (text) => updateField(field, text), placeholder: placeholder, editable: editable, variant: variant, maxLength: maxLength, keyboardType: variant === 'numeric' ? 'numeric' : variant === 'email' ? 'email-address' : 'default', autoCapitalize: variant === 'email' ? 'none' : 'words', onFocus: () => textInputRef && handleFieldFocus(textInputRef), textInputRef: textInputRef
|
|
470
|
-
if (textInputRef === null || textInputRef === void 0 ? void 0 : textInputRef.current) {
|
|
471
|
-
textInputRef.current.blur();
|
|
472
|
-
}
|
|
473
|
-
react_native_1.Keyboard.dismiss();
|
|
474
|
-
} }),
|
|
458
|
+
react_1.default.createElement(TextFieldWithLabel_1.default, { label: label, value: value, onChangeText: (text) => updateField(field, text), placeholder: placeholder, editable: editable, variant: variant, maxLength: maxLength, keyboardType: variant === 'numeric' ? 'numeric' : variant === 'email' ? 'email-address' : 'default', autoCapitalize: variant === 'email' ? 'none' : 'words', onFocus: () => textInputRef && handleFieldFocus(textInputRef), textInputRef: textInputRef }),
|
|
475
459
|
renderFieldError(field)));
|
|
476
460
|
const renderMaritalStatusDropdown = () => {
|
|
477
461
|
return (react_1.default.createElement(react_native_1.View, null,
|
|
@@ -493,93 +477,59 @@ const ReviewKYC = ({ onGoBack, onContinue, initialData, }) => {
|
|
|
493
477
|
const renderDateField = (label, value, field, editable = true, textInputRef) => (react_1.default.createElement(react_native_1.View, null,
|
|
494
478
|
react_1.default.createElement(TextFieldWithLabel_1.default, { label: label, value: value, onChangeText: (text) => updateField(field, text), variant: "date", placeholder: "DD/MM/YYYY", maxLength: 10, dateFormat: "DD/MM/YYYY", editable: editable, onFocus: () => textInputRef && handleFieldFocus(textInputRef), textInputRef: textInputRef, onDatePress: () => {
|
|
495
479
|
// TODO: Implement date picker if needed
|
|
496
|
-
}, returnKeyType: "done", onSubmitEditing: () => {
|
|
497
|
-
if (textInputRef === null || textInputRef === void 0 ? void 0 : textInputRef.current) {
|
|
498
|
-
textInputRef.current.blur();
|
|
499
|
-
}
|
|
500
|
-
react_native_1.Keyboard.dismiss();
|
|
501
480
|
} }),
|
|
502
481
|
renderFieldError(field)));
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
(0, react_1.useEffect)(() => {
|
|
527
|
-
if (react_native_1.Platform.OS !== 'android')
|
|
528
|
-
return;
|
|
529
|
-
const onHardwareBackPress = () => {
|
|
530
|
-
handleBackPress();
|
|
531
|
-
return true; // Prevent default behavior
|
|
532
|
-
};
|
|
533
|
-
const backHandler = react_native_1.BackHandler.addEventListener('hardwareBackPress', onHardwareBackPress);
|
|
534
|
-
return () => backHandler.remove();
|
|
535
|
-
}, [defaultProviderId, workflowInstanceId, applicationId, entityId]);
|
|
536
|
-
return (react_1.default.createElement(SafeAreaWrapper_1.default, { includeTop: false, bottomPadding: 25, statusBarColor: "#000000", statusBarStyle: "light-content" },
|
|
537
|
-
react_1.default.createElement(components_1.Header, { title: "Review KYC", onBackPress: handleBackPress, backgroundColor: colors.primary }),
|
|
538
|
-
react_1.default.createElement(react_native_1.KeyboardAvoidingView, { behavior: react_native_1.Platform.OS === 'ios' ? 'padding' : undefined, style: styles.keyboardAvoidingView, keyboardVerticalOffset: react_native_1.Platform.OS === 'ios' ? 0 : 0 },
|
|
539
|
-
react_1.default.createElement(react_native_1.ScrollView, { style: styles.container, showsVerticalScrollIndicator: false, scrollEnabled: !isLoadingPanRapid, keyboardShouldPersistTaps: "handled", contentContainerStyle: styles.scrollContent },
|
|
540
|
-
react_1.default.createElement(react_native_1.TouchableWithoutFeedback, { onPress: isLoadingPanRapid ? undefined : closeDropdown },
|
|
482
|
+
return (react_1.default.createElement(SafeAreaWrapper_1.default, { includeTop: false, bottomPadding: 25, statusBarColor: "#f8f9fa", statusBarStyle: "dark-content" },
|
|
483
|
+
react_1.default.createElement(components_1.Header, { title: "Review KYC", onBackPress: async () => {
|
|
484
|
+
try {
|
|
485
|
+
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
486
|
+
await previousState({
|
|
487
|
+
providerId: defaultProviderId,
|
|
488
|
+
workflowInstanceId,
|
|
489
|
+
userreferenceid: userInfo.userReferenceId,
|
|
490
|
+
applicationid: applicationId,
|
|
491
|
+
entityid: entityId,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
catch (e) {
|
|
495
|
+
// Handle error silently
|
|
496
|
+
}
|
|
497
|
+
finally {
|
|
498
|
+
//onGoBack?.();
|
|
499
|
+
(0, helpers_1.navigate)('FDCalculator');
|
|
500
|
+
}
|
|
501
|
+
}, backgroundColor: colors.primary }),
|
|
502
|
+
react_1.default.createElement(react_native_1.ScrollView, { style: styles.container, showsVerticalScrollIndicator: false, scrollEnabled: !isLoadingPanRapid },
|
|
503
|
+
react_1.default.createElement(react_native_1.TouchableWithoutFeedback, { onPress: isLoadingPanRapid ? undefined : closeDropdown },
|
|
504
|
+
react_1.default.createElement(react_native_1.View, null,
|
|
541
505
|
react_1.default.createElement(react_native_1.View, null,
|
|
542
|
-
react_1.default.createElement(
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
react_1.default.createElement(react_native_1.
|
|
560
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.checkbox, onPress: () => updateField('useExistingAddress', !kycData.useExistingAddress) },
|
|
561
|
-
react_1.default.createElement(react_native_1.View, { style: [
|
|
562
|
-
styles.checkboxBox,
|
|
563
|
-
kycData.useExistingAddress && styles.checkboxChecked
|
|
564
|
-
] }, kycData.useExistingAddress ? (react_1.default.createElement(react_native_1.Image, { source: { uri: (themeName === 'dark') ? base64Images_1.base64Images.checkBoxDark : base64Images_1.base64Images.filledCheckBox }, resizeMode: "cover", width: 20, height: 20 })) : ((themeName === 'dark') ? (react_1.default.createElement(react_native_1.Image, { source: { uri: base64Images_1.base64Images.unCheckBoxDark }, resizeMode: "cover", width: 20, height: 20 })) : null))),
|
|
565
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.checkboxText }, "For existing customers, we'll use the address from our records. For new customers, the address from your Aadhar card will be used. To update, please raise a service request with valid address proof.")))))),
|
|
506
|
+
react_1.default.createElement(TextFieldWithLabel_1.default, { label: "Pan Card", value: kycData.panCard, onChangeText: (text) => updateField('panCard', text), placeholder: "Enter PAN Card", editable: false, variant: "text", maxLength: 10, keyboardType: "default", autoCapitalize: "characters", onFocus: () => handleFieldFocus(panCardRef), textInputRef: panCardRef }),
|
|
507
|
+
renderFieldError('panCard')),
|
|
508
|
+
renderDateField('Date of Birth', kycData.dateOfBirth, 'dateOfBirth', false, dateOfBirthRef),
|
|
509
|
+
renderMaritalStatusDropdown(),
|
|
510
|
+
renderInputField('Area', kycData.area, 'area', 'Enter Area', true, 'text', 50, areaRef),
|
|
511
|
+
renderInputField('City', kycData.city, 'city', 'Enter City', true, 'text', 30, cityRef),
|
|
512
|
+
renderInputField('Address line 1', kycData.addressLine1, 'addressLine1', 'Enter Address Line 1', true, 'text', 100, addressLine1Ref),
|
|
513
|
+
renderInputField('Address line 2', kycData.addressLine2, 'addressLine2', 'Enter Address Line 2', true, 'text', 100, addressLine2Ref),
|
|
514
|
+
renderInputField('Pincode', kycData.pincode, 'pincode', 'Enter Pincode', true, 'numeric', 6, pincodeRef),
|
|
515
|
+
renderInputField('State', kycData.state, 'state', 'Enter State', true, 'text', undefined, stateRef),
|
|
516
|
+
renderInputField('Country', kycData.country, 'country', 'Enter Country', true, 'text', undefined, countryRef),
|
|
517
|
+
react_1.default.createElement(react_native_1.View, { style: styles.checkboxContainer },
|
|
518
|
+
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.checkbox, onPress: () => updateField('useExistingAddress', !kycData.useExistingAddress) },
|
|
519
|
+
react_1.default.createElement(react_native_1.View, { style: [
|
|
520
|
+
styles.checkboxBox,
|
|
521
|
+
kycData.useExistingAddress && styles.checkboxChecked
|
|
522
|
+
] }, kycData.useExistingAddress ? (react_1.default.createElement(react_native_1.Image, { source: { uri: (themeName === 'dark') ? base64Images_1.base64Images.checkBoxDark : base64Images_1.base64Images.filledCheckBox }, resizeMode: "cover", width: 20, height: 20 })) : ((themeName === 'dark') ? (react_1.default.createElement(react_native_1.Image, { source: { uri: base64Images_1.base64Images.unCheckBoxDark }, resizeMode: "cover", width: 20, height: 20 })) : null))),
|
|
523
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.checkboxText }, "For existing customers, we'll use the address from our records. For new customers, the address from your Aadhar card will be used. To update, please raise a service request with valid address proof."))))),
|
|
566
524
|
react_1.default.createElement(ActionButton_1.default, { title: "Continue", onPress: handleContinue, disabled: !kycData.useExistingAddress || isLoadingPanRapid || !validateForm(), loading: isLoadingPanRapid }),
|
|
567
|
-
isLoadingPanRapid && (react_1.default.createElement(react_native_1.View, { style: styles.loadingOverlay, pointerEvents: "auto" }))
|
|
568
|
-
isGoingBack && (react_1.default.createElement(react_native_1.View, { style: styles.loadingOverlay, pointerEvents: "auto" },
|
|
569
|
-
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: colors.primary })))));
|
|
525
|
+
isLoadingPanRapid && (react_1.default.createElement(react_native_1.View, { style: styles.loadingOverlay, pointerEvents: "auto" }))));
|
|
570
526
|
};
|
|
571
527
|
const createStyles = (colors, typography, themeName) => react_native_1.StyleSheet.create({
|
|
572
|
-
keyboardAvoidingView: {
|
|
573
|
-
flex: 1,
|
|
574
|
-
},
|
|
575
528
|
container: {
|
|
576
529
|
flex: 1,
|
|
577
530
|
paddingHorizontal: 16,
|
|
578
531
|
paddingTop: 20,
|
|
579
532
|
},
|
|
580
|
-
scrollContent: {
|
|
581
|
-
flexGrow: 1,
|
|
582
|
-
},
|
|
583
533
|
checkboxContainer: {
|
|
584
534
|
flexDirection: 'row',
|
|
585
535
|
alignItems: 'flex-start',
|
|
@@ -652,8 +602,6 @@ const createStyles = (colors, typography, themeName) => react_native_1.StyleShee
|
|
|
652
602
|
right: 0,
|
|
653
603
|
bottom: 0,
|
|
654
604
|
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
655
|
-
justifyContent: 'center',
|
|
656
|
-
alignItems: 'center',
|
|
657
605
|
zIndex: 1000,
|
|
658
606
|
},
|
|
659
607
|
});
|
package/package.json
CHANGED
package/src/api/baseApi.ts
CHANGED
|
@@ -339,6 +339,11 @@ const baseQueryWithEncryption: BaseQueryFn<
|
|
|
339
339
|
baseUrl: apiConfig.baseUrl,
|
|
340
340
|
timeout: apiConfig.timeout,
|
|
341
341
|
prepareHeaders: (headers, { getState }) => {
|
|
342
|
+
// Disable HTTP-level caching for all SDK API calls
|
|
343
|
+
headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
344
|
+
headers.set('Pragma', 'no-cache');
|
|
345
|
+
headers.set('Expires', '0');
|
|
346
|
+
|
|
342
347
|
const token = (getState() as any)?.auth?.token;
|
|
343
348
|
if (token) headers.set('authorization', `Bearer ${token}`);
|
|
344
349
|
|
|
@@ -439,9 +444,14 @@ const baseQueryWithEncryption: BaseQueryFn<
|
|
|
439
444
|
// Log response
|
|
440
445
|
const duration = Date.now() - timestamp;
|
|
441
446
|
|
|
447
|
+
const statusFromMeta = result.meta?.response?.status;
|
|
448
|
+
const statusFromError = typeof result.error?.status === 'number' ? result.error.status : undefined;
|
|
449
|
+
const status = statusFromMeta ?? statusFromError ?? (result.error ? 0 : 200);
|
|
450
|
+
const statusText = result.meta?.response?.statusText || (result.error ? 'ERROR' : 'OK');
|
|
451
|
+
|
|
442
452
|
const responseLogData: ResponseLogData = {
|
|
443
|
-
status
|
|
444
|
-
statusText
|
|
453
|
+
status,
|
|
454
|
+
statusText,
|
|
445
455
|
headers: {},
|
|
446
456
|
data: result.data,
|
|
447
457
|
timestamp: Date.now(),
|
|
@@ -454,8 +464,7 @@ const baseQueryWithEncryption: BaseQueryFn<
|
|
|
454
464
|
|
|
455
465
|
// Log response details in DEV mode (AFTER decryption)
|
|
456
466
|
if (__DEV__) {
|
|
457
|
-
const
|
|
458
|
-
const isSuccess = status >= 200 && status < 300;
|
|
467
|
+
const isSuccess = !result.error && status >= 200 && status < 300;
|
|
459
468
|
|
|
460
469
|
console.log('═══════════════════════════════════════════════════════════════');
|
|
461
470
|
console.log(isSuccess ? '✅ [ShriramSDK] API RESPONSE - SUCCESS' : '❌ [ShriramSDK] API RESPONSE - ERROR');
|
|
@@ -464,7 +473,7 @@ const baseQueryWithEncryption: BaseQueryFn<
|
|
|
464
473
|
console.log('🔗 Endpoint:', url);
|
|
465
474
|
console.log('📌 Full URL:', `${apiConfig.baseUrl}${url}`);
|
|
466
475
|
console.log('🔧 Method:', method);
|
|
467
|
-
console.log('📊 Status:', status,
|
|
476
|
+
console.log('📊 Status:', status, statusText);
|
|
468
477
|
console.log('⏱️ Duration:', `${duration}ms`);
|
|
469
478
|
console.log('🔐 Encryption:', currentEncryptionState ? 'Enabled' : 'Disabled');
|
|
470
479
|
console.log('🆔 Request ID:', requestId);
|
|
@@ -507,7 +516,11 @@ export const baseApi = createApi({
|
|
|
507
516
|
baseQuery: baseQueryWithEncryption,
|
|
508
517
|
tagTypes: ['InterestRate'],
|
|
509
518
|
endpoints: () => ({}),
|
|
519
|
+
keepUnusedDataFor: 0,
|
|
520
|
+
refetchOnMountOrArgChange: true,
|
|
521
|
+
refetchOnFocus: true,
|
|
522
|
+
refetchOnReconnect: true,
|
|
510
523
|
});
|
|
511
524
|
|
|
512
525
|
// Export hooks
|
|
513
|
-
export const { usePrefetch } = baseApi;
|
|
526
|
+
export const { usePrefetch } = baseApi;
|