@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.
- package/lib/api/baseApi.js +17 -6
- package/lib/api/masterDataApi.js +21 -1
- package/lib/api/workflowApi.js +46 -1
- package/lib/config/appDataConfig.d.ts +5 -0
- package/lib/hooks/usePaymentSSE.d.ts +7 -1
- package/lib/hooks/usePaymentSSE.js +287 -63
- 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 +159 -27
- package/lib/screens/PaymentStatus.js +139 -25
- package/lib/screens/ReviewKYC.js +45 -97
- package/lib/utils/sseParser.js +19 -3
- 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/config/appDataConfig.ts +5 -0
- package/src/hooks/usePaymentSSE.ts +307 -66
- 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 +181 -38
- package/src/screens/PaymentStatus.tsx +158 -43
- package/src/screens/ReviewKYC.tsx +94 -170
- package/src/utils/sseParser.ts +20 -4
|
@@ -14,9 +14,12 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { useCallback, useRef } from 'react';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
17
|
+
import { Platform } from 'react-native';
|
|
18
|
+
import { parseSSEBuffer } from '../utils/sseParser';
|
|
19
|
+
import { getEnvironmentData, getUserInfoForAPI } from '../config/appDataConfig';
|
|
20
|
+
import { getApiConfig, getSecureHeaders } from '../config/apiConfig';
|
|
21
|
+
import { decryptResponse } from '../utils/encryption';
|
|
22
|
+
import { getEncryptionConfig } from '../config/encryptionConfig';
|
|
20
23
|
|
|
21
24
|
// -- Types --
|
|
22
25
|
|
|
@@ -26,23 +29,46 @@ interface UsePaymentSSECallbacks {
|
|
|
26
29
|
onConnected?: () => void;
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
export interface PaymentSSEExtraHeaders {
|
|
33
|
+
workflowInstanceId?: string;
|
|
34
|
+
applicationId?: string;
|
|
35
|
+
entityid?: string;
|
|
36
|
+
providerId?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
// -- Hook --
|
|
30
40
|
|
|
31
41
|
export function usePaymentSSE() {
|
|
32
42
|
// Store the XMLHttpRequest so we can abort it later
|
|
33
43
|
const xhrRef = useRef<XMLHttpRequest | null>(null);
|
|
44
|
+
const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
45
|
+
const connectWatchdogTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
46
|
+
const stopRequestedRef = useRef<boolean>(false);
|
|
47
|
+
const connectionIdRef = useRef<number>(0);
|
|
34
48
|
// Track how much of responseText we've already parsed
|
|
35
49
|
const lastIndexRef = useRef<number>(0);
|
|
36
50
|
// SSE text buffer (persists across onprogress calls)
|
|
37
51
|
const bufferRef = useRef<{ value: string }>({ value: '' });
|
|
38
52
|
|
|
39
53
|
const start = useCallback(
|
|
40
|
-
(applicationId: string, callbacks: UsePaymentSSECallbacks) => {
|
|
54
|
+
(applicationId: string, callbacks: UsePaymentSSECallbacks, extraHeaders?: PaymentSSEExtraHeaders) => {
|
|
55
|
+
connectionIdRef.current += 1;
|
|
56
|
+
const connectionId = connectionIdRef.current;
|
|
57
|
+
stopRequestedRef.current = false;
|
|
58
|
+
|
|
41
59
|
// Clean up any existing connection first
|
|
42
60
|
if (xhrRef.current) {
|
|
43
61
|
xhrRef.current.abort();
|
|
44
62
|
xhrRef.current = null;
|
|
45
63
|
}
|
|
64
|
+
if (reconnectTimerRef.current) {
|
|
65
|
+
clearTimeout(reconnectTimerRef.current);
|
|
66
|
+
reconnectTimerRef.current = null;
|
|
67
|
+
}
|
|
68
|
+
if (connectWatchdogTimerRef.current) {
|
|
69
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
70
|
+
connectWatchdogTimerRef.current = null;
|
|
71
|
+
}
|
|
46
72
|
|
|
47
73
|
// Reset parsing state
|
|
48
74
|
lastIndexRef.current = 0;
|
|
@@ -51,95 +77,310 @@ export function usePaymentSSE() {
|
|
|
51
77
|
// 1. Build the SSE endpoint URL
|
|
52
78
|
const envData = getEnvironmentData();
|
|
53
79
|
const apiConfig = getApiConfig();
|
|
54
|
-
const baseUrl = envData?.apiBaseUrl || apiConfig?.baseUrl || '';
|
|
55
|
-
const url = `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}
|
|
80
|
+
const baseUrl = (envData?.apiBaseUrl || apiConfig?.baseUrl || '').replace(/\/$/, '');
|
|
81
|
+
const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
|
|
56
82
|
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
83
|
+
const minimalLogs = envData?.sseMinimalLogs === true;
|
|
84
|
+
const verboseSSE = envData?.enableVerboseSSELogging !== false;
|
|
85
|
+
const maxReconnectAttempts = Number(envData?.sseReconnectAttempts ?? 4);
|
|
86
|
+
const reconnectDelayMs = Number(envData?.sseReconnectDelayMs ?? 2000);
|
|
87
|
+
const connectWatchdogMs = Number(envData?.sseConnectTimeoutMs ?? 15000);
|
|
88
|
+
const rnVersion = (() => {
|
|
89
|
+
const v = (Platform as any)?.constants?.reactNativeVersion;
|
|
90
|
+
return v ? `${v.major}.${v.minor}.${v.patch}` : 'unknown';
|
|
91
|
+
})();
|
|
92
|
+
const jsEngine = (global as any)?.HermesInternal ? 'hermes' : 'jsc/other';
|
|
93
|
+
let reconnectAttempts = 0;
|
|
94
|
+
let connected = false;
|
|
60
95
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const apiKey = envData?.apiKey || apiConfig?.headers?.['X-API-Key'] || '';
|
|
65
|
-
if (apiKey) {
|
|
66
|
-
xhr.setRequestHeader('x-api-key', apiKey);
|
|
96
|
+
if (!url) {
|
|
97
|
+
if (__DEV__ && verboseSSE) console.warn('[usePaymentSSE] No base URL, skipping SSE');
|
|
98
|
+
return;
|
|
67
99
|
}
|
|
68
|
-
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
69
|
-
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
|
70
100
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
101
|
+
const scheduleReconnect = (reason: string) => {
|
|
102
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId) return;
|
|
103
|
+
if (connectWatchdogTimerRef.current) {
|
|
104
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
105
|
+
connectWatchdogTimerRef.current = null;
|
|
106
|
+
}
|
|
107
|
+
if (reconnectAttempts >= maxReconnectAttempts) {
|
|
108
|
+
callbacks.onError?.(new Error(reason));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
reconnectAttempts += 1;
|
|
113
|
+
const delay = reconnectDelayMs * reconnectAttempts;
|
|
114
|
+
|
|
115
|
+
if (__DEV__ && !minimalLogs) {
|
|
116
|
+
console.warn(`[usePaymentSSE] Reconnecting (${reconnectAttempts}/${maxReconnectAttempts}) in ${delay}ms`);
|
|
117
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
118
|
+
reason,
|
|
119
|
+
platform: Platform.OS,
|
|
120
|
+
osVersion: String(Platform.Version),
|
|
121
|
+
rnVersion,
|
|
122
|
+
jsEngine,
|
|
123
|
+
applicationId,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (reconnectTimerRef.current) {
|
|
128
|
+
clearTimeout(reconnectTimerRef.current);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
reconnectTimerRef.current = setTimeout(() => {
|
|
132
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId) return;
|
|
133
|
+
openConnection();
|
|
134
|
+
}, delay);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const openConnection = () => {
|
|
138
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId) return;
|
|
139
|
+
connected = false;
|
|
140
|
+
|
|
141
|
+
// 2. Create XMLHttpRequest
|
|
142
|
+
const xhr = new XMLHttpRequest();
|
|
143
|
+
xhrRef.current = xhr;
|
|
77
144
|
|
|
78
|
-
|
|
145
|
+
xhr.open('GET', url);
|
|
79
146
|
|
|
80
|
-
//
|
|
81
|
-
const
|
|
147
|
+
// 3. Set headers (same headers your baseApi interceptor uses)
|
|
148
|
+
const apiKey = envData?.apiKey || apiConfig?.headers?.['X-API-Key'] || '';
|
|
149
|
+
if (apiKey) {
|
|
150
|
+
xhr.setRequestHeader('x-api-key', apiKey);
|
|
151
|
+
xhr.setRequestHeader('X-API-Key', apiKey);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Add secure headers (Content-Type, User-Agent, etc.)
|
|
155
|
+
const secureHeaders = getSecureHeaders();
|
|
156
|
+
Object.entries(secureHeaders).forEach(([key, value]) => {
|
|
157
|
+
if (key.toLowerCase() !== 'content-type') {
|
|
158
|
+
xhr.setRequestHeader(key, value);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// SSE-specific headers
|
|
163
|
+
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
164
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
165
|
+
xhr.setRequestHeader('Pragma', 'no-cache');
|
|
166
|
+
xhr.setRequestHeader('Expires', '0');
|
|
167
|
+
|
|
168
|
+
// Add userreferenceid header (required for authentication) - both cases
|
|
169
|
+
try {
|
|
170
|
+
const userInfo = getUserInfoForAPI();
|
|
171
|
+
const userRefId = userInfo?.userReferenceId || userInfo?.id;
|
|
172
|
+
if (userRefId) {
|
|
173
|
+
xhr.setRequestHeader('userreferenceid', userRefId);
|
|
174
|
+
xhr.setRequestHeader('userReferenceId', userRefId);
|
|
175
|
+
}
|
|
176
|
+
} catch {
|
|
177
|
+
if (__DEV__ && verboseSSE) console.warn('[usePaymentSSE] Could not get userReferenceId');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Add provider header variants
|
|
181
|
+
if (extraHeaders?.providerId) {
|
|
182
|
+
xhr.setRequestHeader('provider', extraHeaders.providerId);
|
|
183
|
+
xhr.setRequestHeader('providerid', extraHeaders.providerId);
|
|
184
|
+
xhr.setRequestHeader('providerId', extraHeaders.providerId);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Add onboarding headers - both camelCase and lowercase variants
|
|
188
|
+
if (extraHeaders?.workflowInstanceId) {
|
|
189
|
+
xhr.setRequestHeader('workflowInstanceId', extraHeaders.workflowInstanceId);
|
|
190
|
+
xhr.setRequestHeader('workflowinstanceid', extraHeaders.workflowInstanceId);
|
|
191
|
+
}
|
|
192
|
+
if (extraHeaders?.applicationId) {
|
|
193
|
+
xhr.setRequestHeader('applicationId', extraHeaders.applicationId);
|
|
194
|
+
xhr.setRequestHeader('applicationid', extraHeaders.applicationId);
|
|
195
|
+
}
|
|
196
|
+
if (extraHeaders?.entityid) {
|
|
197
|
+
xhr.setRequestHeader('entityid', extraHeaders.entityid);
|
|
198
|
+
xhr.setRequestHeader('entityId', extraHeaders.entityid);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const markConnected = (path: 'headers' | 'progress') => {
|
|
202
|
+
if (connected) return;
|
|
203
|
+
connected = true;
|
|
204
|
+
reconnectAttempts = 0;
|
|
205
|
+
if (connectWatchdogTimerRef.current) {
|
|
206
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
207
|
+
connectWatchdogTimerRef.current = null;
|
|
208
|
+
}
|
|
209
|
+
callbacks.onConnected?.();
|
|
210
|
+
if (__DEV__ && !minimalLogs) {
|
|
211
|
+
console.log('[usePaymentSSE] Connected to SSE stream');
|
|
212
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
213
|
+
path,
|
|
214
|
+
platform: Platform.OS,
|
|
215
|
+
osVersion: String(Platform.Version),
|
|
216
|
+
rnVersion,
|
|
217
|
+
jsEngine,
|
|
218
|
+
applicationId,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
};
|
|
82
222
|
|
|
83
|
-
// Handle
|
|
84
|
-
|
|
85
|
-
if (
|
|
223
|
+
// 4. Handle incoming data
|
|
224
|
+
xhr.onprogress = () => {
|
|
225
|
+
if (xhr.responseText && xhr.responseText.length > 0) {
|
|
226
|
+
markConnected('progress');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// responseText contains ALL text received so far
|
|
230
|
+
// Only parse the NEW text since last call
|
|
231
|
+
const newText = xhr.responseText.slice(lastIndexRef.current);
|
|
232
|
+
lastIndexRef.current = xhr.responseText.length;
|
|
233
|
+
|
|
234
|
+
if (!newText) return;
|
|
235
|
+
|
|
236
|
+
// Parse new text into SSE events
|
|
237
|
+
const events = parseSSEBuffer(bufferRef.current, newText);
|
|
238
|
+
|
|
239
|
+
// Handle each event (support encrypted payload like web)
|
|
240
|
+
const handleEventData = async (rawData: string) => {
|
|
86
241
|
try {
|
|
87
|
-
const parsed = JSON.parse(
|
|
88
|
-
|
|
89
|
-
|
|
242
|
+
const parsed = JSON.parse(rawData || '{}') as Record<string, unknown>;
|
|
243
|
+
let payload = parsed;
|
|
244
|
+
if (typeof parsed?.encryptedResponse === 'string' && parsed.encryptedResponse) {
|
|
245
|
+
try {
|
|
246
|
+
const config = getEncryptionConfig();
|
|
247
|
+
const decrypted = await decryptResponse(
|
|
248
|
+
{ encryptedResponse: parsed.encryptedResponse },
|
|
249
|
+
config
|
|
250
|
+
);
|
|
251
|
+
payload = (decrypted || {}) as Record<string, unknown>;
|
|
252
|
+
} catch {
|
|
253
|
+
if (__DEV__ && verboseSSE) console.warn('[usePaymentSSE] Decrypt failed, using raw');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const payloadData = (payload?.data as Record<string, unknown> | undefined) || {};
|
|
257
|
+
const status = String(
|
|
258
|
+
payload?.paymentStatus ??
|
|
259
|
+
payload?.payment_status ??
|
|
260
|
+
payloadData?.paymentStatus ??
|
|
261
|
+
payloadData?.payment_status ??
|
|
262
|
+
''
|
|
263
|
+
).toUpperCase();
|
|
264
|
+
if (status) callbacks.onPaymentStatus(status, payload);
|
|
90
265
|
} catch (parseError) {
|
|
91
|
-
if (__DEV__)
|
|
92
|
-
|
|
266
|
+
if (__DEV__ && verboseSSE) console.error('[usePaymentSSE] Failed to parse event data:', parseError);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
for (const { eventType, data } of events) {
|
|
271
|
+
if (!data) continue;
|
|
272
|
+
const normalizedEventType = String(eventType || '').trim().toLowerCase();
|
|
273
|
+
if (normalizedEventType === 'fd_payment_status') {
|
|
274
|
+
handleEventData(data);
|
|
275
|
+
} else if (normalizedEventType === 'message') {
|
|
276
|
+
try {
|
|
277
|
+
const parsed = JSON.parse(data) as { event?: string; [k: string]: unknown };
|
|
278
|
+
const embeddedEvent = String(parsed?.event || '').trim().toLowerCase();
|
|
279
|
+
if (embeddedEvent === 'fd_payment_status') handleEventData(data);
|
|
280
|
+
} catch {
|
|
281
|
+
// ignore
|
|
93
282
|
}
|
|
94
283
|
}
|
|
95
284
|
}
|
|
96
|
-
}
|
|
97
|
-
};
|
|
285
|
+
};
|
|
98
286
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
287
|
+
// 5. Handle connection status
|
|
288
|
+
xhr.onreadystatechange = () => {
|
|
289
|
+
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED || xhr.readyState === XMLHttpRequest.LOADING) {
|
|
290
|
+
if (xhr.status === 200) {
|
|
291
|
+
markConnected('headers');
|
|
292
|
+
} else if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED && xhr.status > 0) {
|
|
293
|
+
if (__DEV__) {
|
|
294
|
+
console.error('[usePaymentSSE] Bad status:', xhr.status);
|
|
295
|
+
}
|
|
296
|
+
scheduleReconnect(`SSE response status: ${xhr.status}`);
|
|
106
297
|
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (xhr.readyState === XMLHttpRequest.DONE && !stopRequestedRef.current && connectionIdRef.current === connectionId) {
|
|
301
|
+
if (xhr.status !== 200) {
|
|
302
|
+
scheduleReconnect(`SSE closed with status: ${xhr.status}`);
|
|
110
303
|
}
|
|
111
|
-
callbacks.onError?.(new Error(`SSE response status: ${xhr.status}`));
|
|
112
304
|
}
|
|
113
|
-
}
|
|
114
|
-
};
|
|
305
|
+
};
|
|
115
306
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
307
|
+
// 6. Handle errors
|
|
308
|
+
xhr.onerror = () => {
|
|
309
|
+
if (__DEV__ && verboseSSE) {
|
|
310
|
+
console.error('[usePaymentSSE] Connection error');
|
|
311
|
+
}
|
|
312
|
+
scheduleReconnect('SSE connection failed');
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// 7. Handle timeout
|
|
316
|
+
xhr.ontimeout = () => {
|
|
317
|
+
if (__DEV__) {
|
|
318
|
+
console.error('[usePaymentSSE] Connection timed out');
|
|
319
|
+
}
|
|
320
|
+
scheduleReconnect('SSE connection timed out');
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// 8. Send the request (connection stays open)
|
|
324
|
+
xhr.send();
|
|
325
|
+
|
|
326
|
+
// If we never get connected callback/progress, restart connection.
|
|
327
|
+
if (connectWatchdogTimerRef.current) {
|
|
328
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
120
329
|
}
|
|
121
|
-
|
|
122
|
-
|
|
330
|
+
connectWatchdogTimerRef.current = setTimeout(() => {
|
|
331
|
+
if (connected || stopRequestedRef.current || connectionIdRef.current !== connectionId) return;
|
|
332
|
+
try {
|
|
333
|
+
xhr.abort();
|
|
334
|
+
} catch {
|
|
335
|
+
// ignore
|
|
336
|
+
}
|
|
337
|
+
scheduleReconnect('SSE connect watchdog timeout');
|
|
338
|
+
}, connectWatchdogMs);
|
|
123
339
|
|
|
124
|
-
// 7. Handle timeout
|
|
125
|
-
xhr.ontimeout = () => {
|
|
126
340
|
if (__DEV__) {
|
|
127
|
-
console.
|
|
341
|
+
console.log('[usePaymentSSE] Starting SSE connection to:', url);
|
|
342
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
343
|
+
phase: 'start',
|
|
344
|
+
platform: Platform.OS,
|
|
345
|
+
osVersion: String(Platform.Version),
|
|
346
|
+
rnVersion,
|
|
347
|
+
jsEngine,
|
|
348
|
+
applicationId,
|
|
349
|
+
});
|
|
350
|
+
console.log('[usePaymentSSE] Headers:', {
|
|
351
|
+
'x-api-key': apiKey ? '***' : 'missing',
|
|
352
|
+
'userreferenceid': (() => {
|
|
353
|
+
try {
|
|
354
|
+
const userInfo = getUserInfoForAPI();
|
|
355
|
+
return userInfo?.userReferenceId || userInfo?.id || 'missing';
|
|
356
|
+
} catch {
|
|
357
|
+
return 'missing';
|
|
358
|
+
}
|
|
359
|
+
})(),
|
|
360
|
+
'provider': extraHeaders?.providerId || 'missing',
|
|
361
|
+
'workflowInstanceId': extraHeaders?.workflowInstanceId || 'missing',
|
|
362
|
+
'applicationId': extraHeaders?.applicationId || 'missing',
|
|
363
|
+
'entityid': extraHeaders?.entityid || 'missing',
|
|
364
|
+
});
|
|
128
365
|
}
|
|
129
|
-
callbacks.onError?.(new Error('SSE connection timed out'));
|
|
130
366
|
};
|
|
131
367
|
|
|
132
|
-
|
|
133
|
-
xhr.send();
|
|
134
|
-
|
|
135
|
-
if (__DEV__) {
|
|
136
|
-
console.log('[usePaymentSSE] Starting SSE connection to:', url);
|
|
137
|
-
}
|
|
368
|
+
openConnection();
|
|
138
369
|
},
|
|
139
370
|
[]
|
|
140
371
|
);
|
|
141
372
|
|
|
142
373
|
const stop = useCallback(() => {
|
|
374
|
+
stopRequestedRef.current = true;
|
|
375
|
+
connectionIdRef.current += 1;
|
|
376
|
+
if (reconnectTimerRef.current) {
|
|
377
|
+
clearTimeout(reconnectTimerRef.current);
|
|
378
|
+
reconnectTimerRef.current = null;
|
|
379
|
+
}
|
|
380
|
+
if (connectWatchdogTimerRef.current) {
|
|
381
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
382
|
+
connectWatchdogTimerRef.current = null;
|
|
383
|
+
}
|
|
143
384
|
if (xhrRef.current) {
|
|
144
385
|
xhrRef.current.abort();
|
|
145
386
|
xhrRef.current = null;
|
|
@@ -152,4 +393,4 @@ export function usePaymentSSE() {
|
|
|
152
393
|
}, []);
|
|
153
394
|
|
|
154
395
|
return { start, stop };
|
|
155
|
-
}
|
|
396
|
+
}
|
|
@@ -312,15 +312,21 @@ const RootNavigator: React.FC<RootNavigatorProps> = ({
|
|
|
312
312
|
onGoBack={() => goBack()}
|
|
313
313
|
paymentUrl={(getPaymentSession().paymentUrl) || ''}
|
|
314
314
|
onPaymentSuccess={(data) => {
|
|
315
|
+
const payload = data && typeof data === 'object' ? data : {};
|
|
316
|
+
const transactionId = (payload as any)?.transactionId ?? (payload as any)?.transaction_id ?? (payload as any)?.TransactionId;
|
|
315
317
|
navigate('PaymentStatus', {
|
|
316
318
|
status: 'success',
|
|
317
|
-
paymentData: data
|
|
319
|
+
paymentData: data,
|
|
320
|
+
transactionId,
|
|
318
321
|
} as any);
|
|
319
322
|
}}
|
|
320
323
|
onPaymentFailure={(error) => {
|
|
324
|
+
const payload = error && typeof error === 'object' ? error : {};
|
|
325
|
+
const transactionId = (payload as any)?.transactionId ?? (payload as any)?.transaction_id ?? (payload as any)?.TransactionId;
|
|
321
326
|
navigate('PaymentStatus', {
|
|
322
327
|
status: 'failed',
|
|
323
|
-
paymentData: error
|
|
328
|
+
paymentData: error,
|
|
329
|
+
transactionId,
|
|
324
330
|
} as any);
|
|
325
331
|
}}
|
|
326
332
|
onPaymentPending={(info) => {
|
|
@@ -295,7 +295,7 @@ const AadhaarVerification: React.FC<AadhaarVerificationProps> = ({
|
|
|
295
295
|
applicationid: applicationId,
|
|
296
296
|
entityid: entityId,
|
|
297
297
|
// Request params/body
|
|
298
|
-
|
|
298
|
+
targetTaskCaption: WORKFLOW_TASKS.VALIDATE_OTP,
|
|
299
299
|
}).unwrap();
|
|
300
300
|
setIsValidateOtpTaskCalled(true);
|
|
301
301
|
} else {
|
|
@@ -357,7 +357,7 @@ const AadhaarVerification: React.FC<AadhaarVerificationProps> = ({
|
|
|
357
357
|
applicationid: applicationId,
|
|
358
358
|
entityid: entityId,
|
|
359
359
|
// Request params/body
|
|
360
|
-
|
|
360
|
+
targetTaskCaption: WORKFLOW_TASKS.RESEND_OTP,
|
|
361
361
|
}).unwrap();
|
|
362
362
|
|
|
363
363
|
|
|
@@ -140,7 +140,12 @@ const FDCalculator: React.FC<FDCalculatorProps> = ({ onGoBack, onExitSDK, onPanR
|
|
|
140
140
|
|
|
141
141
|
const { data: fallbackMasterData, isLoading: isLoadingFallback, error: fallbackError, refetch: refetchMasterData } = useGetMasterDataQuery(
|
|
142
142
|
{ providerId: defaultProviderId }, // Use default provider ID
|
|
143
|
-
{
|
|
143
|
+
{
|
|
144
|
+
skip: !!masterData || !defaultProviderId,
|
|
145
|
+
refetchOnMountOrArgChange: true,
|
|
146
|
+
refetchOnFocus: true,
|
|
147
|
+
refetchOnReconnect: true,
|
|
148
|
+
}
|
|
144
149
|
);
|
|
145
150
|
|
|
146
151
|
// Use fallback master data if global master data is not available
|
|
@@ -1011,4 +1016,4 @@ const createStyles = (typography: any, colors: any, themeName: string) => StyleS
|
|
|
1011
1016
|
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
1012
1017
|
zIndex: 1000,
|
|
1013
1018
|
},
|
|
1014
|
-
});
|
|
1019
|
+
});
|