@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.
@@ -14,9 +14,11 @@
14
14
  */
15
15
 
16
16
  import { useCallback, useRef } from 'react';
17
- import { parseSSEBuffer, type SSEEvent } from '../utils/sseParser';
18
- import { getEnvironmentData } from '../config/appDataConfig';
19
- import { getApiConfig } from '../config/apiConfig';
17
+ import { parseSSEBuffer } from '../utils/sseParser';
18
+ import { getEnvironmentData, getUserInfoForAPI } from '../config/appDataConfig';
19
+ import { getApiConfig, getSecureHeaders } from '../config/apiConfig';
20
+ import { decryptResponse } from '../utils/encryption';
21
+ import { getEncryptionConfig } from '../config/encryptionConfig';
20
22
 
21
23
  // -- Types --
22
24
 
@@ -26,6 +28,13 @@ interface UsePaymentSSECallbacks {
26
28
  onConnected?: () => void;
27
29
  }
28
30
 
31
+ export interface PaymentSSEExtraHeaders {
32
+ workflowInstanceId?: string;
33
+ applicationId?: string;
34
+ entityid?: string;
35
+ providerId?: string;
36
+ }
37
+
29
38
  // -- Hook --
30
39
 
31
40
  export function usePaymentSSE() {
@@ -37,7 +46,7 @@ export function usePaymentSSE() {
37
46
  const bufferRef = useRef<{ value: string }>({ value: '' });
38
47
 
39
48
  const start = useCallback(
40
- (applicationId: string, callbacks: UsePaymentSSECallbacks) => {
49
+ (applicationId: string, callbacks: UsePaymentSSECallbacks, extraHeaders?: PaymentSSEExtraHeaders) => {
41
50
  // Clean up any existing connection first
42
51
  if (xhrRef.current) {
43
52
  xhrRef.current.abort();
@@ -51,8 +60,13 @@ export function usePaymentSSE() {
51
60
  // 1. Build the SSE endpoint URL
52
61
  const envData = getEnvironmentData();
53
62
  const apiConfig = getApiConfig();
54
- const baseUrl = envData?.apiBaseUrl || apiConfig?.baseUrl || '';
55
- const url = `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}`;
63
+ const baseUrl = (envData?.apiBaseUrl || apiConfig?.baseUrl || '').replace(/\/$/, '');
64
+ const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
65
+
66
+ if (!url) {
67
+ if (__DEV__) console.warn('[usePaymentSSE] No base URL, skipping SSE');
68
+ return;
69
+ }
56
70
 
57
71
  // 2. Create XMLHttpRequest
58
72
  const xhr = new XMLHttpRequest();
@@ -65,8 +79,50 @@ export function usePaymentSSE() {
65
79
  if (apiKey) {
66
80
  xhr.setRequestHeader('x-api-key', apiKey);
67
81
  }
82
+
83
+ // Add secure headers (Content-Type, User-Agent, etc.)
84
+ const secureHeaders = getSecureHeaders();
85
+ Object.entries(secureHeaders).forEach(([key, value]) => {
86
+ if (key.toLowerCase() !== 'content-type') {
87
+ xhr.setRequestHeader(key, value);
88
+ }
89
+ });
90
+
91
+ // SSE-specific headers
68
92
  xhr.setRequestHeader('Accept', 'text/event-stream');
69
- xhr.setRequestHeader('Cache-Control', 'no-cache');
93
+ xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
94
+ xhr.setRequestHeader('Pragma', 'no-cache');
95
+ xhr.setRequestHeader('Expires', '0');
96
+
97
+ // Add userreferenceid header (required for authentication) - both cases
98
+ try {
99
+ const userInfo = getUserInfoForAPI();
100
+ const userRefId = userInfo?.userReferenceId || userInfo?.id;
101
+ if (userRefId) {
102
+ xhr.setRequestHeader('userreferenceid', userRefId);
103
+ xhr.setRequestHeader('userReferenceId', userRefId);
104
+ }
105
+ } catch {
106
+ if (__DEV__) console.warn('[usePaymentSSE] Could not get userReferenceId');
107
+ }
108
+
109
+ // Add provider header (required for authentication)
110
+ if (extraHeaders?.providerId) {
111
+ xhr.setRequestHeader('provider', extraHeaders.providerId);
112
+ }
113
+
114
+ // Add onboarding headers - both camelCase and lowercase variants
115
+ if (extraHeaders?.workflowInstanceId) {
116
+ xhr.setRequestHeader('workflowInstanceId', extraHeaders.workflowInstanceId);
117
+ }
118
+ if (extraHeaders?.applicationId) {
119
+ xhr.setRequestHeader('applicationId', extraHeaders.applicationId);
120
+ xhr.setRequestHeader('applicationid', extraHeaders.applicationId);
121
+ }
122
+ if (extraHeaders?.entityid) {
123
+ xhr.setRequestHeader('entityid', extraHeaders.entityid);
124
+ xhr.setRequestHeader('entityId', extraHeaders.entityid);
125
+ }
70
126
 
71
127
  // 4. Handle incoming data
72
128
  xhr.onprogress = () => {
@@ -80,17 +136,40 @@ export function usePaymentSSE() {
80
136
  // Parse new text into SSE events
81
137
  const events = parseSSEBuffer(bufferRef.current, newText);
82
138
 
83
- // Handle each event
139
+ // Handle each event (support encrypted payload like web)
140
+ const handleEventData = async (rawData: string) => {
141
+ try {
142
+ const parsed = JSON.parse(rawData || '{}') as Record<string, unknown>;
143
+ let payload = parsed;
144
+ if (typeof parsed?.encryptedResponse === 'string' && parsed.encryptedResponse) {
145
+ try {
146
+ const config = getEncryptionConfig();
147
+ const decrypted = await decryptResponse(
148
+ { encryptedResponse: parsed.encryptedResponse },
149
+ config
150
+ );
151
+ payload = (decrypted || {}) as Record<string, unknown>;
152
+ } catch {
153
+ if (__DEV__) console.warn('[usePaymentSSE] Decrypt failed, using raw');
154
+ }
155
+ }
156
+ const status = String(payload?.paymentStatus ?? payload?.payment_status ?? '').toUpperCase();
157
+ if (status) callbacks.onPaymentStatus(status, payload);
158
+ } catch (parseError) {
159
+ if (__DEV__) console.error('[usePaymentSSE] Failed to parse event data:', parseError);
160
+ }
161
+ };
162
+
84
163
  for (const { eventType, data } of events) {
164
+ if (!data) continue;
85
165
  if (eventType === 'fd_payment_status') {
166
+ handleEventData(data);
167
+ } else if (eventType === 'message') {
86
168
  try {
87
- const parsed = JSON.parse(data);
88
- const status = (parsed.paymentStatus ?? '').toUpperCase();
89
- callbacks.onPaymentStatus(status, parsed);
90
- } catch (parseError) {
91
- if (__DEV__) {
92
- console.error('[usePaymentSSE] Failed to parse event data:', parseError);
93
- }
169
+ const parsed = JSON.parse(data) as { event?: string; [k: string]: unknown };
170
+ if (parsed?.event === 'fd_payment_status') handleEventData(data);
171
+ } catch {
172
+ // ignore
94
173
  }
95
174
  }
96
175
  }
@@ -134,6 +213,21 @@ export function usePaymentSSE() {
134
213
 
135
214
  if (__DEV__) {
136
215
  console.log('[usePaymentSSE] Starting SSE connection to:', url);
216
+ console.log('[usePaymentSSE] Headers:', {
217
+ 'x-api-key': apiKey ? '***' : 'missing',
218
+ 'userreferenceid': (() => {
219
+ try {
220
+ const userInfo = getUserInfoForAPI();
221
+ return userInfo?.userReferenceId || userInfo?.id || 'missing';
222
+ } catch {
223
+ return 'missing';
224
+ }
225
+ })(),
226
+ 'provider': extraHeaders?.providerId || 'missing',
227
+ 'workflowInstanceId': extraHeaders?.workflowInstanceId || 'missing',
228
+ 'applicationId': extraHeaders?.applicationId || 'missing',
229
+ 'entityid': extraHeaders?.entityid || 'missing',
230
+ });
137
231
  }
138
232
  },
139
233
  []
@@ -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
- targetTaskId: WORKFLOW_TASKS.VALIDATE_OTP,
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
- targetTaskId: WORKFLOW_TASKS.RESEND_OTP,
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
- { skip: !!masterData } // Skip if master data is already available
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
+ });
@@ -20,7 +20,6 @@ import { useGetCustomerApplicationsMutation } from '../api/customerApi';
20
20
  import { useGetMasterDataQuery } from '../api/masterDataApi';
21
21
  import { useMasterData } from '../providers/MasterDataProvider';
22
22
  import { useTerminateWorkflowMutation } from '../api/workflowApi';
23
- import { usePaymentReverseFeedMutation } from '../api/fdApi';
24
23
  import type { ColorScheme, ThemeName } from '../theme';
25
24
  import SafeAreaWrapper from '../components/SafeAreaWrapper';
26
25
  import { getUserInfoForAPI, getAppData } from '../config/appDataConfig';
@@ -99,22 +98,9 @@ const FDList: React.FC<FDListProps> = ({
99
98
  isLoading: isTerminatingWorkflow,
100
99
  }] = useTerminateWorkflowMutation();
101
100
 
102
- // Payment Reverse Feed API
103
- const [paymentReverseFeed, {
104
- data: paymentReverseFeedResponse,
105
- error: paymentReverseFeedError,
106
- isLoading: isLoadingPaymentReverseFeed,
107
- }] = usePaymentReverseFeedMutation();
108
-
109
101
  const styles = createStyles(colors, typography, spacing, themeName);
110
102
  const { setMasterData } = useMasterData();
111
103
 
112
- // Redux selectors for workflow IDs
113
- const workflowInstanceId = useAppSelector((state: any) => state?.onboarding?.workflowInstanceId);
114
- const applicationId = useAppSelector((state: any) => state?.onboarding?.applicationId);
115
- const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
116
- const providerId = useAppSelector((state: any) => state?.onboarding?.providerId);
117
-
118
104
  // Helper function to check if customer applications is empty
119
105
  const isCustomerApplicationsEmpty = () => {
120
106
  if (!customerApplications) {
@@ -223,7 +209,12 @@ const FDList: React.FC<FDListProps> = ({
223
209
 
224
210
  const { data: masterData, isLoading: isLoadingMaster } = useGetMasterDataQuery(
225
211
  { providerId: inferredProviderId },
226
- { skip: !inferredProviderId }
212
+ {
213
+ skip: !inferredProviderId,
214
+ refetchOnMountOrArgChange: true,
215
+ refetchOnFocus: true,
216
+ refetchOnReconnect: true,
217
+ }
227
218
  );
228
219
 
229
220
  // Only render once all three API calls have completed (success or error)
@@ -491,26 +482,34 @@ const FDList: React.FC<FDListProps> = ({
491
482
 
492
483
  // Persist onboarding identifiers globally for subsequent API calls (like FDCalculator)
493
484
  try {
494
- // Extract workflow parameters from response
485
+ // Extract workflow parameters from response (support array / data[] / applications[])
495
486
  const responseData = customerApplications?.data || customerApplications;
496
- let applicationData = Array.isArray(responseData) ? responseData[0] : responseData;
487
+ let applicationsData: any[] = [];
488
+ if (Array.isArray(responseData)) {
489
+ applicationsData = responseData;
490
+ } else if (responseData?.applications && Array.isArray(responseData.applications)) {
491
+ applicationsData = responseData.applications;
492
+ } else if (Array.isArray(customerApplications?.applications)) {
493
+ applicationsData = customerApplications.applications;
494
+ }
495
+
496
+ let applicationData = applicationsData.length > 0 ? applicationsData[0] : (Array.isArray(responseData) ? responseData[0] : responseData);
497
497
 
498
498
  // Prefer the application with wf_status === 'Active'
499
- if (Array.isArray(responseData)) {
500
- const activeOnly = responseData.find((app: any) => {
499
+ if (applicationsData.length > 0) {
500
+ const activeOnly = applicationsData.find((app: any) => {
501
501
  const status = (app.wf_status || app.status || '').toString();
502
502
  return status === 'Active';
503
503
  });
504
504
  if (activeOnly) applicationData = activeOnly;
505
505
  }
506
506
 
507
- if (Array.isArray(responseData)) {
508
- completeFDData = responseData.find((app: any) => {
509
- const status = (app.wf_status || app.status || '').toString();
510
- return status === 'Completed';
511
- });
512
- setGlobalData({ completeFDData: !!completeFDData });
513
- }
507
+ // Set completed flag robustly for downstream ReviewKYC/Aadhaar flow decisions
508
+ completeFDData = applicationsData.find((app: any) => {
509
+ const status = (app.wf_status || app.status || '').toString().toLowerCase();
510
+ return status === 'completed';
511
+ });
512
+ setGlobalData({ completeFDData: !!completeFDData });
514
513
  if (applicationData) {
515
514
  const ids = {
516
515
  workflowInstanceId: applicationData.workflow_instance_id,
@@ -593,56 +592,18 @@ const FDList: React.FC<FDListProps> = ({
593
592
  // Handle error silently
594
593
  }
595
594
 
596
- // If current state is payment and transactionId is available, call payment reverse feed API
595
+ // If current state is payment and transactionId is available,
596
+ // open PaymentStatus and let SSE (/events) drive status updates.
597
597
  if (currentState === WORKFLOW_STATES.PAYMENT && transactionId) {
598
- try {
599
- // Get user info and required IDs
600
- const userInfo = getUserInfoForAPI();
601
-
602
- // Prepare payment reverse feed request
603
- const paymentReverseFeedRequest = {
604
- // Headers
605
- providerId: providerId,
606
- workflowInstanceId: workflowInstanceId,
607
- userreferenceid: userInfo.id,
608
- applicationid: applicationId,
609
- entityid: entityId,
610
- // Body
611
- transactionId: transactionId,
612
- };
613
-
614
- const response = await paymentReverseFeed(paymentReverseFeedRequest).unwrap();
615
-
616
- // Handle the response based on payment status
617
- const paymentStatus = (response?.data?.paymentStatus || '').toLowerCase();
618
- const statusParam = paymentStatus === 'success' ? 'success' : paymentStatus === 'failed' ? 'failed' : 'pending';
619
-
620
- // Build fdData for display
621
- const fdDataParam = activeFD ? {
622
- companyName: activeFD.name,
623
- amount: Number(activeFD.invested) || 0,
624
- fdRate: `${activeFD.returns}% p.a.`,
625
- tenure: activeFD.maturityDate ? `${activeFD.maturityDate}` : '-',
626
- interestPayout: activeFD.interestPayout || 'Yearly',
627
- } : undefined;
628
-
629
- navigate('PaymentStatus', { status: statusParam, transactionId, fdData: fdDataParam } as any);
630
- return;
631
-
632
- } catch (error) {
633
- // Handle error silently
634
-
635
- // On error, navigate with pending status as fallback
636
- const fdDataParam = activeFD ? {
637
- companyName: activeFD.name,
638
- amount: Number(activeFD.invested) || 0,
639
- fdRate: `${activeFD.returns}% p.a.`,
640
- tenure: activeFD.maturityDate ? `${activeFD.maturityDate}` : '-',
641
- interestPayout: activeFD.interestPayout || 'Yearly',
642
- } : undefined;
643
- navigate('PaymentStatus', { status: 'pending', transactionId, fdData: fdDataParam } as any);
644
- return;
645
- }
598
+ const fdDataParam = activeFD ? {
599
+ companyName: activeFD.name,
600
+ amount: Number(activeFD.invested) || 0,
601
+ fdRate: `${activeFD.returns}% p.a.`,
602
+ tenure: activeFD.maturityDate ? `${activeFD.maturityDate}` : '-',
603
+ interestPayout: activeFD.interestPayout || 'Yearly',
604
+ } : undefined;
605
+ navigate('PaymentStatus', { status: 'pending', transactionId, fdData: fdDataParam } as any);
606
+ return;
646
607
  }
647
608
 
648
609
  // Use workflow navigation based on current state (non-payment states or no transactionId)
@@ -1281,4 +1242,4 @@ const createStyles = (colors: ColorScheme, typography: any, spacing: any, themeN
1281
1242
  },
1282
1243
  });
1283
1244
 
1284
- export default FDList;
1245
+ export default FDList;
@@ -5,9 +5,8 @@ import SafeAreaWrapper from '../components/SafeAreaWrapper';
5
5
  import { useColors } from '../theme/ThemeContext';
6
6
  import { decryptResponse } from '../utils/encryption';
7
7
  import { getEncryptionConfig } from '../config/encryptionConfig';
8
- import { useFocusEffect } from '@react-navigation/native';
9
- import { getPaymentSession } from '../state/paymentSession';
10
- import { usePaymentStatusTimer, PaymentStatus } from '../hooks/usePaymentStatusTimer';
8
+ import { useAppSelector } from '../store';
9
+ import { usePaymentSSE } from '../hooks/usePaymentSSE';
11
10
 
12
11
  export interface PaymentProps {
13
12
  onGoBack?: () => void;
@@ -32,33 +31,16 @@ const Payment: React.FC<PaymentProps> = ({
32
31
  const styles = createStyles(colors);
33
32
  const webViewRef = useRef<WebView>(null);
34
33
  const [loading, setLoading] = useState(true);
35
- const currentStatusRef = useRef<PaymentStatus>('pending');
36
- const { transactionId } = getPaymentSession();
37
34
 
38
- const { startTimer, stopTimer } = usePaymentStatusTimer({
39
- transactionId,
40
- onStatusUpdate: (status, response) => {
41
- currentStatusRef.current = status;
42
-
43
- if (status === 'success') {
44
- onPaymentSuccess?.(response);
45
- }
46
- else if (status === 'failed') {
47
- onPaymentFailure?.(response);
48
- }
49
- else if (status === 'pending') {
50
- onPaymentPending?.(response);
51
- }
52
- }
53
-
54
- });
55
-
56
- useFocusEffect(
57
- React.useCallback(() => {
58
- startTimer();
59
-
60
- }, [startTimer, stopTimer])
61
- );
35
+ const applicationId = useAppSelector((state: any) => state?.onboarding?.applicationId);
36
+ const workflowInstanceId = useAppSelector((state: any) => state?.onboarding?.workflowInstanceId);
37
+ const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
38
+ const providerId = useAppSelector((state: any) => state?.onboarding?.providerId);
39
+ const { start: startPaymentSSE, stop: stopPaymentSSE } = usePaymentSSE();
40
+ const onSuccessRef = useRef(onPaymentSuccess);
41
+ const onFailureRef = useRef(onPaymentFailure);
42
+ onSuccessRef.current = onPaymentSuccess;
43
+ onFailureRef.current = onPaymentFailure;
62
44
 
63
45
 
64
46
 
@@ -89,6 +71,40 @@ const Payment: React.FC<PaymentProps> = ({
89
71
  setLoading(false);
90
72
  };
91
73
 
74
+ // SSE: listen for payment status while user is on Payment WebView (same as web integration)
75
+ useEffect(() => {
76
+ if (!applicationId || !paymentUrl?.trim()) return;
77
+
78
+ startPaymentSSE(
79
+ applicationId,
80
+ {
81
+ onPaymentStatus: (status, payload) => {
82
+ const normalized = String(status || '').toUpperCase();
83
+ if (normalized === 'SUCCESS') {
84
+ stopPaymentSSE();
85
+ onSuccessRef.current?.(payload);
86
+ return;
87
+ }
88
+ if (normalized === 'FAILED') {
89
+ stopPaymentSSE();
90
+ onFailureRef.current?.(payload);
91
+ }
92
+ },
93
+ onError: () => {
94
+ if (__DEV__) console.warn('[Payment] SSE connection error');
95
+ },
96
+ onConnected: () => {
97
+ if (__DEV__) console.log('[Payment] SSE connected for payment status');
98
+ },
99
+ },
100
+ { workflowInstanceId, applicationId, entityid: entityId, providerId }
101
+ );
102
+
103
+ return () => {
104
+ stopPaymentSSE();
105
+ };
106
+ }, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId, startPaymentSSE, stopPaymentSSE]);
107
+
92
108
  const handleMessage = async (event: any) => {
93
109
  try {
94
110
  const dataString = event.nativeEvent.data;
@@ -133,18 +149,13 @@ const Payment: React.FC<PaymentProps> = ({
133
149
  const paymentStatus = response.data?.paymentStatus?.toLowerCase();
134
150
 
135
151
  if (paymentStatus === 'success') {
136
- currentStatusRef.current = "success";
137
- stopTimer();
138
152
  onPaymentSuccess?.(response);
139
153
  } else if (paymentStatus === 'failed') {
140
- currentStatusRef.current = "failed";
141
- stopTimer();
142
154
  onPaymentFailure?.(response);
143
155
  } else {
144
156
  onPaymentPending?.(response);
145
157
  }
146
158
  } else {
147
- currentStatusRef.current = "pending";
148
159
  onPaymentPending?.(response);
149
160
  }
150
161
 
@@ -252,4 +263,3 @@ const createStyles = (colors: any) => StyleSheet.create({
252
263
  });
253
264
 
254
265
  export default Payment;
255
-
@@ -15,8 +15,7 @@ import { setPaymentSession, getPaymentSession } from '../state/paymentSession';
15
15
  import { useRoute } from '@react-navigation/native';
16
16
  import { BANK_STRINGS } from '../constants/strings/bank';
17
17
  import { COMMON_STRINGS } from '../constants/strings/common';
18
- import { getApiConfig } from '../config/apiConfig';
19
- import { usePaymentStatusTimer } from '../hooks/usePaymentStatusTimer';
18
+ import { usePaymentSSE } from '../hooks/usePaymentSSE';
20
19
 
21
20
  export interface PaymentStatusProps {
22
21
  onRetry?: () => void;
@@ -64,23 +63,7 @@ const PaymentStatus: React.FC<PaymentStatusProps> = ({
64
63
  const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
65
64
  const providerId = useAppSelector((state: any) => state?.onboarding?.providerId);
66
65
 
67
- const {
68
- startTimer,
69
- stopTimer,
70
- triggerStatusCheck,
71
- isCheckingStatus,
72
- } = usePaymentStatusTimer({
73
- transactionId: finalTransactionId,
74
- overrides: {
75
- providerId,
76
- workflowInstanceId,
77
- applicationid: applicationId,
78
- entityid: entityId,
79
- },
80
- onStatusUpdate: (nextStatus) => {
81
- setCurrentStatus(nextStatus);
82
- },
83
- });
66
+ const { start: startPaymentSSE, stop: stopPaymentSSE } = usePaymentSSE();
84
67
 
85
68
  // Payment Retry API
86
69
  const [paymentRetry, {
@@ -118,20 +101,33 @@ const PaymentStatus: React.FC<PaymentStatusProps> = ({
118
101
  };
119
102
 
120
103
  useEffect(() => {
121
- if (currentStatus === 'pending') {
122
- startTimer();
123
- } else {
124
- stopTimer();
104
+ if (currentStatus !== 'pending' || !applicationId) {
105
+ stopPaymentSSE();
106
+ return;
125
107
  }
126
108
 
109
+ startPaymentSSE(applicationId, {
110
+ onPaymentStatus: (status) => {
111
+ const normalized = String(status || '').toUpperCase();
112
+ if (normalized === 'SUCCESS') {
113
+ setCurrentStatus('success');
114
+ stopPaymentSSE();
115
+ return;
116
+ }
117
+ if (normalized === 'FAILED') {
118
+ setCurrentStatus('failed');
119
+ stopPaymentSSE();
120
+ }
121
+ },
122
+ onError: () => {
123
+ // keep pending state; stream can be restarted on re-render
124
+ },
125
+ });
126
+
127
127
  return () => {
128
- stopTimer();
128
+ stopPaymentSSE();
129
129
  };
130
- }, [currentStatus, startTimer, stopTimer]);
131
-
132
- const handlePaymentReverseFeed = async () => {
133
- await triggerStatusCheck();
134
- };
130
+ }, [applicationId, currentStatus, startPaymentSSE, stopPaymentSSE]);
135
131
 
136
132
  // Handle payment retry when status is failed
137
133
  const handlePaymentRetry = async () => {
@@ -181,9 +177,6 @@ const PaymentStatus: React.FC<PaymentStatusProps> = ({
181
177
  // Get user info from app data
182
178
  const userInfo = getUserInfoForAPI();
183
179
 
184
- // Get API configuration
185
- const apiConfig = getApiConfig();
186
-
187
180
  // Prepare request payload
188
181
  const requestPayload = {
189
182
  userReferenceId: userInfo.id
@@ -412,13 +405,6 @@ const PaymentStatus: React.FC<PaymentStatusProps> = ({
412
405
  disabled={isLoadingPaymentRetry}
413
406
  />
414
407
  )}
415
- {/* {currentStatus === 'pending' && (
416
- <ActionButton
417
- title={isCheckingStatus ? COMMON_STRINGS.CHECKING : BANK_STRINGS.REFRESH_STATUS_BUTTON}
418
- onPress={handlePaymentReverseFeed}
419
- disabled={isCheckingStatus}
420
- />
421
- )} */}
422
408
  </View>
423
409
  </View>
424
410
  </SafeAreaWrapper>
@@ -545,4 +531,3 @@ const createStyles = (colors: any, typography: any, status: 'success' | 'failed'
545
531
  };
546
532
 
547
533
  export default PaymentStatus;
548
-