@test-web/react-native-sdk 1.0.0 → 2.0.0

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.
Files changed (125) hide show
  1. package/README.md +824 -26
  2. package/assets/images/Chrome-logo.svg +1 -0
  3. package/assets/images/Firefox-logo.png +0 -0
  4. package/assets/images/IDM-logo.jpg +0 -0
  5. package/assets/images/MRZOverlay.png +0 -0
  6. package/assets/images/Safari-logo.png +0 -0
  7. package/assets/images/aadhar.png +0 -0
  8. package/assets/images/camera-bg.png +0 -0
  9. package/assets/images/card-overlay-back.png +0 -0
  10. package/assets/images/card-overlay.png +0 -0
  11. package/assets/images/card-scan-back-icon.jpg +0 -0
  12. package/assets/images/card-scan-front-icon.png +0 -0
  13. package/assets/images/card-scan-icon-aadhaar-1.png +0 -0
  14. package/assets/images/card-scan-icon-aadhaar-back.png +0 -0
  15. package/assets/images/card-scan-icon-aadhaar-scan-qr.png +0 -0
  16. package/assets/images/card-scan-icon-aadhaar.png +0 -0
  17. package/assets/images/card-scan-icon-can-pr.png +0 -0
  18. package/assets/images/card-scan-icon-default-back.png +0 -0
  19. package/assets/images/card-scan-icon-dl.png +0 -0
  20. package/assets/images/card-scan-icon-greencard-back.jpg +0 -0
  21. package/assets/images/card-scan-icon-greencard.jpg +0 -0
  22. package/assets/images/card-scan-icon-hc.png +0 -0
  23. package/assets/images/card-scan-icon-ni-argentina-back.jpg +0 -0
  24. package/assets/images/card-scan-icon-ni-argentina-old.png +0 -0
  25. package/assets/images/card-scan-icon-ni-argentina.jpg +0 -0
  26. package/assets/images/card-scan-icon-ni-barcode.jpg +0 -0
  27. package/assets/images/card-scan-icon-ni-brazil-back.jpg +0 -0
  28. package/assets/images/card-scan-icon-ni-brazil.jpg +0 -0
  29. package/assets/images/card-scan-icon-ni-dominican-republic-back.png +0 -0
  30. package/assets/images/card-scan-icon-ni-dominican-republic-front.png +0 -0
  31. package/assets/images/card-scan-icon-ni-dominican-republic-mrz.png +0 -0
  32. package/assets/images/card-scan-icon-ni-dominicanaRepublic-back.jpg +0 -0
  33. package/assets/images/card-scan-icon-ni-france-back.png +0 -0
  34. package/assets/images/card-scan-icon-ni-france-front.png +0 -0
  35. package/assets/images/card-scan-icon-ni-france-scan-mrz.png +0 -0
  36. package/assets/images/card-scan-icon-ni-germany-back.jpg +0 -0
  37. package/assets/images/card-scan-icon-ni-germany.jpg +0 -0
  38. package/assets/images/card-scan-icon-ni-paraguay-back.png +0 -0
  39. package/assets/images/card-scan-icon-ni-paraguay-front.png +0 -0
  40. package/assets/images/card-scan-icon-ni-paraguay-scan-mrz.png +0 -0
  41. package/assets/images/card-scan-icon-ni-uae-back.png +0 -0
  42. package/assets/images/card-scan-icon-ni-uae-front.png +0 -0
  43. package/assets/images/card-scan-icon-ni-uae-scan-mrz.png +0 -0
  44. package/assets/images/card-scan-icon-ni-uganda-front.png +0 -0
  45. package/assets/images/card-scan-icon-ni-uganda-scan-mrz.png +0 -0
  46. package/assets/images/card-scan-icon-ni-ukrain-back.png +0 -0
  47. package/assets/images/card-scan-icon-ni-ukrain-front.png +0 -0
  48. package/assets/images/card-scan-icon-ni-ukrain-scan-mrz.png +0 -0
  49. package/assets/images/card-scan-icon-ni.png +0 -0
  50. package/assets/images/card-scan-icon-old.jpg +0 -0
  51. package/assets/images/card-scan-icon-pan.png +0 -0
  52. package/assets/images/card-scan-icon-passport-card-back.jpg +0 -0
  53. package/assets/images/card-scan-icon-passport-card.jpg +0 -0
  54. package/assets/images/card-scan-icon-passport-old.png +0 -0
  55. package/assets/images/card-scan-icon-passport.png +0 -0
  56. package/assets/images/card-scan-icon-pr.png +0 -0
  57. package/assets/images/card-scan-icon.jpg +0 -0
  58. package/assets/images/check.png +0 -0
  59. package/assets/images/chrome-animation-GPS-permissions-setting.gif +0 -0
  60. package/assets/images/chrome-animation-camera-permissions-setting.gif +0 -0
  61. package/assets/images/denied.png +0 -0
  62. package/assets/images/dl.png +0 -0
  63. package/assets/images/driver-license.png +0 -0
  64. package/assets/images/firefox-animation-permissions-setting.gif +0 -0
  65. package/assets/images/flashlight_on.png +0 -0
  66. package/assets/images/gallery.png +0 -0
  67. package/assets/images/greencard.png +0 -0
  68. package/assets/images/header.jpg +0 -0
  69. package/assets/images/health-card.png +0 -0
  70. package/assets/images/ic_camera_front_white_36px.svg +4 -0
  71. package/assets/images/ic_camera_rear_white_36px.svg +4 -0
  72. package/assets/images/ic_fullscreen_exit_white_48px.svg +4 -0
  73. package/assets/images/ic_fullscreen_white_48px.svg +4 -0
  74. package/assets/images/ic_photo_camera_white_48px.svg +5 -0
  75. package/assets/images/id-card.png +0 -0
  76. package/assets/images/idcardimg.png +0 -0
  77. package/assets/images/idmval-barcode.png +0 -0
  78. package/assets/images/information.png +0 -0
  79. package/assets/images/loader.gif +0 -0
  80. package/assets/images/loading.svg +1 -0
  81. package/assets/images/logo.jpg +0 -0
  82. package/assets/images/logo.png +0 -0
  83. package/assets/images/mrz-back.png +0 -0
  84. package/assets/images/mrz-ni.png +0 -0
  85. package/assets/images/mrz.png +0 -0
  86. package/assets/images/mrz1.png +0 -0
  87. package/assets/images/mrz_old.png +0 -0
  88. package/assets/images/mrz_small.png +0 -0
  89. package/assets/images/national-id.png +0 -0
  90. package/assets/images/nationalID.png +0 -0
  91. package/assets/images/no-wifi.png +0 -0
  92. package/assets/images/passport-card.png +0 -0
  93. package/assets/images/passport.png +0 -0
  94. package/assets/images/permit-card.png +0 -0
  95. package/assets/images/photo-overlay.png +0 -0
  96. package/assets/images/placeholder.jpg +0 -0
  97. package/assets/images/qr-code.png +0 -0
  98. package/assets/images/right-checkmark.jpg +0 -0
  99. package/assets/images/selfie.jpg +0 -0
  100. package/assets/images/showing-sec.png +0 -0
  101. package/assets/images/spinner.gif +0 -0
  102. package/assets/images/splash-icon.png +0 -0
  103. package/assets/images/take-selfie.jpg +0 -0
  104. package/assets/images/torch_off.png +0 -0
  105. package/assets/images/warning-icon.jpg +0 -0
  106. package/assets/images/warning-stick.jpg +0 -0
  107. package/assets/images/wrong-checkmark.jpg +0 -0
  108. package/package.json +44 -8
  109. package/src/apis/index.ts +338 -17
  110. package/src/components/common/Loader.tsx +16 -2
  111. package/src/config/apiConfig.ts +6 -0
  112. package/src/index.tsx +123 -7
  113. package/src/screens/BarcodeCapture.tsx +154 -24
  114. package/src/screens/DocumentCaptureBack.tsx +133 -24
  115. package/src/screens/DocumentCaptureFront.tsx +146 -24
  116. package/src/screens/MrzCapture.tsx +205 -16
  117. package/src/screens/SelectDocuments.tsx +37 -56
  118. package/src/screens/SelfieCapture.tsx +114 -18
  119. package/src/screens/ThankYou.tsx +34 -1
  120. package/src/services/getUserData.ts +111 -0
  121. package/src/types/IDMConf.ts +81 -7
  122. package/src/utils/base64.ts +25 -0
  123. package/src/utils/flowManager.ts +138 -0
  124. package/src/utils/imageProcessor.ts +96 -0
  125. package/src/utils/index.ts +18 -0
package/src/apis/index.ts CHANGED
@@ -1,32 +1,353 @@
1
1
  import { IDMConf } from '../types/IDMConf';
2
+ import { getBaseURL } from '../config/apiConfig';
3
+ import { base64Encode } from '../utils/base64';
4
+ import getUserData from '../services/getUserData';
2
5
 
3
- export async function getUserData(): Promise<any> {
4
- // Static implementation - replace with actual API call
5
- return {
6
- permissionGranted: true,
7
- };
6
+ /**
7
+ * Get user data including location, device info, and permissions
8
+ */
9
+ export async function getUserDataAPI(): Promise<any> {
10
+ return await getUserData();
8
11
  }
9
12
 
13
+ /**
14
+ * Generate access token using client credentials
15
+ */
10
16
  export async function generateAccessToken(conf: IDMConf): Promise<string> {
11
- // Static implementation - replace with actual API call
12
- return 'static-access-token';
17
+ const { clientID, clientSecret, environment } = conf;
18
+
19
+ if (!clientID || !clientSecret) {
20
+ throw new Error('clientID and clientSecret are required.');
21
+ }
22
+
23
+ const URL = `${getBaseURL(environment)}/token`;
24
+ const encodedCredentials = base64Encode(`${clientID}:${clientSecret}`);
25
+ const params = new URLSearchParams({
26
+ grant_type: 'client_credentials',
27
+ scope: 'idmvalidate',
28
+ });
29
+
30
+ try {
31
+ const response = await fetch(URL, {
32
+ method: 'POST',
33
+ headers: {
34
+ 'Content-Type': 'application/x-www-form-urlencoded',
35
+ Authorization: `Basic ${encodedCredentials}`,
36
+ },
37
+ body: params.toString(),
38
+ });
39
+
40
+ if (!response.ok) {
41
+ const errorBody = await response.text();
42
+ throw new Error(
43
+ `Failed to generate access token: ${response.status} ${response.statusText} - ${errorBody}`
44
+ );
45
+ }
46
+
47
+ const data = await response.json();
48
+ return data.access_token;
49
+ } catch (error: any) {
50
+ console.error('Error generating access token:', error);
51
+ throw new Error(`Failed to generate access token: ${error.message}`);
52
+ }
13
53
  }
14
54
 
55
+ /**
56
+ * Generate verification request
57
+ */
15
58
  export async function generateRequest(conf: IDMConf, requestData: any): Promise<any> {
16
- // Static implementation - replace with actual API call
17
- return {
18
- verificationCode: 'static-verification-code',
19
- };
59
+ if (!conf.accessToken) {
60
+ throw new Error('Access token is missing');
61
+ }
62
+
63
+ const URL = `${getBaseURL(conf.environment)}/verify`;
64
+
65
+ try {
66
+ const response = await fetch(URL, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ Authorization: `Bearer ${conf.accessToken}`,
71
+ },
72
+ body: JSON.stringify(requestData),
73
+ });
74
+
75
+ if (!response.ok) {
76
+ const errorBody = await response.text();
77
+ throw new Error(
78
+ `API call failed: ${response.status} ${response.statusText} - ${errorBody}`
79
+ );
80
+ }
81
+
82
+ const data = await response.json();
83
+ const verificationCode = data.verificationLink?.split('/').pop() || null;
84
+ return {
85
+ ...data,
86
+ verificationCode,
87
+ };
88
+ } catch (error: any) {
89
+ console.error('generateRequest error:', error);
90
+ throw new Error(`generateRequest failed: ${error.message}`);
91
+ }
20
92
  }
21
93
 
94
+ /**
95
+ * Get configuration for verification
96
+ */
22
97
  export async function getConfiguration(conf: IDMConf, verificationCode: string): Promise<any> {
23
- // Static implementation - replace with actual API call
24
- return {
25
- // Your configuration data
26
- };
98
+ if (!conf.accessToken) {
99
+ throw new Error('Access token is missing');
100
+ }
101
+
102
+ const URL = `${getBaseURL(conf.environment)}/verify/configuration/${verificationCode}`;
103
+
104
+ try {
105
+ const response = await fetch(URL, {
106
+ method: 'GET',
107
+ headers: {
108
+ 'Content-Type': 'application/json',
109
+ Authorization: `Bearer ${conf.accessToken}`,
110
+ },
111
+ });
112
+
113
+ if (!response.ok) {
114
+ const errorBody = await response.text();
115
+ throw new Error(
116
+ `API call failed: ${response.status} ${response.statusText} - ${errorBody}`
117
+ );
118
+ }
119
+
120
+ const data = await response.json();
121
+ return data;
122
+ } catch (error: any) {
123
+ console.error('getConfiguration error:', error);
124
+ throw new Error(`getConfiguration failed: ${error.message}`);
125
+ }
27
126
  }
28
127
 
128
+ /**
129
+ * Get list of countries with metadata
130
+ */
29
131
  export async function getCountries(conf: IDMConf): Promise<any> {
30
- // Static implementation - replace with actual API call
31
- return [];
132
+ if (!conf.accessToken) {
133
+ throw new Error('Access token is missing');
134
+ }
135
+
136
+ const URL = `${getBaseURL(conf.environment)}/metadata/country/list/${conf.verificationCode}`;
137
+
138
+ try {
139
+ const response = await fetch(URL, {
140
+ method: 'GET',
141
+ headers: {
142
+ 'Content-Type': 'application/json',
143
+ Authorization: `Bearer ${conf.accessToken}`,
144
+ },
145
+ });
146
+
147
+ if (!response.ok) {
148
+ const errorBody = await response.text();
149
+ throw new Error(
150
+ `Failed to load countries: ${response.status} ${response.statusText} - ${errorBody}`
151
+ );
152
+ }
153
+
154
+ const data = await response.json();
155
+ return data;
156
+ } catch (error: any) {
157
+ console.error('getCountries error:', error);
158
+ throw new Error(`getCountries failed: ${error.message}`);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Capture document front image
164
+ */
165
+ export async function captureDocumentFront(
166
+ conf: IDMConf,
167
+ requestData: {
168
+ latitude: string;
169
+ longitude: string;
170
+ token: string;
171
+ persistLoc: string;
172
+ metadataIndex: string;
173
+ file: string;
174
+ }
175
+ ): Promise<any> {
176
+ if (!conf.accessToken) {
177
+ throw new Error('Access token is missing');
178
+ }
179
+
180
+ const URL = `${getBaseURL(conf.environment)}/ocr/base64/document`;
181
+
182
+ try {
183
+ const formData = new FormData();
184
+ formData.append('file', requestData.file);
185
+ formData.append('token', requestData.token);
186
+ formData.append('latitude', requestData.latitude);
187
+ formData.append('longitude', requestData.longitude);
188
+ formData.append('persistLoc', 'false');
189
+ formData.append('metadataIndex', requestData.metadataIndex);
190
+
191
+ const response = await fetch(URL, {
192
+ method: 'POST',
193
+ headers: {
194
+ Authorization: `Bearer ${conf.accessToken}`,
195
+ },
196
+ body: formData,
197
+ });
198
+
199
+ const data = await response.json();
200
+ return data;
201
+ } catch (error: any) {
202
+ console.error('captureDocumentFront error:', error);
203
+ throw new Error(`captureDocumentFront failed: ${error.message}`);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Capture document back image
209
+ */
210
+ export async function captureDocumentBack(
211
+ conf: IDMConf,
212
+ requestData: {
213
+ token: string;
214
+ file: string;
215
+ }
216
+ ): Promise<any> {
217
+ if (!conf.accessToken) {
218
+ throw new Error('Access token is missing');
219
+ }
220
+
221
+ const URL = `${getBaseURL(conf.environment)}/ocr/document/text/back`;
222
+
223
+ try {
224
+ const formData = new FormData();
225
+ formData.append('file', requestData.file);
226
+ formData.append('token', requestData.token);
227
+
228
+ const response = await fetch(URL, {
229
+ method: 'POST',
230
+ headers: {
231
+ Authorization: `Bearer ${conf.accessToken}`,
232
+ },
233
+ body: formData,
234
+ });
235
+
236
+ const data = await response.json();
237
+ return data;
238
+ } catch (error: any) {
239
+ console.error('captureDocumentBack error:', error);
240
+ throw new Error(`captureDocumentBack failed: ${error.message}`);
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Capture barcode data
246
+ */
247
+ export async function captureBarcode(
248
+ conf: IDMConf,
249
+ requestData: {
250
+ token: string;
251
+ text: string;
252
+ }
253
+ ): Promise<any> {
254
+ if (!conf.accessToken) {
255
+ throw new Error('Access token is missing');
256
+ }
257
+
258
+ const URL = `${getBaseURL(conf.environment)}/ocr/base64/barcode/text`;
259
+
260
+ try {
261
+ const formData = new FormData();
262
+ formData.append('text', requestData.text);
263
+ formData.append('token', requestData.token);
264
+
265
+ const response = await fetch(URL, {
266
+ method: 'POST',
267
+ headers: {
268
+ Authorization: `Bearer ${conf.accessToken}`,
269
+ },
270
+ body: formData,
271
+ });
272
+
273
+ const data = await response.json();
274
+ return data;
275
+ } catch (error: any) {
276
+ console.error('captureBarcode error:', error);
277
+ throw new Error(`captureBarcode failed: ${error.message}`);
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Capture MRZ data
283
+ */
284
+ export async function captureMRZ(
285
+ conf: IDMConf,
286
+ requestData: {
287
+ token: string;
288
+ code: string;
289
+ engine: string;
290
+ }
291
+ ): Promise<any> {
292
+ if (!conf.accessToken) {
293
+ throw new Error('Access token is missing');
294
+ }
295
+
296
+ const URL = `${getBaseURL(conf.environment)}/ocr/mrz/text`;
297
+
298
+ try {
299
+ const formData = new FormData();
300
+ formData.append('token', requestData.token);
301
+ formData.append('code', requestData.code);
302
+ formData.append('engine', requestData.engine);
303
+
304
+ const response = await fetch(URL, {
305
+ method: 'POST',
306
+ headers: {
307
+ Authorization: `Bearer ${conf.accessToken}`,
308
+ },
309
+ body: formData,
310
+ });
311
+
312
+ const data = await response.json();
313
+ return data;
314
+ } catch (error: any) {
315
+ console.error('captureMRZ error:', error);
316
+ throw new Error(`captureMRZ failed: ${error.message}`);
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Complete verification process
322
+ */
323
+ export async function completeVerification(conf: IDMConf): Promise<any> {
324
+ if (!conf.accessToken) {
325
+ throw new Error('Access token is missing');
326
+ }
327
+
328
+ const URL = `${getBaseURL(conf.environment)}/verify/complete/${conf.verificationCode}`;
329
+
330
+ try {
331
+ const response = await fetch(URL, {
332
+ method: 'POST',
333
+ headers: {
334
+ 'Content-Type': 'application/json',
335
+ Authorization: `Bearer ${conf.accessToken}`,
336
+ },
337
+ });
338
+
339
+ if (!response.ok) {
340
+ const errorBody = await response.text();
341
+ throw new Error(
342
+ `API call failed: ${response.status} ${response.statusText} - ${errorBody}`
343
+ );
344
+ }
345
+
346
+ const data = await response.json();
347
+ return data;
348
+ } catch (error: any) {
349
+ console.error('completeVerification error:', error);
350
+ throw new Error(`completeVerification failed: ${error.message}`);
351
+ }
32
352
  }
353
+
@@ -1,13 +1,22 @@
1
1
  import React, { memo } from 'react';
2
- import { View, ActivityIndicator, StyleSheet } from 'react-native';
2
+ import { View, ActivityIndicator, StyleSheet, Text } from 'react-native';
3
3
  import { useTheme } from '../../context/ThemeContext';
4
4
 
5
- function Loader() {
5
+ interface LoaderProps {
6
+ message?: string;
7
+ }
8
+
9
+ function Loader({ message }: LoaderProps) {
6
10
  const { theme } = useTheme();
7
11
 
8
12
  return (
9
13
  <View style={[styles.container, { backgroundColor: theme.colors.background }]}>
10
14
  <ActivityIndicator size="large" color={theme.colors.primary} />
15
+ {message && (
16
+ <Text style={[styles.message, { color: theme.colors.text }]}>
17
+ {message}
18
+ </Text>
19
+ )}
11
20
  </View>
12
21
  );
13
22
  }
@@ -18,6 +27,11 @@ const styles = StyleSheet.create({
18
27
  justifyContent: 'center',
19
28
  alignItems: 'center',
20
29
  },
30
+ message: {
31
+ marginTop: 16,
32
+ fontSize: 16,
33
+ textAlign: 'center',
34
+ },
21
35
  });
22
36
 
23
37
  export default memo(Loader);
@@ -0,0 +1,6 @@
1
+ export const SANDBOX_BASE_URL = 'https://sandbox-api.idmerit.com';
2
+ export const PRODUCTION_BASE_URL = 'https://api.idmerit.com';
3
+
4
+ export const getBaseURL = (environment: 'sandbox' | 'production'): string => {
5
+ return environment?.toLowerCase() === 'sandbox' ? SANDBOX_BASE_URL : PRODUCTION_BASE_URL;
6
+ };
package/src/index.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useMemo, useCallback } from 'react';
1
+ import React, { useState, useMemo, useCallback, useEffect } from 'react';
2
2
  import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
3
3
  import { createNativeStackNavigator } from '@react-navigation/native-stack';
4
4
  import BarcodeCapture from './screens/BarcodeCapture';
@@ -21,10 +21,18 @@ import MrzAdvice from './screens/MrzAdvice';
21
21
  import { ThemeProvider } from './context/ThemeContext';
22
22
  import { themes } from './context/themes';
23
23
  import { IDMConf } from './types/IDMConf';
24
- import { IDMProvider } from './context/IDMConfigurationContext';
24
+ import { IDMProvider, useIDM } from './context/IDMConfigurationContext';
25
25
  import { KeyboardProvider, useKeyboard } from './context/KeyboardContext';
26
26
  import Footer from './components/common/Footer';
27
27
  import Header from './components/common/Header';
28
+ import Loader from './components/common/Loader';
29
+ import {
30
+ getUserDataAPI,
31
+ generateAccessToken,
32
+ generateRequest,
33
+ getConfiguration,
34
+ getCountries,
35
+ } from './apis';
28
36
 
29
37
  const Stack = createNativeStackNavigator();
30
38
 
@@ -41,23 +49,26 @@ const HIDE_HEADER_FOOTER_ROUTES = new Set([
41
49
  ]);
42
50
 
43
51
  interface IDMScanProps {
44
- idmConf?: IDMConf;
52
+ idmConf: IDMConf;
45
53
  }
46
54
 
47
- export default function IDMScan({ idmConf = {} }: IDMScanProps) {
55
+ export default function IDMScan({ idmConf }: IDMScanProps) {
48
56
  return (
49
57
  <IDMProvider initialConf={idmConf}>
50
58
  <KeyboardProvider>
51
- <IDMScanContent idmConf={idmConf} />
59
+ <IDMScanContent />
52
60
  </KeyboardProvider>
53
61
  </IDMProvider>
54
62
  );
55
63
  }
56
64
 
57
- function IDMScanContent({ idmConf }: { idmConf: IDMConf }) {
65
+ function IDMScanContent() {
58
66
  const { isKeyboardVisible } = useKeyboard();
67
+ const { idmConf, setIDMConf } = useIDM();
59
68
  const navigationRef = useNavigationContainerRef();
60
69
  const [currentRoute, setCurrentRoute] = useState<string | undefined>();
70
+ const [loading, setLoading] = useState(true);
71
+ const [error, setError] = useState<string | null>(null);
61
72
 
62
73
  // Memoize theme calculation
63
74
  const theme = useMemo(
@@ -80,11 +91,116 @@ function IDMScanContent({ idmConf }: { idmConf: IDMConf }) {
80
91
  setCurrentRoute(route?.name);
81
92
  }, [navigationRef]);
82
93
 
94
+ // Dynamic initialization flow
95
+ useEffect(() => {
96
+ const initializeSDK = async () => {
97
+ try {
98
+ setLoading(true);
99
+ setError(null);
100
+
101
+ // Step 1: Get user data if not provided
102
+ if (!idmConf.userDetails) {
103
+ console.log('Fetching user data...');
104
+ const userData = await getUserDataAPI();
105
+ const updatedConf = { ...idmConf, userDetails: userData };
106
+ setIDMConf(updatedConf);
107
+
108
+ // Step 2: Generate access token if not provided
109
+ if (!idmConf.accessToken) {
110
+ console.log('Generating access token...');
111
+ const token = await generateAccessToken(updatedConf);
112
+ const confWithToken = { ...updatedConf, accessToken: token };
113
+ setIDMConf(confWithToken);
114
+
115
+ // Step 3: Generate verification request
116
+ console.log('Generating verification request...');
117
+ const requestResult = await generateRequest(confWithToken, idmConf.requestData);
118
+ const confWithVerifyCode = {
119
+ ...confWithToken,
120
+ verificationCode: requestResult.verificationCode,
121
+ };
122
+ setIDMConf(confWithVerifyCode);
123
+
124
+ // Step 4: Get configuration
125
+ console.log('Fetching configuration...');
126
+ const fetchedConfig = await getConfiguration(
127
+ confWithVerifyCode,
128
+ requestResult.verificationCode
129
+ );
130
+ setIDMConf({
131
+ ...confWithVerifyCode,
132
+ configuration: fetchedConfig,
133
+ });
134
+ }
135
+ }
136
+ } catch (err: any) {
137
+ console.error('SDK initialization error:', err);
138
+ setError(err.message || 'Failed to initialize SDK');
139
+ } finally {
140
+ setLoading(false);
141
+ }
142
+ };
143
+
144
+ initializeSDK();
145
+ }, []); // Run once on mount
146
+
147
+ // Fetch countries when access token and verification code are available
148
+ useEffect(() => {
149
+ const fetchCountriesData = async () => {
150
+ if (idmConf.accessToken && idmConf.verificationCode && !idmConf.countryDetails) {
151
+ try {
152
+ console.log('Fetching countries...');
153
+ const response = await getCountries(idmConf);
154
+ const countriesArray = Array.isArray(response) ? response : response?.data || [];
155
+
156
+ const mapped = countriesArray.map((singleCountry: any) => ({
157
+ label: singleCountry.country,
158
+ value: singleCountry.index,
159
+ metadata: singleCountry.metadata || [],
160
+ }));
161
+
162
+ setIDMConf({
163
+ ...idmConf,
164
+ countryDetails: mapped,
165
+ });
166
+ } catch (err: any) {
167
+ console.error('Error fetching countries:', err);
168
+ }
169
+ }
170
+ };
171
+
172
+ fetchCountriesData();
173
+ }, [idmConf.accessToken, idmConf.verificationCode]);
174
+
175
+ // Determine initial route based on permissions
176
+ const initialRouteName = useMemo(() => {
177
+ if (idmConf.userDetails?.permissionGranted) {
178
+ return 'VerifyIdentity';
179
+ }
180
+ return 'LocationPermission';
181
+ }, [idmConf.userDetails?.permissionGranted]);
182
+
183
+ if (loading) {
184
+ return (
185
+ <ThemeProvider theme={theme}>
186
+ <Loader />
187
+ </ThemeProvider>
188
+ );
189
+ }
190
+
191
+ if (error) {
192
+ return (
193
+ <ThemeProvider theme={theme}>
194
+ <Loader message={`Error: ${error}`} />
195
+ </ThemeProvider>
196
+ );
197
+ }
198
+
83
199
  return (
84
200
  <ThemeProvider theme={theme}>
85
201
  {shouldShowHeaderFooter && <Header />}
86
202
  <NavigationContainer ref={navigationRef} onStateChange={handleStateChange}>
87
- <Stack.Navigator initialRouteName="VerifyIdentity" screenOptions={SCREEN_OPTIONS}>
203
+ <Stack.Navigator initialRouteName={initialRouteName} screenOptions={SCREEN_OPTIONS}>
88
204
  <Stack.Screen name="VerifyIdentity" component={VerifyIdentity} />
89
205
  <Stack.Screen name="SelfieAdvice" component={SelfieAdvice} />
90
206
  <Stack.Screen name="SelfieCapture" component={SelfieCapture} />