@finspringinnovations/fdsdk 0.0.2 → 0.0.3

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.
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  const react_native_1 = require("react-native");
8
+ const Ionicons_1 = __importDefault(require("react-native-vector-icons/Ionicons"));
8
9
  const base64Images_1 = require("../constants/strings/base64Images");
9
10
  const ThemeContext_1 = require("../theme/ThemeContext");
10
11
  const theme_1 = require("../theme");
@@ -39,7 +40,7 @@ const AmountInput = ({ label, value, onChangeText, onBlur, onFocus, placeholder
39
40
  react_1.default.createElement(react_native_1.Image, { source: { uri: base64Images_1.base64Images.error }, style: { width: 16, height: 16, marginRight: 6 }, resizeMode: "contain" }),
40
41
  react_1.default.createElement(react_native_1.Text, { style: styles.errorText }, errorMessage))),
41
42
  noteText && (react_1.default.createElement(react_native_1.View, { style: styles.noteRow },
42
- react_1.default.createElement(react_native_1.Image, { source: { uri: base64Images_1.base64Images.info }, style: [styles.noteIcon, { width: 14, height: 14, tintColor: colors.textLight }], resizeMode: "contain" }),
43
+ react_1.default.createElement(Ionicons_1.default, { name: "information-circle-outline", size: 14, color: themeName === 'dark' ? colors.labelColor : colors.textLight, style: styles.noteIcon }),
43
44
  react_1.default.createElement(react_native_1.Text, { style: styles.noteText }, noteText))),
44
45
  minMaxText && (react_1.default.createElement(react_native_1.View, { style: styles.limitContainer },
45
46
  react_1.default.createElement(react_native_1.Text, { style: styles.limitLabel }, "Min: "),
@@ -21,20 +21,20 @@ const createStyles = (colors, typography, themeName) => react_native_1.StyleShee
21
21
  flexDirection: 'row',
22
22
  alignItems: 'center',
23
23
  paddingVertical: 0,
24
- paddingHorizontal: 5
25
24
  },
26
25
  checkbox: {
27
26
  width: 18,
28
27
  height: 18,
29
28
  borderRadius: 3,
30
29
  borderWidth: 1.5,
31
- borderColor: colors.inputBorder || colors.border,
30
+ borderColor: themeName === 'dark' ? colors.tabSelected : colors.primary,
32
31
  marginRight: 12,
33
32
  alignItems: 'center',
34
33
  justifyContent: 'center',
35
34
  },
36
35
  checkboxChecked: {
37
- borderColor: colors.inputBorder || colors.border,
36
+ // backgroundColor: colors.tabSelected,
37
+ borderColor: colors.tabSelected,
38
38
  },
39
39
  label: Object.assign(Object.assign({}, typography.styles.bodyMedium), { color: colors.text, flex: 1 }),
40
40
  });
@@ -117,7 +117,7 @@ const createStyles = (colors, typography, themeName) => react_native_1.StyleShee
117
117
  marginBottom: 16,
118
118
  gap: 8,
119
119
  },
120
- otpInput: Object.assign(Object.assign({ width: 48, height: 48, borderWidth: 1, borderColor: colors.inputBorder || colors.border, borderRadius: 8 }, typography.styles.bodyLarge), { color: colors.text, backgroundColor: themeName === 'dark' ? colors.inputBackground : 'white' }),
120
+ otpInput: Object.assign(Object.assign({ width: 48, height: 48, borderWidth: 1, borderColor: themeName === 'dark' ? colors.inputBorder : colors.primary, borderRadius: 8 }, typography.styles.bodyLarge), { color: colors.text, backgroundColor: themeName === 'dark' ? colors.inputBackground : 'white' }),
121
121
  otpInputError: {
122
122
  borderColor: colors.error,
123
123
  borderWidth: 2,
@@ -47,11 +47,11 @@ const createStyles = (colors, typography, spacing, themeName) => react_native_1.
47
47
  },
48
48
  bottomSheet: {
49
49
  padding: spacing.sm,
50
- backgroundColor: colors.background,
50
+ backgroundColor: themeName === 'dark' ? colors.background : 'white',
51
51
  borderTopLeftRadius: 20,
52
52
  borderTopRightRadius: 20,
53
53
  borderWidth: themeName === 'dark' ? 1 : 0,
54
- borderColor: themeName === 'dark' ? colors.border : 'transparent',
54
+ borderColor: themeName === 'dark' ? '#ffffff' : 'transparent',
55
55
  maxHeight: react_native_1.Dimensions.get('window').height * 0.8,
56
56
  minHeight: react_native_1.Platform.OS === 'ios' ? 430 : 400,
57
57
  },
@@ -71,7 +71,7 @@ const createStyles = (colors, typography, spacing, themeName) => react_native_1.
71
71
  title: {
72
72
  fontSize: 17,
73
73
  fontWeight: '500',
74
- color: colors.text,
74
+ color: themeName === 'dark' ? colors.labelColor : '#333',
75
75
  flex: 1,
76
76
  marginRight: spacing.md,
77
77
  lineHeight: 24,
@@ -80,7 +80,7 @@ const createStyles = (colors, typography, spacing, themeName) => react_native_1.
80
80
  width: 32,
81
81
  height: 32,
82
82
  borderRadius: 16,
83
- backgroundColor: colors.surface,
83
+ backgroundColor: '#f5f5f5',
84
84
  justifyContent: 'center',
85
85
  alignItems: 'center',
86
86
  },
@@ -90,13 +90,13 @@ const createStyles = (colors, typography, spacing, themeName) => react_native_1.
90
90
  paddingTop: spacing.lg,
91
91
  paddingBottom: react_native_1.Platform.OS === 'ios' ? 20 : 0,
92
92
  },
93
- sectionTitle: Object.assign(Object.assign({}, typography.styles.h3), { color: colors.text, marginBottom: spacing.md }),
93
+ sectionTitle: Object.assign(Object.assign({}, typography.styles.h3), { color: themeName === 'dark' ? colors.labelColor : '#333', marginBottom: spacing.md }),
94
94
  bookNewButton: {
95
95
  marginTop: spacing.xxxl,
96
96
  marginBottom: spacing.xxxl,
97
97
  alignItems: 'center',
98
98
  },
99
- bookNewText: Object.assign(Object.assign({}, typography.styles.body2), { color: colors.text }),
99
+ bookNewText: Object.assign(Object.assign({}, typography.styles.body2), { color: themeName === 'dark' ? colors.labelColor : '#000000' }),
100
100
  disabledButton: {
101
101
  opacity: 0.6,
102
102
  },
@@ -110,13 +110,13 @@ const createStyles = (colors, typography, spacing, themeName) => react_native_1.
110
110
  },
111
111
  continueButton: {
112
112
  height: 50,
113
- backgroundColor: colors.buttonBackground || colors.headerBg,
113
+ backgroundColor: colors.buttonBackground || colors.headerBg || '#007AFF',
114
114
  borderRadius: 25,
115
115
  paddingHorizontal: spacing.lg,
116
116
  alignItems: 'center',
117
117
  justifyContent: 'center',
118
118
  marginBottom: react_native_1.Platform.OS === 'ios' ? spacing.lg + 20 : spacing.lg,
119
119
  },
120
- continueButtonText: Object.assign(Object.assign({}, typography.styles.button), { color: colors.buttonTextColor || colors.headerText, fontWeight: '600' }),
120
+ continueButtonText: Object.assign(Object.assign({}, typography.styles.button), { color: colors.buttonTextColor || colors.headerText || '#FFFFFF', fontWeight: '600' }),
121
121
  });
122
122
  exports.default = PendingFDBottomSheet;
@@ -91,7 +91,7 @@ const TextFieldWithLabel = ({ label, value, onChangeText, placeholder, placehold
91
91
  return { borderColor: colors.success, borderWidth: 1 };
92
92
  }
93
93
  if (isFocused) {
94
- return { borderColor: colors.inputBorder || colors.border, borderWidth: 1 };
94
+ return { borderColor: colors.primary, borderWidth: 1 };
95
95
  }
96
96
  if (themeName === 'dark') {
97
97
  return {
@@ -238,7 +238,7 @@ const createStyles = (colors, typography, themeName) => react_native_1.StyleShee
238
238
  height: '100%',
239
239
  },
240
240
  disabledTextInput: {
241
- color: '#000000',
241
+ color: colors.text,
242
242
  },
243
243
  leftIcon: {
244
244
  marginRight: 12,
@@ -41,7 +41,7 @@ export interface AppData {
41
41
  gender: string;
42
42
  mobNo: string;
43
43
  email: string;
44
- panNumber: string;
44
+ panNumber?: string;
45
45
  address?: string;
46
46
  area?: string;
47
47
  city?: string;
@@ -55,6 +55,7 @@ export interface AppData {
55
55
  maritalStatus?: string;
56
56
  userReferenceId?: string;
57
57
  eventNotifyUrl?: string;
58
+ startFDAlertMessage?: string;
58
59
  }
59
60
  /**
60
61
  * Initialize the SDK with app data from the main application
@@ -90,7 +91,7 @@ export declare const getUserInfoForAPI: () => {
90
91
  name: string;
91
92
  dob: string;
92
93
  gender: string;
93
- panNumber: string;
94
+ panNumber: string | undefined;
94
95
  mobileNumber: string;
95
96
  email: string;
96
97
  eventNotifyUrl: string | undefined;
@@ -54,7 +54,7 @@ const initializeSDK = (appData, onValidationError) => {
54
54
  { field: 'gender', label: 'Gender' },
55
55
  { field: 'mobNo', label: 'Mobile Number' },
56
56
  { field: 'email', label: 'Email' },
57
- { field: 'panNumber', label: 'PAN Number' },
57
+ // { field: 'panNumber', label: 'PAN Number' },
58
58
  ];
59
59
  const missingFields = [];
60
60
  requiredFields.forEach(({ field, label }) => {
@@ -203,7 +203,7 @@ exports.getUserDemographics = getUserDemographics;
203
203
  * Validate app data
204
204
  */
205
205
  const validateAppData = (appData) => {
206
- var _a, _b, _c, _d, _e, _f;
206
+ var _a, _b, _c, _d, _e;
207
207
  const errors = [];
208
208
  // Required fields validation
209
209
  if (!((_a = appData.id) === null || _a === void 0 ? void 0 : _a.trim()))
@@ -218,13 +218,13 @@ const validateAppData = (appData) => {
218
218
  errors.push('Mobile number is required');
219
219
  if (!((_e = appData.email) === null || _e === void 0 ? void 0 : _e.trim()))
220
220
  errors.push('Email is required');
221
- if (!((_f = appData.panNumber) === null || _f === void 0 ? void 0 : _f.trim()))
222
- errors.push('PAN number is required');
221
+ // PAN is optional validated later on FD Calculator screen
222
+ // if (!appData.panNumber?.trim()) errors.push('PAN number is required');
223
223
  // Format validation (only if fields are provided)
224
224
  if (appData.dob && !/^\d{4}-\d{2}-\d{2}$/.test(appData.dob)) {
225
225
  errors.push('Date of birth must be in YYYY-MM-DD format');
226
226
  }
227
- if (appData.panNumber && !/^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(appData.panNumber)) {
227
+ if (appData.panNumber && appData.panNumber.trim() && !/^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(appData.panNumber)) {
228
228
  errors.push('PAN number must be in valid format (e.g., ABCDE1234F)');
229
229
  }
230
230
  if (appData.mobNo && !/^[6-9]\d{9}$/.test(appData.mobNo)) {
@@ -1,23 +1,19 @@
1
1
  /**
2
2
  * usePaymentSSE - React Native SSE hook for payment status tracking.
3
3
  *
4
- * Mirrors the web app's usePaymentSSE (FDWebApplication/src/hooks/usePaymentSSE.ts).
5
- * Uses XMLHttpRequest instead of fetch+ReadableStream because
4
+ * Uses XMLHttpRequest instead of fetch streams because
6
5
  * React Native does not support ReadableStream / getReader().
7
6
  *
8
- * Backend spec:
9
- * Endpoint: GET /events?applicationId=<id>
10
- * Events: fd_payment_status, digilocker_verification_status
11
- * Format: Standard SSE → event: fd_payment_status\ndata: {"paymentStatus":"FAILED"}\n\n
12
- *
13
7
  * Usage:
14
8
  * const { start, stop } = usePaymentSSE();
15
- * start(applicationId, { onPaymentStatus: (status, payload) => { ... } });
16
- * stop();
9
+ * start(applicationId, {
10
+ * onPaymentStatus: (status, payload) => { ... },
11
+ * onError: (error) => { ... },
12
+ * });
13
+ * stop(); // to cancel
17
14
  */
18
- export interface UsePaymentSSECallbacks {
15
+ interface UsePaymentSSECallbacks {
19
16
  onPaymentStatus: (status: string, payload: Record<string, unknown>) => void;
20
- onDigilockerStatus?: (payload: Record<string, unknown>) => void;
21
17
  onError?: (error: any) => void;
22
18
  onConnected?: () => void;
23
19
  }
@@ -25,3 +21,4 @@ export declare function usePaymentSSE(): {
25
21
  start: (applicationId: string, callbacks: UsePaymentSSECallbacks) => void;
26
22
  stop: () => void;
27
23
  };
24
+ export {};
@@ -2,85 +2,34 @@
2
2
  /**
3
3
  * usePaymentSSE - React Native SSE hook for payment status tracking.
4
4
  *
5
- * Mirrors the web app's usePaymentSSE (FDWebApplication/src/hooks/usePaymentSSE.ts).
6
- * Uses XMLHttpRequest instead of fetch+ReadableStream because
5
+ * Uses XMLHttpRequest instead of fetch streams because
7
6
  * React Native does not support ReadableStream / getReader().
8
7
  *
9
- * Backend spec:
10
- * Endpoint: GET /events?applicationId=<id>
11
- * Events: fd_payment_status, digilocker_verification_status
12
- * Format: Standard SSE → event: fd_payment_status\ndata: {"paymentStatus":"FAILED"}\n\n
13
- *
14
8
  * Usage:
15
9
  * const { start, stop } = usePaymentSSE();
16
- * start(applicationId, { onPaymentStatus: (status, payload) => { ... } });
17
- * stop();
10
+ * start(applicationId, {
11
+ * onPaymentStatus: (status, payload) => { ... },
12
+ * onError: (error) => { ... },
13
+ * });
14
+ * stop(); // to cancel
18
15
  */
19
16
  Object.defineProperty(exports, "__esModule", { value: true });
20
17
  exports.usePaymentSSE = usePaymentSSE;
21
18
  const react_1 = require("react");
19
+ const sseParser_1 = require("../utils/sseParser");
22
20
  const appDataConfig_1 = require("../config/appDataConfig");
23
21
  const apiConfig_1 = require("../config/apiConfig");
24
- const baseApi_1 = require("../api/baseApi");
25
- const encryption_1 = require("../utils/encryption");
26
- const encryptionConfig_1 = require("../config/encryptionConfig");
27
- // ─── SSE Parser (standard format: event:/data: lines separated by \n\n) ─────
28
- function parseSSEBuffer(buffer, chunk) {
29
- const results = [];
30
- buffer.value += chunk;
31
- const delim = '\n\n';
32
- let idx;
33
- while ((idx = buffer.value.indexOf(delim)) >= 0) {
34
- const block = buffer.value.slice(0, idx);
35
- buffer.value = buffer.value.slice(idx + delim.length);
36
- let eventType = 'message';
37
- const dataParts = [];
38
- for (const line of block.split(/\r?\n/)) {
39
- if (line.startsWith('event:')) {
40
- eventType = line.slice(6).trim();
41
- }
42
- else if (line.startsWith('data:')) {
43
- dataParts.push(line.slice(5).trim());
44
- }
45
- }
46
- const data = dataParts.join('\n').trim();
47
- if (data)
48
- results.push({ eventType, data });
49
- }
50
- return results;
51
- }
52
- // ─── SSE Data Parser (handles encrypted responses) ──────────────────────────
53
- async function parseSSEData(raw) {
54
- const parsed = JSON.parse(raw || '{}');
55
- const encrypted = parsed === null || parsed === void 0 ? void 0 : parsed.encryptedResponse;
56
- if (typeof encrypted === 'string' && encrypted.length > 0) {
57
- try {
58
- const encryptionConfig = (0, encryptionConfig_1.getEncryptionConfig)();
59
- const decrypted = await (0, encryption_1.decryptResponse)({ encryptedResponse: encrypted }, encryptionConfig);
60
- return (decrypted || {});
61
- }
62
- catch (e) {
63
- if (__DEV__) {
64
- console.warn('[usePaymentSSE] Failed to decrypt SSE data, using raw:', e);
65
- }
66
- return parsed;
67
- }
68
- }
69
- return parsed;
70
- }
71
- // ─── Hook ───────────────────────────────────────────────────────────────────
22
+ // -- Hook --
72
23
  function usePaymentSSE() {
24
+ // Store the XMLHttpRequest so we can abort it later
73
25
  const xhrRef = (0, react_1.useRef)(null);
26
+ // Track how much of responseText we've already parsed
74
27
  const lastIndexRef = (0, react_1.useRef)(0);
28
+ // SSE text buffer (persists across onprogress calls)
75
29
  const bufferRef = (0, react_1.useRef)({ value: '' });
76
30
  const start = (0, react_1.useCallback)((applicationId, callbacks) => {
77
- var _a, _b;
78
- if (!(applicationId === null || applicationId === void 0 ? void 0 : applicationId.trim())) {
79
- if (__DEV__)
80
- console.warn('[usePaymentSSE] start() skipped: applicationId is empty');
81
- return;
82
- }
83
- // Clean up any existing connection
31
+ var _a;
32
+ // Clean up any existing connection first
84
33
  if (xhrRef.current) {
85
34
  xhrRef.current.abort();
86
35
  xhrRef.current = null;
@@ -88,113 +37,50 @@ function usePaymentSSE() {
88
37
  // Reset parsing state
89
38
  lastIndexRef.current = 0;
90
39
  bufferRef.current = { value: '' };
91
- // 1. Build URL
40
+ // 1. Build the SSE endpoint URL
92
41
  const envData = (0, appDataConfig_1.getEnvironmentData)();
93
42
  const apiConfig = (0, apiConfig_1.getApiConfig)();
94
43
  const baseUrl = (envData === null || envData === void 0 ? void 0 : envData.apiBaseUrl) || (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.baseUrl) || '';
95
44
  const url = `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}`;
96
- // 2. Create XHR
45
+ // 2. Create XMLHttpRequest
97
46
  const xhr = new XMLHttpRequest();
98
47
  xhrRef.current = xhr;
99
48
  xhr.open('GET', url);
100
- // 3. Set headers mirror web app's getApiHeaders() exactly
101
- // (Content-Type, x-api-key, onboarding IDs, userReferenceId, provider)
102
- xhr.setRequestHeader('Content-Type', 'application/json');
103
- xhr.setRequestHeader('Accept', 'text/event-stream');
104
- xhr.setRequestHeader('Cache-Control', 'no-cache');
105
- // API key
49
+ // 3. Set headers (same headers your baseApi interceptor uses)
106
50
  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']) || '';
107
51
  if (apiKey) {
108
52
  xhr.setRequestHeader('x-api-key', apiKey);
109
53
  }
110
- // Onboarding identifiers from Redux store
111
- const storeRef = (0, baseApi_1.getSDKStoreRef)();
112
- if (storeRef) {
113
- const state = storeRef.getState();
114
- const onboarding = state === null || state === void 0 ? void 0 : state.onboarding;
115
- if (onboarding === null || onboarding === void 0 ? void 0 : onboarding.workflowInstanceId) {
116
- xhr.setRequestHeader('workflowInstanceId', onboarding.workflowInstanceId);
117
- }
118
- if (onboarding === null || onboarding === void 0 ? void 0 : onboarding.applicationId) {
119
- xhr.setRequestHeader('applicationId', onboarding.applicationId);
120
- }
121
- if (onboarding === null || onboarding === void 0 ? void 0 : onboarding.entityid) {
122
- // Web app sends BOTH casings
123
- xhr.setRequestHeader('entityid', onboarding.entityid);
124
- xhr.setRequestHeader('entityId', onboarding.entityid);
125
- }
126
- if (onboarding === null || onboarding === void 0 ? void 0 : onboarding.providerId) {
127
- xhr.setRequestHeader('provider', onboarding.providerId);
128
- }
129
- }
130
- // userReferenceId from app data
131
- const appData = (0, appDataConfig_1.getAppData)();
132
- if (appData === null || appData === void 0 ? void 0 : appData.id) {
133
- xhr.setRequestHeader('userReferenceId', appData.id);
134
- }
54
+ xhr.setRequestHeader('Accept', 'text/event-stream');
55
+ xhr.setRequestHeader('Cache-Control', 'no-cache');
135
56
  // 4. Handle incoming data
136
57
  xhr.onprogress = () => {
58
+ var _a;
59
+ // responseText contains ALL text received so far
60
+ // Only parse the NEW text since last call
137
61
  const newText = xhr.responseText.slice(lastIndexRef.current);
138
62
  lastIndexRef.current = xhr.responseText.length;
139
63
  if (!newText)
140
64
  return;
141
- const events = parseSSEBuffer(bufferRef.current, newText);
65
+ // Parse new text into SSE events
66
+ const events = (0, sseParser_1.parseSSEBuffer)(bufferRef.current, newText);
67
+ // Handle each event
142
68
  for (const { eventType, data } of events) {
143
- if (!data)
144
- continue;
145
- const handlePaymentStatus = async () => {
146
- var _a;
69
+ if (eventType === 'fd_payment_status') {
147
70
  try {
148
- const parsed = await parseSSEData(data);
71
+ const parsed = JSON.parse(data);
149
72
  const status = ((_a = parsed.paymentStatus) !== null && _a !== void 0 ? _a : '').toUpperCase();
150
- if (__DEV__) {
151
- console.log('[usePaymentSSE] fd_payment_status:', { status, payload: parsed });
152
- }
153
73
  callbacks.onPaymentStatus(status, parsed);
154
74
  }
155
- catch (err) {
156
- if (__DEV__) {
157
- console.warn('[usePaymentSSE] Failed to parse fd_payment_status:', err);
158
- }
159
- }
160
- };
161
- const handleDigilockerStatus = async () => {
162
- var _a;
163
- try {
164
- const parsed = await parseSSEData(data);
165
- (_a = callbacks.onDigilockerStatus) === null || _a === void 0 ? void 0 : _a.call(callbacks, parsed);
166
- }
167
- catch (err) {
75
+ catch (parseError) {
168
76
  if (__DEV__) {
169
- console.warn('[usePaymentSSE] Failed to parse digilocker_verification_status:', err);
170
- }
171
- }
172
- };
173
- // Match event type — same logic as web app
174
- if (eventType === 'fd_payment_status') {
175
- handlePaymentStatus();
176
- }
177
- else if (eventType === 'digilocker_verification_status') {
178
- handleDigilockerStatus();
179
- }
180
- else if (eventType === 'message') {
181
- // Fallback: check "event" field inside the JSON data
182
- try {
183
- const parsed = JSON.parse(data);
184
- if (parsed.event === 'fd_payment_status') {
185
- handlePaymentStatus();
77
+ console.error('[usePaymentSSE] Failed to parse event data:', parseError);
186
78
  }
187
- else if (parsed.event === 'digilocker_verification_status') {
188
- handleDigilockerStatus();
189
- }
190
- }
191
- catch (_a) {
192
- // ignore
193
79
  }
194
80
  }
195
81
  }
196
82
  };
197
- // 5. Handle connection status
83
+ // 5. Handle successful connection
198
84
  xhr.onreadystatechange = () => {
199
85
  var _a, _b;
200
86
  if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
@@ -228,12 +114,10 @@ function usePaymentSSE() {
228
114
  }
229
115
  (_a = callbacks.onError) === null || _a === void 0 ? void 0 : _a.call(callbacks, new Error('SSE connection timed out'));
230
116
  };
231
- // 8. Send
117
+ // 8. Send the request (connection stays open)
232
118
  xhr.send();
233
119
  if (__DEV__) {
234
- const onboarding = (_b = storeRef === null || storeRef === void 0 ? void 0 : storeRef.getState()) === null || _b === void 0 ? void 0 : _b.onboarding;
235
- console.log('[usePaymentSSE] Connecting to:', url);
236
- console.log('[usePaymentSSE] Headers → apiKey:', !!apiKey, '| entityid:', onboarding === null || onboarding === void 0 ? void 0 : onboarding.entityid, '| applicationId:', onboarding === null || onboarding === void 0 ? void 0 : onboarding.applicationId, '| workflowInstanceId:', onboarding === null || onboarding === void 0 ? void 0 : onboarding.workflowInstanceId, '| providerId:', onboarding === null || onboarding === void 0 ? void 0 : onboarding.providerId, '| userReferenceId:', appData === null || appData === void 0 ? void 0 : appData.id);
120
+ console.log('[usePaymentSSE] Starting SSE connection to:', url);
237
121
  }
238
122
  }, []);
239
123
  const stop = (0, react_1.useCallback)(() => {
@@ -131,7 +131,7 @@ const RootNavigator = ({ config = {}, onExit }) => {
131
131
  } }, props)))),
132
132
  react_1.default.createElement(Stack.Screen, { name: "FDCalculator", options: { title: 'FD Calculator' } }, (props) => {
133
133
  var _a;
134
- return (react_1.default.createElement(FDCalculator_1.default, Object.assign({ onGoBack: () => (0, helpers_2.goBack)(), onNavigateToReviewKYC: () => { var _a; return (0, helpers_2.navigate)('ReviewKYC', { fdData: (_a = props.route.params) === null || _a === void 0 ? void 0 : _a.fdData }); }, fdData: (_a = props.route.params) === null || _a === void 0 ? void 0 : _a.fdData }, props)));
134
+ return (react_1.default.createElement(FDCalculator_1.default, Object.assign({ onGoBack: () => (0, helpers_2.goBack)(), onExitSDK: () => onExit === null || onExit === void 0 ? void 0 : onExit(), onNavigateToReviewKYC: () => { var _a; return (0, helpers_2.navigate)('ReviewKYC', { fdData: (_a = props.route.params) === null || _a === void 0 ? void 0 : _a.fdData }); }, fdData: (_a = props.route.params) === null || _a === void 0 ? void 0 : _a.fdData }, props)));
135
135
  }),
136
136
  react_1.default.createElement(Stack.Screen, { name: "AadhaarVerification", options: { title: 'Aadhaar Verification' } }, (props) => (react_1.default.createElement(AadhaarVerification_1.default, Object.assign({ onGoBack: () => (0, helpers_2.goBack)(), onVerificationComplete: (aadhaarNumber) => {
137
137
  // Navigate to Employee (occupation) screen after verification
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  export interface FDCalculatorProps {
3
3
  onGoBack?: () => void;
4
+ onExitSDK?: () => void;
4
5
  onNavigateToReviewKYC?: () => void;
5
6
  fdData?: {
6
7
  id: string;
@@ -55,7 +55,7 @@ const fdListSelectedSlice_1 = require("../store/fdListSelectedSlice");
55
55
  const helpers_1 = require("../navigation/helpers");
56
56
  const strings_1 = require("../constants/strings");
57
57
  const base64Images_1 = require("../constants/strings/base64Images");
58
- const FDCalculator = ({ onGoBack, onNavigateToReviewKYC, fdData }) => {
58
+ const FDCalculator = ({ onGoBack, onExitSDK, onNavigateToReviewKYC, fdData }) => {
59
59
  const typography = (0, ThemeContext_1.useTypography)();
60
60
  const colors = (0, ThemeContext_1.useColors)();
61
61
  const { themeName } = (0, ThemeContext_1.useTheme)();
@@ -312,7 +312,7 @@ const FDCalculator = ({ onGoBack, onNavigateToReviewKYC, fdData }) => {
312
312
  }, [debounceTimer, handleCalculateFD, payoutValue]);
313
313
  // Function to call onboarding API
314
314
  const handleStartOnboarding = react_1.default.useCallback(async (selectedPayout) => {
315
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
315
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
316
316
  if (isBooking)
317
317
  return;
318
318
  setIsBooking(true);
@@ -331,20 +331,35 @@ const FDCalculator = ({ onGoBack, onNavigateToReviewKYC, fdData }) => {
331
331
  if (amountValue < 5000) {
332
332
  return;
333
333
  }
334
+ const appData = (0, appDataConfig_1.getAppData)();
335
+ const hasEssentialData = (_a = appData === null || appData === void 0 ? void 0 : appData.panNumber) === null || _a === void 0 ? void 0 : _a.trim();
336
+ if (!hasEssentialData) {
337
+ const alertMessage = (appData === null || appData === void 0 ? void 0 : appData.startFDAlertMessage) || 'Please complete your KYC details to start an FD, Update your profile in the app and try again.';
338
+ react_native_1.Alert.alert('Action Required', alertMessage, [
339
+ {
340
+ text: 'OK',
341
+ onPress: () => {
342
+ if (onExitSDK) {
343
+ onExitSDK();
344
+ }
345
+ },
346
+ },
347
+ ], { cancelable: false });
348
+ return;
349
+ }
334
350
  // Get providerId from interest rates data
335
- const sdr = ((_a = interestRates === null || interestRates === void 0 ? void 0 : interestRates.data) === null || _a === void 0 ? void 0 : _a.sdrScheme) || [];
336
- const fdr = ((_b = interestRates === null || interestRates === void 0 ? void 0 : interestRates.data) === null || _b === void 0 ? void 0 : _b.fdrScheme) || [];
351
+ const sdr = ((_b = interestRates === null || interestRates === void 0 ? void 0 : interestRates.data) === null || _b === void 0 ? void 0 : _b.sdrScheme) || [];
352
+ const fdr = ((_c = interestRates === null || interestRates === void 0 ? void 0 : interestRates.data) === null || _c === void 0 ? void 0 : _c.fdrScheme) || [];
337
353
  const firstRate = sdr[0] || fdr[0];
338
354
  const providerId = firstRate === null || firstRate === void 0 ? void 0 : firstRate.providerId;
339
355
  // Get user data for all required fields
340
- const appData = (0, appDataConfig_1.getAppData)();
341
356
  const userDob = (appData === null || appData === void 0 ? void 0 : appData.dob) || '1990-01-01';
342
357
  const isWomenDepositor = (appData === null || appData === void 0 ? void 0 : appData.gender) === 'F';
343
358
  // Get calculated values from API response based on investment type
344
359
  const investmentType = payoutValue === 'On Maturity' ? 'SDR' : 'FDR';
345
360
  const calcData = investmentType === 'SDR'
346
- ? (_d = (_c = calculationResult === null || calculationResult === void 0 ? void 0 : calculationResult.data) === null || _c === void 0 ? void 0 : _c.sdrCalc) === null || _d === void 0 ? void 0 : _d[0]
347
- : (_f = (_e = calculationResult === null || calculationResult === void 0 ? void 0 : calculationResult.data) === null || _e === void 0 ? void 0 : _e.fdrCalc) === null || _f === void 0 ? void 0 : _f[0];
361
+ ? (_e = (_d = calculationResult === null || calculationResult === void 0 ? void 0 : calculationResult.data) === null || _d === void 0 ? void 0 : _d.sdrCalc) === null || _e === void 0 ? void 0 : _e[0]
362
+ : (_g = (_f = calculationResult === null || calculationResult === void 0 ? void 0 : calculationResult.data) === null || _f === void 0 ? void 0 : _f.fdrCalc) === null || _g === void 0 ? void 0 : _g[0];
348
363
  const interestRate = calcData === null || calcData === void 0 ? void 0 : calcData.wRoi;
349
364
  const maturityAmount = calcData === null || calcData === void 0 ? void 0 : calcData.maturityAmount;
350
365
  // Calculate maturity date
@@ -356,8 +371,8 @@ const FDCalculator = ({ onGoBack, onNavigateToReviewKYC, fdData }) => {
356
371
  mobile: (appData === null || appData === void 0 ? void 0 : appData.mobNo) || '',
357
372
  prefix: (appData === null || appData === void 0 ? void 0 : appData.gender) === 'M' ? 'Mr.' : ((appData === null || appData === void 0 ? void 0 : appData.gender) === 'F' ? 'Ms.' : 'Mr.'),
358
373
  fullName: (appData === null || appData === void 0 ? void 0 : appData.name) || '',
359
- firstName: ((_g = appData === null || appData === void 0 ? void 0 : appData.name) === null || _g === void 0 ? void 0 : _g.split(' ')[0]) || '',
360
- lastName: ((_h = appData === null || appData === void 0 ? void 0 : appData.name) === null || _h === void 0 ? void 0 : _h.split(' ').slice(1).join(' ')) || '',
374
+ firstName: ((_h = appData === null || appData === void 0 ? void 0 : appData.name) === null || _h === void 0 ? void 0 : _h.split(' ')[0]) || '',
375
+ lastName: ((_j = appData === null || appData === void 0 ? void 0 : appData.name) === null || _j === void 0 ? void 0 : _j.split(' ').slice(1).join(' ')) || '',
361
376
  userReferenceId: (appData === null || appData === void 0 ? void 0 : appData.id) || '',
362
377
  dob: userDob,
363
378
  email: (appData === null || appData === void 0 ? void 0 : appData.email) || '',
@@ -403,11 +418,11 @@ const FDCalculator = ({ onGoBack, onNavigateToReviewKYC, fdData }) => {
403
418
  // Persist onboarding identifiers globally for subsequent API calls
404
419
  try {
405
420
  const ids = {
406
- workflowInstanceId: (_j = result === null || result === void 0 ? void 0 : result.data) === null || _j === void 0 ? void 0 : _j.workflowInstanceId,
407
- applicationId: (_k = result === null || result === void 0 ? void 0 : result.data) === null || _k === void 0 ? void 0 : _k.applicationId,
408
- entityid: (_l = result === null || result === void 0 ? void 0 : result.data) === null || _l === void 0 ? void 0 : _l.entityid,
409
- customerId: (_m = result === null || result === void 0 ? void 0 : result.data) === null || _m === void 0 ? void 0 : _m.customerId,
410
- fdId: (_o = result === null || result === void 0 ? void 0 : result.data) === null || _o === void 0 ? void 0 : _o.fdId,
421
+ workflowInstanceId: (_k = result === null || result === void 0 ? void 0 : result.data) === null || _k === void 0 ? void 0 : _k.workflowInstanceId,
422
+ applicationId: (_l = result === null || result === void 0 ? void 0 : result.data) === null || _l === void 0 ? void 0 : _l.applicationId,
423
+ entityid: (_m = result === null || result === void 0 ? void 0 : result.data) === null || _m === void 0 ? void 0 : _m.entityid,
424
+ customerId: (_o = result === null || result === void 0 ? void 0 : result.data) === null || _o === void 0 ? void 0 : _o.customerId,
425
+ fdId: (_p = result === null || result === void 0 ? void 0 : result.data) === null || _p === void 0 ? void 0 : _p.fdId,
411
426
  };
412
427
  if (dispatch && setOnboardingIds) {
413
428
  dispatch(setOnboardingIds(ids));