@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
|
@@ -2,6 +2,10 @@ import React from 'react';
|
|
|
2
2
|
interface InterestRateCardProps {
|
|
3
3
|
interestRate: string;
|
|
4
4
|
maturityAmount: string;
|
|
5
|
+
/** Interest payout amount (e.g. from sdrCalc[0].intPayAmt), shown below Interest Rate */
|
|
6
|
+
intPayAmt?: string;
|
|
7
|
+
/** Total interest earnings (e.g. from sdrCalc[0].totalInterestEarnings), shown below On Maturity */
|
|
8
|
+
totalInterestEarnings?: string;
|
|
5
9
|
children?: React.ReactNode;
|
|
6
10
|
}
|
|
7
11
|
declare const InterestRateCard: React.FC<InterestRateCardProps>;
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const react_1 = __importDefault(require("react"));
|
|
7
7
|
const react_native_1 = require("react-native");
|
|
8
8
|
const ThemeContext_1 = require("../theme/ThemeContext");
|
|
9
|
-
const InterestRateCard = ({ interestRate, maturityAmount, children, }) => {
|
|
9
|
+
const InterestRateCard = ({ interestRate, maturityAmount, intPayAmt, totalInterestEarnings, children, }) => {
|
|
10
10
|
const colors = (0, ThemeContext_1.useColors)();
|
|
11
11
|
const typography = (0, ThemeContext_1.useTypography)();
|
|
12
12
|
const { themeName } = (0, ThemeContext_1.useTheme)();
|
|
@@ -17,8 +17,15 @@ const InterestRateCard = ({ interestRate, maturityAmount, children, }) => {
|
|
|
17
17
|
react_1.default.createElement(react_native_1.Text, { style: styles.label }, "Interest Rate"),
|
|
18
18
|
react_1.default.createElement(react_native_1.Text, { style: styles.value }, interestRate)),
|
|
19
19
|
react_1.default.createElement(react_native_1.View, { style: styles.right },
|
|
20
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.label }, "On Maturity"),
|
|
20
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.label }, "Amount On Maturity"),
|
|
21
21
|
react_1.default.createElement(react_native_1.Text, { style: styles.valueRight }, maturityAmount))),
|
|
22
|
+
(intPayAmt != null || totalInterestEarnings != null) && (react_1.default.createElement(react_native_1.View, { style: [styles.row, styles.secondRow] },
|
|
23
|
+
react_1.default.createElement(react_native_1.View, { style: styles.left }, intPayAmt != null && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
24
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.label }, "Total Interest"),
|
|
25
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.value }, intPayAmt)))),
|
|
26
|
+
react_1.default.createElement(react_native_1.View, { style: styles.right }, totalInterestEarnings != null && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
27
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.label }, "On Maturity Interest"),
|
|
28
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.valueRight }, totalInterestEarnings)))))),
|
|
22
29
|
children));
|
|
23
30
|
};
|
|
24
31
|
const createStyles = (colors, typography, themeName) => react_native_1.StyleSheet.create({
|
|
@@ -33,6 +40,9 @@ const createStyles = (colors, typography, themeName) => react_native_1.StyleShee
|
|
|
33
40
|
flexDirection: 'row',
|
|
34
41
|
justifyContent: 'space-between',
|
|
35
42
|
},
|
|
43
|
+
secondRow: {
|
|
44
|
+
marginTop: 12,
|
|
45
|
+
},
|
|
36
46
|
left: {
|
|
37
47
|
flex: 1,
|
|
38
48
|
},
|
|
@@ -42,6 +52,6 @@ const createStyles = (colors, typography, themeName) => react_native_1.StyleShee
|
|
|
42
52
|
},
|
|
43
53
|
label: Object.assign(Object.assign({}, typography.styles.bodySmall), { color: colors.textLight, marginBottom: 4 }),
|
|
44
54
|
value: Object.assign(Object.assign({}, typography.styles.bodyLarge), { fontWeight: '600', color: colors.text }),
|
|
45
|
-
valueRight: Object.assign(Object.assign({}, typography.styles.bodyLarge), { fontWeight: '700', color: colors.text }),
|
|
55
|
+
valueRight: Object.assign(Object.assign({}, typography.styles.bodyLarge), { fontWeight: '700', color: colors.text, alignItems: 'center', justifyContent: 'center', marginRight: 10 }),
|
|
46
56
|
});
|
|
47
57
|
exports.default = InterestRateCard;
|
|
@@ -4,6 +4,11 @@ export interface EnvironmentData {
|
|
|
4
4
|
apiKey?: string;
|
|
5
5
|
encryptionKey?: string;
|
|
6
6
|
enableLogging?: boolean;
|
|
7
|
+
sseMinimalLogs?: boolean;
|
|
8
|
+
enableVerboseSSELogging?: boolean;
|
|
9
|
+
sseReconnectAttempts?: number;
|
|
10
|
+
sseReconnectDelayMs?: number;
|
|
11
|
+
sseConnectTimeoutMs?: number;
|
|
7
12
|
}
|
|
8
13
|
/**
|
|
9
14
|
* Custom color overrides that can be passed during SDK initialization.
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.usePaymentSSE = usePaymentSSE;
|
|
18
18
|
const react_1 = require("react");
|
|
19
|
+
const react_native_1 = require("react-native");
|
|
19
20
|
const sseParser_1 = require("../utils/sseParser");
|
|
20
21
|
const appDataConfig_1 = require("../config/appDataConfig");
|
|
21
22
|
const apiConfig_1 = require("../config/apiConfig");
|
|
@@ -25,17 +26,32 @@ const encryptionConfig_1 = require("../config/encryptionConfig");
|
|
|
25
26
|
function usePaymentSSE() {
|
|
26
27
|
// Store the XMLHttpRequest so we can abort it later
|
|
27
28
|
const xhrRef = (0, react_1.useRef)(null);
|
|
29
|
+
const reconnectTimerRef = (0, react_1.useRef)(null);
|
|
30
|
+
const connectWatchdogTimerRef = (0, react_1.useRef)(null);
|
|
31
|
+
const stopRequestedRef = (0, react_1.useRef)(false);
|
|
32
|
+
const connectionIdRef = (0, react_1.useRef)(0);
|
|
28
33
|
// Track how much of responseText we've already parsed
|
|
29
34
|
const lastIndexRef = (0, react_1.useRef)(0);
|
|
30
35
|
// SSE text buffer (persists across onprogress calls)
|
|
31
36
|
const bufferRef = (0, react_1.useRef)({ value: '' });
|
|
32
37
|
const start = (0, react_1.useCallback)((applicationId, callbacks, extraHeaders) => {
|
|
33
|
-
var _a;
|
|
38
|
+
var _a, _b, _c;
|
|
39
|
+
connectionIdRef.current += 1;
|
|
40
|
+
const connectionId = connectionIdRef.current;
|
|
41
|
+
stopRequestedRef.current = false;
|
|
34
42
|
// Clean up any existing connection first
|
|
35
43
|
if (xhrRef.current) {
|
|
36
44
|
xhrRef.current.abort();
|
|
37
45
|
xhrRef.current = null;
|
|
38
46
|
}
|
|
47
|
+
if (reconnectTimerRef.current) {
|
|
48
|
+
clearTimeout(reconnectTimerRef.current);
|
|
49
|
+
reconnectTimerRef.current = null;
|
|
50
|
+
}
|
|
51
|
+
if (connectWatchdogTimerRef.current) {
|
|
52
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
53
|
+
connectWatchdogTimerRef.current = null;
|
|
54
|
+
}
|
|
39
55
|
// Reset parsing state
|
|
40
56
|
lastIndexRef.current = 0;
|
|
41
57
|
bufferRef.current = { value: '' };
|
|
@@ -44,172 +60,291 @@ function usePaymentSSE() {
|
|
|
44
60
|
const apiConfig = (0, apiConfig_1.getApiConfig)();
|
|
45
61
|
const baseUrl = ((envData === null || envData === void 0 ? void 0 : envData.apiBaseUrl) || (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.baseUrl) || '').replace(/\/$/, '');
|
|
46
62
|
const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
|
|
63
|
+
const minimalLogs = (envData === null || envData === void 0 ? void 0 : envData.sseMinimalLogs) === true;
|
|
64
|
+
const verboseSSE = (envData === null || envData === void 0 ? void 0 : envData.enableVerboseSSELogging) !== false;
|
|
65
|
+
const maxReconnectAttempts = Number((_a = envData === null || envData === void 0 ? void 0 : envData.sseReconnectAttempts) !== null && _a !== void 0 ? _a : 4);
|
|
66
|
+
const reconnectDelayMs = Number((_b = envData === null || envData === void 0 ? void 0 : envData.sseReconnectDelayMs) !== null && _b !== void 0 ? _b : 2000);
|
|
67
|
+
const connectWatchdogMs = Number((_c = envData === null || envData === void 0 ? void 0 : envData.sseConnectTimeoutMs) !== null && _c !== void 0 ? _c : 15000);
|
|
68
|
+
const rnVersion = (() => {
|
|
69
|
+
var _a;
|
|
70
|
+
const v = (_a = react_native_1.Platform === null || react_native_1.Platform === void 0 ? void 0 : react_native_1.Platform.constants) === null || _a === void 0 ? void 0 : _a.reactNativeVersion;
|
|
71
|
+
return v ? `${v.major}.${v.minor}.${v.patch}` : 'unknown';
|
|
72
|
+
})();
|
|
73
|
+
const jsEngine = (global === null || global === void 0 ? void 0 : global.HermesInternal) ? 'hermes' : 'jsc/other';
|
|
74
|
+
let reconnectAttempts = 0;
|
|
75
|
+
let connected = false;
|
|
47
76
|
if (!url) {
|
|
48
|
-
if (__DEV__)
|
|
77
|
+
if (__DEV__ && verboseSSE)
|
|
49
78
|
console.warn('[usePaymentSSE] No base URL, skipping SSE');
|
|
50
79
|
return;
|
|
51
80
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
xhr.setRequestHeader('x-api-key', apiKey);
|
|
60
|
-
}
|
|
61
|
-
// Add secure headers (Content-Type, User-Agent, etc.)
|
|
62
|
-
const secureHeaders = (0, apiConfig_1.getSecureHeaders)();
|
|
63
|
-
Object.entries(secureHeaders).forEach(([key, value]) => {
|
|
64
|
-
if (key.toLowerCase() !== 'content-type') {
|
|
65
|
-
xhr.setRequestHeader(key, value);
|
|
81
|
+
const scheduleReconnect = (reason) => {
|
|
82
|
+
var _a;
|
|
83
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
84
|
+
return;
|
|
85
|
+
if (connectWatchdogTimerRef.current) {
|
|
86
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
87
|
+
connectWatchdogTimerRef.current = null;
|
|
66
88
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
71
|
-
xhr.setRequestHeader('Pragma', 'no-cache');
|
|
72
|
-
xhr.setRequestHeader('Expires', '0');
|
|
73
|
-
// Add userreferenceid header (required for authentication) - both cases
|
|
74
|
-
try {
|
|
75
|
-
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
76
|
-
const userRefId = (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id);
|
|
77
|
-
if (userRefId) {
|
|
78
|
-
xhr.setRequestHeader('userreferenceid', userRefId);
|
|
79
|
-
xhr.setRequestHeader('userReferenceId', userRefId);
|
|
89
|
+
if (reconnectAttempts >= maxReconnectAttempts) {
|
|
90
|
+
(_a = callbacks.onError) === null || _a === void 0 ? void 0 : _a.call(callbacks, new Error(reason));
|
|
91
|
+
return;
|
|
80
92
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (__DEV__)
|
|
84
|
-
console.warn(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const newText = xhr.responseText.slice(lastIndexRef.current);
|
|
107
|
-
lastIndexRef.current = xhr.responseText.length;
|
|
108
|
-
if (!newText)
|
|
93
|
+
reconnectAttempts += 1;
|
|
94
|
+
const delay = reconnectDelayMs * reconnectAttempts;
|
|
95
|
+
if (__DEV__ && !minimalLogs) {
|
|
96
|
+
console.warn(`[usePaymentSSE] Reconnecting (${reconnectAttempts}/${maxReconnectAttempts}) in ${delay}ms`);
|
|
97
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
98
|
+
reason,
|
|
99
|
+
platform: react_native_1.Platform.OS,
|
|
100
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
101
|
+
rnVersion,
|
|
102
|
+
jsEngine,
|
|
103
|
+
applicationId,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (reconnectTimerRef.current) {
|
|
107
|
+
clearTimeout(reconnectTimerRef.current);
|
|
108
|
+
}
|
|
109
|
+
reconnectTimerRef.current = setTimeout(() => {
|
|
110
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
111
|
+
return;
|
|
112
|
+
openConnection();
|
|
113
|
+
}, delay);
|
|
114
|
+
};
|
|
115
|
+
const openConnection = () => {
|
|
116
|
+
var _a;
|
|
117
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
109
118
|
return;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
console.warn('[usePaymentSSE] Decrypt failed, using raw');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const status = String((_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 : '').toUpperCase();
|
|
130
|
-
if (status)
|
|
131
|
-
callbacks.onPaymentStatus(status, payload);
|
|
119
|
+
connected = false;
|
|
120
|
+
// 2. Create XMLHttpRequest
|
|
121
|
+
const xhr = new XMLHttpRequest();
|
|
122
|
+
xhrRef.current = xhr;
|
|
123
|
+
xhr.open('GET', url);
|
|
124
|
+
// 3. Set headers (same headers your baseApi interceptor uses)
|
|
125
|
+
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']) || '';
|
|
126
|
+
if (apiKey) {
|
|
127
|
+
xhr.setRequestHeader('x-api-key', apiKey);
|
|
128
|
+
xhr.setRequestHeader('X-API-Key', apiKey);
|
|
129
|
+
}
|
|
130
|
+
// Add secure headers (Content-Type, User-Agent, etc.)
|
|
131
|
+
const secureHeaders = (0, apiConfig_1.getSecureHeaders)();
|
|
132
|
+
Object.entries(secureHeaders).forEach(([key, value]) => {
|
|
133
|
+
if (key.toLowerCase() !== 'content-type') {
|
|
134
|
+
xhr.setRequestHeader(key, value);
|
|
132
135
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
});
|
|
137
|
+
// SSE-specific headers
|
|
138
|
+
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
139
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
140
|
+
xhr.setRequestHeader('Pragma', 'no-cache');
|
|
141
|
+
xhr.setRequestHeader('Expires', '0');
|
|
142
|
+
// Add userreferenceid header (required for authentication) - both cases
|
|
143
|
+
try {
|
|
144
|
+
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
145
|
+
const userRefId = (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id);
|
|
146
|
+
if (userRefId) {
|
|
147
|
+
xhr.setRequestHeader('userreferenceid', userRefId);
|
|
148
|
+
xhr.setRequestHeader('userReferenceId', userRefId);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (_b) {
|
|
152
|
+
if (__DEV__ && verboseSSE)
|
|
153
|
+
console.warn('[usePaymentSSE] Could not get userReferenceId');
|
|
154
|
+
}
|
|
155
|
+
// Add provider header variants
|
|
156
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.providerId) {
|
|
157
|
+
xhr.setRequestHeader('provider', extraHeaders.providerId);
|
|
158
|
+
xhr.setRequestHeader('providerid', extraHeaders.providerId);
|
|
159
|
+
xhr.setRequestHeader('providerId', extraHeaders.providerId);
|
|
160
|
+
}
|
|
161
|
+
// Add onboarding headers - both camelCase and lowercase variants
|
|
162
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.workflowInstanceId) {
|
|
163
|
+
xhr.setRequestHeader('workflowInstanceId', extraHeaders.workflowInstanceId);
|
|
164
|
+
xhr.setRequestHeader('workflowinstanceid', extraHeaders.workflowInstanceId);
|
|
165
|
+
}
|
|
166
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.applicationId) {
|
|
167
|
+
xhr.setRequestHeader('applicationId', extraHeaders.applicationId);
|
|
168
|
+
xhr.setRequestHeader('applicationid', extraHeaders.applicationId);
|
|
169
|
+
}
|
|
170
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.entityid) {
|
|
171
|
+
xhr.setRequestHeader('entityid', extraHeaders.entityid);
|
|
172
|
+
xhr.setRequestHeader('entityId', extraHeaders.entityid);
|
|
173
|
+
}
|
|
174
|
+
const markConnected = (path) => {
|
|
175
|
+
var _a;
|
|
176
|
+
if (connected)
|
|
177
|
+
return;
|
|
178
|
+
connected = true;
|
|
179
|
+
reconnectAttempts = 0;
|
|
180
|
+
if (connectWatchdogTimerRef.current) {
|
|
181
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
182
|
+
connectWatchdogTimerRef.current = null;
|
|
183
|
+
}
|
|
184
|
+
(_a = callbacks.onConnected) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
185
|
+
if (__DEV__ && !minimalLogs) {
|
|
186
|
+
console.log('[usePaymentSSE] Connected to SSE stream');
|
|
187
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
188
|
+
path,
|
|
189
|
+
platform: react_native_1.Platform.OS,
|
|
190
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
191
|
+
rnVersion,
|
|
192
|
+
jsEngine,
|
|
193
|
+
applicationId,
|
|
194
|
+
});
|
|
136
195
|
}
|
|
137
196
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
handleEventData(data);
|
|
197
|
+
// 4. Handle incoming data
|
|
198
|
+
xhr.onprogress = () => {
|
|
199
|
+
if (xhr.responseText && xhr.responseText.length > 0) {
|
|
200
|
+
markConnected('progress');
|
|
143
201
|
}
|
|
144
|
-
|
|
202
|
+
// responseText contains ALL text received so far
|
|
203
|
+
// Only parse the NEW text since last call
|
|
204
|
+
const newText = xhr.responseText.slice(lastIndexRef.current);
|
|
205
|
+
lastIndexRef.current = xhr.responseText.length;
|
|
206
|
+
if (!newText)
|
|
207
|
+
return;
|
|
208
|
+
// Parse new text into SSE events
|
|
209
|
+
const events = (0, sseParser_1.parseSSEBuffer)(bufferRef.current, newText);
|
|
210
|
+
// Handle each event (support encrypted payload like web)
|
|
211
|
+
const handleEventData = async (rawData) => {
|
|
212
|
+
var _a, _b, _c, _d;
|
|
145
213
|
try {
|
|
146
|
-
const parsed = JSON.parse(
|
|
147
|
-
|
|
148
|
-
|
|
214
|
+
const parsed = JSON.parse(rawData || '{}');
|
|
215
|
+
let payload = parsed;
|
|
216
|
+
if (typeof (parsed === null || parsed === void 0 ? void 0 : parsed.encryptedResponse) === 'string' && parsed.encryptedResponse) {
|
|
217
|
+
try {
|
|
218
|
+
const config = (0, encryptionConfig_1.getEncryptionConfig)();
|
|
219
|
+
const decrypted = await (0, encryption_1.decryptResponse)({ encryptedResponse: parsed.encryptedResponse }, config);
|
|
220
|
+
payload = (decrypted || {});
|
|
221
|
+
}
|
|
222
|
+
catch (_e) {
|
|
223
|
+
if (__DEV__ && verboseSSE)
|
|
224
|
+
console.warn('[usePaymentSSE] Decrypt failed, using raw');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const payloadData = (payload === null || payload === void 0 ? void 0 : payload.data) || {};
|
|
228
|
+
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();
|
|
229
|
+
if (status)
|
|
230
|
+
callbacks.onPaymentStatus(status, payload);
|
|
231
|
+
}
|
|
232
|
+
catch (parseError) {
|
|
233
|
+
if (__DEV__ && verboseSSE)
|
|
234
|
+
console.error('[usePaymentSSE] Failed to parse event data:', parseError);
|
|
149
235
|
}
|
|
150
|
-
|
|
151
|
-
|
|
236
|
+
};
|
|
237
|
+
for (const { eventType, data } of events) {
|
|
238
|
+
if (!data)
|
|
239
|
+
continue;
|
|
240
|
+
const normalizedEventType = String(eventType || '').trim().toLowerCase();
|
|
241
|
+
if (normalizedEventType === 'fd_payment_status') {
|
|
242
|
+
handleEventData(data);
|
|
243
|
+
}
|
|
244
|
+
else if (normalizedEventType === 'message') {
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(data);
|
|
247
|
+
const embeddedEvent = String((parsed === null || parsed === void 0 ? void 0 : parsed.event) || '').trim().toLowerCase();
|
|
248
|
+
if (embeddedEvent === 'fd_payment_status')
|
|
249
|
+
handleEventData(data);
|
|
250
|
+
}
|
|
251
|
+
catch (_a) {
|
|
252
|
+
// ignore
|
|
253
|
+
}
|
|
152
254
|
}
|
|
153
255
|
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
256
|
+
};
|
|
257
|
+
// 5. Handle connection status
|
|
258
|
+
xhr.onreadystatechange = () => {
|
|
259
|
+
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED || xhr.readyState === XMLHttpRequest.LOADING) {
|
|
260
|
+
if (xhr.status === 200) {
|
|
261
|
+
markConnected('headers');
|
|
262
|
+
}
|
|
263
|
+
else if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED && xhr.status > 0) {
|
|
264
|
+
if (__DEV__) {
|
|
265
|
+
console.error('[usePaymentSSE] Bad status:', xhr.status);
|
|
266
|
+
}
|
|
267
|
+
scheduleReconnect(`SSE response status: ${xhr.status}`);
|
|
164
268
|
}
|
|
165
269
|
}
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
|
|
270
|
+
if (xhr.readyState === XMLHttpRequest.DONE && !stopRequestedRef.current && connectionIdRef.current === connectionId) {
|
|
271
|
+
if (xhr.status !== 200) {
|
|
272
|
+
scheduleReconnect(`SSE closed with status: ${xhr.status}`);
|
|
169
273
|
}
|
|
170
|
-
(_b = callbacks.onError) === null || _b === void 0 ? void 0 : _b.call(callbacks, new Error(`SSE response status: ${xhr.status}`));
|
|
171
274
|
}
|
|
275
|
+
};
|
|
276
|
+
// 6. Handle errors
|
|
277
|
+
xhr.onerror = () => {
|
|
278
|
+
if (__DEV__ && verboseSSE) {
|
|
279
|
+
console.error('[usePaymentSSE] Connection error');
|
|
280
|
+
}
|
|
281
|
+
scheduleReconnect('SSE connection failed');
|
|
282
|
+
};
|
|
283
|
+
// 7. Handle timeout
|
|
284
|
+
xhr.ontimeout = () => {
|
|
285
|
+
if (__DEV__) {
|
|
286
|
+
console.error('[usePaymentSSE] Connection timed out');
|
|
287
|
+
}
|
|
288
|
+
scheduleReconnect('SSE connection timed out');
|
|
289
|
+
};
|
|
290
|
+
// 8. Send the request (connection stays open)
|
|
291
|
+
xhr.send();
|
|
292
|
+
// If we never get connected callback/progress, restart connection.
|
|
293
|
+
if (connectWatchdogTimerRef.current) {
|
|
294
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
172
295
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
var _a;
|
|
296
|
+
connectWatchdogTimerRef.current = setTimeout(() => {
|
|
297
|
+
if (connected || stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
298
|
+
return;
|
|
299
|
+
try {
|
|
300
|
+
xhr.abort();
|
|
301
|
+
}
|
|
302
|
+
catch (_a) {
|
|
303
|
+
// ignore
|
|
304
|
+
}
|
|
305
|
+
scheduleReconnect('SSE connect watchdog timeout');
|
|
306
|
+
}, connectWatchdogMs);
|
|
185
307
|
if (__DEV__) {
|
|
186
|
-
console.
|
|
308
|
+
console.log('[usePaymentSSE] Starting SSE connection to:', url);
|
|
309
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
310
|
+
phase: 'start',
|
|
311
|
+
platform: react_native_1.Platform.OS,
|
|
312
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
313
|
+
rnVersion,
|
|
314
|
+
jsEngine,
|
|
315
|
+
applicationId,
|
|
316
|
+
});
|
|
317
|
+
console.log('[usePaymentSSE] Headers:', {
|
|
318
|
+
'x-api-key': apiKey ? '***' : 'missing',
|
|
319
|
+
'userreferenceid': (() => {
|
|
320
|
+
try {
|
|
321
|
+
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
322
|
+
return (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) || 'missing';
|
|
323
|
+
}
|
|
324
|
+
catch (_a) {
|
|
325
|
+
return 'missing';
|
|
326
|
+
}
|
|
327
|
+
})(),
|
|
328
|
+
'provider': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.providerId) || 'missing',
|
|
329
|
+
'workflowInstanceId': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.workflowInstanceId) || 'missing',
|
|
330
|
+
'applicationId': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.applicationId) || 'missing',
|
|
331
|
+
'entityid': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.entityid) || 'missing',
|
|
332
|
+
});
|
|
187
333
|
}
|
|
188
|
-
(_a = callbacks.onError) === null || _a === void 0 ? void 0 : _a.call(callbacks, new Error('SSE connection timed out'));
|
|
189
334
|
};
|
|
190
|
-
|
|
191
|
-
xhr.send();
|
|
192
|
-
if (__DEV__) {
|
|
193
|
-
console.log('[usePaymentSSE] Starting SSE connection to:', url);
|
|
194
|
-
console.log('[usePaymentSSE] Headers:', {
|
|
195
|
-
'x-api-key': apiKey ? '***' : 'missing',
|
|
196
|
-
'userreferenceid': (() => {
|
|
197
|
-
try {
|
|
198
|
-
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
199
|
-
return (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) || 'missing';
|
|
200
|
-
}
|
|
201
|
-
catch (_a) {
|
|
202
|
-
return 'missing';
|
|
203
|
-
}
|
|
204
|
-
})(),
|
|
205
|
-
'provider': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.providerId) || 'missing',
|
|
206
|
-
'workflowInstanceId': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.workflowInstanceId) || 'missing',
|
|
207
|
-
'applicationId': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.applicationId) || 'missing',
|
|
208
|
-
'entityid': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.entityid) || 'missing',
|
|
209
|
-
});
|
|
210
|
-
}
|
|
335
|
+
openConnection();
|
|
211
336
|
}, []);
|
|
212
337
|
const stop = (0, react_1.useCallback)(() => {
|
|
338
|
+
stopRequestedRef.current = true;
|
|
339
|
+
connectionIdRef.current += 1;
|
|
340
|
+
if (reconnectTimerRef.current) {
|
|
341
|
+
clearTimeout(reconnectTimerRef.current);
|
|
342
|
+
reconnectTimerRef.current = null;
|
|
343
|
+
}
|
|
344
|
+
if (connectWatchdogTimerRef.current) {
|
|
345
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
346
|
+
connectWatchdogTimerRef.current = null;
|
|
347
|
+
}
|
|
213
348
|
if (xhrRef.current) {
|
|
214
349
|
xhrRef.current.abort();
|
|
215
350
|
xhrRef.current = null;
|
|
@@ -617,7 +617,31 @@ const FDCalculator = ({ onGoBack, onExitSDK, onPanRequired, onNavigateToReviewKY
|
|
|
617
617
|
? (_a = data === null || data === void 0 ? void 0 : data.sdrCalc) === null || _a === void 0 ? void 0 : _a[0]
|
|
618
618
|
: (_b = data === null || data === void 0 ? void 0 : data.fdrCalc) === null || _b === void 0 ? void 0 : _b[0];
|
|
619
619
|
const maturityAmount = (calcData === null || calcData === void 0 ? void 0 : calcData.maturityAmount) || (data === null || data === void 0 ? void 0 : data.maturityAmount) || (data === null || data === void 0 ? void 0 : data.totalAmount) || (data === null || data === void 0 ? void 0 : data.finalAmount) || (data === null || data === void 0 ? void 0 : data.amount);
|
|
620
|
-
return maturityAmount ? `₹${maturityAmount.toLocaleString()}` : "";
|
|
620
|
+
return maturityAmount ? `₹${Number(maturityAmount).toLocaleString()}` : "";
|
|
621
|
+
})(), intPayAmt: (() => {
|
|
622
|
+
var _a, _b;
|
|
623
|
+
const data = calculationResult === null || calculationResult === void 0 ? void 0 : calculationResult.data;
|
|
624
|
+
const investmentType = payoutValue === 'On Maturity' ? 'SDR' : 'FDR';
|
|
625
|
+
const calcData = investmentType === 'SDR'
|
|
626
|
+
? (_a = data === null || data === void 0 ? void 0 : data.sdrCalc) === null || _a === void 0 ? void 0 : _a[0]
|
|
627
|
+
: (_b = data === null || data === void 0 ? void 0 : data.fdrCalc) === null || _b === void 0 ? void 0 : _b[0];
|
|
628
|
+
const val = calcData === null || calcData === void 0 ? void 0 : calcData.intPayAmt;
|
|
629
|
+
if (val == null)
|
|
630
|
+
return undefined;
|
|
631
|
+
const num = Number(val);
|
|
632
|
+
return Number.isFinite(num) ? `₹ ${num.toLocaleString()}` : String(val);
|
|
633
|
+
})(), totalInterestEarnings: (() => {
|
|
634
|
+
var _a, _b;
|
|
635
|
+
const data = calculationResult === null || calculationResult === void 0 ? void 0 : calculationResult.data;
|
|
636
|
+
const investmentType = payoutValue === 'On Maturity' ? 'SDR' : 'FDR';
|
|
637
|
+
const calcData = investmentType === 'SDR'
|
|
638
|
+
? (_a = data === null || data === void 0 ? void 0 : data.sdrCalc) === null || _a === void 0 ? void 0 : _a[0]
|
|
639
|
+
: (_b = data === null || data === void 0 ? void 0 : data.fdrCalc) === null || _b === void 0 ? void 0 : _b[0];
|
|
640
|
+
const val = calcData === null || calcData === void 0 ? void 0 : calcData.totalInterestEarnings;
|
|
641
|
+
if (val == null)
|
|
642
|
+
return undefined;
|
|
643
|
+
const num = Number(val);
|
|
644
|
+
return Number.isFinite(num) ? `₹ ${num.toLocaleString()}` : String(val);
|
|
621
645
|
})() },
|
|
622
646
|
react_1.default.createElement(components_1.CheckboxOption, { label: strings_1.FD_STRINGS.SENIOR_CITIZEN_BENEFIT, checked: seniorCitizen, onPress: () => setSeniorCitizen(!seniorCitizen), numberOfLines: 1, containerStyle: { marginTop: 12 }, disabled: true })),
|
|
623
647
|
react_1.default.createElement(react_native_1.View, { style: [styles.checkboxCard, !taxResident && styles.checkboxCardError] },
|