@transfergratis/react-native-sdk 0.1.28 → 0.1.29
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 +64 -31
- 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 +215 -50
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +2 -0
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +16 -19
- 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 +115 -86
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +2 -2
- package/src/hooks/useTemplateKYCFlow.tsx +1 -1
- package/src/modules/api/CardAuthentification.ts +289 -64
- package/src/modules/api/KYCService.ts +25 -33
- package/src/modules/camera/VisionCameraModule.ts +2 -2
- package/src/utils/cropByObb.ts +22 -3
- package/src/utils/pathToBase64.ts +1 -1
|
@@ -43,7 +43,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
43
43
|
const { t, locale } = useI18n();
|
|
44
44
|
const [showCamera, setShowCamera] = useState(false);
|
|
45
45
|
const [capturedImages, setCapturedImages] = useState<Record<string, IIDCardPayload>>(value || {});
|
|
46
|
-
const [cropImageUri, setCropImageUri] = useState<string>('');
|
|
46
|
+
// const [cropImageUri, setCropImageUri] = useState<string>('');
|
|
47
47
|
const [currentSide, setCurrentSide] = useState<string>('front');
|
|
48
48
|
// Stocker les bbox par côté pour pouvoir restaurer les images croppées
|
|
49
49
|
const [bboxBySide, setBboxBySide] = useState<Record<string, IBbox>>({});
|
|
@@ -97,6 +97,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
97
97
|
return countrySelectionData;
|
|
98
98
|
}, [countrySelectionData]);
|
|
99
99
|
|
|
100
|
+
// console.log();
|
|
100
101
|
|
|
101
102
|
// Synchroniser capturedImages avec value quand les données sont chargées (ex: reprise de session)
|
|
102
103
|
useEffect(() => {
|
|
@@ -131,7 +132,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
131
132
|
logger.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
|
|
132
133
|
if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
|
|
133
134
|
cropImageWithBBox(capturedImages[currentSide].dir, silentCaptureResult.bbox)?.then((uri) => {
|
|
134
|
-
setCropImageUri(uri);
|
|
135
|
+
// setCropImageUri(uri);
|
|
135
136
|
});
|
|
136
137
|
}
|
|
137
138
|
}, [capturedImages[currentSide]?.dir, silentCaptureResult?.bbox])
|
|
@@ -145,9 +146,11 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
145
146
|
|
|
146
147
|
return {
|
|
147
148
|
aspectRatio: 4 / 3,
|
|
148
|
-
quality: 0.
|
|
149
|
+
quality: 0.7,
|
|
149
150
|
flashMode: 'auto' as const,
|
|
150
151
|
cameraType: 'back' as const,
|
|
152
|
+
autoFocus: 'on',
|
|
153
|
+
whiteBalance: 'auto',
|
|
151
154
|
allowRetake: true,
|
|
152
155
|
maxRetakes: 3,
|
|
153
156
|
overlay: {
|
|
@@ -170,8 +173,19 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
170
173
|
setShowCamera(true);
|
|
171
174
|
actions.showCustomStepper(false);
|
|
172
175
|
setCapturedImages({ ...capturedImages, [currentSide]: { dir: '', file: '', mrz: '' } });
|
|
173
|
-
|
|
174
|
-
|
|
176
|
+
|
|
177
|
+
setSilentCaptureResult((prev) => ({
|
|
178
|
+
...prev,
|
|
179
|
+
path: '',
|
|
180
|
+
success: false,
|
|
181
|
+
isAnalyzing: false,
|
|
182
|
+
error: '',
|
|
183
|
+
templatePath: '',
|
|
184
|
+
bbox: undefined,
|
|
185
|
+
mrz: ''
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
// setCropImageUri('');
|
|
175
189
|
onValueChange({ ...value, [currentSide]: { dir: '', file: '', mrz: '' } });
|
|
176
190
|
};
|
|
177
191
|
|
|
@@ -381,31 +395,32 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
381
395
|
}
|
|
382
396
|
}
|
|
383
397
|
|
|
384
|
-
// Handle capture
|
|
385
398
|
const handleCapture = async (result: { success: boolean; path?: string; error?: string }) => {
|
|
386
|
-
console.log("handleCapture", JSON.stringify(truncateFields({ result, silentCaptureResult }), null, 2));
|
|
387
|
-
|
|
388
399
|
if (silentCaptureResult.path) {
|
|
389
|
-
// Créer une image rognée avec tolérance de 10% pour l'envoi
|
|
390
400
|
let imagePathForUpload = silentCaptureResult.path;
|
|
391
401
|
if (silentCaptureResult.bbox) {
|
|
392
402
|
try {
|
|
393
|
-
logger.log("Début du rognage avec tolérance, URI original:", silentCaptureResult.path);
|
|
394
403
|
imagePathForUpload = await cropImageWithBBoxWithTolerance(silentCaptureResult.path, silentCaptureResult.bbox, 0.05);
|
|
395
|
-
logger.log("Image rognée avec tolérance créée pour l'envoi, URI final:", imagePathForUpload);
|
|
396
404
|
} catch (error) {
|
|
397
|
-
logger.log("Erreur lors du rognage avec tolérance, utilisation de l'image originale:", truncateFields(error));
|
|
398
|
-
// En cas d'erreur, on utilise l'image originale
|
|
399
405
|
imagePathForUpload = silentCaptureResult.path;
|
|
400
406
|
}
|
|
401
407
|
}
|
|
402
408
|
|
|
403
409
|
const base64 = await pathToBase64(imagePathForUpload);
|
|
404
410
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
411
|
+
// ✅ FIX: Use 'imagePathForUpload' (the cropped image) for the local display directory!
|
|
412
|
+
const newImages = {
|
|
413
|
+
...capturedImages,
|
|
414
|
+
[currentSide]: {
|
|
415
|
+
dir: imagePathForUpload, // <--- CHANGED THIS LINE
|
|
416
|
+
file: base64,
|
|
417
|
+
mrz: silentCaptureResult.mrz || "",
|
|
418
|
+
templatePath: silentCaptureResult.templatePath
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
408
422
|
setCapturedImages(newImages);
|
|
423
|
+
|
|
409
424
|
if (silentCaptureResult.country && silentCaptureResult.documentType) {
|
|
410
425
|
onValueChange({
|
|
411
426
|
...newImages,
|
|
@@ -425,10 +440,6 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
425
440
|
setShowCamera(false);
|
|
426
441
|
};
|
|
427
442
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
443
|
useEffect(() => {
|
|
433
444
|
actions.showCustomStepper(!showCamera);
|
|
434
445
|
}, [showCamera]);
|
|
@@ -531,7 +542,6 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
531
542
|
|
|
532
543
|
|
|
533
544
|
if (showCamera) {
|
|
534
|
-
|
|
535
545
|
return (
|
|
536
546
|
<View style={styles.cameraContainer}>
|
|
537
547
|
<EnhancedCameraView
|
|
@@ -548,54 +558,63 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
548
558
|
silentCaptureResult={silentCaptureResult}
|
|
549
559
|
captureStabilizationDelayMs={3000}
|
|
550
560
|
enableFlash={cameraConfig.flashMode === 'auto' || cameraConfig.flashMode === 'on'}
|
|
551
|
-
overlayComponent={
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
561
|
+
overlayComponent={
|
|
562
|
+
<IdCardOverlay
|
|
563
|
+
xMin={cameraConfig.overlay.bbox.xMin}
|
|
564
|
+
yMin={cameraConfig.overlay.bbox.yMin}
|
|
565
|
+
xMax={cameraConfig.overlay.bbox.xMax}
|
|
566
|
+
yMax={cameraConfig.overlay.bbox.yMax}
|
|
567
|
+
instructions={cameraConfig.overlay.guideText}
|
|
568
|
+
cornerOpacity={cameraConfig.overlay.bbox.cornerRadius || 0 as number}
|
|
569
|
+
isSuccess={silentCaptureResult.success}
|
|
570
|
+
language={state.currentLanguage}
|
|
571
|
+
stepperProps={{
|
|
572
|
+
back: () => {
|
|
573
|
+
if (currentSide === 'back') {
|
|
574
|
+
setCurrentSide('front');
|
|
575
|
+
setShowCamera(false);
|
|
576
|
+
// Si une image front existe, on la restaure pour l'afficher
|
|
577
|
+
if (capturedImages['front']?.dir) {
|
|
578
|
+
// Restaurer l'état de capture du front pour afficher l'image
|
|
579
|
+
const frontImage = capturedImages['front'];
|
|
580
|
+
const frontBbox = bboxBySide['front'];
|
|
581
|
+
setSilentCaptureResult((prev) => ({
|
|
582
|
+
path: frontImage.dir,
|
|
583
|
+
success: true,
|
|
584
|
+
isAnalyzing: false,
|
|
585
|
+
error: '',
|
|
586
|
+
mrz: frontImage.mrz || '',
|
|
587
|
+
templatePath: frontImage.templatePath || '',
|
|
588
|
+
country: silentCaptureResult.country,
|
|
589
|
+
documentType: silentCaptureResult.documentType,
|
|
590
|
+
bbox: frontBbox // Restaurer le bbox pour recalculer le cropImageUri
|
|
591
|
+
}));
|
|
592
|
+
} else {
|
|
593
|
+
// Pas d'image front, on réinitialise
|
|
594
|
+
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '', templatePath: '' }));
|
|
595
|
+
}
|
|
582
596
|
} else {
|
|
583
|
-
//
|
|
584
|
-
|
|
597
|
+
// Retour au composant précédent (country_selection)
|
|
598
|
+
actions.previousComponent();
|
|
585
599
|
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
totalSteps: state.template.components.length,
|
|
594
|
-
side: currentSide,
|
|
595
|
-
}}
|
|
596
|
-
/>
|
|
600
|
+
},
|
|
601
|
+
selectedDocumentType: selectedDocumentType ? (locale === 'en' ? getDocumentTypeInfo(selectedDocumentType.type).name.en : getDocumentTypeInfo(selectedDocumentType.type).name.fr) : '',
|
|
602
|
+
step: state.currentComponentIndex + 1,
|
|
603
|
+
totalSteps: state.template.components.length,
|
|
604
|
+
side: currentSide,
|
|
605
|
+
}}
|
|
606
|
+
/>
|
|
597
607
|
}
|
|
598
608
|
/>
|
|
609
|
+
|
|
610
|
+
{silentCaptureResult.error ? (
|
|
611
|
+
<View style={styles.floatingErrorBanner}>
|
|
612
|
+
<Text style={styles.floatingErrorText}>
|
|
613
|
+
{silentCaptureResult.error}
|
|
614
|
+
</Text>
|
|
615
|
+
</View>
|
|
616
|
+
) : null}
|
|
617
|
+
|
|
599
618
|
</View>
|
|
600
619
|
);
|
|
601
620
|
}
|
|
@@ -614,26 +633,25 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
614
633
|
</Text>
|
|
615
634
|
|
|
616
635
|
<View style={{ alignItems: 'center', justifyContent: 'center', flexDirection: "column", gap: 16 }}>
|
|
617
|
-
|
|
636
|
+
<View
|
|
618
637
|
style={{
|
|
619
638
|
width: '100%',
|
|
620
639
|
height: 200,
|
|
621
640
|
borderRadius: 12,
|
|
622
641
|
padding: 1,
|
|
623
642
|
overflow: 'hidden',
|
|
624
|
-
// Shadow for iOS
|
|
625
643
|
shadowColor: '#000',
|
|
626
644
|
shadowOffset: { width: 0, height: 4 },
|
|
627
645
|
shadowOpacity: 0.18,
|
|
628
646
|
shadowRadius: 8,
|
|
629
|
-
// Shadow for Android
|
|
630
647
|
elevation: 8,
|
|
631
|
-
backgroundColor: '#fff',
|
|
648
|
+
backgroundColor: '#fff',
|
|
632
649
|
}}
|
|
633
650
|
>
|
|
634
|
-
{
|
|
651
|
+
{/* Simplified logic: Always show the saved, pre-cropped capture! */}
|
|
652
|
+
{capturedImages[currentSide]?.dir ? (
|
|
635
653
|
<Image
|
|
636
|
-
source={{ uri:
|
|
654
|
+
source={{ uri: capturedImages[currentSide].dir }}
|
|
637
655
|
style={{
|
|
638
656
|
width: '100%',
|
|
639
657
|
height: 200,
|
|
@@ -641,8 +659,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
641
659
|
resizeMode: 'cover',
|
|
642
660
|
}}
|
|
643
661
|
/>
|
|
644
|
-
) :
|
|
645
|
-
{!cropImageUri && silentCaptureResult.path ? (
|
|
662
|
+
) : silentCaptureResult.path ? (
|
|
646
663
|
<Image
|
|
647
664
|
source={{ uri: silentCaptureResult.path }}
|
|
648
665
|
style={{
|
|
@@ -653,18 +670,6 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
653
670
|
}}
|
|
654
671
|
/>
|
|
655
672
|
) : null}
|
|
656
|
-
{!cropImageUri && !silentCaptureResult.path && capturedImages[currentSide]?.dir ? (
|
|
657
|
-
<Image
|
|
658
|
-
source={{ uri: capturedImages[currentSide].dir }}
|
|
659
|
-
style={{
|
|
660
|
-
width: '100%',
|
|
661
|
-
height: 200,
|
|
662
|
-
borderRadius: 12,
|
|
663
|
-
resizeMode: 'cover',
|
|
664
|
-
}}
|
|
665
|
-
/>
|
|
666
|
-
) : null}
|
|
667
|
-
|
|
668
673
|
</View>
|
|
669
674
|
{/* Capture button si aucune image n'a été capturée */}
|
|
670
675
|
{!capturedImages[currentSide]?.dir && (
|
|
@@ -701,7 +706,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
701
706
|
setShowCamera(true);
|
|
702
707
|
setCurrentSide('back');
|
|
703
708
|
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '', mrz: '', templatePath: '' }));
|
|
704
|
-
setCropImageUri('');
|
|
709
|
+
// setCropImageUri('');
|
|
705
710
|
}
|
|
706
711
|
}}
|
|
707
712
|
variant="primary"
|
|
@@ -980,4 +985,28 @@ const styles = StyleSheet.create({
|
|
|
980
985
|
color: '#666',
|
|
981
986
|
fontWeight: '600',
|
|
982
987
|
},
|
|
988
|
+
floatingErrorBanner: {
|
|
989
|
+
position: 'absolute',
|
|
990
|
+
top: 60, // Pushes it down slightly from the very top of the screen
|
|
991
|
+
left: '10%',
|
|
992
|
+
right: '10%',
|
|
993
|
+
backgroundColor: 'rgba(220, 38, 38, 0.95)', // Bright red
|
|
994
|
+
paddingVertical: 12,
|
|
995
|
+
paddingHorizontal: 16,
|
|
996
|
+
borderRadius: 8,
|
|
997
|
+
alignItems: 'center',
|
|
998
|
+
justifyContent: 'center',
|
|
999
|
+
shadowColor: '#000',
|
|
1000
|
+
shadowOffset: { width: 0, height: 4 },
|
|
1001
|
+
shadowOpacity: 0.3,
|
|
1002
|
+
shadowRadius: 5,
|
|
1003
|
+
elevation: 8,
|
|
1004
|
+
zIndex: 100,
|
|
1005
|
+
},
|
|
1006
|
+
floatingErrorText: {
|
|
1007
|
+
color: 'white',
|
|
1008
|
+
fontSize: 14,
|
|
1009
|
+
fontWeight: '700',
|
|
1010
|
+
textAlign: 'center',
|
|
1011
|
+
},
|
|
983
1012
|
});
|
|
@@ -76,9 +76,9 @@ export const SelfieCaptureTemplate: React.FC<SelfieCaptureTemplateProps> = ({
|
|
|
76
76
|
const getOrientationLabel = (orientation: OrientationType): string => {
|
|
77
77
|
switch (orientation) {
|
|
78
78
|
case 'center':
|
|
79
|
-
return state.currentLanguage === "en" ? "Front
|
|
79
|
+
return state.currentLanguage === "en" ? "Front Profile Selfie" : "Selfie de face";
|
|
80
80
|
case 'left':
|
|
81
|
-
return state.currentLanguage === "en" ? "Left
|
|
81
|
+
return state.currentLanguage === "en" ? "Left Profile Selfie" : "Selfie profil gauche";
|
|
82
82
|
case 'right':
|
|
83
83
|
return state.currentLanguage === "en" ? "Right Profile Selfie" : "Selfie profil droit";
|
|
84
84
|
default:
|
|
@@ -822,7 +822,7 @@ export const useTemplateKYCFlow = (
|
|
|
822
822
|
isProcessing: false,
|
|
823
823
|
errors: {
|
|
824
824
|
...prev.errors,
|
|
825
|
-
[currentComp.id]: state.currentLanguage === "en" ? "please complete this step before
|
|
825
|
+
[currentComp.id]: state.currentLanguage === "en" ? "please complete this step before moving on" : " 'Veuillez compléter cette étape avant de continuer'"
|
|
826
826
|
}
|
|
827
827
|
}));
|
|
828
828
|
return;
|