@transfergratis/react-native-sdk 0.1.9 → 0.1.11

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 (77) hide show
  1. package/README.md +433 -94
  2. package/build/components/EnhancedCameraView.d.ts.map +1 -1
  3. package/build/components/EnhancedCameraView.js +8 -1
  4. package/build/components/EnhancedCameraView.js.map +1 -1
  5. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  6. package/build/components/KYCElements/IDCardCapture.js +115 -25
  7. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  8. package/build/components/KYCElements/ReviewSubmitTemplate.js +1 -1
  9. package/build/components/KYCElements/ReviewSubmitTemplate.js.map +1 -1
  10. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
  11. package/build/components/KYCElements/SelfieCaptureTemplate.js +1 -0
  12. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  13. package/build/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  14. package/build/components/KYCElements/VerificationProgressTemplate.js +10 -9
  15. package/build/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  16. package/build/components/OverLay/IdCard.js +3 -3
  17. package/build/components/OverLay/IdCard.js.map +1 -1
  18. package/build/components/OverLay/StepOverlay.d.ts.map +1 -1
  19. package/build/components/OverLay/StepOverlay.js +3 -1
  20. package/build/components/OverLay/StepOverlay.js.map +1 -1
  21. package/build/components/OverLay/type.d.ts +5 -0
  22. package/build/components/OverLay/type.d.ts.map +1 -1
  23. package/build/components/OverLay/type.js.map +1 -1
  24. package/build/components/TemplateKYCExample.js +2 -2
  25. package/build/components/TemplateKYCExample.js.map +1 -1
  26. package/build/config/countriesData.d.ts.map +1 -1
  27. package/build/config/countriesData.js +1 -0
  28. package/build/config/countriesData.js.map +1 -1
  29. package/build/config/region_mapping.d.ts.map +1 -1
  30. package/build/config/region_mapping.js +98 -49
  31. package/build/config/region_mapping.js.map +1 -1
  32. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  33. package/build/hooks/useTemplateKYCFlow.js +7 -6
  34. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  35. package/build/i18n/en/index.d.ts +6 -0
  36. package/build/i18n/en/index.d.ts.map +1 -1
  37. package/build/i18n/en/index.js +7 -1
  38. package/build/i18n/en/index.js.map +1 -1
  39. package/build/i18n/fr/index.d.ts +6 -0
  40. package/build/i18n/fr/index.d.ts.map +1 -1
  41. package/build/i18n/fr/index.js +7 -1
  42. package/build/i18n/fr/index.js.map +1 -1
  43. package/build/modules/api/CardAuthentification.d.ts +23 -2
  44. package/build/modules/api/CardAuthentification.d.ts.map +1 -1
  45. package/build/modules/api/CardAuthentification.js +53 -15
  46. package/build/modules/api/CardAuthentification.js.map +1 -1
  47. package/build/modules/api/KYCService.d.ts +9 -0
  48. package/build/modules/api/KYCService.d.ts.map +1 -1
  49. package/build/modules/api/KYCService.js +52 -29
  50. package/build/modules/api/KYCService.js.map +1 -1
  51. package/build/types/KYC.types.d.ts +3 -0
  52. package/build/types/KYC.types.d.ts.map +1 -1
  53. package/build/types/KYC.types.js.map +1 -1
  54. package/build/utils/logger.d.ts +12 -0
  55. package/build/utils/logger.d.ts.map +1 -0
  56. package/build/utils/logger.js +45 -0
  57. package/build/utils/logger.js.map +1 -0
  58. package/package.json +1 -1
  59. package/src/components/EnhancedCameraView.tsx +8 -2
  60. package/src/components/KYCElements/IDCardCapture.tsx +124 -29
  61. package/src/components/KYCElements/ReviewSubmitTemplate.tsx +1 -1
  62. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +1 -0
  63. package/src/components/KYCElements/VerificationProgressTemplate.tsx +10 -9
  64. package/src/components/OverLay/IdCard.tsx +3 -3
  65. package/src/components/OverLay/StepOverlay.tsx +3 -1
  66. package/src/components/OverLay/type.ts +15 -9
  67. package/src/components/TemplateKYCExample.tsx +2 -2
  68. package/src/config/countriesData.ts +1 -0
  69. package/src/config/region_mapping.json +735 -0
  70. package/src/config/region_mapping.ts +98 -49
  71. package/src/hooks/useTemplateKYCFlow.tsx +7 -6
  72. package/src/i18n/en/index.ts +7 -1
  73. package/src/i18n/fr/index.ts +9 -2
  74. package/src/modules/api/CardAuthentification.ts +61 -18
  75. package/src/modules/api/KYCService.ts +57 -32
  76. package/src/types/KYC.types.ts +3 -0
  77. package/src/utils/logger.ts +48 -0
@@ -1,17 +1,18 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, ScrollView, Dimensions } from 'react-native';
3
3
  import { EnhancedCameraView } from '../EnhancedCameraView';
4
- import { TemplateComponent, IDCardConfig, LocalizedText, GovernmentDocumentType, ISilentCaptureResult } from '../../types/KYC.types';
4
+ import { TemplateComponent, IDCardConfig, LocalizedText, GovernmentDocumentType, ISilentCaptureResult, IBbox } from '../../types/KYC.types';
5
5
  import IdCardOverlay from '../OverLay/IdCard';
6
6
  import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
7
7
  import { useI18n } from '../../hooks/useI18n';
8
8
  import { Button } from '../ui/Button';
9
9
  import { removeDuplicates } from '../../utils/remove-duplicate';
10
- import { backVerification, frontVerification } from '../../modules/api/CardAuthentification';
10
+ import { backVerification, checkTemplateType, frontVerification } from '../../modules/api/CardAuthentification';
11
11
  import { getDocumentTypeInfo } from '../../utils/get-document-type-info';
12
12
  import pathToBase64 from '../../utils/pathToBase64';
13
13
  import { truncateFields } from '../../modules/api/KYCService';
14
- import { cropImageWithBBox } from '../../utils/cropByObb';
14
+ import { cropByObb, cropImageWithBBox } from '../../utils/cropByObb';
15
+ import { logger } from '../../utils/logger';
15
16
 
16
17
 
17
18
  interface IIDCardPayload {
@@ -36,11 +37,13 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
36
37
  error,
37
38
  language = 'en',
38
39
  }) => {
39
- const { t } = useI18n();
40
+ const { t, locale } = useI18n();
40
41
  const [showCamera, setShowCamera] = useState(false);
41
42
  const [capturedImages, setCapturedImages] = useState<Record<string, IIDCardPayload>>(value || {});
42
43
  const [cropImageUri, setCropImageUri] = useState<string>('');
43
44
  const [currentSide, setCurrentSide] = useState<string>('front');
45
+ // Stocker les bbox par côté pour pouvoir restaurer les images croppées
46
+ const [bboxBySide, setBboxBySide] = useState<Record<string, IBbox>>({});
44
47
  const [selectedDocumentType, setSelectedDocumentType] = useState<{
45
48
  type: GovernmentDocumentType;
46
49
  region: string;
@@ -60,12 +63,12 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
60
63
  const { actions, state, } = useTemplateKYCFlowContext();
61
64
  const config = component.config as IDCardConfig;
62
65
 
63
-
66
+
64
67
 
65
68
  const getLocalizedText = (text: LocalizedText | Record<string, LocalizedText>): string => {
66
69
  // console.log("text", text, JSON.stringify(component, null, 2));
67
- if (text && typeof text[currentSide] === 'object' && text[currentSide][language]) {
68
- return text[currentSide][language] || '';
70
+ if (text && typeof text[currentSide] === 'object' && text[currentSide][locale]) {
71
+ return text[currentSide][locale] || '';
69
72
  }
70
73
  return "";
71
74
  };
@@ -92,13 +95,13 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
92
95
  });
93
96
  }
94
97
  }
95
- console.log("newconfig", truncateFields(newconfig));
98
+ logger.log("newconfig", truncateFields(newconfig));
96
99
  return newconfig;
97
100
  }, []);
98
101
 
99
102
 
100
103
  useEffect(() => {
101
- console.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
104
+ logger.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
102
105
  if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
103
106
  cropImageWithBBox(capturedImages[currentSide].dir, silentCaptureResult.bbox)?.then((uri) => {
104
107
  setCropImageUri(uri);
@@ -117,7 +120,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
117
120
  maxRetakes: 3,
118
121
  overlay: {
119
122
  showGuide: true,
120
- guideText: selectedDocumentType ? getDocumentTypeInfo(selectedDocumentType.type).instructions.en : getLocalizedText(component.instructions as Record<string, LocalizedText>),
123
+ guideText: selectedDocumentType ? (locale === 'en' ? getDocumentTypeInfo(selectedDocumentType.type).instructions.en : getDocumentTypeInfo(selectedDocumentType.type).instructions.fr) : getLocalizedText(component.instructions as Record<string, LocalizedText>),
121
124
  bbox: selectedDocumentType && config.bbox_configs[selectedDocumentType.type] ? config.bbox_configs[selectedDocumentType.type] : {
122
125
  xMin: 20,
123
126
  yMin: 140,
@@ -158,6 +161,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
158
161
  const getCurrentSideVerification = (currentSide: string) => {
159
162
  const regionMapping = countryData?.regionMapping[selectedDocumentType?.type as GovernmentDocumentType];
160
163
  const authMethod: string[] = [];
164
+ const mrzTypes: string[] = [];
161
165
 
162
166
  const key = selectedDocumentType?.region?.trim()?.length > 0 ? selectedDocumentType?.region?.trim() : 'root';
163
167
  // console.log("regionMapping", JSON.stringify(regionMapping, null, 2), selectedDocumentType?.region);
@@ -167,44 +171,99 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
167
171
  regionMapping[key].forEach((item: any) => {
168
172
  if (item[currentSide as keyof typeof item]) {
169
173
  authMethod.push(item[currentSide as keyof typeof item]);
174
+ if (item?.mrz_type) {
175
+ mrzTypes.push(item?.mrz_type);
176
+ }
170
177
  }
171
178
  });
172
179
  }
173
180
 
174
- console.log("regionMapping", JSON.stringify(truncateFields({ regionMapping, selectedDocumentType: selectedDocumentType?.region, key }), null, 2));
181
+ logger.log("regionMapping", JSON.stringify(truncateFields({ regionMapping, selectedDocumentType: selectedDocumentType?.region, key }), null, 2));
175
182
 
176
- return removeDuplicates(authMethod);
183
+ return { authMethod: removeDuplicates(authMethod), mrzTypes: removeDuplicates(mrzTypes), regionMapping: regionMapping, key: key };
177
184
  }
178
185
 
186
+ const getCorrespondingMrzType = (templatePath: string, mapping: any, selectedDocumentType: string = "root") => {
187
+ if (!mapping[selectedDocumentType]) return null;
188
+
189
+ // Extraire le nom du fichier depuis le template_path
190
+ const fileName = templatePath.split("/").pop()?.replace(".jpg", "").replace(".png", "");
191
+
192
+ if (!fileName) return null;
193
+
194
+ // Normaliser en .py
195
+ const pyName = `${fileName}.py`; // ex: cameroon_id_back_3_1.py
179
196
 
180
- const handleSilentCapture = (result: { success: boolean; path?: string; error?: string }) => {
197
+ // Chercher dans la liste
198
+ const found = mapping[selectedDocumentType].find((item: any) => item.py_file === pyName);
199
+
200
+ return found?.mrz_type || null;
201
+ }
202
+
203
+ const handleSilentCapture = async (result: { success: boolean; path?: string; error?: string }) => {
181
204
  if (silentCaptureResult.isAnalyzing) {
182
205
  return;
183
206
  }
184
207
  if (result.success && result.path) {
185
208
  setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: true, success: false, error: '' }));
209
+ let templatePath = silentCaptureResult.templatePath || '';
210
+ let templateBbox: IBbox | undefined;
211
+
212
+ const regionMappings = getCurrentSideVerification(currentSide)
213
+ // logger.log("regionMappings", JSON.stringify(truncateFields({regionMappings, templatePath}), null, 2));
214
+ if (regionMappings.authMethod.includes('MRZ') && templatePath.length === 0) {
215
+ try {
216
+ const templateType = await checkTemplateType({ path: result.path || '', docType: selectedDocumentType?.type as GovernmentDocumentType, docRegion: countryData?.code || "", postfix: currentSide });
217
+
218
+ if (templateType.template_path) {
219
+ templatePath = templateType.template_path;
220
+ logger.log("templatePath", templatePath);
221
+ setSilentCaptureResult((prev) => ({ ...prev, templatePath: templatePath }));
222
+ }
223
+ if (templateType.card_obb) {
224
+ let bbox: IBbox | undefined;
225
+ try {
226
+ const crop = await cropByObb(result?.path || '', (templateType as any).card_obb);
227
+ bbox = crop.bbox;
228
+ templateBbox = bbox;
229
+ } catch { }
230
+ }
231
+ } catch (e: any) {
232
+ logger.log("error checking template type", truncateFields(e));
233
+ setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: e?.message || 'Erreur de vérification du template' }));
234
+ }
235
+ }
186
236
  if (currentSide === 'front') {
237
+
187
238
  frontVerification(
188
239
  {
189
240
  path: result.path,
190
- regionMapping: getCurrentSideVerification(currentSide),
241
+ regionMapping: regionMappings,
191
242
  selectedDocumentType: selectedDocumentType?.type || '',
192
243
  code: countryData?.code || '',
193
244
  currentSide: currentSide,
194
-
245
+ templatePath: templatePath,
246
+ mrzType: getCorrespondingMrzType(templatePath, regionMappings.regionMapping, regionMappings.key || '') || '',
195
247
  }).then((mrz) => {
196
- console.log("front verification result", truncateFields(mrz));
248
+ logger.log("front verification result", truncateFields(mrz));
249
+ const bbox = (mrz as any)?.bbox || templateBbox;
197
250
  setSilentCaptureResult((prev) => ({
198
251
  ...prev, path: result.path,
199
- bbox: (mrz as any)?.bbox, success: true,
252
+ bbox: bbox, success: true,
200
253
  mrz: JSON.stringify(mrz), isAnalyzing: false,
201
254
  country: countryData?.code,
202
- documentType: selectedDocumentType?.type
255
+ documentType: selectedDocumentType?.type,
256
+ templatePath: "",
203
257
  }),
204
258
  );
259
+ // Stocker le bbox pour ce côté
260
+ if (bbox && typeof bbox === 'object') {
261
+ setBboxBySide((prev) => ({ ...prev, [currentSide]: bbox }));
262
+ }
263
+
205
264
  }).catch((e: any) => {
206
- console.log("error front verification", truncateFields(e));
207
- setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
265
+ logger.log("error front verification", truncateFields(e));
266
+ setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
208
267
  // Alert.alert('Erreur', e?.message || 'Erreur de détection du MRZ');
209
268
  })
210
269
  } else {
@@ -214,18 +273,25 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
214
273
  selectedDocumentType: selectedDocumentType?.type || '',
215
274
  code: countryData?.code || '',
216
275
  currentSide: currentSide,
217
-
276
+ templatePath: templatePath,
277
+ mrzType: getCorrespondingMrzType(templatePath, regionMappings.regionMapping, regionMappings.key || '') || '',
218
278
  }).then((mrz) => {
219
- console.log("back verification result", truncateFields(mrz));
279
+ logger.log("back verification result", truncateFields(mrz));
280
+ const bbox = (mrz as any)?.bbox || templateBbox;
220
281
  setSilentCaptureResult((prev) => ({
221
- ...prev, path: result.path, bbox: (mrz as any)?.bbox,
282
+ ...prev, path: result.path, bbox: bbox,
222
283
  success: true, mrz: JSON.stringify(mrz), isAnalyzing: false,
223
284
  country: countryData?.code,
224
- documentType: selectedDocumentType?.type
285
+ documentType: selectedDocumentType?.type,
286
+ templatePath: "",
225
287
  }));
288
+ // Stocker le bbox pour ce côté
289
+ if (bbox && typeof bbox === 'object') {
290
+ setBboxBySide((prev) => ({ ...prev, [currentSide]: bbox }));
291
+ }
226
292
  }).catch((e: any) => {
227
- console.log("error back verification", truncateFields(e));
228
- setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
293
+ logger.log("error back verification", truncateFields(e));
294
+ setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
229
295
  // Alert.alert('Erreur', e?.message || 'Erreur de détection du MRZ');
230
296
  })
231
297
  }
@@ -344,7 +410,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
344
410
  }
345
411
 
346
412
  if (showDocumentSelection.regionSelection) {
347
- console.log("showDocumentSelection", JSON.stringify(truncateFields(showDocumentSelection), null, 2));
413
+ logger.log("showDocumentSelection", JSON.stringify(truncateFields(showDocumentSelection), null, 2));
348
414
  setShowDocumentSelection({
349
415
  documentSelection: false,
350
416
  regionSelection: false
@@ -420,7 +486,26 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
420
486
  documentSelection: false,
421
487
  regionSelection: false
422
488
  });
423
- setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '' }));
489
+ // Si une image front existe, on la restaure pour l'afficher
490
+ if (capturedImages['front']?.dir) {
491
+ // Restaurer l'état de capture du front pour afficher l'image
492
+ const frontImage = capturedImages['front'];
493
+ const frontBbox = bboxBySide['front'];
494
+ setSilentCaptureResult((prev) => ({
495
+ path: frontImage.dir,
496
+ success: true,
497
+ isAnalyzing: false,
498
+ error: '',
499
+ mrz: frontImage.mrz || '',
500
+ country: silentCaptureResult.country,
501
+ documentType: silentCaptureResult.documentType,
502
+ bbox: frontBbox // Restaurer le bbox pour recalculer le cropImageUri
503
+ }));
504
+ // Le useEffect va automatiquement recalculer le cropImageUri si bbox existe
505
+ } else {
506
+ // Pas d'image front, on réinitialise
507
+ setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '' }));
508
+ }
424
509
  } else {
425
510
  setShowDocumentSelection({
426
511
  documentSelection: true,
@@ -429,9 +514,10 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
429
514
  actions.showCustomStepper(true);
430
515
  }
431
516
  },
432
- selectedDocumentType: getDocumentTypeInfo(selectedDocumentType?.type || "identity_card").name.en || '',
517
+ selectedDocumentType: locale === 'en' ? getDocumentTypeInfo(selectedDocumentType?.type || "identity_card").name.en : getDocumentTypeInfo(selectedDocumentType?.type || "identity_card").name.fr || '',
433
518
  step: state.currentComponentIndex + 1,
434
519
  totalSteps: state.template.components.length,
520
+ side: currentSide,
435
521
  }}
436
522
  />
437
523
  }
@@ -482,6 +568,15 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
482
568
  }}
483
569
  />
484
570
  ) : null}
571
+ {silentCaptureResult.path ? (<Image
572
+ source={{ uri: silentCaptureResult.path }}
573
+ style={{
574
+ width: '100%',
575
+ height: 200,
576
+ borderRadius: 12,
577
+ resizeMode: 'cover',
578
+ }}
579
+ />) : null}
485
580
 
486
581
  </View>
487
582
  {/* retake button */}
@@ -89,7 +89,7 @@ export const ReviewSubmitTemplate: React.FC<ReviewSubmitTemplateProps> = () => {
89
89
  const colorStyle = o === 'center' ? styles.pink : o === 'right' ? styles.blue : styles.purple;
90
90
  return (
91
91
  <View key={o} style={[styles.tile, colorStyle, has ? styles.active : null]}>
92
- <Text style={styles.tileLabel}>{o.charAt(0).toUpperCase() + o.slice(1)}</Text>
92
+ <Text style={styles.tileLabel}>{t(`kyc.reviewSubmit.selfieSide.${o}`)}</Text>
93
93
  {has ? <Text style={styles.check}>✓</Text> : null}
94
94
  </View>
95
95
  );
@@ -253,6 +253,7 @@ export const SelfieCaptureTemplate: React.FC<SelfieCaptureTemplateProps> = ({
253
253
  selectedDocumentType: "Selfie",
254
254
  step: state.currentComponentIndex + 1,
255
255
  totalSteps: state.template.components.length,
256
+ side: currentOrientation,
256
257
  }} />}
257
258
  />
258
259
  </View>
@@ -4,6 +4,7 @@ import { TemplateComponent } from '../../types/KYC.types';
4
4
  import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
5
5
  import { useI18n } from '../../hooks/useI18n';
6
6
  import kycService from '../../modules/api/KYCService';
7
+ import { logger } from '../../utils/logger';
7
8
 
8
9
  interface VerificationProgressTemplateProps {
9
10
  component: TemplateComponent;
@@ -28,12 +29,12 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
28
29
  // Fonction pour récupérer le résultat de vérification avec retry
29
30
  const getVerificationResult = async (currentRetryCount = 0, maxRetries = 40) => {
30
31
  try {
31
- console.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
32
+ logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
32
33
 
33
34
  const result = await kycService.getVerificationResult(state.session.session_id);
34
35
  const verificationResult = result[state.session.session_id].data;
35
36
 
36
- console.log('getVerificationResult result', JSON.stringify(result, null, 2));
37
+ logger.log('getVerificationResult result', JSON.stringify(result, null, 2));
37
38
 
38
39
  // Vérifier le statut de vérification
39
40
  if (verificationResult.verification_status === null || verificationResult.verification_status === "processing" || verificationResult.verification_status === "pending") {
@@ -42,7 +43,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
42
43
  setRetryCount(nextRetryCount);
43
44
  setIsRetrying(true);
44
45
 
45
- console.log(`Verification still processing, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
46
+ logger.log(`Verification still processing, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
46
47
 
47
48
  // Nettoyer le timeout précédent s'il existe
48
49
  if (timeoutId) {
@@ -57,7 +58,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
57
58
  setTimeoutId(newTimeoutId);
58
59
  return; // Sortir de la fonction pour éviter de traiter le résultat
59
60
  } else {
60
- console.error('Max retries reached, verification still processing');
61
+ logger.error('Max retries reached, verification still processing');
61
62
  setIsRetrying(false);
62
63
  return;
63
64
  }
@@ -86,7 +87,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
86
87
  setIsRetrying(false);
87
88
 
88
89
  } catch (error) {
89
- console.error('getVerificationResult error', error);
90
+ logger.error('getVerificationResult error', error);
90
91
 
91
92
  // En cas d'erreur, on peut aussi retry
92
93
  if (currentRetryCount < maxRetries) {
@@ -94,7 +95,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
94
95
  setRetryCount(nextRetryCount);
95
96
  setIsRetrying(true);
96
97
 
97
- console.log(`Error occurred, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
98
+ logger.log(`Error occurred, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
98
99
 
99
100
  // Nettoyer le timeout précédent s'il existe
100
101
  if (timeoutId) {
@@ -108,7 +109,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
108
109
  setTimeoutId(newTimeoutId);
109
110
  } else {
110
111
  setIsRetrying(false);
111
- console.error('Max retries reached after errors');
112
+ logger.error('Max retries reached after errors');
112
113
  }
113
114
  }
114
115
  };
@@ -155,7 +156,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
155
156
  ))}
156
157
  </View>
157
158
  <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.goToComponent(state.template.components.find(c => c.type !== 'review_submit' && c.type !== 'verification_progress')?.id || 0)}>
158
- <Text style={styles.buttonText}>{t('common.retry')}</Text>
159
+ <Text style={styles.buttonText}>{t('kyc.verificationProgress.status.retry')}</Text>
159
160
  </TouchableOpacity>
160
161
  <TouchableOpacity style={[styles.button, styles.secondary]}>
161
162
  <Text style={styles.secondaryText}>{t('common.info')}</Text>
@@ -178,7 +179,7 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
178
179
  <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>
179
180
  <Text style={styles.subtitle}>
180
181
  {isRetrying
181
- ? `${t('kyc.verificationProgress.retrying')} (${retryCount}/10)`
182
+ ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: 40 })}`
182
183
  : t('kyc.verificationProgress.estimatedTime')
183
184
  }
184
185
  </Text>
@@ -141,14 +141,14 @@ const IdCardOverlay = ({ xMin: xMinProps, yMin: yMinProps, xMax: xMaxProps, yMax
141
141
 
142
142
  <View style={styles.bottomIntruction}>
143
143
  <Text style={styles.bottomTitle}>
144
- {language === "en" ? "Measure 100cm in height.":"Mesurez 100cm de hauteur."}
144
+ {language === "en" ? `Scan the ${stepperProps?.side === 'front' ? 'front' : 'back'} side of your ${stepperProps?.selectedDocumentType}.`:`Scanner de la face ${stepperProps?.side === 'front' ? 'avant' : 'arrière'} de votre ${stepperProps?.selectedDocumentType}.`}
145
145
 
146
146
  </Text>
147
147
  <Text style={styles.bottomSubtitle}>
148
148
  {
149
149
  language === "en"
150
- ? "Do not move the camera during capture. Do not move the camera during capture."
151
- : "Ne pas déplacer la caméra pendant la capture. Ne pas déplacer la caméra pendant la capture."
150
+ ? "Hold your ID card steady and make sure all corners are visible. Do not move your phone while the image is being captured."
151
+ : "Maintenez votre carte d'identité stable et assurez-vous que tous les coins sont visibles. Ne déplacez pas votre téléphone pendant la capture."
152
152
  }
153
153
 
154
154
  </Text>
@@ -1,4 +1,5 @@
1
1
  import { StyleSheet, View, TouchableOpacity, Text } from "react-native";
2
+ import useI18n from "../../hooks/useI18n";
2
3
 
3
4
  interface StepOverlayProps {
4
5
  back: () => void;
@@ -7,6 +8,7 @@ interface StepOverlayProps {
7
8
  totalSteps: number;
8
9
  }
9
10
  const StepOverlay = ({ back, selectedDocumentType, step, totalSteps }: StepOverlayProps) => {
11
+ const { t } = useI18n();
10
12
  return (
11
13
  <View style={styles.stepperContainer}>
12
14
  <TouchableOpacity onPress={back} style={styles.back}>
@@ -16,7 +18,7 @@ const StepOverlay = ({ back, selectedDocumentType, step, totalSteps }: StepOverl
16
18
  <Text style={styles.stepperItemText}>{selectedDocumentType}</Text>
17
19
  </View>
18
20
  <View style={styles.stepperDetails}>
19
- <Text style={styles.stepperDetailsText}>Step {step} of {totalSteps}</Text>
21
+ <Text style={styles.stepperDetailsText}>{t('kyc.step', { current: step, total: totalSteps })}</Text>
20
22
  </View>
21
23
  </View>
22
24
  )
@@ -15,7 +15,7 @@ export interface IdCardOverlayProps {
15
15
  orientation?: 'center' | 'left' | 'right';
16
16
  isAnalyzing?: boolean;
17
17
  isSuccess?: boolean;
18
- language:string
18
+ language: string
19
19
  }
20
20
 
21
21
 
@@ -24,6 +24,7 @@ interface StepperProps {
24
24
  selectedDocumentType: string;
25
25
  step: number;
26
26
  totalSteps: number;
27
+ side: string;
27
28
  }
28
29
 
29
30
  export interface ExtractMrzTextResponse {
@@ -65,13 +66,13 @@ export interface EnhancedCameraViewProps {
65
66
  showSwitchCamera?: boolean;
66
67
  overlayComponent?: React.ReactNode;
67
68
  bbox?: {
68
- xMin: number;
69
- yMin: number;
70
- xMax: number;
71
- yMax: number;
72
- borderColor?: string;
73
- borderWidth?: number;
74
- cornerRadius?: number;
69
+ xMin: number;
70
+ yMin: number;
71
+ xMax: number;
72
+ yMax: number;
73
+ borderColor?: string;
74
+ borderWidth?: number;
75
+ cornerRadius?: number;
75
76
  };
76
77
  canFlip?: boolean;
77
78
  // Video recording props
@@ -80,4 +81,9 @@ export interface EnhancedCameraViewProps {
80
81
  onVideoRecordingStart?: () => void;
81
82
  onVideoRecordingStop?: (result: { success: boolean; path?: string; error?: string }) => void;
82
83
  videoDuration?: number;
83
- }
84
+ }
85
+
86
+ export interface CheckTemplateTypeResponse {
87
+ template_path: string;
88
+ lpips_score: number;
89
+ }
@@ -56,8 +56,8 @@ const advancedVerificationTemplate: KYCTemplate = {
56
56
  buttonText: { en: "Confirm", fr: "Confirmer" }
57
57
  },
58
58
  config: {
59
- allowed_countries: ["CA", "FR", "CM", "US", "DE", "SN", "NG", "MA", "DZ","CI", "KE","GH"],
60
- default_country: "CA",
59
+ allowed_countries: ["CM", "NG", "CI", "KE","GH"],
60
+ default_country: "CM",
61
61
  required: true
62
62
  } as const
63
63
  },
@@ -81,4 +81,5 @@ export const countryData: Record<string, Country> = {
81
81
  IS: { name: 'Islande', name_en: "Iceland", flag: '🇮🇸' },
82
82
  IE: { name: 'Irlande', name_en: "Ireland", flag: '🇮🇪' },
83
83
  NZ: { name: 'Nouvelle-Zélande', name_en: "New Zealand", flag: '🇳🇿' },
84
+ GH: { name: 'Ghana', name_en: "Ghana", flag: '🇬🇭' },
84
85
  };