@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.
- package/README.md +824 -26
- package/assets/images/Chrome-logo.svg +1 -0
- package/assets/images/Firefox-logo.png +0 -0
- package/assets/images/IDM-logo.jpg +0 -0
- package/assets/images/MRZOverlay.png +0 -0
- package/assets/images/Safari-logo.png +0 -0
- package/assets/images/aadhar.png +0 -0
- package/assets/images/camera-bg.png +0 -0
- package/assets/images/card-overlay-back.png +0 -0
- package/assets/images/card-overlay.png +0 -0
- package/assets/images/card-scan-back-icon.jpg +0 -0
- package/assets/images/card-scan-front-icon.png +0 -0
- package/assets/images/card-scan-icon-aadhaar-1.png +0 -0
- package/assets/images/card-scan-icon-aadhaar-back.png +0 -0
- package/assets/images/card-scan-icon-aadhaar-scan-qr.png +0 -0
- package/assets/images/card-scan-icon-aadhaar.png +0 -0
- package/assets/images/card-scan-icon-can-pr.png +0 -0
- package/assets/images/card-scan-icon-default-back.png +0 -0
- package/assets/images/card-scan-icon-dl.png +0 -0
- package/assets/images/card-scan-icon-greencard-back.jpg +0 -0
- package/assets/images/card-scan-icon-greencard.jpg +0 -0
- package/assets/images/card-scan-icon-hc.png +0 -0
- package/assets/images/card-scan-icon-ni-argentina-back.jpg +0 -0
- package/assets/images/card-scan-icon-ni-argentina-old.png +0 -0
- package/assets/images/card-scan-icon-ni-argentina.jpg +0 -0
- package/assets/images/card-scan-icon-ni-barcode.jpg +0 -0
- package/assets/images/card-scan-icon-ni-brazil-back.jpg +0 -0
- package/assets/images/card-scan-icon-ni-brazil.jpg +0 -0
- package/assets/images/card-scan-icon-ni-dominican-republic-back.png +0 -0
- package/assets/images/card-scan-icon-ni-dominican-republic-front.png +0 -0
- package/assets/images/card-scan-icon-ni-dominican-republic-mrz.png +0 -0
- package/assets/images/card-scan-icon-ni-dominicanaRepublic-back.jpg +0 -0
- package/assets/images/card-scan-icon-ni-france-back.png +0 -0
- package/assets/images/card-scan-icon-ni-france-front.png +0 -0
- package/assets/images/card-scan-icon-ni-france-scan-mrz.png +0 -0
- package/assets/images/card-scan-icon-ni-germany-back.jpg +0 -0
- package/assets/images/card-scan-icon-ni-germany.jpg +0 -0
- package/assets/images/card-scan-icon-ni-paraguay-back.png +0 -0
- package/assets/images/card-scan-icon-ni-paraguay-front.png +0 -0
- package/assets/images/card-scan-icon-ni-paraguay-scan-mrz.png +0 -0
- package/assets/images/card-scan-icon-ni-uae-back.png +0 -0
- package/assets/images/card-scan-icon-ni-uae-front.png +0 -0
- package/assets/images/card-scan-icon-ni-uae-scan-mrz.png +0 -0
- package/assets/images/card-scan-icon-ni-uganda-front.png +0 -0
- package/assets/images/card-scan-icon-ni-uganda-scan-mrz.png +0 -0
- package/assets/images/card-scan-icon-ni-ukrain-back.png +0 -0
- package/assets/images/card-scan-icon-ni-ukrain-front.png +0 -0
- package/assets/images/card-scan-icon-ni-ukrain-scan-mrz.png +0 -0
- package/assets/images/card-scan-icon-ni.png +0 -0
- package/assets/images/card-scan-icon-old.jpg +0 -0
- package/assets/images/card-scan-icon-pan.png +0 -0
- package/assets/images/card-scan-icon-passport-card-back.jpg +0 -0
- package/assets/images/card-scan-icon-passport-card.jpg +0 -0
- package/assets/images/card-scan-icon-passport-old.png +0 -0
- package/assets/images/card-scan-icon-passport.png +0 -0
- package/assets/images/card-scan-icon-pr.png +0 -0
- package/assets/images/card-scan-icon.jpg +0 -0
- package/assets/images/check.png +0 -0
- package/assets/images/chrome-animation-GPS-permissions-setting.gif +0 -0
- package/assets/images/chrome-animation-camera-permissions-setting.gif +0 -0
- package/assets/images/denied.png +0 -0
- package/assets/images/dl.png +0 -0
- package/assets/images/driver-license.png +0 -0
- package/assets/images/firefox-animation-permissions-setting.gif +0 -0
- package/assets/images/flashlight_on.png +0 -0
- package/assets/images/gallery.png +0 -0
- package/assets/images/greencard.png +0 -0
- package/assets/images/header.jpg +0 -0
- package/assets/images/health-card.png +0 -0
- package/assets/images/ic_camera_front_white_36px.svg +4 -0
- package/assets/images/ic_camera_rear_white_36px.svg +4 -0
- package/assets/images/ic_fullscreen_exit_white_48px.svg +4 -0
- package/assets/images/ic_fullscreen_white_48px.svg +4 -0
- package/assets/images/ic_photo_camera_white_48px.svg +5 -0
- package/assets/images/id-card.png +0 -0
- package/assets/images/idcardimg.png +0 -0
- package/assets/images/idmval-barcode.png +0 -0
- package/assets/images/information.png +0 -0
- package/assets/images/loader.gif +0 -0
- package/assets/images/loading.svg +1 -0
- package/assets/images/logo.jpg +0 -0
- package/assets/images/logo.png +0 -0
- package/assets/images/mrz-back.png +0 -0
- package/assets/images/mrz-ni.png +0 -0
- package/assets/images/mrz.png +0 -0
- package/assets/images/mrz1.png +0 -0
- package/assets/images/mrz_old.png +0 -0
- package/assets/images/mrz_small.png +0 -0
- package/assets/images/national-id.png +0 -0
- package/assets/images/nationalID.png +0 -0
- package/assets/images/no-wifi.png +0 -0
- package/assets/images/passport-card.png +0 -0
- package/assets/images/passport.png +0 -0
- package/assets/images/permit-card.png +0 -0
- package/assets/images/photo-overlay.png +0 -0
- package/assets/images/placeholder.jpg +0 -0
- package/assets/images/qr-code.png +0 -0
- package/assets/images/right-checkmark.jpg +0 -0
- package/assets/images/selfie.jpg +0 -0
- package/assets/images/showing-sec.png +0 -0
- package/assets/images/spinner.gif +0 -0
- package/assets/images/splash-icon.png +0 -0
- package/assets/images/take-selfie.jpg +0 -0
- package/assets/images/torch_off.png +0 -0
- package/assets/images/warning-icon.jpg +0 -0
- package/assets/images/warning-stick.jpg +0 -0
- package/assets/images/wrong-checkmark.jpg +0 -0
- package/package.json +44 -8
- package/src/apis/index.ts +338 -17
- package/src/components/common/Loader.tsx +16 -2
- package/src/config/apiConfig.ts +6 -0
- package/src/index.tsx +123 -7
- package/src/screens/BarcodeCapture.tsx +154 -24
- package/src/screens/DocumentCaptureBack.tsx +133 -24
- package/src/screens/DocumentCaptureFront.tsx +146 -24
- package/src/screens/MrzCapture.tsx +205 -16
- package/src/screens/SelectDocuments.tsx +37 -56
- package/src/screens/SelfieCapture.tsx +114 -18
- package/src/screens/ThankYou.tsx +34 -1
- package/src/services/getUserData.ts +111 -0
- package/src/types/IDMConf.ts +81 -7
- package/src/utils/base64.ts +25 -0
- package/src/utils/flowManager.ts +138 -0
- package/src/utils/imageProcessor.ts +96 -0
- 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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
31
|
-
|
|
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
|
-
|
|
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
|
|
52
|
+
idmConf: IDMConf;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
export default function IDMScan({ idmConf
|
|
55
|
+
export default function IDMScan({ idmConf }: IDMScanProps) {
|
|
48
56
|
return (
|
|
49
57
|
<IDMProvider initialConf={idmConf}>
|
|
50
58
|
<KeyboardProvider>
|
|
51
|
-
<IDMScanContent
|
|
59
|
+
<IDMScanContent />
|
|
52
60
|
</KeyboardProvider>
|
|
53
61
|
</IDMProvider>
|
|
54
62
|
);
|
|
55
63
|
}
|
|
56
64
|
|
|
57
|
-
function IDMScanContent(
|
|
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=
|
|
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} />
|