@finspringinnovations/fdsdk 0.0.4 → 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/hooks/usePaymentSSE.d.ts +7 -1
- package/lib/hooks/usePaymentSSE.js +101 -12
- package/lib/navigation/RootNavigator.js +10 -2
- package/lib/screens/AadhaarVerification.js +2 -2
- package/lib/screens/FDCalculator.js +6 -2
- 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/hooks/usePaymentSSE.ts +109 -15
- package/src/navigation/RootNavigator.tsx +8 -2
- package/src/screens/AadhaarVerification.tsx +2 -2
- package/src/screens/FDCalculator.tsx +7 -2
- 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/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;
|
package/src/api/masterDataApi.ts
CHANGED
|
@@ -12,17 +12,35 @@ export const masterDataApi = baseApi.injectEndpoints({
|
|
|
12
12
|
const request = {
|
|
13
13
|
url: 'masterdata',
|
|
14
14
|
method: 'GET' as const,
|
|
15
|
+
cache: 'no-store' as const,
|
|
15
16
|
headers: {
|
|
16
17
|
workflowInstanceId: '{{workflowInstanceId}}',
|
|
17
18
|
'x-api-key': '{{X-API-KEY}}',
|
|
18
19
|
encryptdecrypt: 'false',
|
|
20
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
21
|
+
Pragma: 'no-cache',
|
|
22
|
+
Expires: '0',
|
|
19
23
|
provider: providerId || '{{shriramprovider}}',
|
|
20
24
|
},
|
|
21
25
|
};
|
|
22
26
|
return request;
|
|
23
27
|
},
|
|
24
|
-
transformResponse: (response) => {
|
|
25
|
-
return response;
|
|
28
|
+
transformResponse: (response: any) => {
|
|
29
|
+
if (response == null) return response;
|
|
30
|
+
// If API returns a JSON string, parse it
|
|
31
|
+
let data = response;
|
|
32
|
+
if (typeof response === 'string') {
|
|
33
|
+
try {
|
|
34
|
+
data = JSON.parse(response);
|
|
35
|
+
} catch {
|
|
36
|
+
return response;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Unwrap { data: ... } so consumers get a consistent shape
|
|
40
|
+
if (typeof data === 'object' && data !== null && 'data' in data && Object.keys(data).length === 1) {
|
|
41
|
+
return data.data;
|
|
42
|
+
}
|
|
43
|
+
return data;
|
|
26
44
|
},
|
|
27
45
|
}),
|
|
28
46
|
}),
|
|
@@ -31,4 +49,4 @@ export const masterDataApi = baseApi.injectEndpoints({
|
|
|
31
49
|
|
|
32
50
|
export const {
|
|
33
51
|
useGetMasterDataQuery
|
|
34
|
-
} = masterDataApi;
|
|
52
|
+
} = masterDataApi;
|
package/src/api/workflowApi.ts
CHANGED
|
@@ -9,6 +9,38 @@ export interface TerminateWorkflowRequest {
|
|
|
9
9
|
|
|
10
10
|
export type TerminateWorkflowResponse = any; // Replace with concrete type when available
|
|
11
11
|
|
|
12
|
+
const TASK_ID_TO_CAPTION: Record<string, string> = {
|
|
13
|
+
'11042': 'SHRIRAM_V1_S1_T1_START',
|
|
14
|
+
'11043': 'SHRIRAM_V1_S1_T2_GET_PERSONAL_DETAILS_AND_BASIC_FD_INFO',
|
|
15
|
+
'11044': 'SHRIRAM_V1_S1_T3_END',
|
|
16
|
+
'11050': 'SHRIRAM_V1_S2_T1_KYC_START',
|
|
17
|
+
'11051': 'SHRIRAM_V1_S2_T2_CHECK_FOR_PAN_RAPID_STATUS',
|
|
18
|
+
'11052': 'SHRIRAM_V1_S2_T3_CHECK_IF_AADHAAR_ALREADY_VERIFIED',
|
|
19
|
+
'11045': 'SHRIRAM_V1_S2_T4_SEND_AADHAR_OTP',
|
|
20
|
+
'11046': 'SHRIRAM_V1_S2_T5_CHECK_FOR_OTP',
|
|
21
|
+
'11047': 'SHRIRAM_V1_S2_T6_VALIDATE_AADHAR_OTP',
|
|
22
|
+
'11053': 'SHRIRAM_V1_S2_T7_AADHAAR_VERIFIED',
|
|
23
|
+
'11049': 'SHRIRAM_V1_S2_T8_TERMINATE_TASK_AND_WORKFLOW_AFTER_KYC_RETRIES',
|
|
24
|
+
'11048': 'SHRIRAM_V1_S2_T9_KYC_END',
|
|
25
|
+
'11054': 'SHRIRAM_V1_S3_T1_OCCUPATION_START',
|
|
26
|
+
'11055': 'SHRIRAM_V1_S3_T2_CAPTURE_OCCUPATION_DETAILS',
|
|
27
|
+
'11056': 'SHRIRAM_V1_S3_T3_OCCUPATION_END',
|
|
28
|
+
'11057': 'SHRIRAM_V1_S4_T1_NOMINEE_START',
|
|
29
|
+
'11058': 'SHRIRAM_V1_S4_T2_CAPTURE_NOMINEE_DETAILS',
|
|
30
|
+
'11059': 'SHRIRAM_V1_S4_T3_NOMINEE_END',
|
|
31
|
+
'11060': 'SHRIRAM_V1_S5_T1_BANK_DETAILS_START',
|
|
32
|
+
'11061': 'SHRIRAM_V1_S5_T2_CAPTURE_BANK_DETAILS',
|
|
33
|
+
'11062': 'SHRIRAM_V1_S5_T3_BANK_DETAILS_END',
|
|
34
|
+
'11063': 'SHRIRAM_V1_S6_T1_FD_CREATION_START',
|
|
35
|
+
'11064': 'SHRIRAM_V1_S6_T2_CREATE_FD',
|
|
36
|
+
'11065': 'SHRIRAM_V1_S6_T3_FD_CREATION_END',
|
|
37
|
+
'11069': 'SHRIRAM_V1_S7_T1_PAYMENT_START',
|
|
38
|
+
'11068': 'SHRIRAM_V1_S7_T2_PAYMENT',
|
|
39
|
+
'11067': 'SHRIRAM_V1_S7_T3_CHECK_FOR_PAYMENT_STATUS',
|
|
40
|
+
'11070': 'SHRIRAM_V1_S7_T4_TERMINATE_TASK_AND_WORKFLOW_AFTER_PAYMENT_RETRIES',
|
|
41
|
+
'11066': 'SHRIRAM_V1_S7_T5_PAYMENT_END',
|
|
42
|
+
};
|
|
43
|
+
|
|
12
44
|
export const workflowApi = baseApi.injectEndpoints({
|
|
13
45
|
endpoints: (builder) => ({
|
|
14
46
|
terminateWorkflow: builder.mutation<
|
|
@@ -37,11 +69,28 @@ export const workflowApi = baseApi.injectEndpoints({
|
|
|
37
69
|
updateTask: builder.mutation<any, any>({
|
|
38
70
|
query: (body) => {
|
|
39
71
|
const { providerId, workflowInstanceId, userreferenceid, applicationid, entityid, ...requestBody } = body;
|
|
72
|
+
const normalizedRequestBody = { ...requestBody } as Record<string, any>;
|
|
73
|
+
|
|
74
|
+
// Backend now expects caption-based field name.
|
|
75
|
+
// Keep compatibility if any caller still passes targetTaskId.
|
|
76
|
+
if (!normalizedRequestBody.targetTaskCaption && normalizedRequestBody.targetTaskId) {
|
|
77
|
+
normalizedRequestBody.targetTaskCaption = normalizedRequestBody.targetTaskId;
|
|
78
|
+
delete normalizedRequestBody.targetTaskId;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Normalize numeric task IDs to caption values if provided.
|
|
82
|
+
if (normalizedRequestBody.targetTaskCaption !== undefined && normalizedRequestBody.targetTaskCaption !== null) {
|
|
83
|
+
const key = String(normalizedRequestBody.targetTaskCaption).trim();
|
|
84
|
+
if (TASK_ID_TO_CAPTION[key]) {
|
|
85
|
+
normalizedRequestBody.targetTaskCaption = TASK_ID_TO_CAPTION[key];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
40
89
|
return {
|
|
41
90
|
url: 'taskflow/update',
|
|
42
91
|
method: 'POST',
|
|
43
92
|
body: {
|
|
44
|
-
...
|
|
93
|
+
...normalizedRequestBody,
|
|
45
94
|
workflowInstanceId: workflowInstanceId,
|
|
46
95
|
},
|
|
47
96
|
headers: {
|