@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.
Files changed (39) hide show
  1. package/build/components/EnhancedCameraView.js +1 -1
  2. package/build/components/EnhancedCameraView.js.map +1 -1
  3. package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  4. package/build/components/KYCElements/CountrySelectionTemplate.js +13 -42
  5. package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  6. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  7. package/build/components/KYCElements/IDCardCapture.js +113 -49
  8. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  9. package/build/components/KYCElements/SelfieCaptureTemplate.js +2 -2
  10. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  11. package/build/hooks/useTemplateKYCFlow.js +1 -1
  12. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  13. package/build/modules/api/CardAuthentification.d.ts +15 -7
  14. package/build/modules/api/CardAuthentification.d.ts.map +1 -1
  15. package/build/modules/api/CardAuthentification.js +360 -104
  16. package/build/modules/api/CardAuthentification.js.map +1 -1
  17. package/build/modules/api/KYCService.d.ts +3 -1
  18. package/build/modules/api/KYCService.d.ts.map +1 -1
  19. package/build/modules/api/KYCService.js +25 -24
  20. package/build/modules/api/KYCService.js.map +1 -1
  21. package/build/modules/camera/VisionCameraModule.js +2 -2
  22. package/build/modules/camera/VisionCameraModule.js.map +1 -1
  23. package/build/utils/cropByObb.d.ts +8 -0
  24. package/build/utils/cropByObb.d.ts.map +1 -1
  25. package/build/utils/cropByObb.js +20 -3
  26. package/build/utils/cropByObb.js.map +1 -1
  27. package/build/utils/pathToBase64.js +1 -1
  28. package/build/utils/pathToBase64.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/components/EnhancedCameraView.tsx +1 -1
  31. package/src/components/KYCElements/CountrySelectionTemplate.tsx +24 -52
  32. package/src/components/KYCElements/IDCardCapture.tsx +179 -109
  33. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +2 -2
  34. package/src/hooks/useTemplateKYCFlow.tsx +1 -1
  35. package/src/modules/api/CardAuthentification.ts +450 -113
  36. package/src/modules/api/KYCService.ts +52 -39
  37. package/src/modules/camera/VisionCameraModule.ts +2 -2
  38. package/src/utils/cropByObb.ts +22 -3
  39. package/src/utils/pathToBase64.ts +1 -1
@@ -25,7 +25,7 @@ async function copyFileCompat(from, to) {
25
25
  // This is the recommended way to avoid deprecation warnings
26
26
  try {
27
27
  // @ts-ignore - legacy export might not be in types
28
- const LegacyFileSystem = require('expo-file-system/legacy');
28
+ const LegacyFileSystem = require('expo-file-system');
29
29
  if (LegacyFileSystem && LegacyFileSystem.copyAsync && typeof LegacyFileSystem.copyAsync === 'function') {
30
30
  await LegacyFileSystem.copyAsync({ from, to });
31
31
  return;
@@ -80,7 +80,7 @@ function getDocumentDirectory() {
80
80
  // This is the recommended way to avoid deprecation warnings
81
81
  try {
82
82
  // @ts-ignore
83
- const LegacyFileSystem = require('expo-file-system/legacy');
83
+ const LegacyFileSystem = require('expo-file-system');
84
84
  if (LegacyFileSystem && LegacyFileSystem.documentDirectory) {
85
85
  return LegacyFileSystem.documentDirectory;
86
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VisionCameraModule.js","sourceRoot":"","sources":["../../../src/modules/camera/VisionCameraModule.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\nimport { Camera, CameraDevice, CameraPermissionStatus, PhotoFile } from 'react-native-vision-camera';\n\n/**\n * Backward-compatible file copy function\n * Tries new File API first (Expo SDK 54+), then legacy API, then regular import for SDK 53\n */\nasync function copyFileCompat(from: string, to: string): Promise<void> {\n // Try new File API first (Expo SDK 54+)\n try {\n // @ts-ignore - File API might not be in types yet\n const { File } = require('expo-file-system');\n if (File && typeof File === 'function') {\n const sourceFile = new File(from);\n const destFile = new File(to);\n // File.copy() is synchronous but may throw\n sourceFile.copy(destFile);\n return;\n }\n } catch (error) {\n // New API not available or failed, try legacy\n // Continue to legacy API\n }\n\n // Try legacy API from expo-file-system/legacy (Expo SDK 54+)\n // This is the recommended way to avoid deprecation warnings\n try {\n // @ts-ignore - legacy export might not be in types\n const LegacyFileSystem = require('expo-file-system/legacy');\n if (LegacyFileSystem && LegacyFileSystem.copyAsync && typeof LegacyFileSystem.copyAsync === 'function') {\n await LegacyFileSystem.copyAsync({ from, to });\n return;\n }\n } catch (error) {\n // Legacy not available (SDK 53 or earlier), fall through to regular import\n // Check if it's a \"module not found\" error (SDK 53) vs other error\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (errorMessage.includes('Cannot find module') || errorMessage.includes('Module not found')) {\n // SDK 53 or earlier - use regular import as fallback\n // This will show a deprecation warning on SDK 54+, but is necessary for SDK 53 compatibility\n } else {\n // Other error, re-throw\n throw new Error(`Unable to copy file: legacy FileSystem API error. Error: ${errorMessage}`);\n }\n }\n\n // Fallback to regular import for SDK 53 and earlier\n // Note: This will show a deprecation warning on SDK 54+, but is necessary for backward compatibility\n try {\n // @ts-ignore\n const FileSystem = require('expo-file-system');\n if (FileSystem && FileSystem.copyAsync && typeof FileSystem.copyAsync === 'function') {\n await FileSystem.copyAsync({ from, to });\n return;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Unable to copy file: all FileSystem APIs failed. Last error: ${errorMessage}`);\n }\n\n throw new Error('Unable to copy file: no compatible FileSystem API found');\n}\n\n/**\n * Get document directory path in a backward-compatible way\n * Supports SDK 53 (regular import) and SDK 54+ (legacy or new API)\n */\nfunction getDocumentDirectory(): string {\n try {\n // Try new Paths API first (Expo SDK 54+)\n // @ts-ignore\n const { Paths } = require('expo-file-system');\n if (Paths?.document) {\n return Paths.document.uri;\n }\n } catch (_) {\n // New API not available, try legacy\n }\n\n // Try legacy API from expo-file-system/legacy (Expo SDK 54+)\n // This is the recommended way to avoid deprecation warnings\n try {\n // @ts-ignore\n const LegacyFileSystem = require('expo-file-system/legacy');\n if (LegacyFileSystem && LegacyFileSystem.documentDirectory) {\n return LegacyFileSystem.documentDirectory;\n }\n } catch (error) {\n // Legacy not available (SDK 53 or earlier), fall through to regular import\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (errorMessage.includes('Cannot find module') || errorMessage.includes('Module not found')) {\n // SDK 53 or earlier - use regular import as fallback\n // This will show a deprecation warning on SDK 54+, but is necessary for SDK 53 compatibility\n } else {\n // Other error, continue to fallback\n }\n }\n\n // Fallback to regular import for SDK 53 and earlier\n // Note: This will show a deprecation warning on SDK 54+, but is necessary for backward compatibility\n try {\n // @ts-ignore\n const FileSystem = require('expo-file-system');\n if (FileSystem && FileSystem.documentDirectory) {\n return FileSystem.documentDirectory;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Unable to get document directory: all FileSystem APIs failed. Last error: ${errorMessage}`);\n }\n\n throw new Error('Unable to get document directory: no compatible FileSystem API found');\n}\n\nexport interface CameraCaptureResult {\n success: boolean;\n path?: string;\n error?: string;\n}\n\nexport interface CameraPermissions {\n camera: CameraPermissionStatus;\n microphone: CameraPermissionStatus;\n}\n\nexport class VisionCameraModule {\n private static instance: VisionCameraModule;\n\n public static getInstance(): VisionCameraModule {\n if (!VisionCameraModule.instance) {\n VisionCameraModule.instance = new VisionCameraModule();\n }\n return VisionCameraModule.instance;\n }\n\n /**\n * Get available camera devices\n */\n async getCameraDevices(): Promise<CameraDevice[]> {\n try {\n const devices = Camera.getAvailableCameraDevices();\n return devices;\n } catch (error) {\n console.error('Error getting camera devices:', error);\n return [];\n }\n }\n\n /**\n * Get the best available device for selfies (front camera)\n */\n async getFrontCameraDevice(): Promise<CameraDevice | null> {\n try {\n const devices = await this.getCameraDevices();\n const frontCamera = devices.find(device => device.position === 'front');\n return frontCamera || null;\n } catch (error) {\n console.error('Error getting front camera:', error);\n return null;\n }\n }\n\n /**\n * Get the best available device for document capture (back camera)\n */\n async getBackCameraDevice(): Promise<CameraDevice | null> {\n try {\n const devices = await this.getCameraDevices();\n const backCamera = devices.find(device => device.position === 'back');\n return backCamera || null;\n } catch (error) {\n console.error('Error getting back camera:', error);\n return null;\n }\n }\n\n /**\n * Request camera permissions\n */\n async requestCameraPermission(): Promise<boolean> {\n try {\n const permission = await Camera.requestCameraPermission();\n return permission === 'granted';\n } catch (error) {\n console.error('Error requesting camera permission:', error);\n return false;\n }\n }\n\n /**\n * Request microphone permissions\n */\n async requestMicrophonePermission(): Promise<boolean> {\n try {\n const permission = await Camera.requestMicrophonePermission();\n return permission === 'granted';\n } catch (error) {\n console.error('Error requesting microphone permission:', error);\n return false;\n }\n }\n\n /**\n * Get current permission status\n */\n async getPermissionStatus(): Promise<CameraPermissions> {\n try {\n const cameraStatus = await Camera.getCameraPermissionStatus();\n const microphoneStatus = await Camera.getMicrophonePermissionStatus();\n\n return {\n camera: cameraStatus,\n microphone: microphoneStatus,\n };\n } catch (error) {\n console.error('Error getting permission status:', error);\n return {\n camera: 'denied',\n microphone: 'denied',\n };\n }\n }\n\n /**\n * Check if all required permissions are granted\n */\n async hasAllPermissions(): Promise<boolean> {\n try {\n const status = await this.getPermissionStatus();\n console.log('status', status);\n return status.camera === 'granted';\n } catch (error) {\n console.error('Error checking permissions:', error);\n return false;\n }\n }\n\n /**\n * Request all required permissions\n */\n async requestAllPermissions(): Promise<boolean> {\n try {\n const [cameraGranted, microphoneGranted] = await Promise.all([\n this.requestCameraPermission(),\n this.requestMicrophonePermission(),\n ]);\n\n return cameraGranted && microphoneGranted;\n } catch (error) {\n console.error('Error requesting permissions:', error);\n return false;\n }\n }\n\n /**\n * Check if camera is available\n */\n async isCameraAvailable(): Promise<boolean> {\n try {\n if (Platform.OS === 'web') {\n return false; // Vision Camera doesn't support web\n }\n\n const devices = await this.getCameraDevices();\n return devices.length > 0;\n } catch (error) {\n console.error('Error checking camera availability:', error);\n return false;\n }\n }\n\n /**\n * Process photo capture result\n */\n async processPhotoResult(photo: PhotoFile): Promise<CameraCaptureResult> {\n try {\n const documentDir = getDocumentDirectory();\n const newPath = documentDir + `photo_${Date.now()}.jpg`;\n\n await copyFileCompat(`file://${photo.path}`, newPath);\n\n return {\n success: true,\n path: newPath,\n };\n } catch (error) {\n console.error('Error processing photo result:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error processing photo',\n };\n }\n }\n\n /**\n * Legacy method for backward compatibility\n * @deprecated Use VisionCameraView component instead\n */\n async openCameraWithInstructions(instructions: string): Promise<CameraCaptureResult> {\n console.warn('openCameraWithInstructions is deprecated. Use VisionCameraView component instead.');\n\n try {\n const hasPermissions = await this.requestAllPermissions();\n if (!hasPermissions) {\n return {\n success: false,\n error: 'Camera permissions not granted',\n };\n }\n\n const isAvailable = await this.isCameraAvailable();\n if (!isAvailable) {\n return {\n success: false,\n error: 'Camera not available',\n };\n }\n\n // Return a placeholder result since this should be handled by the component\n return {\n success: true,\n path: `mock_photo_${Date.now()}.jpg`,\n };\n } catch (error) {\n console.error('Error in openCameraWithInstructions:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n}\n\nexport default VisionCameraModule.getInstance();"]}
1
+ {"version":3,"file":"VisionCameraModule.js","sourceRoot":"","sources":["../../../src/modules/camera/VisionCameraModule.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\nimport { Camera, CameraDevice, CameraPermissionStatus, PhotoFile } from 'react-native-vision-camera';\n\n/**\n * Backward-compatible file copy function\n * Tries new File API first (Expo SDK 54+), then legacy API, then regular import for SDK 53\n */\nasync function copyFileCompat(from: string, to: string): Promise<void> {\n // Try new File API first (Expo SDK 54+)\n try {\n // @ts-ignore - File API might not be in types yet\n const { File } = require('expo-file-system');\n if (File && typeof File === 'function') {\n const sourceFile = new File(from);\n const destFile = new File(to);\n // File.copy() is synchronous but may throw\n sourceFile.copy(destFile);\n return;\n }\n } catch (error) {\n // New API not available or failed, try legacy\n // Continue to legacy API\n }\n\n // Try legacy API from expo-file-system/legacy (Expo SDK 54+)\n // This is the recommended way to avoid deprecation warnings\n try {\n // @ts-ignore - legacy export might not be in types\n const LegacyFileSystem = require('expo-file-system');\n if (LegacyFileSystem && LegacyFileSystem.copyAsync && typeof LegacyFileSystem.copyAsync === 'function') {\n await LegacyFileSystem.copyAsync({ from, to });\n return;\n }\n } catch (error) {\n // Legacy not available (SDK 53 or earlier), fall through to regular import\n // Check if it's a \"module not found\" error (SDK 53) vs other error\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (errorMessage.includes('Cannot find module') || errorMessage.includes('Module not found')) {\n // SDK 53 or earlier - use regular import as fallback\n // This will show a deprecation warning on SDK 54+, but is necessary for SDK 53 compatibility\n } else {\n // Other error, re-throw\n throw new Error(`Unable to copy file: legacy FileSystem API error. Error: ${errorMessage}`);\n }\n }\n\n // Fallback to regular import for SDK 53 and earlier\n // Note: This will show a deprecation warning on SDK 54+, but is necessary for backward compatibility\n try {\n // @ts-ignore\n const FileSystem = require('expo-file-system');\n if (FileSystem && FileSystem.copyAsync && typeof FileSystem.copyAsync === 'function') {\n await FileSystem.copyAsync({ from, to });\n return;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Unable to copy file: all FileSystem APIs failed. Last error: ${errorMessage}`);\n }\n\n throw new Error('Unable to copy file: no compatible FileSystem API found');\n}\n\n/**\n * Get document directory path in a backward-compatible way\n * Supports SDK 53 (regular import) and SDK 54+ (legacy or new API)\n */\nfunction getDocumentDirectory(): string {\n try {\n // Try new Paths API first (Expo SDK 54+)\n // @ts-ignore\n const { Paths } = require('expo-file-system');\n if (Paths?.document) {\n return Paths.document.uri;\n }\n } catch (_) {\n // New API not available, try legacy\n }\n\n // Try legacy API from expo-file-system/legacy (Expo SDK 54+)\n // This is the recommended way to avoid deprecation warnings\n try {\n // @ts-ignore\n const LegacyFileSystem = require('expo-file-system');\n if (LegacyFileSystem && LegacyFileSystem.documentDirectory) {\n return LegacyFileSystem.documentDirectory;\n }\n } catch (error) {\n // Legacy not available (SDK 53 or earlier), fall through to regular import\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (errorMessage.includes('Cannot find module') || errorMessage.includes('Module not found')) {\n // SDK 53 or earlier - use regular import as fallback\n // This will show a deprecation warning on SDK 54+, but is necessary for SDK 53 compatibility\n } else {\n // Other error, continue to fallback\n }\n }\n\n // Fallback to regular import for SDK 53 and earlier\n // Note: This will show a deprecation warning on SDK 54+, but is necessary for backward compatibility\n try {\n // @ts-ignore\n const FileSystem = require('expo-file-system');\n if (FileSystem && FileSystem.documentDirectory) {\n return FileSystem.documentDirectory;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Unable to get document directory: all FileSystem APIs failed. Last error: ${errorMessage}`);\n }\n\n throw new Error('Unable to get document directory: no compatible FileSystem API found');\n}\n\nexport interface CameraCaptureResult {\n success: boolean;\n path?: string;\n error?: string;\n}\n\nexport interface CameraPermissions {\n camera: CameraPermissionStatus;\n microphone: CameraPermissionStatus;\n}\n\nexport class VisionCameraModule {\n private static instance: VisionCameraModule;\n\n public static getInstance(): VisionCameraModule {\n if (!VisionCameraModule.instance) {\n VisionCameraModule.instance = new VisionCameraModule();\n }\n return VisionCameraModule.instance;\n }\n\n /**\n * Get available camera devices\n */\n async getCameraDevices(): Promise<CameraDevice[]> {\n try {\n const devices = Camera.getAvailableCameraDevices();\n return devices;\n } catch (error) {\n console.error('Error getting camera devices:', error);\n return [];\n }\n }\n\n /**\n * Get the best available device for selfies (front camera)\n */\n async getFrontCameraDevice(): Promise<CameraDevice | null> {\n try {\n const devices = await this.getCameraDevices();\n const frontCamera = devices.find(device => device.position === 'front');\n return frontCamera || null;\n } catch (error) {\n console.error('Error getting front camera:', error);\n return null;\n }\n }\n\n /**\n * Get the best available device for document capture (back camera)\n */\n async getBackCameraDevice(): Promise<CameraDevice | null> {\n try {\n const devices = await this.getCameraDevices();\n const backCamera = devices.find(device => device.position === 'back');\n return backCamera || null;\n } catch (error) {\n console.error('Error getting back camera:', error);\n return null;\n }\n }\n\n /**\n * Request camera permissions\n */\n async requestCameraPermission(): Promise<boolean> {\n try {\n const permission = await Camera.requestCameraPermission();\n return permission === 'granted';\n } catch (error) {\n console.error('Error requesting camera permission:', error);\n return false;\n }\n }\n\n /**\n * Request microphone permissions\n */\n async requestMicrophonePermission(): Promise<boolean> {\n try {\n const permission = await Camera.requestMicrophonePermission();\n return permission === 'granted';\n } catch (error) {\n console.error('Error requesting microphone permission:', error);\n return false;\n }\n }\n\n /**\n * Get current permission status\n */\n async getPermissionStatus(): Promise<CameraPermissions> {\n try {\n const cameraStatus = await Camera.getCameraPermissionStatus();\n const microphoneStatus = await Camera.getMicrophonePermissionStatus();\n\n return {\n camera: cameraStatus,\n microphone: microphoneStatus,\n };\n } catch (error) {\n console.error('Error getting permission status:', error);\n return {\n camera: 'denied',\n microphone: 'denied',\n };\n }\n }\n\n /**\n * Check if all required permissions are granted\n */\n async hasAllPermissions(): Promise<boolean> {\n try {\n const status = await this.getPermissionStatus();\n console.log('status', status);\n return status.camera === 'granted';\n } catch (error) {\n console.error('Error checking permissions:', error);\n return false;\n }\n }\n\n /**\n * Request all required permissions\n */\n async requestAllPermissions(): Promise<boolean> {\n try {\n const [cameraGranted, microphoneGranted] = await Promise.all([\n this.requestCameraPermission(),\n this.requestMicrophonePermission(),\n ]);\n\n return cameraGranted && microphoneGranted;\n } catch (error) {\n console.error('Error requesting permissions:', error);\n return false;\n }\n }\n\n /**\n * Check if camera is available\n */\n async isCameraAvailable(): Promise<boolean> {\n try {\n if (Platform.OS === 'web') {\n return false; // Vision Camera doesn't support web\n }\n\n const devices = await this.getCameraDevices();\n return devices.length > 0;\n } catch (error) {\n console.error('Error checking camera availability:', error);\n return false;\n }\n }\n\n /**\n * Process photo capture result\n */\n async processPhotoResult(photo: PhotoFile): Promise<CameraCaptureResult> {\n try {\n const documentDir = getDocumentDirectory();\n const newPath = documentDir + `photo_${Date.now()}.jpg`;\n\n await copyFileCompat(`file://${photo.path}`, newPath);\n\n return {\n success: true,\n path: newPath,\n };\n } catch (error) {\n console.error('Error processing photo result:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error processing photo',\n };\n }\n }\n\n /**\n * Legacy method for backward compatibility\n * @deprecated Use VisionCameraView component instead\n */\n async openCameraWithInstructions(instructions: string): Promise<CameraCaptureResult> {\n console.warn('openCameraWithInstructions is deprecated. Use VisionCameraView component instead.');\n\n try {\n const hasPermissions = await this.requestAllPermissions();\n if (!hasPermissions) {\n return {\n success: false,\n error: 'Camera permissions not granted',\n };\n }\n\n const isAvailable = await this.isCameraAvailable();\n if (!isAvailable) {\n return {\n success: false,\n error: 'Camera not available',\n };\n }\n\n // Return a placeholder result since this should be handled by the component\n return {\n success: true,\n path: `mock_photo_${Date.now()}.jpg`,\n };\n } catch (error) {\n console.error('Error in openCameraWithInstructions:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n}\n\nexport default VisionCameraModule.getInstance();"]}
@@ -14,6 +14,14 @@ export declare function getObbConfidence(cardObb: any): number | null;
14
14
  * - false => card not fully in frame
15
15
  * - null => field not present (backward compatibility)
16
16
  */
17
+ /**
18
+ * Extracts the framing data from card_obb.
19
+ * STRICT CHECK: Returns true ONLY if card_in_frame is true AND cropped_sides is empty.
20
+ * Returns:
21
+ * - true => card fully in frame (no sides cropped)
22
+ * - false => card not fully in frame OR edges are cropped
23
+ * - null => field not present (backward compatibility)
24
+ */
17
25
  export declare function getCardInFrame(cardObb: any): boolean | null;
18
26
  export declare function cropByObb(uri: string, cardObb: any): Promise<{
19
27
  base64?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"cropByObb.d.ts","sourceRoot":"","sources":["../../src/utils/cropByObb.ts"],"names":[],"mappings":"AAOA,2FAA2F;AAC3F,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAc5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI,CAkB3D;AA4CD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,CAsB7J;AAMD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,mBA4B7D;AAGD,wBAAsB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CA0ErH"}
1
+ {"version":3,"file":"cropByObb.d.ts","sourceRoot":"","sources":["../../src/utils/cropByObb.ts"],"names":[],"mappings":"AAOA,2FAA2F;AAC3F,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAc5D;AAED;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI,CA6B3D;AA4CD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,CAsB7J;AAMD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,mBA4B7D;AAGD,wBAAsB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CA0ErH"}
@@ -32,16 +32,33 @@ export function getObbConfidence(cardObb) {
32
32
  * - false => card not fully in frame
33
33
  * - null => field not present (backward compatibility)
34
34
  */
35
+ /**
36
+ * Extracts the framing data from card_obb.
37
+ * STRICT CHECK: Returns true ONLY if card_in_frame is true AND cropped_sides is empty.
38
+ * Returns:
39
+ * - true => card fully in frame (no sides cropped)
40
+ * - false => card not fully in frame OR edges are cropped
41
+ * - null => field not present (backward compatibility)
42
+ */
35
43
  export function getCardInFrame(cardObb) {
36
44
  if (!cardObb)
37
45
  return null;
38
46
  // card_obb can be an array of objects or a single object
39
47
  const first = Array.isArray(cardObb) ? cardObb[0] : cardObb;
40
48
  if (first && typeof first === 'object' && 'card_in_frame' in first) {
41
- const value = first.card_in_frame;
42
- return typeof value === 'boolean' ? value : null;
49
+ const isCardInFrame = first.card_in_frame === true;
50
+ const hasCroppedSides = Array.isArray(first.cropped_sides) && first.cropped_sides.length > 0;
51
+ // If the API explicitly says it's not in frame, OR if it lists cropped edges, reject it.
52
+ if (!isCardInFrame || hasCroppedSides) {
53
+ if (hasCroppedSides) {
54
+ console.warn(`Card is cropped on sides: ${first.cropped_sides.join(', ')}`);
55
+ }
56
+ return false;
57
+ }
58
+ // If we made it here, card_in_frame is true AND cropped_sides is empty.
59
+ return true;
43
60
  }
44
- // Some APIs might put card_in_frame at the top level
61
+ // Backward compatibility check
45
62
  if (cardObb && typeof cardObb === 'object' && 'card_in_frame' in cardObb) {
46
63
  const value = cardObb.card_in_frame;
47
64
  return typeof value === 'boolean' ? value : null;
@@ -1 +1 @@
1
- {"version":3,"file":"cropByObb.js","sourceRoot":"","sources":["../../src/utils/cropByObb.ts"],"names":[],"mappings":"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","sourcesContent":["import { Image as RNImage, Platform } from 'react-native';\nimport * as ImageManipulator from \"expo-image-manipulator\";\nimport { truncateFields } from '../modules/api/KYCService';\nimport { logger } from './logger';\n\ntype Point = [number, number];\n\n/** OBB confidence below this = card not fully in frame; don't crop, give user feedback. */\nexport const OBB_CONFIDENCE_THRESHOLD = 0.85;\n\n/**\n * card_obb format from API:\n * - Legacy: [ [ [p1,p2,p3,p4], confidence ] ]\n * - New: [ { obb: [p1,p2,p3,p4], confidence, card_in_frame?, cropped_sides? } ]\n * Returns confidence in [0,1] or null if not present.\n */\nexport function getObbConfidence(cardObb: any): number | null {\n if (!cardObb || !Array.isArray(cardObb) || cardObb.length === 0) return null;\n const first = cardObb[0];\n\n // New format: first is an object with a confidence field\n if (first && typeof first === 'object' && 'confidence' in first) {\n const score = (first as any).confidence;\n return typeof score === 'number' ? score : null;\n }\n\n // Legacy format: [ [points], score ]\n if (!Array.isArray(first) || first.length < 2) return null;\n const score = first[1];\n return typeof score === 'number' ? score : null;\n}\n\n/**\n * Extracts the card_in_frame flag from card_obb when present.\n * Returns:\n * - true => card fully in frame\n * - false => card not fully in frame\n * - null => field not present (backward compatibility)\n */\nexport function getCardInFrame(cardObb: any): boolean | null {\n if (!cardObb) return null;\n\n // card_obb can be an array of objects or a single object\n const first = Array.isArray(cardObb) ? cardObb[0] : cardObb;\n\n if (first && typeof first === 'object' && 'card_in_frame' in first) {\n const value = (first as any).card_in_frame;\n return typeof value === 'boolean' ? value : null;\n }\n\n // Some APIs might put card_in_frame at the top level\n if (cardObb && typeof cardObb === 'object' && 'card_in_frame' in cardObb) {\n const value = (cardObb as any).card_in_frame;\n return typeof value === 'boolean' ? value : null;\n }\n\n return null;\n}\n\n// Compute axis-aligned bounding box from oriented quadrilateral\nfunction computeAabb(points: Point[]) {\n const xs = points.map(p => p[0]);\n const ys = points.map(p => p[1]);\n const minX = Math.min(...xs);\n const minY = Math.min(...ys);\n const maxX = Math.max(...xs);\n const maxY = Math.max(...ys);\n return { minX, minY, maxX, maxY, width: maxX - minX, height: maxY - minY };\n}\n\n// Web-only crop using Canvas; returns dataURL (base64)\nasync function cropWeb(uri: string, points: Point[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n const { minX, minY, width, height } = computeAabb(points);\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(width));\n canvas.height = Math.max(1, Math.round(height));\n const ctx = canvas.getContext('2d');\n if (!ctx) return reject(new Error('Canvas context not available'));\n ctx.drawImage(\n img,\n minX, // sx\n minY, // sy\n width, // sw\n height, // sh\n 0,\n 0,\n canvas.width,\n canvas.height\n );\n resolve(canvas.toDataURL('image/jpeg', 0.92));\n };\n img.onerror = (e) => reject(e);\n img.src = uri;\n });\n}\n\n// Fallback: return original for native (no dependency added); caller can still use bbox to draw overlay\nexport async function cropByObb(uri: string, cardObb: any): Promise<{ base64?: string; bbox?: { minX: number; minY: number; width: number; height: number } }> {\n try {\n // card_obb format: [ [ [p1,p2,p3,p4], score ] ] — if confidence too low, don't crop (send full image)\n const confidence = getObbConfidence(cardObb);\n if (confidence !== null && confidence < OBB_CONFIDENCE_THRESHOLD) {\n return {};\n }\n const first = Array.isArray(cardObb) ? cardObb[0] : null;\n const points = Array.isArray(first?.[0]) ? (first[0] as Point[]) : null;\n if (!points || points.length !== 4) return {};\n\n const { minX, minY, width, height } = computeAabb(points);\n\n if (Platform.OS === 'web') {\n const base64 = await cropWeb(uri, points);\n return { base64, bbox: { minX, minY, width, height } };\n }\n // Native: return bbox only; keep base64 undefined\n return { bbox: { minX, minY, width, height } };\n } catch (e) {\n return {};\n }\n}\n\n\n\n\n// exemple d'appel :\nexport async function cropImageWithBBox(uri: string, bbox: any) {\n // 1️⃣ Récupère la taille originale de l'image\n await RNImage.getSize(uri, (width, height) => {\n console.log(\"Image originale:\", width, height);\n });\n\n // // 2️⃣ Suppose que ton bbox vient d'une image affichée dans `displayedSize`\n // const scaleX = originalWidth / displayedSize.width;\n // const scaleY = originalHeight / displayedSize.height;\n\n // 3️⃣ Convertir le bbox à la taille réelle scale 0.10 = 10%\n const crop = {\n originX: bbox.minX,\n originY: bbox.minY,\n width: bbox.width,\n height: bbox.height,\n };\n\n // 4️⃣ Appliquer le crop\n // @ts-ignore - manipulateAsync is deprecated but still functional, new API (useImageManipulator) is a React hook and not suitable for utility functions\n const result = await ImageManipulator.manipulateAsync(\n uri,\n [{ crop }],\n { compress: 1, format: ImageManipulator.SaveFormat.PNG }\n );\n\n console.log(\"Image recadrée:\", result.uri);\n return result.uri;\n}\n\n// Fonction pour rogner avec une tolérance de 10% autour du bbox\nexport async function cropImageWithBBoxWithTolerance(uri: string, bbox: any, tolerance: number = 0.1): Promise<string> {\n console.log(\"cropImageWithBBoxWithTolerance\", JSON.stringify(truncateFields({ uri, bbox, tolerance }), null, 2));\n \n return new Promise<string>((resolve, reject) => {\n let isResolved = false;\n \n // Timeout de sécurité (15 secondes)\n const timeout = setTimeout(() => {\n if (!isResolved) {\n isResolved = true;\n console.warn(\"Timeout lors du rognage avec tolérance, utilisation de l'image originale\");\n resolve(uri); // Retourner l'URI original en cas de timeout\n }\n }, 15000);\n\n // 1️⃣ Récupère la taille originale de l'image\n RNImage.getSize(uri, (imageWidth, imageHeight) => {\n if (isResolved) return;\n \n // 2️⃣ Calculer la tolérance en pixels (10% de chaque côté)\n const toleranceX = bbox.width * tolerance;\n const toleranceY = bbox.height * tolerance;\n\n // 3️⃣ Ajuster le bbox avec la tolérance\n // Calculer les nouvelles coordonnées avec tolérance\n const newMinX = Math.max(0, bbox.minX - toleranceX);\n const newMinY = Math.max(0, bbox.minY - toleranceY);\n const newMaxX = Math.min(imageWidth, bbox.minX + bbox.width + toleranceX);\n const newMaxY = Math.min(imageHeight, bbox.minY + bbox.height + toleranceY);\n\n // Calculer la largeur et hauteur finales\n const finalWidth = newMaxX - newMinX;\n const finalHeight = newMaxY - newMinY;\n\n const crop = {\n originX: newMinX,\n originY: newMinY,\n width: finalWidth,\n height: finalHeight,\n };\n\n logger.log(\"cropImageWithBBoxWithTolerance - crop params\", JSON.stringify(truncateFields({ uri, crop, tolerance, imageWidth, imageHeight }), null, 2));\n\n // 4️⃣ Appliquer le crop avec tolérance\n // @ts-ignore - manipulateAsync is deprecated but still functional, new API (useImageManipulator) is a React hook and not suitable for utility functions\n ImageManipulator.manipulateAsync(\n uri,\n [{ crop }],\n { compress: 0.95, format: ImageManipulator.SaveFormat.JPEG }\n )\n .then((result) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n console.log(\"Image recadrée avec tolérance:\", result.uri);\n resolve(result.uri);\n })\n .catch((error) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n console.error(\"Erreur lors du rognage avec tolérance:\", error);\n // En cas d'erreur, retourner l'URI original au lieu de rejeter\n resolve(uri);\n });\n }, (error) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n console.error(\"Erreur lors de la récupération de la taille de l'image:\", error);\n // En cas d'erreur, retourner l'URI original au lieu de rejeter\n resolve(uri);\n });\n });\n}\n"]}
1
+ {"version":3,"file":"cropByObb.js","sourceRoot":"","sources":["../../src/utils/cropByObb.ts"],"names":[],"mappings":"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","sourcesContent":["import { Image as RNImage, Platform } from 'react-native';\nimport * as ImageManipulator from \"expo-image-manipulator\";\nimport { truncateFields } from '../modules/api/KYCService';\nimport { logger } from './logger';\n\ntype Point = [number, number];\n\n/** OBB confidence below this = card not fully in frame; don't crop, give user feedback. */\nexport const OBB_CONFIDENCE_THRESHOLD = 0.85;\n\n/**\n * card_obb format from API:\n * - Legacy: [ [ [p1,p2,p3,p4], confidence ] ]\n * - New: [ { obb: [p1,p2,p3,p4], confidence, card_in_frame?, cropped_sides? } ]\n * Returns confidence in [0,1] or null if not present.\n */\nexport function getObbConfidence(cardObb: any): number | null {\n if (!cardObb || !Array.isArray(cardObb) || cardObb.length === 0) return null;\n const first = cardObb[0];\n\n // New format: first is an object with a confidence field\n if (first && typeof first === 'object' && 'confidence' in first) {\n const score = (first as any).confidence;\n return typeof score === 'number' ? score : null;\n }\n\n // Legacy format: [ [points], score ]\n if (!Array.isArray(first) || first.length < 2) return null;\n const score = first[1];\n return typeof score === 'number' ? score : null;\n}\n\n/**\n * Extracts the card_in_frame flag from card_obb when present.\n * Returns:\n * - true => card fully in frame\n * - false => card not fully in frame\n * - null => field not present (backward compatibility)\n */\n/**\n * Extracts the framing data from card_obb.\n * STRICT CHECK: Returns true ONLY if card_in_frame is true AND cropped_sides is empty.\n * Returns:\n * - true => card fully in frame (no sides cropped)\n * - false => card not fully in frame OR edges are cropped\n * - null => field not present (backward compatibility)\n */\nexport function getCardInFrame(cardObb: any): boolean | null {\n if (!cardObb) return null;\n\n // card_obb can be an array of objects or a single object\n const first = Array.isArray(cardObb) ? cardObb[0] : cardObb;\n\n if (first && typeof first === 'object' && 'card_in_frame' in first) {\n const isCardInFrame = first.card_in_frame === true;\n const hasCroppedSides = Array.isArray(first.cropped_sides) && first.cropped_sides.length > 0;\n\n // If the API explicitly says it's not in frame, OR if it lists cropped edges, reject it.\n if (!isCardInFrame || hasCroppedSides) {\n if (hasCroppedSides) {\n console.warn(`Card is cropped on sides: ${first.cropped_sides.join(', ')}`);\n }\n return false; \n }\n\n // If we made it here, card_in_frame is true AND cropped_sides is empty.\n return true; \n }\n\n // Backward compatibility check\n if (cardObb && typeof cardObb === 'object' && 'card_in_frame' in cardObb) {\n const value = (cardObb as any).card_in_frame;\n return typeof value === 'boolean' ? value : null;\n }\n\n return null;\n}\n\n// Compute axis-aligned bounding box from oriented quadrilateral\nfunction computeAabb(points: Point[]) {\n const xs = points.map(p => p[0]);\n const ys = points.map(p => p[1]);\n const minX = Math.min(...xs);\n const minY = Math.min(...ys);\n const maxX = Math.max(...xs);\n const maxY = Math.max(...ys);\n return { minX, minY, maxX, maxY, width: maxX - minX, height: maxY - minY };\n}\n\n// Web-only crop using Canvas; returns dataURL (base64)\nasync function cropWeb(uri: string, points: Point[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n const { minX, minY, width, height } = computeAabb(points);\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(width));\n canvas.height = Math.max(1, Math.round(height));\n const ctx = canvas.getContext('2d');\n if (!ctx) return reject(new Error('Canvas context not available'));\n ctx.drawImage(\n img,\n minX, // sx\n minY, // sy\n width, // sw\n height, // sh\n 0,\n 0,\n canvas.width,\n canvas.height\n );\n resolve(canvas.toDataURL('image/jpeg', 0.92));\n };\n img.onerror = (e) => reject(e);\n img.src = uri;\n });\n}\n\n// Fallback: return original for native (no dependency added); caller can still use bbox to draw overlay\nexport async function cropByObb(uri: string, cardObb: any): Promise<{ base64?: string; bbox?: { minX: number; minY: number; width: number; height: number } }> {\n try {\n // card_obb format: [ [ [p1,p2,p3,p4], score ] ] — if confidence too low, don't crop (send full image)\n const confidence = getObbConfidence(cardObb);\n if (confidence !== null && confidence < OBB_CONFIDENCE_THRESHOLD) {\n return {};\n }\n const first = Array.isArray(cardObb) ? cardObb[0] : null;\n const points = Array.isArray(first?.[0]) ? (first[0] as Point[]) : null;\n if (!points || points.length !== 4) return {};\n\n const { minX, minY, width, height } = computeAabb(points);\n\n if (Platform.OS === 'web') {\n const base64 = await cropWeb(uri, points);\n return { base64, bbox: { minX, minY, width, height } };\n }\n // Native: return bbox only; keep base64 undefined\n return { bbox: { minX, minY, width, height } };\n } catch (e) {\n return {};\n }\n}\n\n\n\n\n// exemple d'appel :\nexport async function cropImageWithBBox(uri: string, bbox: any) {\n // 1️⃣ Récupère la taille originale de l'image\n await RNImage.getSize(uri, (width, height) => {\n console.log(\"Image originale:\", width, height);\n });\n\n // // 2️⃣ Suppose que ton bbox vient d'une image affichée dans `displayedSize`\n // const scaleX = originalWidth / displayedSize.width;\n // const scaleY = originalHeight / displayedSize.height;\n\n // 3️⃣ Convertir le bbox à la taille réelle scale 0.10 = 10%\n const crop = {\n originX: bbox.minX,\n originY: bbox.minY,\n width: bbox.width,\n height: bbox.height,\n };\n\n // 4️⃣ Appliquer le crop\n // @ts-ignore - manipulateAsync is deprecated but still functional, new API (useImageManipulator) is a React hook and not suitable for utility functions\n const result = await ImageManipulator.manipulateAsync(\n uri,\n [{ crop }],\n { compress: 1, format: ImageManipulator.SaveFormat.PNG }\n );\n\n console.log(\"Image recadrée:\", result.uri);\n return result.uri;\n}\n\n// Fonction pour rogner avec une tolérance de 10% autour du bbox\nexport async function cropImageWithBBoxWithTolerance(uri: string, bbox: any, tolerance: number = 0.1): Promise<string> {\n console.log(\"cropImageWithBBoxWithTolerance\", JSON.stringify(truncateFields({ uri, bbox, tolerance }), null, 2));\n \n return new Promise<string>((resolve, reject) => {\n let isResolved = false;\n \n // Timeout de sécurité (15 secondes)\n const timeout = setTimeout(() => {\n if (!isResolved) {\n isResolved = true;\n console.warn(\"Timeout lors du rognage avec tolérance, utilisation de l'image originale\");\n resolve(uri); // Retourner l'URI original en cas de timeout\n }\n }, 15000);\n\n // 1️⃣ Récupère la taille originale de l'image\n RNImage.getSize(uri, (imageWidth, imageHeight) => {\n if (isResolved) return;\n \n // 2️⃣ Calculer la tolérance en pixels (10% de chaque côté)\n const toleranceX = bbox.width * tolerance;\n const toleranceY = bbox.height * tolerance;\n\n // 3️⃣ Ajuster le bbox avec la tolérance\n // Calculer les nouvelles coordonnées avec tolérance\n const newMinX = Math.max(0, bbox.minX - toleranceX);\n const newMinY = Math.max(0, bbox.minY - toleranceY);\n const newMaxX = Math.min(imageWidth, bbox.minX + bbox.width + toleranceX);\n const newMaxY = Math.min(imageHeight, bbox.minY + bbox.height + toleranceY);\n\n // Calculer la largeur et hauteur finales\n const finalWidth = newMaxX - newMinX;\n const finalHeight = newMaxY - newMinY;\n\n const crop = {\n originX: newMinX,\n originY: newMinY,\n width: finalWidth,\n height: finalHeight,\n };\n\n logger.log(\"cropImageWithBBoxWithTolerance - crop params\", JSON.stringify(truncateFields({ uri, crop, tolerance, imageWidth, imageHeight }), null, 2));\n\n // 4️⃣ Appliquer le crop avec tolérance\n // @ts-ignore - manipulateAsync is deprecated but still functional, new API (useImageManipulator) is a React hook and not suitable for utility functions\n ImageManipulator.manipulateAsync(\n uri,\n [{ crop }],\n { compress: 0.95, format: ImageManipulator.SaveFormat.JPEG }\n )\n .then((result) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n console.log(\"Image recadrée avec tolérance:\", result.uri);\n resolve(result.uri);\n })\n .catch((error) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n console.error(\"Erreur lors du rognage avec tolérance:\", error);\n // En cas d'erreur, retourner l'URI original au lieu de rejeter\n resolve(uri);\n });\n }, (error) => {\n if (isResolved) return;\n isResolved = true;\n clearTimeout(timeout);\n console.error(\"Erreur lors de la récupération de la taille de l'image:\", error);\n // En cas d'erreur, retourner l'URI original au lieu de rejeter\n resolve(uri);\n });\n });\n}\n"]}
@@ -12,7 +12,7 @@ export async function pathToBase64(uri) {
12
12
  // This is the recommended way to avoid deprecation warnings
13
13
  try {
14
14
  // @ts-ignore - legacy export might not be in types
15
- const LegacyFileSystem = require('expo-file-system/legacy');
15
+ const LegacyFileSystem = require('expo-file-system');
16
16
  if (LegacyFileSystem?.readAsStringAsync) {
17
17
  const base64 = await LegacyFileSystem.readAsStringAsync(uri, { encoding: LegacyFileSystem.EncodingType.Base64 });
18
18
  if (base64)
@@ -1 +1 @@
1
- {"version":3,"file":"pathToBase64.js","sourceRoot":"","sources":["../../src/utils/pathToBase64.ts"],"names":[],"mappings":"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","sourcesContent":["export async function pathToBase64(uri: string): Promise<string> {\n if (!uri) throw new Error('pathToBase64: uri is required');\n\n // If already a data URI, return the base64 part\n if (uri.startsWith('data:')) {\n const commaIndex = uri.indexOf(',');\n return commaIndex !== -1 ? uri.substring(commaIndex + 1) : uri;\n }\n\n // Try Expo FileSystem if available (React Native + Expo)\n try {\n // Try legacy API from expo-file-system/legacy first (Expo SDK 54+)\n // This is the recommended way to avoid deprecation warnings\n try {\n // @ts-ignore - legacy export might not be in types\n const LegacyFileSystem = require('expo-file-system/legacy');\n if (LegacyFileSystem?.readAsStringAsync) {\n const base64 = await LegacyFileSystem.readAsStringAsync(uri, { encoding: LegacyFileSystem.EncodingType.Base64 });\n if (base64) return base64;\n }\n } catch (legacyError) {\n // Legacy not available (SDK 53 or earlier), try regular import\n const errorMessage = legacyError instanceof Error ? legacyError.message : String(legacyError);\n if (errorMessage.includes('Cannot find module') || errorMessage.includes('Module not found')) {\n // SDK 53 or earlier - use regular import as fallback\n // @ts-ignore\n const FileSystem = require('expo-file-system');\n if (FileSystem?.readAsStringAsync) {\n const base64 = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64 });\n if (base64) return base64;\n }\n }\n // If it's a different error, continue to other strategies\n }\n } catch (_) {\n // All FileSystem APIs failed, fall back to other strategies (fetch + FileReader)\n }\n\n // Generic fetch + FileReader strategy (works on web; often works on RN for file:// URIs)\n try {\n const response = await fetch(uri);\n const blob = await response.blob();\n const dataUrl = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n if (typeof reader.result === 'string') resolve(reader.result);\n else reject(new Error('Failed to convert blob to data URL'));\n };\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n const commaIndex = dataUrl.indexOf(',');\n return commaIndex !== -1 ? dataUrl.substring(commaIndex + 1) : dataUrl;\n } catch (err) {\n // continue to final error\n }\n\n throw new Error('pathToBase64: unable to convert uri to base64');\n}\n\nexport default pathToBase64;\n\n\n"]}
1
+ {"version":3,"file":"pathToBase64.js","sourceRoot":"","sources":["../../src/utils/pathToBase64.ts"],"names":[],"mappings":"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","sourcesContent":["export async function pathToBase64(uri: string): Promise<string> {\n if (!uri) throw new Error('pathToBase64: uri is required');\n\n // If already a data URI, return the base64 part\n if (uri.startsWith('data:')) {\n const commaIndex = uri.indexOf(',');\n return commaIndex !== -1 ? uri.substring(commaIndex + 1) : uri;\n }\n\n // Try Expo FileSystem if available (React Native + Expo)\n try {\n // Try legacy API from expo-file-system/legacy first (Expo SDK 54+)\n // This is the recommended way to avoid deprecation warnings\n try {\n // @ts-ignore - legacy export might not be in types\n const LegacyFileSystem = require('expo-file-system');\n if (LegacyFileSystem?.readAsStringAsync) {\n const base64 = await LegacyFileSystem.readAsStringAsync(uri, { encoding: LegacyFileSystem.EncodingType.Base64 });\n if (base64) return base64;\n }\n } catch (legacyError) {\n // Legacy not available (SDK 53 or earlier), try regular import\n const errorMessage = legacyError instanceof Error ? legacyError.message : String(legacyError);\n if (errorMessage.includes('Cannot find module') || errorMessage.includes('Module not found')) {\n // SDK 53 or earlier - use regular import as fallback\n // @ts-ignore\n const FileSystem = require('expo-file-system');\n if (FileSystem?.readAsStringAsync) {\n const base64 = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64 });\n if (base64) return base64;\n }\n }\n // If it's a different error, continue to other strategies\n }\n } catch (_) {\n // All FileSystem APIs failed, fall back to other strategies (fetch + FileReader)\n }\n\n // Generic fetch + FileReader strategy (works on web; often works on RN for file:// URIs)\n try {\n const response = await fetch(uri);\n const blob = await response.blob();\n const dataUrl = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n if (typeof reader.result === 'string') resolve(reader.result);\n else reject(new Error('Failed to convert blob to data URL'));\n };\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n const commaIndex = dataUrl.indexOf(',');\n return commaIndex !== -1 ? dataUrl.substring(commaIndex + 1) : dataUrl;\n } catch (err) {\n // continue to final error\n }\n\n throw new Error('pathToBase64: unable to convert uri to base64');\n}\n\nexport default pathToBase64;\n\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transfergratis/react-native-sdk",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "description": "transfergratis react native sdk",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -140,7 +140,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
140
140
 
141
141
  const intervalId = setInterval(() => {
142
142
  captureSilentPhoto();
143
- }, 5000);
143
+ }, 2500);
144
144
 
145
145
  return () => clearInterval(intervalId);
146
146
  }, [showCamera, isInitialized, captureSilentPhoto]);
@@ -16,7 +16,6 @@ interface CountrySelectionTemplateProps {
16
16
 
17
17
  type SelectionStep = 'country' | 'documentType' | 'region';
18
18
 
19
- // Type étendu pour IDCardConfig avec les propriétés additionnelles
20
19
  type ExtendedIDCardConfig = IDCardConfig & {
21
20
  selectedCountries?: string[];
22
21
  documentTypesByCountry?: Record<string, string[]>;
@@ -34,7 +33,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
34
33
  const config = component.config as CountrySelectionConfig;
35
34
  const { actions, state } = useTemplateKYCFlowContext();
36
35
 
37
- // Récupérer les données depuis le composant id_card
38
36
  const idCardComponent = useMemo(() => {
39
37
  return state.template.components.find(c => c.type === 'id_card');
40
38
  }, [state.template.components]);
@@ -43,30 +41,26 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
43
41
  return idCardComponent?.config as ExtendedIDCardConfig | undefined;
44
42
  }, [idCardComponent]);
45
43
 
46
- // États de navigation - initialiser depuis value si disponible
47
44
  const [currentStep, setCurrentStep] = useState<SelectionStep>(() => {
48
- // Si value existe, on a déjà sélectionné -> aller à la dernière étape nécessaire
49
45
  if (value?.code && value?.documentType) {
50
46
  if (value.region) return 'region';
51
47
  return 'documentType';
52
48
  }
53
49
  return 'country';
54
50
  });
51
+
55
52
  const [selectedCountryCode, setSelectedCountryCode] = useState<string | null>(value?.code || null);
56
53
  const [selectedDocumentType, setSelectedDocumentType] = useState<string | null>(value?.documentType || null);
57
54
  const [selectedRegion, setSelectedRegion] = useState<string | null>(value?.region || null);
58
55
 
59
- // Restaurer l'état depuis value si le composant est remonté avec des données
60
56
  useEffect(() => {
61
57
  if (value?.code && value?.documentType) {
62
58
  setSelectedCountryCode(value.code);
63
59
  setSelectedDocumentType(value.documentType);
64
60
  setSelectedRegion(value.region || null);
65
- // Déterminer l'étape actuelle
66
61
  if (value.region) {
67
62
  setCurrentStep('region');
68
63
  } else {
69
- // Vérifier si une région est nécessaire
70
64
  const needsRegionCheck = value.code && value.documentType && idCardConfig?.regionsByCountry?.[value.code]?.[value.documentType];
71
65
  if (needsRegionCheck && Array.isArray(needsRegionCheck) && needsRegionCheck.length > 0) {
72
66
  setCurrentStep('region');
@@ -75,7 +69,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
75
69
  }
76
70
  }
77
71
  } else {
78
- // Réinitialiser si value est vide
79
72
  setSelectedCountryCode(null);
80
73
  setSelectedDocumentType(null);
81
74
  setSelectedRegion(null);
@@ -83,7 +76,12 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
83
76
  }
84
77
  }, [value?.code, value?.documentType, value?.region, idCardConfig]);
85
78
 
86
- // Récupérer les pays disponibles
79
+ useEffect(() => {
80
+ if (error) {
81
+ actions.updateComponentData(component.id, value);
82
+ }
83
+ }, []);
84
+
87
85
  const availableCountries = useMemo(() => {
88
86
  const countries = idCardConfig?.selectedCountries || config.allowed_countries || Object.keys(countryData);
89
87
  return countries
@@ -92,13 +90,11 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
92
90
  .sort((a: Country & { code?: string }, b: Country & { code?: string }) => a.name.localeCompare(b.name));
93
91
  }, [idCardConfig?.selectedCountries, config.allowed_countries]);
94
92
 
95
- // Récupérer les types de documents disponibles pour le pays sélectionné
96
93
  const availableDocumentTypes = useMemo(() => {
97
94
  if (!selectedCountryCode || !idCardConfig?.documentTypesByCountry) return [];
98
95
  return idCardConfig.documentTypesByCountry[selectedCountryCode] || [];
99
96
  }, [selectedCountryCode, idCardConfig?.documentTypesByCountry]);
100
97
 
101
- // Récupérer les régions disponibles pour le pays et type de document sélectionnés
102
98
  const availableRegions = useMemo(() => {
103
99
  if (!selectedCountryCode || !selectedDocumentType || !idCardConfig?.regionsByCountry) return [];
104
100
  const regions = idCardConfig.regionsByCountry[selectedCountryCode];
@@ -106,7 +102,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
106
102
  return Array.isArray(regions[selectedDocumentType]) ? regions[selectedDocumentType] : [];
107
103
  }, [selectedCountryCode, selectedDocumentType, idCardConfig?.regionsByCountry]);
108
104
 
109
- // Vérifier si une région est nécessaire
110
105
  const needsRegion = useMemo(() => {
111
106
  return availableRegions.length > 0;
112
107
  }, [availableRegions]);
@@ -115,34 +110,22 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
115
110
  return text[state.currentLanguage] || text.en || '';
116
111
  };
117
112
 
118
- // Navigation entre les étapes
113
+ // 1. Only highlights the country
119
114
  const handleCountrySelect = (countryCode: string) => {
120
115
  setSelectedCountryCode(countryCode);
121
116
  setSelectedDocumentType(null);
122
117
  setSelectedRegion(null);
123
- setCurrentStep('documentType');
124
118
  };
125
119
 
120
+ // 2. Only highlights the document type
126
121
  const handleDocumentTypeSelect = (docType: string) => {
127
122
  setSelectedDocumentType(docType);
128
123
  setSelectedRegion(null);
129
- // Vérifier si une région est nécessaire (doit être recalculé après setSelectedDocumentType)
130
- const regions = selectedCountryCode && idCardConfig?.regionsByCountry?.[selectedCountryCode]?.[docType];
131
- if (regions && Array.isArray(regions) && regions.length > 0) {
132
- setCurrentStep('region');
133
- } else {
134
- // Pas de région nécessaire, on peut finaliser
135
- if (selectedCountryCode) {
136
- finalizeSelection(selectedCountryCode, docType, null);
137
- }
138
- }
139
124
  };
140
125
 
126
+ // 3. Only highlights the region
141
127
  const handleRegionSelect = (region: string) => {
142
128
  setSelectedRegion(region);
143
- if (selectedCountryCode && selectedDocumentType) {
144
- finalizeSelection(selectedCountryCode, selectedDocumentType, region);
145
- }
146
129
  };
147
130
 
148
131
  const finalizeSelection = (countryCode: string, docType: string, region: string | null) => {
@@ -159,10 +142,10 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
159
142
  };
160
143
 
161
144
  onValueChange(countryObj);
162
- // Passer à l'étape suivante après un court délai
145
+
163
146
  setTimeout(() => {
164
- actions.nextComponent();
165
- }, 300);
147
+ actions.nextComponent(countryObj);
148
+ }, 100);
166
149
  };
167
150
 
168
151
  const handleBack = () => {
@@ -174,7 +157,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
174
157
  setSelectedDocumentType(null);
175
158
  setSelectedRegion(null);
176
159
  } else if (currentStep === 'country') {
177
- // Retour au composant précédent
178
160
  actions.previousComponent();
179
161
  }
180
162
  };
@@ -197,7 +179,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
197
179
  }
198
180
  };
199
181
 
200
- // Rendu de l'étape de sélection du pays
201
182
  const renderCountrySelection = () => {
202
183
  return (
203
184
  <>
@@ -236,13 +217,11 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
236
217
  );
237
218
  };
238
219
 
239
- // Rendu de l'étape de sélection du type de document
240
220
  const renderDocumentTypeSelection = () => {
241
221
  const instructions = selectedDocumentType && idCardConfig?.instructionsByDocumentType?.[selectedDocumentType]
242
222
  ? getLocalizedText(idCardConfig.instructionsByDocumentType[selectedDocumentType])
243
223
  : null;
244
224
 
245
- // Mapping des labels pour l'affichage
246
225
  const documentTypeLabels: Record<string, { en: string; fr: string; icon?: string }> = {
247
226
  'nationalId': { en: 'National ID', fr: 'Carte nationale d\'identité', icon: '🏛️' },
248
227
  'passport': { en: 'Passport', fr: 'Passeport', icon: '📘' },
@@ -298,7 +277,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
298
277
  );
299
278
  };
300
279
 
301
- // Rendu de l'étape de sélection de la région
302
280
  const renderRegionSelection = () => {
303
281
  return (
304
282
  <>
@@ -338,7 +316,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
338
316
  );
339
317
  };
340
318
 
341
- // Titres des étapes
342
319
  const getStepTitle = (): string => {
343
320
  switch (currentStep) {
344
321
  case 'country':
@@ -369,7 +346,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
369
346
  }
370
347
  };
371
348
 
372
- // Indicateur de progression
373
349
  const getProgressStep = (): number => {
374
350
  if (currentStep === 'country') return 1;
375
351
  if (currentStep === 'documentType') return 2;
@@ -390,7 +366,6 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
390
366
  return (
391
367
  <View style={styles.root}>
392
368
  <View style={styles.container}>
393
- {/* Indicateur de progression */}
394
369
  <View style={styles.progressContainer}>
395
370
  <Text style={styles.progressText}>
396
371
  {state.currentLanguage === "en"
@@ -402,30 +377,27 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
402
377
  <Text style={styles.title}>{getStepTitle()}</Text>
403
378
  <Text style={styles.description}>{getStepDescription()}</Text>
404
379
 
405
- {/* Contenu de l'étape actuelle */}
406
380
  {currentStep === 'country' && renderCountrySelection()}
407
381
  {currentStep === 'documentType' && renderDocumentTypeSelection()}
408
382
  {currentStep === 'region' && renderRegionSelection()}
409
383
 
410
- {/* Boutons de navigation */}
411
384
  <View style={styles.buttonContainer}>
412
385
  <Button
413
386
  title={state.currentLanguage === "en" ? "Back" : "Retour"}
414
387
  onPress={handleBack}
415
388
  variant={currentStep === 'country' ? "secondary" : "outline"}
416
389
  size="large"
417
- style={currentStep === 'country' ? { flex: 1 } : { flex: 1, marginRight: 8 }}
390
+ style={{ flex: 1, marginRight: 8 }}
391
+ />
392
+
393
+ <Button
394
+ title={state.currentLanguage === "en" ? "Next" : "Suivant"}
395
+ onPress={handleNext}
396
+ variant="primary"
397
+ size="large"
398
+ style={{ flex: 1 }}
399
+ disabled={!canGoNext()}
418
400
  />
419
- {currentStep !== 'country' && (
420
- <Button
421
- title={state.currentLanguage === "en" ? "Next" : "Suivant"}
422
- onPress={handleNext}
423
- variant="primary"
424
- size="large"
425
- style={{ flex: 1 }}
426
- disabled={!canGoNext()}
427
- />
428
- )}
429
401
  </View>
430
402
 
431
403
  {error && (
@@ -551,4 +523,4 @@ const styles = StyleSheet.create({
551
523
  marginTop: 8,
552
524
  textAlign: 'center',
553
525
  },
554
- });
526
+ });