@finspringinnovations/fdsdk 0.0.4 → 0.0.6

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.
@@ -127,8 +127,12 @@ const FDCalculator = ({ onGoBack, onExitSDK, onPanRequired, onNavigateToReviewKY
127
127
  const defaultProviderId = (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; }); // Default Shriram provider ID
128
128
  // Default Shriram provider ID
129
129
  const { data: fallbackMasterData, isLoading: isLoadingFallback, error: fallbackError, refetch: refetchMasterData } = (0, masterDataApi_1.useGetMasterDataQuery)({ providerId: defaultProviderId }, // Use default provider ID
130
- { skip: !!masterData } // Skip if master data is already available
131
- );
130
+ {
131
+ skip: !!masterData || !defaultProviderId,
132
+ refetchOnMountOrArgChange: true,
133
+ refetchOnFocus: true,
134
+ refetchOnReconnect: true,
135
+ });
132
136
  // Use fallback master data if global master data is not available
133
137
  // Store only the data parameter after stringifying instead of complete response
134
138
  const effectiveMasterData = react_1.default.useMemo(() => {
@@ -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)) {
@@ -42,35 +42,35 @@ const react_native_webview_1 = require("react-native-webview");
42
42
  const SafeAreaWrapper_1 = __importDefault(require("../components/SafeAreaWrapper"));
43
43
  const ThemeContext_1 = require("../theme/ThemeContext");
44
44
  const encryption_1 = require("../utils/encryption");
45
+ const sseParser_1 = require("../utils/sseParser");
45
46
  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");
47
+ const appDataConfig_1 = require("../config/appDataConfig");
48
+ const apiConfig_1 = require("../config/apiConfig");
49
+ const store_1 = require("../store");
49
50
  const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPending, paymentUrl, successUrl = 'payment/success', failureUrl = 'payment/failure', }) => {
50
51
  const colors = (0, ThemeContext_1.useColors)();
51
52
  const styles = createStyles(colors);
52
53
  const webViewRef = (0, react_1.useRef)(null);
53
54
  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
- }
55
+ 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; });
56
+ 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; });
57
+ 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; });
58
+ 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; });
59
+ const sseXhrRef = (0, react_1.useRef)(null);
60
+ const sseLastIndexRef = (0, react_1.useRef)(0);
61
+ const sseBufferRef = (0, react_1.useRef)({ value: '' });
62
+ const onSuccessRef = (0, react_1.useRef)(onPaymentSuccess);
63
+ const onFailureRef = (0, react_1.useRef)(onPaymentFailure);
64
+ onSuccessRef.current = onPaymentSuccess;
65
+ onFailureRef.current = onPaymentFailure;
66
+ const stopPaymentSSE = (0, react_1.useCallback)(() => {
67
+ if (sseXhrRef.current) {
68
+ sseXhrRef.current.abort();
69
+ sseXhrRef.current = null;
69
70
  }
70
- });
71
- (0, native_1.useFocusEffect)(react_1.default.useCallback(() => {
72
- startTimer();
73
- }, [startTimer, stopTimer]));
71
+ sseLastIndexRef.current = 0;
72
+ sseBufferRef.current = { value: '' };
73
+ }, []);
74
74
  const handleNavigationStateChange = async (navState) => {
75
75
  const { url } = navState;
76
76
  if (url.includes('payment/status')) {
@@ -92,6 +92,143 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
92
92
  const handleLoadEnd = () => {
93
93
  setLoading(false);
94
94
  };
95
+ // SSE: listen for payment status while user is on Payment WebView (same as web integration)
96
+ (0, react_1.useEffect)(() => {
97
+ var _a;
98
+ if (!applicationId || !(paymentUrl === null || paymentUrl === void 0 ? void 0 : paymentUrl.trim())) {
99
+ stopPaymentSSE();
100
+ return;
101
+ }
102
+ const envData = (0, appDataConfig_1.getEnvironmentData)();
103
+ const apiConfig = (0, apiConfig_1.getApiConfig)();
104
+ const baseUrl = ((envData === null || envData === void 0 ? void 0 : envData.apiBaseUrl) || (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.baseUrl) || '').replace(/\/$/, '');
105
+ const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
106
+ if (!url)
107
+ return;
108
+ stopPaymentSSE();
109
+ const xhr = new XMLHttpRequest();
110
+ sseXhrRef.current = xhr;
111
+ xhr.open('GET', url);
112
+ const apiKey = (envData === null || envData === void 0 ? void 0 : envData.apiKey) || ((_a = apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.headers) === null || _a === void 0 ? void 0 : _a['X-API-Key']) || '';
113
+ if (apiKey) {
114
+ xhr.setRequestHeader('x-api-key', apiKey);
115
+ xhr.setRequestHeader('X-API-Key', apiKey);
116
+ }
117
+ const secureHeaders = (0, apiConfig_1.getSecureHeaders)();
118
+ Object.entries(secureHeaders).forEach(([key, value]) => {
119
+ if (key.toLowerCase() !== 'content-type') {
120
+ xhr.setRequestHeader(key, value);
121
+ }
122
+ });
123
+ xhr.setRequestHeader('Accept', 'text/event-stream');
124
+ xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
125
+ xhr.setRequestHeader('Pragma', 'no-cache');
126
+ xhr.setRequestHeader('Expires', '0');
127
+ try {
128
+ const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
129
+ const userRefId = (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id);
130
+ if (userRefId) {
131
+ xhr.setRequestHeader('userreferenceid', userRefId);
132
+ xhr.setRequestHeader('userReferenceId', userRefId);
133
+ }
134
+ }
135
+ catch (_b) {
136
+ // ignore
137
+ }
138
+ if (providerId) {
139
+ xhr.setRequestHeader('provider', providerId);
140
+ xhr.setRequestHeader('providerid', providerId);
141
+ xhr.setRequestHeader('providerId', providerId);
142
+ }
143
+ if (workflowInstanceId) {
144
+ xhr.setRequestHeader('workflowInstanceId', workflowInstanceId);
145
+ xhr.setRequestHeader('workflowinstanceid', workflowInstanceId);
146
+ }
147
+ if (applicationId) {
148
+ xhr.setRequestHeader('applicationId', applicationId);
149
+ xhr.setRequestHeader('applicationid', applicationId);
150
+ }
151
+ if (entityId) {
152
+ xhr.setRequestHeader('entityid', entityId);
153
+ xhr.setRequestHeader('entityId', entityId);
154
+ }
155
+ const handleEventData = async (rawData) => {
156
+ var _a, _b, _c, _d, _e, _f;
157
+ try {
158
+ const parsed = JSON.parse(rawData || '{}');
159
+ let payload = parsed;
160
+ if (typeof (parsed === null || parsed === void 0 ? void 0 : parsed.encryptedResponse) === 'string' && parsed.encryptedResponse) {
161
+ try {
162
+ const config = (0, encryptionConfig_1.getEncryptionConfig)();
163
+ const decrypted = await (0, encryption_1.decryptResponse)({ encryptedResponse: parsed.encryptedResponse }, config);
164
+ payload = (decrypted || {});
165
+ }
166
+ catch (_g) {
167
+ // ignore and use raw payload
168
+ }
169
+ }
170
+ const payloadData = (payload === null || payload === void 0 ? void 0 : payload.data) || {};
171
+ const status = String((_d = (_c = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.paymentStatus) !== null && _a !== void 0 ? _a : payload === null || payload === void 0 ? void 0 : payload.payment_status) !== null && _b !== void 0 ? _b : payloadData === null || payloadData === void 0 ? void 0 : payloadData.paymentStatus) !== null && _c !== void 0 ? _c : payloadData === null || payloadData === void 0 ? void 0 : payloadData.payment_status) !== null && _d !== void 0 ? _d : '').toUpperCase();
172
+ if (status === 'SUCCESS') {
173
+ stopPaymentSSE();
174
+ (_e = onSuccessRef.current) === null || _e === void 0 ? void 0 : _e.call(onSuccessRef, payload);
175
+ return;
176
+ }
177
+ if (status === 'FAILED') {
178
+ stopPaymentSSE();
179
+ (_f = onFailureRef.current) === null || _f === void 0 ? void 0 : _f.call(onFailureRef, payload);
180
+ }
181
+ }
182
+ catch (_h) {
183
+ // ignore parse errors
184
+ }
185
+ };
186
+ xhr.onprogress = () => {
187
+ setLoading(false);
188
+ const newText = xhr.responseText.slice(sseLastIndexRef.current);
189
+ sseLastIndexRef.current = xhr.responseText.length;
190
+ if (!newText)
191
+ return;
192
+ const events = (0, sseParser_1.parseSSEBuffer)(sseBufferRef.current, newText);
193
+ for (const { eventType, data } of events) {
194
+ if (!data)
195
+ continue;
196
+ const normalizedEventType = String(eventType || '').trim().toLowerCase();
197
+ if (normalizedEventType === 'fd_payment_status') {
198
+ handleEventData(data);
199
+ }
200
+ else if (normalizedEventType === 'message') {
201
+ try {
202
+ const parsed = JSON.parse(data);
203
+ const embeddedEvent = String((parsed === null || parsed === void 0 ? void 0 : parsed.event) || '').trim().toLowerCase();
204
+ if (embeddedEvent === 'fd_payment_status') {
205
+ handleEventData(data);
206
+ }
207
+ }
208
+ catch (_a) {
209
+ // ignore
210
+ }
211
+ }
212
+ }
213
+ };
214
+ xhr.onreadystatechange = () => {
215
+ if ((xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED ||
216
+ xhr.readyState === XMLHttpRequest.LOADING) &&
217
+ xhr.status === 200) {
218
+ setLoading(false);
219
+ if (__DEV__)
220
+ console.log('[Payment] SSE connected for payment status');
221
+ }
222
+ };
223
+ xhr.onerror = () => {
224
+ if (__DEV__)
225
+ console.warn('[Payment] SSE connection error');
226
+ };
227
+ xhr.send();
228
+ return () => {
229
+ stopPaymentSSE();
230
+ };
231
+ }, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId, stopPaymentSSE]);
95
232
  const handleMessage = async (event) => {
96
233
  var _a, _b, _c;
97
234
  try {
@@ -130,13 +267,9 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
130
267
  // Check payment status in data
131
268
  const paymentStatus = (_c = (_b = response.data) === null || _b === void 0 ? void 0 : _b.paymentStatus) === null || _c === void 0 ? void 0 : _c.toLowerCase();
132
269
  if (paymentStatus === 'success') {
133
- currentStatusRef.current = "success";
134
- stopTimer();
135
270
  onPaymentSuccess === null || onPaymentSuccess === void 0 ? void 0 : onPaymentSuccess(response);
136
271
  }
137
272
  else if (paymentStatus === 'failed') {
138
- currentStatusRef.current = "failed";
139
- stopTimer();
140
273
  onPaymentFailure === null || onPaymentFailure === void 0 ? void 0 : onPaymentFailure(response);
141
274
  }
142
275
  else {
@@ -144,7 +277,6 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
144
277
  }
145
278
  }
146
279
  else {
147
- currentStatusRef.current = "pending";
148
280
  onPaymentPending === null || onPaymentPending === void 0 ? void 0 : onPaymentPending(response);
149
281
  }
150
282
  setLoading(false);
@@ -48,13 +48,15 @@ const fdApi_1 = require("../api/fdApi");
48
48
  const customerApi_1 = require("../api/customerApi");
49
49
  const store_1 = require("../store");
50
50
  const appDataConfig_1 = require("../config/appDataConfig");
51
+ const apiConfig_1 = require("../config/apiConfig");
51
52
  const helpers_1 = require("../navigation/helpers");
52
53
  const paymentSession_1 = require("../state/paymentSession");
53
54
  const native_1 = require("@react-navigation/native");
54
55
  const bank_1 = require("../constants/strings/bank");
55
56
  const common_1 = require("../constants/strings/common");
56
- const apiConfig_1 = require("../config/apiConfig");
57
- const usePaymentStatusTimer_1 = require("../hooks/usePaymentStatusTimer");
57
+ const sseParser_1 = require("../utils/sseParser");
58
+ const encryption_1 = require("../utils/encryption");
59
+ const encryptionConfig_1 = require("../config/encryptionConfig");
58
60
  const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) => {
59
61
  var _a;
60
62
  const colors = (0, ThemeContext_1.useColors)();
@@ -75,18 +77,9 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
75
77
  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
78
  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
79
  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
- });
80
+ const sseXhrRef = (0, react_1.useRef)(null);
81
+ const sseLastIndexRef = (0, react_1.useRef)(0);
82
+ const sseBufferRef = (0, react_1.useRef)({ value: '' });
90
83
  // Payment Retry API
91
84
  const [paymentRetry, { data: paymentRetryResponse, error: paymentRetryError, isLoading: isLoadingPaymentRetry, }] = (0, fdApi_1.usePaymentRetryMutation)();
92
85
  // Get Customer Applications API
@@ -110,20 +103,143 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
110
103
  const formatAmount = (amount) => {
111
104
  return amount.toLocaleString('en-IN');
112
105
  };
106
+ const stopPaymentSSE = (0, react_1.useCallback)(() => {
107
+ if (sseXhrRef.current) {
108
+ sseXhrRef.current.abort();
109
+ sseXhrRef.current = null;
110
+ }
111
+ sseLastIndexRef.current = 0;
112
+ sseBufferRef.current = { value: '' };
113
+ }, []);
113
114
  (0, react_1.useEffect)(() => {
114
- if (currentStatus === 'pending') {
115
- startTimer();
115
+ var _a;
116
+ if (currentStatus !== 'pending' || !applicationId) {
117
+ stopPaymentSSE();
118
+ return;
119
+ }
120
+ const envData = (0, appDataConfig_1.getEnvironmentData)();
121
+ const apiConfig = (0, apiConfig_1.getApiConfig)();
122
+ const baseUrl = ((envData === null || envData === void 0 ? void 0 : envData.apiBaseUrl) || (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.baseUrl) || '').replace(/\/$/, '');
123
+ const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
124
+ if (!url)
125
+ return;
126
+ stopPaymentSSE();
127
+ const xhr = new XMLHttpRequest();
128
+ sseXhrRef.current = xhr;
129
+ xhr.open('GET', url);
130
+ const apiKey = (envData === null || envData === void 0 ? void 0 : envData.apiKey) || ((_a = apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.headers) === null || _a === void 0 ? void 0 : _a['X-API-Key']) || '';
131
+ if (apiKey) {
132
+ xhr.setRequestHeader('x-api-key', apiKey);
133
+ xhr.setRequestHeader('X-API-Key', apiKey);
134
+ }
135
+ const secureHeaders = (0, apiConfig_1.getSecureHeaders)();
136
+ Object.entries(secureHeaders).forEach(([key, value]) => {
137
+ if (key.toLowerCase() !== 'content-type') {
138
+ xhr.setRequestHeader(key, value);
139
+ }
140
+ });
141
+ xhr.setRequestHeader('Accept', 'text/event-stream');
142
+ xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
143
+ xhr.setRequestHeader('Pragma', 'no-cache');
144
+ xhr.setRequestHeader('Expires', '0');
145
+ try {
146
+ const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
147
+ const userRefId = (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id);
148
+ if (userRefId) {
149
+ xhr.setRequestHeader('userreferenceid', userRefId);
150
+ xhr.setRequestHeader('userReferenceId', userRefId);
151
+ }
116
152
  }
117
- else {
118
- stopTimer();
153
+ catch (_b) {
154
+ // ignore
119
155
  }
156
+ if (providerId) {
157
+ xhr.setRequestHeader('provider', providerId);
158
+ xhr.setRequestHeader('providerid', providerId);
159
+ xhr.setRequestHeader('providerId', providerId);
160
+ }
161
+ if (workflowInstanceId) {
162
+ xhr.setRequestHeader('workflowInstanceId', workflowInstanceId);
163
+ xhr.setRequestHeader('workflowinstanceid', workflowInstanceId);
164
+ }
165
+ if (applicationId) {
166
+ xhr.setRequestHeader('applicationId', applicationId);
167
+ xhr.setRequestHeader('applicationid', applicationId);
168
+ }
169
+ if (entityId) {
170
+ xhr.setRequestHeader('entityid', entityId);
171
+ xhr.setRequestHeader('entityId', entityId);
172
+ }
173
+ const handleEventData = async (rawData) => {
174
+ var _a, _b, _c, _d;
175
+ try {
176
+ const parsed = JSON.parse(rawData || '{}');
177
+ let payload = parsed;
178
+ if (typeof (parsed === null || parsed === void 0 ? void 0 : parsed.encryptedResponse) === 'string' && parsed.encryptedResponse) {
179
+ try {
180
+ const config = (0, encryptionConfig_1.getEncryptionConfig)();
181
+ const decrypted = await (0, encryption_1.decryptResponse)({ encryptedResponse: parsed.encryptedResponse }, config);
182
+ payload = (decrypted || {});
183
+ }
184
+ catch (_e) {
185
+ // ignore and use raw payload
186
+ }
187
+ }
188
+ const payloadData = (payload === null || payload === void 0 ? void 0 : payload.data) || {};
189
+ const status = String((_d = (_c = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.paymentStatus) !== null && _a !== void 0 ? _a : payload === null || payload === void 0 ? void 0 : payload.payment_status) !== null && _b !== void 0 ? _b : payloadData === null || payloadData === void 0 ? void 0 : payloadData.paymentStatus) !== null && _c !== void 0 ? _c : payloadData === null || payloadData === void 0 ? void 0 : payloadData.payment_status) !== null && _d !== void 0 ? _d : '').toUpperCase();
190
+ if (status === 'SUCCESS') {
191
+ setCurrentStatus('success');
192
+ stopPaymentSSE();
193
+ return;
194
+ }
195
+ if (status === 'FAILED') {
196
+ setCurrentStatus('failed');
197
+ stopPaymentSSE();
198
+ }
199
+ }
200
+ catch (_f) {
201
+ // ignore parse errors
202
+ }
203
+ };
204
+ xhr.onprogress = () => {
205
+ const newText = xhr.responseText.slice(sseLastIndexRef.current);
206
+ sseLastIndexRef.current = xhr.responseText.length;
207
+ if (!newText)
208
+ return;
209
+ const events = (0, sseParser_1.parseSSEBuffer)(sseBufferRef.current, newText);
210
+ for (const { eventType, data } of events) {
211
+ if (!data)
212
+ continue;
213
+ const normalizedEventType = String(eventType || '').trim().toLowerCase();
214
+ if (normalizedEventType === 'fd_payment_status') {
215
+ handleEventData(data);
216
+ }
217
+ else if (normalizedEventType === 'message') {
218
+ try {
219
+ const parsed = JSON.parse(data);
220
+ const embeddedEvent = String((parsed === null || parsed === void 0 ? void 0 : parsed.event) || '').trim().toLowerCase();
221
+ if (embeddedEvent === 'fd_payment_status') {
222
+ handleEventData(data);
223
+ }
224
+ }
225
+ catch (_a) {
226
+ // ignore
227
+ }
228
+ }
229
+ }
230
+ };
231
+ xhr.send();
120
232
  return () => {
121
- stopTimer();
233
+ stopPaymentSSE();
122
234
  };
123
- }, [currentStatus, startTimer, stopTimer]);
124
- const handlePaymentReverseFeed = async () => {
125
- await triggerStatusCheck();
126
- };
235
+ }, [
236
+ applicationId,
237
+ currentStatus,
238
+ entityId,
239
+ providerId,
240
+ stopPaymentSSE,
241
+ workflowInstanceId
242
+ ]);
127
243
  // Handle payment retry when status is failed
128
244
  const handlePaymentRetry = async () => {
129
245
  var _a;
@@ -167,8 +283,6 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
167
283
  try {
168
284
  // Get user info from app data
169
285
  const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
170
- // Get API configuration
171
- const apiConfig = (0, apiConfig_1.getApiConfig)();
172
286
  // Prepare request payload
173
287
  const requestPayload = {
174
288
  userReferenceId: userInfo.id