@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.
@@ -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 }, { skip: !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 applicationData = Array.isArray(responseData) ? responseData[0] : responseData;
419
- // Prefer the application with wf_status === 'Active'
415
+ let applicationsData = [];
420
416
  if (Array.isArray(responseData)) {
421
- const activeOnly = responseData.find((app) => {
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
- if (Array.isArray(responseData)) {
429
- completeFDData = responseData.find((app) => {
430
- const status = (app.wf_status || app.status || '').toString();
431
- return status === 'Completed';
432
- });
433
- (0, globalData_1.setGlobalData)({ completeFDData: !!completeFDData });
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, call payment reverse feed API
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
- try {
522
- // Get user info and required IDs
523
- const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
524
- // Prepare payment reverse feed request
525
- const paymentReverseFeedRequest = {
526
- // Headers
527
- providerId: providerId,
528
- workflowInstanceId: workflowInstanceId,
529
- userreferenceid: userInfo.id,
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)) {
@@ -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 native_1 = require("@react-navigation/native");
47
- const paymentSession_1 = require("../state/paymentSession");
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 currentStatusRef = (0, react_1.useRef)('pending');
55
- const { transactionId } = (0, paymentSession_1.getPaymentSession)();
56
- const { startTimer, stopTimer } = (0, usePaymentStatusTimer_1.usePaymentStatusTimer)({
57
- transactionId,
58
- onStatusUpdate: (status, response) => {
59
- currentStatusRef.current = status;
60
- if (status === 'success') {
61
- onPaymentSuccess === null || onPaymentSuccess === void 0 ? void 0 : onPaymentSuccess(response);
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 apiConfig_1 = require("../config/apiConfig");
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 { startTimer, stopTimer, triggerStatusCheck, isCheckingStatus, } = (0, usePaymentStatusTimer_1.usePaymentStatusTimer)({
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 === 'pending') {
115
- startTimer();
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
- stopTimer();
124
+ stopPaymentSSE();
122
125
  };
123
- }, [currentStatus, startTimer, stopTimer]);
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
@@ -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
- react_native_1.Platform.OS === 'android' && (react_1.default.createElement(Ionicons_1.default, { name: "warning", size: 16, color: colors.error || '#FF0000', style: styles.errorIcon })),
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, returnKeyType: "done", onSubmitEditing: () => {
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
- // Handler for back button (used by both header and hardware back button)
504
- const handleBackPress = async () => {
505
- setIsGoingBack(true);
506
- try {
507
- const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
508
- await previousState({
509
- providerId: defaultProviderId,
510
- workflowInstanceId,
511
- userreferenceid: userInfo.userReferenceId,
512
- applicationid: applicationId,
513
- entityid: entityId,
514
- });
515
- }
516
- catch (e) {
517
- // Handle error silently
518
- }
519
- finally {
520
- setIsGoingBack(false);
521
- //onGoBack?.();
522
- (0, helpers_1.navigate)('FDCalculator');
523
- }
524
- };
525
- // Handle Android hardware back button
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(react_native_1.View, null,
543
- 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, returnKeyType: "done", onSubmitEditing: () => {
544
- if (panCardRef === null || panCardRef === void 0 ? void 0 : panCardRef.current) {
545
- panCardRef.current.blur();
546
- }
547
- react_native_1.Keyboard.dismiss();
548
- } }),
549
- renderFieldError('panCard')),
550
- renderDateField('Date of Birth', kycData.dateOfBirth, 'dateOfBirth', false, dateOfBirthRef),
551
- renderMaritalStatusDropdown(),
552
- renderInputField('District', kycData.area, 'area', 'Enter District', true, 'text', 50, areaRef),
553
- renderInputField('City', kycData.city, 'city', 'Enter City', true, 'text', 30, cityRef),
554
- renderInputField('Address line 1', kycData.addressLine1, 'addressLine1', 'Enter Address Line 1', true, 'text', 100, addressLine1Ref),
555
- renderInputField('Address line 2', kycData.addressLine2, 'addressLine2', 'Enter Address Line 2', true, 'text', 100, addressLine2Ref),
556
- renderInputField('Pincode', kycData.pincode, 'pincode', 'Enter Pincode', true, 'numeric', 6, pincodeRef),
557
- renderInputField('State', kycData.state, 'state', 'Enter State', true, 'text', undefined, stateRef),
558
- renderInputField('Country', kycData.country, 'country', 'Enter Country', true, 'text', undefined, countryRef),
559
- react_1.default.createElement(react_native_1.View, { style: styles.checkboxContainer },
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finspringinnovations/fdsdk",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "FD SDK for React Native applications",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -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: result.meta?.response?.status || 200,
444
- statusText: result.meta?.response?.statusText || 'OK',
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 status = result.meta?.response?.status || 200;
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, result.meta?.response?.statusText || 'OK');
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;