@finspringinnovations/fdsdk 0.0.5 → 0.0.7
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/components/InterestRateCard.d.ts +4 -0
- package/lib/components/InterestRateCard.js +13 -3
- package/lib/config/appDataConfig.d.ts +5 -0
- package/lib/hooks/usePaymentSSE.js +277 -142
- package/lib/screens/FDCalculator.js +25 -1
- package/lib/screens/Payment.js +138 -20
- package/lib/screens/PaymentStatus.js +129 -13
- package/lib/utils/sseParser.js +19 -3
- package/package.json +1 -1
- package/src/components/InterestRateCard.tsx +33 -5
- package/src/config/appDataConfig.ts +5 -0
- package/src/hooks/usePaymentSSE.ts +283 -136
- package/src/screens/FDCalculator.tsx +23 -1
- package/src/screens/Payment.tsx +163 -30
- package/src/screens/PaymentStatus.tsx +146 -16
- package/src/utils/sseParser.ts +20 -4
package/lib/screens/Payment.js
CHANGED
|
@@ -42,9 +42,11 @@ 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");
|
|
47
|
+
const appDataConfig_1 = require("../config/appDataConfig");
|
|
48
|
+
const apiConfig_1 = require("../config/apiConfig");
|
|
46
49
|
const store_1 = require("../store");
|
|
47
|
-
const usePaymentSSE_1 = require("../hooks/usePaymentSSE");
|
|
48
50
|
const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPending, paymentUrl, successUrl = 'payment/success', failureUrl = 'payment/failure', }) => {
|
|
49
51
|
const colors = (0, ThemeContext_1.useColors)();
|
|
50
52
|
const styles = createStyles(colors);
|
|
@@ -54,11 +56,21 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
|
|
|
54
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; });
|
|
55
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; });
|
|
56
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; });
|
|
57
|
-
const
|
|
59
|
+
const sseXhrRef = (0, react_1.useRef)(null);
|
|
60
|
+
const sseLastIndexRef = (0, react_1.useRef)(0);
|
|
61
|
+
const sseBufferRef = (0, react_1.useRef)({ value: '' });
|
|
58
62
|
const onSuccessRef = (0, react_1.useRef)(onPaymentSuccess);
|
|
59
63
|
const onFailureRef = (0, react_1.useRef)(onPaymentFailure);
|
|
60
64
|
onSuccessRef.current = onPaymentSuccess;
|
|
61
65
|
onFailureRef.current = onPaymentFailure;
|
|
66
|
+
const stopPaymentSSE = (0, react_1.useCallback)(() => {
|
|
67
|
+
if (sseXhrRef.current) {
|
|
68
|
+
sseXhrRef.current.abort();
|
|
69
|
+
sseXhrRef.current = null;
|
|
70
|
+
}
|
|
71
|
+
sseLastIndexRef.current = 0;
|
|
72
|
+
sseBufferRef.current = { value: '' };
|
|
73
|
+
}, []);
|
|
62
74
|
const handleNavigationStateChange = async (navState) => {
|
|
63
75
|
const { url } = navState;
|
|
64
76
|
if (url.includes('payment/status')) {
|
|
@@ -82,35 +94,141 @@ const Payment = ({ onGoBack, onPaymentSuccess, onPaymentFailure, onPaymentPendin
|
|
|
82
94
|
};
|
|
83
95
|
// SSE: listen for payment status while user is on Payment WebView (same as web integration)
|
|
84
96
|
(0, react_1.useEffect)(() => {
|
|
85
|
-
|
|
97
|
+
var _a;
|
|
98
|
+
if (!applicationId || !(paymentUrl === null || paymentUrl === void 0 ? void 0 : paymentUrl.trim())) {
|
|
99
|
+
stopPaymentSSE();
|
|
86
100
|
return;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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') {
|
|
92
173
|
stopPaymentSSE();
|
|
93
|
-
(
|
|
174
|
+
(_e = onSuccessRef.current) === null || _e === void 0 ? void 0 : _e.call(onSuccessRef, payload);
|
|
94
175
|
return;
|
|
95
176
|
}
|
|
96
|
-
if (
|
|
177
|
+
if (status === 'FAILED') {
|
|
97
178
|
stopPaymentSSE();
|
|
98
|
-
(
|
|
179
|
+
(_f = onFailureRef.current) === null || _f === void 0 ? void 0 : _f.call(onFailureRef, payload);
|
|
99
180
|
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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);
|
|
106
219
|
if (__DEV__)
|
|
107
220
|
console.log('[Payment] SSE connected for payment status');
|
|
108
|
-
}
|
|
109
|
-
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
xhr.onerror = () => {
|
|
224
|
+
if (__DEV__)
|
|
225
|
+
console.warn('[Payment] SSE connection error');
|
|
226
|
+
};
|
|
227
|
+
xhr.send();
|
|
110
228
|
return () => {
|
|
111
229
|
stopPaymentSSE();
|
|
112
230
|
};
|
|
113
|
-
}, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId,
|
|
231
|
+
}, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId, stopPaymentSSE]);
|
|
114
232
|
const handleMessage = async (event) => {
|
|
115
233
|
var _a, _b, _c;
|
|
116
234
|
try {
|
|
@@ -48,12 +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
|
|
57
|
+
const sseParser_1 = require("../utils/sseParser");
|
|
58
|
+
const encryption_1 = require("../utils/encryption");
|
|
59
|
+
const encryptionConfig_1 = require("../config/encryptionConfig");
|
|
57
60
|
const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) => {
|
|
58
61
|
var _a;
|
|
59
62
|
const colors = (0, ThemeContext_1.useColors)();
|
|
@@ -74,7 +77,9 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
|
|
|
74
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; });
|
|
75
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; });
|
|
76
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; });
|
|
77
|
-
const
|
|
80
|
+
const sseXhrRef = (0, react_1.useRef)(null);
|
|
81
|
+
const sseLastIndexRef = (0, react_1.useRef)(0);
|
|
82
|
+
const sseBufferRef = (0, react_1.useRef)({ value: '' });
|
|
78
83
|
// Payment Retry API
|
|
79
84
|
const [paymentRetry, { data: paymentRetryResponse, error: paymentRetryError, isLoading: isLoadingPaymentRetry, }] = (0, fdApi_1.usePaymentRetryMutation)();
|
|
80
85
|
// Get Customer Applications API
|
|
@@ -98,32 +103,143 @@ const PaymentStatus = ({ onRetry, onContinue, status, transactionId, fdData }) =
|
|
|
98
103
|
const formatAmount = (amount) => {
|
|
99
104
|
return amount.toLocaleString('en-IN');
|
|
100
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
|
+
}, []);
|
|
101
114
|
(0, react_1.useEffect)(() => {
|
|
115
|
+
var _a;
|
|
102
116
|
if (currentStatus !== 'pending' || !applicationId) {
|
|
103
117
|
stopPaymentSSE();
|
|
104
118
|
return;
|
|
105
119
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (_b) {
|
|
154
|
+
// ignore
|
|
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') {
|
|
110
191
|
setCurrentStatus('success');
|
|
111
192
|
stopPaymentSSE();
|
|
112
193
|
return;
|
|
113
194
|
}
|
|
114
|
-
if (
|
|
195
|
+
if (status === 'FAILED') {
|
|
115
196
|
setCurrentStatus('failed');
|
|
116
197
|
stopPaymentSSE();
|
|
117
198
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
}
|
|
122
|
-
}
|
|
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();
|
|
123
232
|
return () => {
|
|
124
233
|
stopPaymentSSE();
|
|
125
234
|
};
|
|
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;
|
package/lib/utils/sseParser.js
CHANGED
|
@@ -4,10 +4,26 @@ exports.parseSSEBuffer = parseSSEBuffer;
|
|
|
4
4
|
function parseSSEBuffer(buffer, chunk) {
|
|
5
5
|
const results = [];
|
|
6
6
|
buffer.value += chunk;
|
|
7
|
-
let idx;
|
|
8
|
-
|
|
7
|
+
let idx = -1;
|
|
8
|
+
let delimiterLength = 0;
|
|
9
|
+
const findDelimiter = () => {
|
|
10
|
+
const unixIdx = buffer.value.indexOf('\n\n');
|
|
11
|
+
const windowsIdx = buffer.value.indexOf('\r\n\r\n');
|
|
12
|
+
if (windowsIdx >= 0 && (unixIdx < 0 || windowsIdx < unixIdx)) {
|
|
13
|
+
idx = windowsIdx;
|
|
14
|
+
delimiterLength = 4;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (unixIdx >= 0) {
|
|
18
|
+
idx = unixIdx;
|
|
19
|
+
delimiterLength = 2;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
};
|
|
24
|
+
while (findDelimiter()) {
|
|
9
25
|
const block = buffer.value.slice(0, idx);
|
|
10
|
-
buffer.value = buffer.value.slice(idx +
|
|
26
|
+
buffer.value = buffer.value.slice(idx + delimiterLength);
|
|
11
27
|
let eventType = 'message';
|
|
12
28
|
const dataparts = [];
|
|
13
29
|
for (const line of block.split(/\r?\n/)) {
|
package/package.json
CHANGED
|
@@ -5,12 +5,18 @@ import { useColors, useTypography, useTheme } from '../theme/ThemeContext';
|
|
|
5
5
|
interface InterestRateCardProps {
|
|
6
6
|
interestRate: string;
|
|
7
7
|
maturityAmount: string;
|
|
8
|
+
/** Interest payout amount (e.g. from sdrCalc[0].intPayAmt), shown below Interest Rate */
|
|
9
|
+
intPayAmt?: string;
|
|
10
|
+
/** Total interest earnings (e.g. from sdrCalc[0].totalInterestEarnings), shown below On Maturity */
|
|
11
|
+
totalInterestEarnings?: string;
|
|
8
12
|
children?: React.ReactNode;
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
const InterestRateCard: React.FC<InterestRateCardProps> = ({
|
|
12
16
|
interestRate,
|
|
13
17
|
maturityAmount,
|
|
18
|
+
intPayAmt,
|
|
19
|
+
totalInterestEarnings,
|
|
14
20
|
children,
|
|
15
21
|
}) => {
|
|
16
22
|
const colors = useColors();
|
|
@@ -26,15 +32,31 @@ const InterestRateCard: React.FC<InterestRateCardProps> = ({
|
|
|
26
32
|
<Text style={styles.value}>{interestRate}</Text>
|
|
27
33
|
</View>
|
|
28
34
|
<View style={styles.right}>
|
|
29
|
-
|
|
30
|
-
<Text style={styles.label}>On Maturity</Text>
|
|
35
|
+
<Text style={styles.label}>Amount On Maturity</Text>
|
|
31
36
|
<Text style={styles.valueRight}>{maturityAmount}</Text>
|
|
32
|
-
|
|
33
37
|
</View>
|
|
34
|
-
|
|
35
38
|
</View>
|
|
39
|
+
{(intPayAmt != null || totalInterestEarnings != null) && (
|
|
40
|
+
<View style={[styles.row, styles.secondRow]}>
|
|
41
|
+
<View style={styles.left}>
|
|
42
|
+
{intPayAmt != null && (
|
|
43
|
+
<>
|
|
44
|
+
<Text style={styles.label}>Total Interest</Text>
|
|
45
|
+
<Text style={styles.value}>{intPayAmt}</Text>
|
|
46
|
+
</>
|
|
47
|
+
)}
|
|
48
|
+
</View>
|
|
49
|
+
<View style={styles.right}>
|
|
50
|
+
{totalInterestEarnings != null && (
|
|
51
|
+
<>
|
|
52
|
+
<Text style={styles.label}>On Maturity Interest</Text>
|
|
53
|
+
<Text style={styles.valueRight}>{totalInterestEarnings}</Text>
|
|
54
|
+
</>
|
|
55
|
+
)}
|
|
56
|
+
</View>
|
|
57
|
+
</View>
|
|
58
|
+
)}
|
|
36
59
|
{children}
|
|
37
|
-
|
|
38
60
|
</View>
|
|
39
61
|
);
|
|
40
62
|
};
|
|
@@ -51,6 +73,9 @@ const createStyles = (colors: any, typography: any, themeName: string) => StyleS
|
|
|
51
73
|
flexDirection: 'row',
|
|
52
74
|
justifyContent: 'space-between',
|
|
53
75
|
},
|
|
76
|
+
secondRow: {
|
|
77
|
+
marginTop: 12,
|
|
78
|
+
},
|
|
54
79
|
left: {
|
|
55
80
|
flex: 1,
|
|
56
81
|
},
|
|
@@ -72,6 +97,9 @@ const createStyles = (colors: any, typography: any, themeName: string) => StyleS
|
|
|
72
97
|
...typography.styles.bodyLarge,
|
|
73
98
|
fontWeight: '700',
|
|
74
99
|
color: colors.text,
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
marginRight: 10,
|
|
75
103
|
},
|
|
76
104
|
});
|
|
77
105
|
|
|
@@ -6,6 +6,11 @@ export interface EnvironmentData {
|
|
|
6
6
|
apiKey?: string;
|
|
7
7
|
encryptionKey?: string;
|
|
8
8
|
enableLogging?: boolean;
|
|
9
|
+
sseMinimalLogs?: boolean;
|
|
10
|
+
enableVerboseSSELogging?: boolean;
|
|
11
|
+
sseReconnectAttempts?: number;
|
|
12
|
+
sseReconnectDelayMs?: number;
|
|
13
|
+
sseConnectTimeoutMs?: number;
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
/**
|