@transfergratis/react-native-sdk 0.1.28 → 0.1.30
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/components/EnhancedCameraView.js +1 -1
- package/build/components/EnhancedCameraView.js.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.js +13 -42
- package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +113 -49
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +2 -2
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +1 -1
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts +15 -7
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +360 -104
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +3 -1
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +25 -24
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/camera/VisionCameraModule.js +2 -2
- package/build/modules/camera/VisionCameraModule.js.map +1 -1
- package/build/utils/cropByObb.d.ts +8 -0
- package/build/utils/cropByObb.d.ts.map +1 -1
- package/build/utils/cropByObb.js +20 -3
- package/build/utils/cropByObb.js.map +1 -1
- package/build/utils/pathToBase64.js +1 -1
- package/build/utils/pathToBase64.js.map +1 -1
- package/package.json +1 -1
- package/src/components/EnhancedCameraView.tsx +1 -1
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +24 -52
- package/src/components/KYCElements/IDCardCapture.tsx +179 -109
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +2 -2
- package/src/hooks/useTemplateKYCFlow.tsx +1 -1
- package/src/modules/api/CardAuthentification.ts +450 -113
- package/src/modules/api/KYCService.ts +52 -39
- package/src/modules/camera/VisionCameraModule.ts +2 -2
- package/src/utils/cropByObb.ts +22 -3
- package/src/utils/pathToBase64.ts +1 -1
|
@@ -19,9 +19,8 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
19
19
|
const { t, locale } = useI18n();
|
|
20
20
|
const [showCamera, setShowCamera] = useState(false);
|
|
21
21
|
const [capturedImages, setCapturedImages] = useState(value || {});
|
|
22
|
-
const [cropImageUri, setCropImageUri] = useState('');
|
|
22
|
+
// const [cropImageUri, setCropImageUri] = useState<string>('');
|
|
23
23
|
const [currentSide, setCurrentSide] = useState('front');
|
|
24
|
-
// Stocker les bbox par côté pour pouvoir restaurer les images croppées
|
|
25
24
|
const [bboxBySide, setBboxBySide] = useState({});
|
|
26
25
|
const [silentCaptureResult, setSilentCaptureResult] = useState({ success: false, isAnalyzing: false });
|
|
27
26
|
const [showQRModal, setShowQRModal] = useState(false);
|
|
@@ -63,6 +62,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
63
62
|
const countryData = useMemo(() => {
|
|
64
63
|
return countrySelectionData;
|
|
65
64
|
}, [countrySelectionData]);
|
|
65
|
+
// console.log();
|
|
66
66
|
// Synchroniser capturedImages avec value quand les données sont chargées (ex: reprise de session)
|
|
67
67
|
useEffect(() => {
|
|
68
68
|
if (value && Object.keys(value).length > 0) {
|
|
@@ -94,7 +94,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
94
94
|
logger.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
|
|
95
95
|
if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
|
|
96
96
|
cropImageWithBBox(capturedImages[currentSide].dir, silentCaptureResult.bbox)?.then((uri) => {
|
|
97
|
-
setCropImageUri(uri);
|
|
97
|
+
// setCropImageUri(uri);
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
}, [capturedImages[currentSide]?.dir, silentCaptureResult?.bbox]);
|
|
@@ -104,9 +104,11 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
104
104
|
: getLocalizedText(component.instructions);
|
|
105
105
|
return {
|
|
106
106
|
aspectRatio: 4 / 3,
|
|
107
|
-
quality: 0.
|
|
107
|
+
quality: 0.7,
|
|
108
108
|
flashMode: 'auto',
|
|
109
109
|
cameraType: 'back',
|
|
110
|
+
autoFocus: 'on',
|
|
111
|
+
whiteBalance: 'auto',
|
|
110
112
|
allowRetake: true,
|
|
111
113
|
maxRetakes: 3,
|
|
112
114
|
overlay: {
|
|
@@ -124,13 +126,30 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
124
126
|
}
|
|
125
127
|
};
|
|
126
128
|
}, [selectedDocumentType, locale, component.instructions]);
|
|
127
|
-
const retakePicture = (
|
|
129
|
+
const retakePicture = (sideToRetake) => {
|
|
130
|
+
// 1. Turn the camera back on and hide the stepper
|
|
128
131
|
setShowCamera(true);
|
|
129
132
|
actions.showCustomStepper(false);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
// 2. WIPE LOCAL STATE: Use functional update to prevent stale closures
|
|
134
|
+
setCapturedImages((prev) => {
|
|
135
|
+
const newState = { ...prev };
|
|
136
|
+
delete newState[sideToRetake];
|
|
137
|
+
return newState;
|
|
138
|
+
});
|
|
139
|
+
setSilentCaptureResult({
|
|
140
|
+
path: '',
|
|
141
|
+
success: false,
|
|
142
|
+
isAnalyzing: false,
|
|
143
|
+
error: '',
|
|
144
|
+
templatePath: '',
|
|
145
|
+
mrz: '',
|
|
146
|
+
bbox: undefined,
|
|
147
|
+
});
|
|
148
|
+
if (value) {
|
|
149
|
+
const newValue = { ...value };
|
|
150
|
+
delete newValue[sideToRetake];
|
|
151
|
+
onValueChange(newValue);
|
|
152
|
+
}
|
|
134
153
|
};
|
|
135
154
|
const getCurrentSideVerification = (currentSide) => {
|
|
136
155
|
if (!selectedDocumentType || !countryData?.regionMapping) {
|
|
@@ -247,15 +266,17 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
247
266
|
console.log("About to call frontVerification function");
|
|
248
267
|
const promise = frontVerification(verificationParams, env);
|
|
249
268
|
console.log("frontVerification promise created", promise);
|
|
250
|
-
promise.then((
|
|
251
|
-
logger.log("front verification result", truncateFields(
|
|
252
|
-
const bbox =
|
|
269
|
+
promise.then((res) => {
|
|
270
|
+
logger.log("front verification result", truncateFields(res));
|
|
271
|
+
const bbox = res?.bbox || templateBbox;
|
|
253
272
|
setSilentCaptureResult((prev) => ({
|
|
254
273
|
...prev,
|
|
255
274
|
path: result.path,
|
|
256
275
|
templatePath: templatePath,
|
|
257
|
-
bbox: bbox,
|
|
258
|
-
|
|
276
|
+
bbox: bbox,
|
|
277
|
+
success: true,
|
|
278
|
+
mrz: res?.mrz ? JSON.stringify(res.mrz) : "",
|
|
279
|
+
isAnalyzing: false,
|
|
259
280
|
country: countryData?.code,
|
|
260
281
|
documentType: selectedDocumentType.type,
|
|
261
282
|
}));
|
|
@@ -263,6 +284,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
263
284
|
if (bbox && typeof bbox === 'object') {
|
|
264
285
|
setBboxBySide((prev) => ({ ...prev, [currentSide]: bbox }));
|
|
265
286
|
}
|
|
287
|
+
}).catch((e) => {
|
|
266
288
|
}).catch((e) => {
|
|
267
289
|
console.log("error front verification", e);
|
|
268
290
|
logger.log("error front verification", truncateFields(e));
|
|
@@ -294,12 +316,16 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
294
316
|
currentSide: currentSide,
|
|
295
317
|
templatePath: templatePath,
|
|
296
318
|
mrzType: getCorrespondingMrzType(templatePath, backRegionMappings.regionMapping, backRegionMappings.key || '') || '',
|
|
297
|
-
}, env).then((
|
|
298
|
-
logger.log("back verification result", truncateFields(
|
|
299
|
-
const bbox =
|
|
319
|
+
}, env).then((res) => {
|
|
320
|
+
logger.log("back verification result", truncateFields(res));
|
|
321
|
+
const bbox = res?.bbox || templateBbox;
|
|
300
322
|
setSilentCaptureResult((prev) => ({
|
|
301
|
-
...prev,
|
|
302
|
-
|
|
323
|
+
...prev,
|
|
324
|
+
path: result.path,
|
|
325
|
+
bbox: bbox,
|
|
326
|
+
success: true,
|
|
327
|
+
mrz: res?.mrz ? JSON.stringify(res.mrz) : "",
|
|
328
|
+
isAnalyzing: false,
|
|
303
329
|
country: countryData?.code,
|
|
304
330
|
documentType: selectedDocumentType.type,
|
|
305
331
|
}));
|
|
@@ -320,28 +346,28 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
320
346
|
}
|
|
321
347
|
}
|
|
322
348
|
};
|
|
323
|
-
// Handle capture
|
|
324
349
|
const handleCapture = async (result) => {
|
|
325
|
-
console.log("handleCapture", JSON.stringify(truncateFields({ result, silentCaptureResult }), null, 2));
|
|
326
350
|
if (silentCaptureResult.path) {
|
|
327
|
-
// Créer une image rognée avec tolérance de 10% pour l'envoi
|
|
328
351
|
let imagePathForUpload = silentCaptureResult.path;
|
|
329
352
|
if (silentCaptureResult.bbox) {
|
|
330
353
|
try {
|
|
331
|
-
logger.log("Début du rognage avec tolérance, URI original:", silentCaptureResult.path);
|
|
332
354
|
imagePathForUpload = await cropImageWithBBoxWithTolerance(silentCaptureResult.path, silentCaptureResult.bbox, 0.05);
|
|
333
|
-
logger.log("Image rognée avec tolérance créée pour l'envoi, URI final:", imagePathForUpload);
|
|
334
355
|
}
|
|
335
356
|
catch (error) {
|
|
336
|
-
logger.log("Erreur lors du rognage avec tolérance, utilisation de l'image originale:", truncateFields(error));
|
|
337
|
-
// En cas d'erreur, on utilise l'image originale
|
|
338
357
|
imagePathForUpload = silentCaptureResult.path;
|
|
339
358
|
}
|
|
340
359
|
}
|
|
341
360
|
const base64 = await pathToBase64(imagePathForUpload);
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
361
|
+
// ✅ FIX: Use 'imagePathForUpload' (the cropped image) for the local display directory!
|
|
362
|
+
const newImages = {
|
|
363
|
+
...capturedImages,
|
|
364
|
+
[currentSide]: {
|
|
365
|
+
dir: imagePathForUpload, // <--- CHANGED THIS LINE
|
|
366
|
+
file: base64,
|
|
367
|
+
mrz: silentCaptureResult.mrz || "",
|
|
368
|
+
templatePath: silentCaptureResult.templatePath
|
|
369
|
+
}
|
|
370
|
+
};
|
|
345
371
|
setCapturedImages(newImages);
|
|
346
372
|
if (silentCaptureResult.country && silentCaptureResult.documentType) {
|
|
347
373
|
onValueChange({
|
|
@@ -468,7 +494,6 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
468
494
|
documentType: silentCaptureResult.documentType,
|
|
469
495
|
bbox: frontBbox // Restaurer le bbox pour recalculer le cropImageUri
|
|
470
496
|
}));
|
|
471
|
-
// Le useEffect va automatiquement recalculer le cropImageUri si bbox existe
|
|
472
497
|
}
|
|
473
498
|
else {
|
|
474
499
|
// Pas d'image front, on réinitialise
|
|
@@ -485,6 +510,13 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
485
510
|
totalSteps: state.template.components.length,
|
|
486
511
|
side: currentSide,
|
|
487
512
|
}}/>}/>
|
|
513
|
+
|
|
514
|
+
{silentCaptureResult.error ? (<View style={styles.floatingErrorBanner}>
|
|
515
|
+
<Text style={styles.floatingErrorText}>
|
|
516
|
+
{silentCaptureResult.error}
|
|
517
|
+
</Text>
|
|
518
|
+
</View>) : null}
|
|
519
|
+
|
|
488
520
|
</View>);
|
|
489
521
|
}
|
|
490
522
|
return (<View style={styles.root}>
|
|
@@ -499,40 +531,48 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
499
531
|
</Text>
|
|
500
532
|
|
|
501
533
|
<View style={{ alignItems: 'center', justifyContent: 'center', flexDirection: "column", gap: 16 }}>
|
|
502
|
-
<View style={{
|
|
534
|
+
{silentCaptureResult?.error === 'TOO_FAR_AWAY' && (<View style={{
|
|
535
|
+
backgroundColor: '#FF9500',
|
|
536
|
+
padding: 12,
|
|
537
|
+
borderRadius: 8,
|
|
538
|
+
width: '100%',
|
|
539
|
+
shadowColor: '#000',
|
|
540
|
+
shadowOffset: { width: 0, height: 2 },
|
|
541
|
+
shadowOpacity: 0.2,
|
|
542
|
+
shadowRadius: 4,
|
|
543
|
+
elevation: 4
|
|
544
|
+
}}>
|
|
545
|
+
<Text style={{ color: 'white', fontWeight: 'bold', textAlign: 'center', fontSize: 16 }}>
|
|
546
|
+
{state.currentLanguage === "en"
|
|
547
|
+
? "Move the document closer to the camera."
|
|
548
|
+
: "Veuillez rapprocher le document de la caméra."}
|
|
549
|
+
</Text>
|
|
550
|
+
</View>)}
|
|
551
|
+
|
|
552
|
+
<View style={{
|
|
503
553
|
width: '100%',
|
|
504
554
|
height: 200,
|
|
505
555
|
borderRadius: 12,
|
|
506
556
|
padding: 1,
|
|
507
557
|
overflow: 'hidden',
|
|
508
|
-
// Shadow for iOS
|
|
509
558
|
shadowColor: '#000',
|
|
510
559
|
shadowOffset: { width: 0, height: 4 },
|
|
511
560
|
shadowOpacity: 0.18,
|
|
512
561
|
shadowRadius: 8,
|
|
513
|
-
// Shadow for Android
|
|
514
562
|
elevation: 8,
|
|
515
|
-
backgroundColor: '#
|
|
563
|
+
backgroundColor: '#000',
|
|
516
564
|
}}>
|
|
517
|
-
{
|
|
565
|
+
{capturedImages[currentSide]?.dir ? (<Image source={{ uri: capturedImages[currentSide].dir }} style={{
|
|
518
566
|
width: '100%',
|
|
519
|
-
height:
|
|
567
|
+
height: '100%',
|
|
520
568
|
borderRadius: 12,
|
|
521
|
-
resizeMode: '
|
|
522
|
-
}}/>) :
|
|
523
|
-
{!cropImageUri && silentCaptureResult.path ? (<Image source={{ uri: silentCaptureResult.path }} style={{
|
|
569
|
+
resizeMode: 'contain',
|
|
570
|
+
}}/>) : silentCaptureResult.path ? (<Image source={{ uri: silentCaptureResult.path }} style={{
|
|
524
571
|
width: '100%',
|
|
525
|
-
height:
|
|
572
|
+
height: '100%',
|
|
526
573
|
borderRadius: 12,
|
|
527
|
-
resizeMode: '
|
|
574
|
+
resizeMode: 'contain',
|
|
528
575
|
}}/>) : null}
|
|
529
|
-
{!cropImageUri && !silentCaptureResult.path && capturedImages[currentSide]?.dir ? (<Image source={{ uri: capturedImages[currentSide].dir }} style={{
|
|
530
|
-
width: '100%',
|
|
531
|
-
height: 200,
|
|
532
|
-
borderRadius: 12,
|
|
533
|
-
resizeMode: 'cover',
|
|
534
|
-
}}/>) : null}
|
|
535
|
-
|
|
536
576
|
</View>
|
|
537
577
|
{/* Capture button si aucune image n'a été capturée */}
|
|
538
578
|
{!capturedImages[currentSide]?.dir && (<Button title={state.currentLanguage === "en" ? "Take Photo" : "Prendre une photo"} onPress={() => {
|
|
@@ -557,7 +597,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
557
597
|
setShowCamera(true);
|
|
558
598
|
setCurrentSide('back');
|
|
559
599
|
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '', mrz: '', templatePath: '' }));
|
|
560
|
-
setCropImageUri('');
|
|
600
|
+
// setCropImageUri('');
|
|
561
601
|
}
|
|
562
602
|
}} variant="primary" size="large" fullWidth/>
|
|
563
603
|
</>)}
|
|
@@ -809,5 +849,29 @@ const styles = StyleSheet.create({
|
|
|
809
849
|
color: '#666',
|
|
810
850
|
fontWeight: '600',
|
|
811
851
|
},
|
|
852
|
+
floatingErrorBanner: {
|
|
853
|
+
position: 'absolute',
|
|
854
|
+
top: 60, // Pushes it down slightly from the very top of the screen
|
|
855
|
+
left: '10%',
|
|
856
|
+
right: '10%',
|
|
857
|
+
backgroundColor: 'rgba(220, 38, 38, 0.95)', // Bright red
|
|
858
|
+
paddingVertical: 12,
|
|
859
|
+
paddingHorizontal: 16,
|
|
860
|
+
borderRadius: 8,
|
|
861
|
+
alignItems: 'center',
|
|
862
|
+
justifyContent: 'center',
|
|
863
|
+
shadowColor: '#000',
|
|
864
|
+
shadowOffset: { width: 0, height: 4 },
|
|
865
|
+
shadowOpacity: 0.3,
|
|
866
|
+
shadowRadius: 5,
|
|
867
|
+
elevation: 8,
|
|
868
|
+
zIndex: 100,
|
|
869
|
+
},
|
|
870
|
+
floatingErrorText: {
|
|
871
|
+
color: 'white',
|
|
872
|
+
fontSize: 14,
|
|
873
|
+
fontWeight: '700',
|
|
874
|
+
textAlign: 'center',
|
|
875
|
+
},
|
|
812
876
|
});
|
|
813
877
|
//# sourceMappingURL=IDCardCapture.js.map
|