@sanctum-key/react-native-sdk 1.0.9 โ 1.0.10
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/build/package.json +1 -1
- package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.js +259 -63
- package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +222 -69
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js +160 -21
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
- package/build/src/config/region_mapping.json +727 -0
- package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/src/modules/api/CardAuthentification.js +3 -7
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +1 -2
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +106 -59
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/package.json +1 -1
- package/src/components/KYCElements/CountrySelection.tsx +300 -74
- package/src/components/KYCElements/IDCardCapture.tsx +310 -156
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +201 -29
- package/src/modules/api/CardAuthentification.ts +5 -8
- package/src/modules/api/KYCService.ts +167 -105
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable } from 'react-native';
|
|
2
|
+
import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable, Modal, FlatList } from 'react-native';
|
|
3
3
|
import { TemplateComponent, LocalizedText } from '../../types/KYC.types';
|
|
4
4
|
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
5
5
|
import { useI18n } from '../../hooks/useI18n';
|
|
@@ -17,6 +17,19 @@ interface PhoneVerificationTemplateProps {
|
|
|
17
17
|
type VerificationStep = 'phone' | 'otp';
|
|
18
18
|
const CODE_LENGTH = 6;
|
|
19
19
|
|
|
20
|
+
// ๐ The Country Codes Array
|
|
21
|
+
const COUNTRY_CODES = [
|
|
22
|
+
{ code: '+254', label: '๐ฐ๐ช Kenya (+254)' },
|
|
23
|
+
{ code: '+255', label: '๐น๐ฟ Tanzania (+255)' },
|
|
24
|
+
{ code: '+256', label: '๐บ๐ฌ Uganda (+256)' },
|
|
25
|
+
{ code: '+250', label: '๐ท๐ผ Rwanda (+250)' },
|
|
26
|
+
{ code: '+234', label: '๐ณ๐ฌ Nigeria (+234)' },
|
|
27
|
+
{ code: '+27', label: '๐ฟ๐ฆ South Africa (+27)' },
|
|
28
|
+
{ code: '+44', label: '๐ฌ๐ง UK (+44)' },
|
|
29
|
+
{ code: '+1', label: '๐บ๐ธ US/Canada (+1)' },
|
|
30
|
+
{ code: '+91', label: '๐ฎ๐ณ India (+91)' },
|
|
31
|
+
];
|
|
32
|
+
|
|
20
33
|
export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps> = ({
|
|
21
34
|
component,
|
|
22
35
|
value,
|
|
@@ -31,10 +44,16 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
31
44
|
|
|
32
45
|
// State
|
|
33
46
|
const [step, setStep] = useState<VerificationStep>('phone');
|
|
47
|
+
const [countryCode, setCountryCode] = useState('+254');
|
|
34
48
|
const [phone, setPhone] = useState('');
|
|
49
|
+
const [showCountryPicker, setShowCountryPicker] = useState(false);
|
|
50
|
+
|
|
35
51
|
const [otp, setOtp] = useState('');
|
|
36
52
|
const [localError, setLocalError] = useState<string | null>(null);
|
|
37
53
|
const [isSimulating, setIsSimulating] = useState(false);
|
|
54
|
+
|
|
55
|
+
// Track actual focus state for visual feedback
|
|
56
|
+
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
38
57
|
|
|
39
58
|
const inputRef = useRef<TextInput>(null);
|
|
40
59
|
|
|
@@ -52,6 +71,22 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
52
71
|
}
|
|
53
72
|
}, [otp]);
|
|
54
73
|
|
|
74
|
+
// --- SAFE AUTO FOCUS LOGIC ---
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
let focusTimer: ReturnType<typeof setTimeout>;
|
|
77
|
+
|
|
78
|
+
// Only attempt focus when we are on the OTP step AND the loading state is completely finished
|
|
79
|
+
if (step === 'otp' && !isSimulating) {
|
|
80
|
+
focusTimer = setTimeout(() => {
|
|
81
|
+
inputRef.current?.focus();
|
|
82
|
+
}, 300); // 300ms guarantees view is painted before requesting keyboard
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return () => {
|
|
86
|
+
if (focusTimer) clearTimeout(focusTimer);
|
|
87
|
+
};
|
|
88
|
+
}, [step, isSimulating]);
|
|
89
|
+
|
|
55
90
|
const handleSendCode = async () => {
|
|
56
91
|
const trimmedPhone = phone.trim();
|
|
57
92
|
if (!trimmedPhone || trimmedPhone.length < 5) {
|
|
@@ -62,11 +97,11 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
62
97
|
setLocalError(null);
|
|
63
98
|
setIsSimulating(true);
|
|
64
99
|
|
|
100
|
+
const fullPhoneNumber = `${countryCode}${trimmedPhone}`;
|
|
101
|
+
|
|
65
102
|
try {
|
|
66
|
-
await kycService.sendWhatsAppVerificationCode(sessionId,
|
|
103
|
+
await kycService.sendWhatsAppVerificationCode(sessionId, fullPhoneNumber, auth);
|
|
67
104
|
setStep('otp');
|
|
68
|
-
// Auto-focus the OTP input shortly after switching steps
|
|
69
|
-
setTimeout(() => inputRef.current?.focus(), 100);
|
|
70
105
|
} catch (err: any) {
|
|
71
106
|
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
|
|
72
107
|
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
@@ -83,29 +118,32 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
83
118
|
|
|
84
119
|
setLocalError(null);
|
|
85
120
|
setIsSimulating(true);
|
|
121
|
+
|
|
122
|
+
const fullPhoneNumber = `${countryCode}${phone.trim()}`;
|
|
86
123
|
|
|
87
124
|
try {
|
|
88
|
-
await kycService.verifyWhatsAppCode(sessionId, otp.trim(), auth);
|
|
89
|
-
|
|
125
|
+
await kycService.verifyWhatsAppCode(sessionId, otp.trim(), fullPhoneNumber, auth);
|
|
126
|
+
|
|
127
|
+
const data = { phone: fullPhoneNumber, otp, verified: true };
|
|
90
128
|
onValueChange(data);
|
|
91
129
|
actions.nextComponent(data);
|
|
92
130
|
} catch (err: any) {
|
|
93
131
|
const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
|
|
94
132
|
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
95
|
-
setOtp('');
|
|
96
|
-
inputRef.current?.focus();
|
|
133
|
+
setOtp('');
|
|
134
|
+
inputRef.current?.focus();
|
|
97
135
|
} finally {
|
|
98
136
|
setIsSimulating(false);
|
|
99
137
|
}
|
|
100
138
|
};
|
|
101
139
|
|
|
102
140
|
const onChangePhone = (text: string) => {
|
|
103
|
-
|
|
141
|
+
const cleaned = text.replace(/[^0-9]/g, '');
|
|
142
|
+
setPhone(cleaned);
|
|
104
143
|
if (localError) setLocalError(null);
|
|
105
144
|
};
|
|
106
145
|
|
|
107
146
|
const onChangeOtp = (text: string) => {
|
|
108
|
-
// Only allow numbers
|
|
109
147
|
const cleaned = text.replace(/[^0-9]/g, '');
|
|
110
148
|
setOtp(cleaned);
|
|
111
149
|
if (localError) setLocalError(null);
|
|
@@ -123,16 +161,19 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
123
161
|
<Pressable style={styles.otpBoxesContainer} onPress={() => inputRef.current?.focus()}>
|
|
124
162
|
{boxes.map((_, index) => {
|
|
125
163
|
const digit = otp[index] || '';
|
|
126
|
-
const isCurrent = index === otp.length;
|
|
127
164
|
const isFilled = index < otp.length;
|
|
165
|
+
|
|
166
|
+
// Only highlight if the input is ACTUALLY focused.
|
|
167
|
+
const isActiveIndex = index === otp.length || (index === CODE_LENGTH - 1 && otp.length === CODE_LENGTH);
|
|
168
|
+
const isCurrent = isInputFocused && isActiveIndex;
|
|
128
169
|
|
|
129
170
|
return (
|
|
130
171
|
<View
|
|
131
172
|
key={index}
|
|
132
173
|
style={[
|
|
133
174
|
styles.otpBox,
|
|
134
|
-
|
|
135
|
-
|
|
175
|
+
isFilled && styles.otpBoxFilled,
|
|
176
|
+
isCurrent && styles.otpBoxActive // Active overrides filled
|
|
136
177
|
]}
|
|
137
178
|
>
|
|
138
179
|
<Text style={styles.otpBoxText}>{digit}</Text>
|
|
@@ -147,22 +188,34 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
147
188
|
<View style={styles.container}>
|
|
148
189
|
<Text style={styles.title}>{title}</Text>
|
|
149
190
|
<Text style={styles.instructions}>
|
|
150
|
-
{step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${phone}`)}
|
|
191
|
+
{step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${countryCode} ${phone}`)}
|
|
151
192
|
</Text>
|
|
152
193
|
|
|
153
194
|
<View style={styles.contentContainer}>
|
|
154
195
|
{step === 'phone' ? (
|
|
155
196
|
<View style={styles.inputContainer}>
|
|
156
197
|
<Text style={styles.label}>{t('common.phone') || 'Phone Number'}</Text>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
198
|
+
|
|
199
|
+
<View style={styles.phoneInputRow}>
|
|
200
|
+
<TouchableOpacity
|
|
201
|
+
style={styles.countryPickerBtn}
|
|
202
|
+
onPress={() => setShowCountryPicker(true)}
|
|
203
|
+
disabled={isSimulating}
|
|
204
|
+
>
|
|
205
|
+
<Text style={styles.countryPickerText}>{countryCode}</Text>
|
|
206
|
+
<Text style={styles.dropdownIcon}>โผ</Text>
|
|
207
|
+
</TouchableOpacity>
|
|
208
|
+
|
|
209
|
+
<TextInput
|
|
210
|
+
style={styles.phoneInput}
|
|
211
|
+
placeholder="712 345 678"
|
|
212
|
+
value={phone}
|
|
213
|
+
onChangeText={onChangePhone}
|
|
214
|
+
keyboardType="phone-pad"
|
|
215
|
+
autoComplete="tel"
|
|
216
|
+
editable={!isSimulating}
|
|
217
|
+
/>
|
|
218
|
+
</View>
|
|
166
219
|
</View>
|
|
167
220
|
) : (
|
|
168
221
|
<View style={styles.inputContainer}>
|
|
@@ -170,7 +223,7 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
170
223
|
|
|
171
224
|
<View style={styles.otpWrapper}>
|
|
172
225
|
{renderOtpBoxes()}
|
|
173
|
-
|
|
226
|
+
|
|
174
227
|
<TextInput
|
|
175
228
|
ref={inputRef}
|
|
176
229
|
style={styles.hiddenInput}
|
|
@@ -181,6 +234,8 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
181
234
|
editable={!isSimulating}
|
|
182
235
|
textContentType="oneTimeCode"
|
|
183
236
|
caretHidden={true}
|
|
237
|
+
onFocus={() => setIsInputFocused(true)}
|
|
238
|
+
onBlur={() => setIsInputFocused(false)}
|
|
184
239
|
/>
|
|
185
240
|
</View>
|
|
186
241
|
|
|
@@ -210,12 +265,14 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
210
265
|
if (isSimulating) return;
|
|
211
266
|
setLocalError(null);
|
|
212
267
|
setIsSimulating(true);
|
|
268
|
+
const fullPhoneNumber = `${countryCode}${phone.trim()}`;
|
|
213
269
|
try {
|
|
214
|
-
await kycService.sendWhatsAppVerificationCode(sessionId,
|
|
270
|
+
await kycService.sendWhatsAppVerificationCode(sessionId, fullPhoneNumber, auth);
|
|
215
271
|
Alert.alert(
|
|
216
272
|
t('common.codeResent') || 'Code Resent',
|
|
217
|
-
t('common.codeResentMessage', { email:
|
|
273
|
+
t('common.codeResentMessage', { email: fullPhoneNumber }) || 'Code resent to ' + fullPhoneNumber
|
|
218
274
|
);
|
|
275
|
+
inputRef.current?.focus();
|
|
219
276
|
} catch (err: any) {
|
|
220
277
|
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
|
|
221
278
|
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
@@ -230,6 +287,45 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
230
287
|
</TouchableOpacity>
|
|
231
288
|
)}
|
|
232
289
|
</View>
|
|
290
|
+
|
|
291
|
+
{/* COUNTRY PICKER MODAL */}
|
|
292
|
+
<Modal
|
|
293
|
+
visible={showCountryPicker}
|
|
294
|
+
animationType="slide"
|
|
295
|
+
transparent={true}
|
|
296
|
+
onRequestClose={() => setShowCountryPicker(false)}
|
|
297
|
+
>
|
|
298
|
+
<TouchableOpacity
|
|
299
|
+
style={styles.modalOverlay}
|
|
300
|
+
activeOpacity={1}
|
|
301
|
+
onPress={() => setShowCountryPicker(false)}
|
|
302
|
+
>
|
|
303
|
+
<View style={styles.modalContent}>
|
|
304
|
+
<View style={styles.modalHeader}>
|
|
305
|
+
<Text style={styles.modalTitle}>Select Country</Text>
|
|
306
|
+
<TouchableOpacity onPress={() => setShowCountryPicker(false)}>
|
|
307
|
+
<Text style={styles.modalClose}>โ</Text>
|
|
308
|
+
</TouchableOpacity>
|
|
309
|
+
</View>
|
|
310
|
+
<FlatList
|
|
311
|
+
data={COUNTRY_CODES}
|
|
312
|
+
keyExtractor={(item) => item.code}
|
|
313
|
+
renderItem={({ item }) => (
|
|
314
|
+
<TouchableOpacity
|
|
315
|
+
style={styles.countryItem}
|
|
316
|
+
onPress={() => {
|
|
317
|
+
setCountryCode(item.code);
|
|
318
|
+
setShowCountryPicker(false);
|
|
319
|
+
}}
|
|
320
|
+
>
|
|
321
|
+
<Text style={styles.countryItemLabel}>{item.label}</Text>
|
|
322
|
+
{countryCode === item.code && <Text style={styles.checkMark}>โ</Text>}
|
|
323
|
+
</TouchableOpacity>
|
|
324
|
+
)}
|
|
325
|
+
/>
|
|
326
|
+
</View>
|
|
327
|
+
</TouchableOpacity>
|
|
328
|
+
</Modal>
|
|
233
329
|
</View>
|
|
234
330
|
);
|
|
235
331
|
};
|
|
@@ -272,7 +368,35 @@ const styles = StyleSheet.create({
|
|
|
272
368
|
marginBottom: 8,
|
|
273
369
|
marginLeft: 4,
|
|
274
370
|
},
|
|
275
|
-
|
|
371
|
+
phoneInputRow: {
|
|
372
|
+
flexDirection: 'row',
|
|
373
|
+
alignItems: 'center',
|
|
374
|
+
gap: 10,
|
|
375
|
+
},
|
|
376
|
+
countryPickerBtn: {
|
|
377
|
+
flexDirection: 'row',
|
|
378
|
+
alignItems: 'center',
|
|
379
|
+
justifyContent: 'space-between',
|
|
380
|
+
borderWidth: 1,
|
|
381
|
+
borderColor: '#e0e0e0',
|
|
382
|
+
paddingHorizontal: 12,
|
|
383
|
+
paddingVertical: 16,
|
|
384
|
+
borderRadius: 12,
|
|
385
|
+
backgroundColor: '#f8f9fa',
|
|
386
|
+
minWidth: 90,
|
|
387
|
+
},
|
|
388
|
+
countryPickerText: {
|
|
389
|
+
fontSize: 16,
|
|
390
|
+
color: '#333',
|
|
391
|
+
fontWeight: '600',
|
|
392
|
+
},
|
|
393
|
+
dropdownIcon: {
|
|
394
|
+
fontSize: 12,
|
|
395
|
+
color: '#666',
|
|
396
|
+
marginLeft: 8,
|
|
397
|
+
},
|
|
398
|
+
phoneInput: {
|
|
399
|
+
flex: 1,
|
|
276
400
|
borderWidth: 1,
|
|
277
401
|
borderColor: '#e0e0e0',
|
|
278
402
|
padding: 16,
|
|
@@ -281,6 +405,54 @@ const styles = StyleSheet.create({
|
|
|
281
405
|
backgroundColor: '#f8f9fa',
|
|
282
406
|
color: '#333',
|
|
283
407
|
},
|
|
408
|
+
modalOverlay: {
|
|
409
|
+
flex: 1,
|
|
410
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
411
|
+
justifyContent: 'flex-end',
|
|
412
|
+
},
|
|
413
|
+
modalContent: {
|
|
414
|
+
backgroundColor: 'white',
|
|
415
|
+
borderTopLeftRadius: 24,
|
|
416
|
+
borderTopRightRadius: 24,
|
|
417
|
+
maxHeight: '60%',
|
|
418
|
+
paddingBottom: 40,
|
|
419
|
+
},
|
|
420
|
+
modalHeader: {
|
|
421
|
+
flexDirection: 'row',
|
|
422
|
+
justifyContent: 'space-between',
|
|
423
|
+
alignItems: 'center',
|
|
424
|
+
padding: 20,
|
|
425
|
+
borderBottomWidth: 1,
|
|
426
|
+
borderBottomColor: '#f0f0f0',
|
|
427
|
+
},
|
|
428
|
+
modalTitle: {
|
|
429
|
+
fontSize: 18,
|
|
430
|
+
fontWeight: '700',
|
|
431
|
+
color: '#1a1a1a',
|
|
432
|
+
},
|
|
433
|
+
modalClose: {
|
|
434
|
+
fontSize: 20,
|
|
435
|
+
color: '#666',
|
|
436
|
+
padding: 5,
|
|
437
|
+
},
|
|
438
|
+
countryItem: {
|
|
439
|
+
flexDirection: 'row',
|
|
440
|
+
justifyContent: 'space-between',
|
|
441
|
+
alignItems: 'center',
|
|
442
|
+
paddingVertical: 16,
|
|
443
|
+
paddingHorizontal: 24,
|
|
444
|
+
borderBottomWidth: 1,
|
|
445
|
+
borderBottomColor: '#f8f9fa',
|
|
446
|
+
},
|
|
447
|
+
countryItemLabel: {
|
|
448
|
+
fontSize: 16,
|
|
449
|
+
color: '#333',
|
|
450
|
+
},
|
|
451
|
+
checkMark: {
|
|
452
|
+
color: '#2DBD60',
|
|
453
|
+
fontSize: 18,
|
|
454
|
+
fontWeight: 'bold',
|
|
455
|
+
},
|
|
284
456
|
otpWrapper: {
|
|
285
457
|
position: 'relative',
|
|
286
458
|
width: '100%',
|
|
@@ -295,7 +467,7 @@ const styles = StyleSheet.create({
|
|
|
295
467
|
},
|
|
296
468
|
otpBox: {
|
|
297
469
|
width: '14%',
|
|
298
|
-
aspectRatio: 1,
|
|
470
|
+
aspectRatio: 1,
|
|
299
471
|
borderWidth: 1,
|
|
300
472
|
borderColor: '#e0e0e0',
|
|
301
473
|
borderRadius: 12,
|
|
@@ -323,7 +495,7 @@ const styles = StyleSheet.create({
|
|
|
323
495
|
left: 0,
|
|
324
496
|
width: '100%',
|
|
325
497
|
height: '100%',
|
|
326
|
-
opacity: 0,
|
|
498
|
+
opacity: 0,
|
|
327
499
|
},
|
|
328
500
|
errorText: {
|
|
329
501
|
color: '#dc2626',
|
|
@@ -82,7 +82,6 @@ export async function frontVerification(
|
|
|
82
82
|
console.log("Front verification START", JSON.stringify({ result }, null, 2));
|
|
83
83
|
logger.log("Front verification", JSON.stringify({ result }, null, 2));
|
|
84
84
|
|
|
85
|
-
// ๐จ FIX 1: Bulletproof Case-Insensitive Check
|
|
86
85
|
const authMethods = Array.isArray(result.regionMapping?.authMethod)
|
|
87
86
|
? result.regionMapping.authMethod.map(m => String(m).toUpperCase())
|
|
88
87
|
: [];
|
|
@@ -164,7 +163,6 @@ export async function frontVerification(
|
|
|
164
163
|
bbox = crop.bbox;
|
|
165
164
|
} catch { }
|
|
166
165
|
|
|
167
|
-
// ๐จ FIX 2: Execute MRZ if required (Removed restrictive guards)
|
|
168
166
|
if (hasMrz) {
|
|
169
167
|
try {
|
|
170
168
|
logger.log("Tentative d'extraction MRZ (Front)");
|
|
@@ -176,7 +174,7 @@ export async function frontVerification(
|
|
|
176
174
|
postfix: result?.currentSide || 'front',
|
|
177
175
|
token: token,
|
|
178
176
|
template_path: result?.templatePath || '',
|
|
179
|
-
mrz_type: result?.mrzType || 'TD1'
|
|
177
|
+
mrz_type: result?.mrzType || 'TD1'
|
|
180
178
|
},
|
|
181
179
|
env
|
|
182
180
|
);
|
|
@@ -201,7 +199,6 @@ export async function frontVerification(
|
|
|
201
199
|
}
|
|
202
200
|
}
|
|
203
201
|
|
|
204
|
-
// โโโ backVerification โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
205
202
|
|
|
206
203
|
export async function backVerification(
|
|
207
204
|
result: {
|
|
@@ -219,12 +216,13 @@ export async function backVerification(
|
|
|
219
216
|
try {
|
|
220
217
|
if (!result.path) throw new Error('No path provided');
|
|
221
218
|
logger.log("result.regionMapping", result.regionMapping, result.currentSide, result.code);
|
|
219
|
+
logger.log('result object', result)
|
|
222
220
|
|
|
223
|
-
// ๐จ FIX 3: Robust Auth Method Resolution for the Back Side
|
|
224
221
|
const authMethods = Array.isArray(result.regionMapping?.authMethod)
|
|
225
222
|
? result.regionMapping.authMethod.map(m => String(m).toUpperCase())
|
|
226
223
|
: [];
|
|
227
|
-
|
|
224
|
+
|
|
225
|
+
const hasMrz = authMethods.some(m => m.includes('MRZ'))
|
|
228
226
|
const hasBarcode = authMethods.some(m => m.includes('BARCODE') || m.includes('2D'));
|
|
229
227
|
|
|
230
228
|
if (env === 'SANDBOX') {
|
|
@@ -338,7 +336,6 @@ export async function backVerification(
|
|
|
338
336
|
|
|
339
337
|
let extractionResult: any = {};
|
|
340
338
|
|
|
341
|
-
// ๐จ FIX 4: Guaranteed MRZ Extraction Attachment
|
|
342
339
|
if (hasMrz) {
|
|
343
340
|
try {
|
|
344
341
|
logger.log("Tentative d'extraction MRZ (Back)");
|
|
@@ -481,7 +478,7 @@ export async function checkTemplateType(
|
|
|
481
478
|
logger.log("templateType result", JSON.stringify(truncateFields(templateType), null, 2));
|
|
482
479
|
return templateType;
|
|
483
480
|
} catch (e: any) {
|
|
484
|
-
logger.error('
|
|
481
|
+
logger.error('Errorrr checking template type:', JSON.stringify(errorMessage(e), null, 2));
|
|
485
482
|
if (e?.message === 'CARD_NOT_FULLY_IN_FRAME' || e?.message === 'TOO_FAR_AWAY' || e?.message?.includes('ne correspond pas')) throw e;
|
|
486
483
|
throw new Error(e?.message || 'Erreur de vรฉrification du template');
|
|
487
484
|
}
|