@trustchex/react-native-sdk 1.381.0 → 1.464.0

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 (204) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
  2. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +60 -13
  3. package/android/src/main/java/com/trustchex/reactnativesdk/mlkit/MLKitModule.kt +1 -1
  4. package/ios/Camera/TrustchexCameraView.swift +10 -13
  5. package/ios/MLKit/MLKitModule.swift +1 -1
  6. package/lib/module/Screens/Debug/BarcodeTestScreen.js +308 -0
  7. package/lib/module/Screens/Debug/MRZTestScreen.js +105 -13
  8. package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
  9. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +49 -32
  10. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +22 -4
  11. package/lib/module/Screens/Dynamic/IdentityDocumentScanningScreen.js +5 -0
  12. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +126 -27
  13. package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
  14. package/lib/module/Screens/Dynamic/VideoCallScreen.js +678 -0
  15. package/lib/module/Screens/Static/OTPVerificationScreen.js +6 -0
  16. package/lib/module/Screens/Static/QrCodeScanningScreen.js +7 -1
  17. package/lib/module/Screens/Static/ResultScreen.js +154 -34
  18. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +59 -51
  19. package/lib/module/Shared/Animations/recording.json +1 -0
  20. package/lib/module/Shared/Animations/video-call.json +1 -0
  21. package/lib/module/Shared/Components/DebugNavigationPanel.js +231 -67
  22. package/lib/module/Shared/Components/EIDScanner.js +213 -112
  23. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
  24. package/lib/module/Shared/Components/IdentityDocumentCamera.js +77 -39
  25. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
  26. package/lib/module/Shared/Components/NavigationManager.js +39 -19
  27. package/lib/module/Shared/Contexts/AppContext.js +1 -0
  28. package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
  29. package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
  30. package/lib/module/Shared/EIDReader/bacKey.js +16 -2
  31. package/lib/module/Shared/EIDReader/eidReader.js +354 -13
  32. package/lib/module/Shared/EIDReader/eidService.js +25 -1
  33. package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
  34. package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
  35. package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
  36. package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
  37. package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
  38. package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
  39. package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
  40. package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
  41. package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
  42. package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
  43. package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
  44. package/lib/module/Shared/Libs/SignalingClient.js +128 -0
  45. package/lib/module/Shared/Libs/analytics.utils.js +8 -0
  46. package/lib/module/Shared/Libs/contains.js +1 -40
  47. package/lib/module/Shared/Libs/country-display.utils.js +34 -0
  48. package/lib/module/Shared/Libs/deeplink.utils.js +9 -1
  49. package/lib/module/Shared/Libs/demo.utils.js +8 -0
  50. package/lib/module/Shared/Libs/http-client.js +9 -0
  51. package/lib/module/Shared/Libs/mrz.utils.js +3 -2
  52. package/lib/module/Shared/Libs/promise.utils.js +16 -2
  53. package/lib/module/Shared/Libs/status-bar.utils.js +23 -0
  54. package/lib/module/Shared/Services/DataUploadService.js +294 -0
  55. package/lib/module/Shared/Services/VideoSessionService.js +156 -0
  56. package/lib/module/Shared/Services/WebRTCService.js +510 -0
  57. package/lib/module/Shared/Types/analytics.types.js +4 -0
  58. package/lib/module/Translation/Resources/en.js +61 -2
  59. package/lib/module/Translation/Resources/tr.js +61 -2
  60. package/lib/module/Trustchex.js +64 -20
  61. package/lib/module/version.js +1 -1
  62. package/lib/typescript/src/Screens/Debug/BarcodeTestScreen.d.ts +3 -0
  63. package/lib/typescript/src/Screens/Debug/BarcodeTestScreen.d.ts.map +1 -0
  64. package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts.map +1 -1
  65. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
  66. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
  67. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  68. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  69. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentScanningScreen.d.ts.map +1 -1
  70. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  71. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
  72. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
  73. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts +3 -0
  74. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -0
  75. package/lib/typescript/src/Screens/Static/OTPVerificationScreen.d.ts.map +1 -1
  76. package/lib/typescript/src/Screens/Static/QrCodeScanningScreen.d.ts.map +1 -1
  77. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  78. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  79. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  80. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  81. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  82. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
  83. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
  84. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
  85. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  86. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  87. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts +1 -0
  88. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts.map +1 -1
  89. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
  90. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
  91. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
  92. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
  93. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
  94. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
  95. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  96. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
  97. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
  98. package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
  99. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
  100. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
  101. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
  102. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
  103. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
  104. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
  105. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
  106. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
  107. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
  108. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
  109. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
  110. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
  111. package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
  112. package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
  113. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
  114. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
  115. package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts +24 -0
  116. package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts.map +1 -0
  117. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  118. package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
  119. package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
  120. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
  121. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
  122. package/lib/typescript/src/Shared/Libs/deeplink.utils.d.ts.map +1 -1
  123. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  124. package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
  125. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  126. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  127. package/lib/typescript/src/Shared/Libs/promise.utils.d.ts.map +1 -1
  128. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts +9 -0
  129. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -0
  130. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts +25 -0
  131. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts.map +1 -0
  132. package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts +33 -0
  133. package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts.map +1 -0
  134. package/lib/typescript/src/Shared/Services/WebRTCService.d.ts +58 -0
  135. package/lib/typescript/src/Shared/Services/WebRTCService.d.ts.map +1 -0
  136. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +4 -0
  137. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  138. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +13 -1
  139. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  140. package/lib/typescript/src/Translation/Resources/en.d.ts +60 -1
  141. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  142. package/lib/typescript/src/Translation/Resources/tr.d.ts +60 -1
  143. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  144. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  145. package/lib/typescript/src/version.d.ts +1 -1
  146. package/package.json +35 -5
  147. package/src/Screens/Debug/BarcodeTestScreen.tsx +317 -0
  148. package/src/Screens/Debug/MRZTestScreen.tsx +107 -13
  149. package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
  150. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +58 -35
  151. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +27 -4
  152. package/src/Screens/Dynamic/IdentityDocumentScanningScreen.tsx +6 -0
  153. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +156 -27
  154. package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
  155. package/src/Screens/Dynamic/VideoCallScreen.tsx +766 -0
  156. package/src/Screens/Static/OTPVerificationScreen.tsx +6 -0
  157. package/src/Screens/Static/QrCodeScanningScreen.tsx +7 -1
  158. package/src/Screens/Static/ResultScreen.tsx +235 -48
  159. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +67 -72
  160. package/src/Shared/Animations/recording.json +1 -0
  161. package/src/Shared/Animations/video-call.json +1 -0
  162. package/src/Shared/Components/DebugNavigationPanel.tsx +252 -51
  163. package/src/Shared/Components/EIDScanner.tsx +223 -116
  164. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
  165. package/src/Shared/Components/IdentityDocumentCamera.tsx +224 -188
  166. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
  167. package/src/Shared/Components/NavigationManager.tsx +41 -19
  168. package/src/Shared/Contexts/AppContext.ts +2 -0
  169. package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
  170. package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
  171. package/src/Shared/EIDReader/bacKey.ts +24 -8
  172. package/src/Shared/EIDReader/eidReader.ts +398 -12
  173. package/src/Shared/EIDReader/eidService.ts +49 -1
  174. package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
  175. package/src/Shared/EIDReader/paceInfo.ts +159 -0
  176. package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
  177. package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
  178. package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
  179. package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
  180. package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
  181. package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
  182. package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
  183. package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
  184. package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
  185. package/src/Shared/Libs/SignalingClient.ts +189 -0
  186. package/src/Shared/Libs/analytics.utils.ts +8 -0
  187. package/src/Shared/Libs/contains.ts +0 -53
  188. package/src/Shared/Libs/country-display.utils.ts +55 -0
  189. package/src/Shared/Libs/crypto.utils.ts +2 -2
  190. package/src/Shared/Libs/deeplink.utils.ts +12 -1
  191. package/src/Shared/Libs/demo.utils.ts +10 -0
  192. package/src/Shared/Libs/http-client.ts +19 -1
  193. package/src/Shared/Libs/mrz.utils.ts +3 -2
  194. package/src/Shared/Libs/promise.utils.ts +16 -2
  195. package/src/Shared/Libs/status-bar.utils.ts +21 -0
  196. package/src/Shared/Services/DataUploadService.ts +395 -0
  197. package/src/Shared/Services/VideoSessionService.ts +190 -0
  198. package/src/Shared/Services/WebRTCService.ts +636 -0
  199. package/src/Shared/Types/analytics.types.ts +4 -0
  200. package/src/Shared/Types/identificationInfo.ts +16 -1
  201. package/src/Translation/Resources/en.ts +88 -3
  202. package/src/Translation/Resources/tr.ts +89 -3
  203. package/src/Trustchex.tsx +65 -19
  204. package/src/version.ts +1 -1
@@ -174,6 +174,7 @@ const IdentityDocumentCamera = ({
174
174
  const isHologramDetectionInProgress = useRef(false); // Prevent concurrent hologram detection calls
175
175
  const isCompletionCallbackInvoked = useRef(false); // Prevent multiple callback invocations when COMPLETED
176
176
  const isStepTransitionInProgress = useRef(false); // Prevent duplicate step transitions from rapid frames
177
+ const isCompletionAnnouncementSpoken = useRef(false); // Prevent duplicate "scan completed" voice guidance
177
178
 
178
179
  const faceDetectionErrorCount = useRef(0);
179
180
  const brightnessHistory = useRef<number[]>([]);
@@ -181,7 +182,6 @@ const IdentityDocumentCamera = ({
181
182
  const faceImages = useRef<string[]>([]);
182
183
  const hologramImageCountRef = useRef(0);
183
184
  const [hologramImageCount, setHologramImageCount] = useState(0);
184
- const lastVoiceGuidanceMessage = useRef<string>('');
185
185
  const [latestHologramFaceImage, setLatestHologramFaceImage] = useState<
186
186
  string | undefined
187
187
  >(undefined);
@@ -264,6 +264,7 @@ const IdentityDocumentCamera = ({
264
264
  setIsActive(true);
265
265
  isCompletionCallbackInvoked.current = false; // Reset callback flag when starting new scan
266
266
  isStepTransitionInProgress.current = false;
267
+ isCompletionAnnouncementSpoken.current = false;
267
268
  } else {
268
269
  setIsActive(false);
269
270
  faceImages.current = [];
@@ -277,9 +278,9 @@ const IdentityDocumentCamera = ({
277
278
  lastValidMRZFields.current = null;
278
279
  validMRZConsecutiveCount.current = 0;
279
280
  cachedBarcode.current = null;
280
- lastVoiceGuidanceMessage.current = '';
281
281
  isCompletionCallbackInvoked.current = false;
282
282
  isStepTransitionInProgress.current = false;
283
+ isCompletionAnnouncementSpoken.current = false;
283
284
  // Clear all captured image states from previous scan
284
285
  setCurrentFaceImage(undefined);
285
286
  setCurrentHologramImage(undefined);
@@ -293,9 +294,9 @@ const IdentityDocumentCamera = ({
293
294
  hologramImageCountRef.current = 0;
294
295
  setHologramImageCount(0);
295
296
  setLatestHologramFaceImage(undefined);
296
- lastVoiceGuidanceMessage.current = '';
297
297
  isCompletionCallbackInvoked.current = false; // Reset callback flag on unmount
298
298
  isStepTransitionInProgress.current = false;
299
+ isCompletionAnnouncementSpoken.current = false;
299
300
  // Clear all captured image states on unmount
300
301
  setCurrentFaceImage(undefined);
301
302
  setCurrentHologramImage(undefined);
@@ -322,9 +323,17 @@ const IdentityDocumentCamera = ({
322
323
  t
323
324
  );
324
325
 
325
- if (message && message !== lastVoiceGuidanceMessage.current) {
326
- lastVoiceGuidanceMessage.current = message;
327
- speak(message, true);
326
+ if (message) {
327
+ if (nextStep === 'COMPLETED') {
328
+ if (isCompletionAnnouncementSpoken.current) {
329
+ return;
330
+ }
331
+ isCompletionAnnouncementSpoken.current = true;
332
+ } else {
333
+ isCompletionAnnouncementSpoken.current = false;
334
+ }
335
+ const shouldBypassInterval = nextStep !== 'COMPLETED';
336
+ speak(message, shouldBypassInterval);
328
337
  }
329
338
  }, [
330
339
  appContext.currentWorkflowStep?.data?.voiceGuidanceActive,
@@ -365,6 +374,20 @@ const IdentityDocumentCamera = ({
365
374
  isStepTransitionInProgress.current = false;
366
375
  }, [nextStep]);
367
376
 
377
+ // Update status bar based on guide visibility
378
+ useEffect(() => {
379
+ if (hasGuideShown) {
380
+ // Scanning camera view - use light icons on dark background
381
+ StatusBar.setBarStyle('light-content', true);
382
+ } else {
383
+ // Guide screen with white background - use dark icons
384
+ StatusBar.setBarStyle('dark-content', true);
385
+ if (Platform.OS === 'android') {
386
+ StatusBar.setBackgroundColor('#ffffff', true);
387
+ }
388
+ }
389
+ }, [hasGuideShown]);
390
+
368
391
  // Error flash animation - flash red text when wrong side detected
369
392
  useEffect(() => {
370
393
  if (status === 'INCORRECT') {
@@ -2230,6 +2253,55 @@ const IdentityDocumentCamera = ({
2230
2253
  []
2231
2254
  );
2232
2255
 
2256
+ // Show the guide immediately — the guide is pure UI and does not need
2257
+ // camera access. Permission is requested in the background (useEffect) so
2258
+ // it will usually be resolved by the time the user taps "Let's Go".
2259
+ // This avoids a white/blank screen while the async permission check runs.
2260
+ if (!hasGuideShown) {
2261
+ return (
2262
+ <View style={StyleSheet.absoluteFill}>
2263
+ <StatusBar
2264
+ barStyle="dark-content"
2265
+ backgroundColor="#ffffff"
2266
+ translucent
2267
+ />
2268
+ <SafeAreaView style={styles.guide}>
2269
+ <LottieView
2270
+ source={require('../../Shared/Animations/id-or-passport.json')}
2271
+ style={styles.guideAnimation}
2272
+ loop={true}
2273
+ autoPlay
2274
+ />
2275
+ <TextView style={styles.guideHeader}>
2276
+ {t('identityDocumentCamera.guideHeader')}
2277
+ </TextView>
2278
+ <View style={styles.guidePoints}>
2279
+ <TextView style={styles.guideText}>
2280
+ {t('identityDocumentCamera.guideText')}
2281
+ </TextView>
2282
+ <TextView style={styles.guideText}>
2283
+ • {t('identityDocumentCamera.guidePoint1')}
2284
+ </TextView>
2285
+ <TextView style={styles.guideText}>
2286
+ • {t('identityDocumentCamera.guidePoint2')}
2287
+ </TextView>
2288
+ <TextView style={styles.guideText}>
2289
+ • {t('identityDocumentCamera.guidePoint3')}
2290
+ </TextView>
2291
+ </View>
2292
+ <StyledButton
2293
+ mode="contained"
2294
+ onPress={() => {
2295
+ setHasGuideShown(true);
2296
+ }}
2297
+ >
2298
+ {t('general.letsGo')}
2299
+ </StyledButton>
2300
+ </SafeAreaView>
2301
+ </View>
2302
+ );
2303
+ }
2304
+
2233
2305
  if (!permissionsRequested) {
2234
2306
  return (
2235
2307
  <SafeAreaView style={styles.permissionContainer}>
@@ -2265,197 +2337,161 @@ const IdentityDocumentCamera = ({
2265
2337
  backgroundColor="transparent"
2266
2338
  translucent
2267
2339
  />
2268
- {!hasGuideShown ? (
2269
- <SafeAreaView style={styles.guide}>
2270
- <LottieView
2271
- source={require('../../Shared/Animations/id-or-passport.json')}
2272
- style={styles.guideAnimation}
2273
- loop={true}
2274
- autoPlay
2275
- />
2276
- <TextView style={styles.guideHeader}>
2277
- {t('identityDocumentCamera.guideHeader')}
2278
- </TextView>
2279
- <View style={styles.guidePoints}>
2280
- <TextView style={styles.guideText}>
2281
- {t('identityDocumentCamera.guideText')}
2282
- </TextView>
2283
- <TextView style={styles.guideText}>
2284
- {t('identityDocumentCamera.guidePoint1')}
2285
- </TextView>
2286
- <TextView style={styles.guideText}>
2287
- {t('identityDocumentCamera.guidePoint2')}
2288
- </TextView>
2289
- <TextView style={styles.guideText}>
2290
- {t('identityDocumentCamera.guidePoint3')}
2291
- </TextView>
2292
- </View>
2293
- <StyledButton
2294
- mode="contained"
2295
- onPress={() => {
2296
- setHasGuideShown(true);
2297
- }}
2298
- >
2299
- {t('general.letsGo')}
2300
- </StyledButton>
2301
- </SafeAreaView>
2302
- ) : (
2303
- <>
2304
- <TrustchexCamera
2305
- ref={cameraRef}
2306
- style={StyleSheet.absoluteFill as ViewStyle}
2307
- cameraType="back"
2308
- enableFrameProcessing={isActive}
2309
- enableFaceDetection={isActive && faceDetectionEnabled}
2310
- enableTextRecognition={isActive}
2311
- enableBarcodeScanning={isActive && nextStep === 'SCAN_ID_BACK'}
2312
- includeBase64={isActive}
2313
- targetFps={10}
2314
- torchEnabled={isTorchOn}
2315
- onFrameAvailable={handleFrame}
2316
- onCameraReady={handleCameraReady}
2317
- onCameraError={handleCameraError}
2318
- />
2319
- <View style={[styles.topZone, { paddingTop: insets.top }]}>
2320
- {nextStep !== 'COMPLETED' &&
2321
- status !== 'SCANNED' &&
2322
- detectedDocumentType !== 'UNKNOWN' && (
2323
- <TextView style={styles.stepIndicator}>
2324
- {nextStep === 'SCAN_ID_FRONT_OR_PASSPORT'
2325
- ? `${t('identityDocumentCamera.frontSide')} • ${t(
2340
+ <>
2341
+ <TrustchexCamera
2342
+ ref={cameraRef}
2343
+ style={StyleSheet.absoluteFill as ViewStyle}
2344
+ cameraType="back"
2345
+ enableFrameProcessing={isActive}
2346
+ enableFaceDetection={isActive && faceDetectionEnabled}
2347
+ enableTextRecognition={isActive}
2348
+ enableBarcodeScanning={isActive && nextStep === 'SCAN_ID_BACK'}
2349
+ includeBase64={isActive}
2350
+ targetFps={10}
2351
+ torchEnabled={isTorchOn}
2352
+ onFrameAvailable={handleFrame}
2353
+ onCameraReady={handleCameraReady}
2354
+ onCameraError={handleCameraError}
2355
+ />
2356
+ <View style={[styles.topZone, { paddingTop: insets.top }]}>
2357
+ {nextStep !== 'COMPLETED' &&
2358
+ status !== 'SCANNED' &&
2359
+ detectedDocumentType !== 'UNKNOWN' && (
2360
+ <TextView style={styles.stepIndicator}>
2361
+ {nextStep === 'SCAN_ID_FRONT_OR_PASSPORT'
2362
+ ? `${t('identityDocumentCamera.frontSide')} • ${t(
2363
+ 'identityDocumentCamera.stepProgress',
2364
+ {
2365
+ current: 1,
2366
+ total: onlyMRZScan
2367
+ ? detectedDocumentType === 'PASSPORT'
2368
+ ? 1
2369
+ : 2
2370
+ : detectedDocumentType === 'PASSPORT'
2371
+ ? 2
2372
+ : 3,
2373
+ }
2374
+ )}`
2375
+ : nextStep === 'SCAN_HOLOGRAM'
2376
+ ? `${t('identityDocumentCamera.hologramCheck')} • ${t(
2326
2377
  'identityDocumentCamera.stepProgress',
2327
2378
  {
2328
- current: 1,
2329
- total: onlyMRZScan
2330
- ? detectedDocumentType === 'PASSPORT'
2331
- ? 1
2332
- : 2
2333
- : detectedDocumentType === 'PASSPORT'
2334
- ? 2
2335
- : 3,
2379
+ current: 2,
2380
+ total: detectedDocumentType === 'PASSPORT' ? 2 : 3,
2336
2381
  }
2337
2382
  )}`
2338
- : nextStep === 'SCAN_HOLOGRAM'
2339
- ? `${t('identityDocumentCamera.hologramCheck')} • ${t(
2340
- 'identityDocumentCamera.stepProgress',
2341
- {
2342
- current: 2,
2343
- total: detectedDocumentType === 'PASSPORT' ? 2 : 3,
2344
- }
2345
- )}`
2346
- : nextStep === 'SCAN_ID_BACK'
2347
- ? `${t('identityDocumentCamera.backSide')} • ${t('identityDocumentCamera.stepProgress', { current: 3, total: 3 })}`
2348
- : ''}
2349
- </TextView>
2350
- )}
2351
-
2352
- <AnimatedText
2353
- style={[
2354
- styles.topZoneText,
2355
- // Priority order for coloring (later styles override earlier ones)
2356
- // 1. Success (green) - scan completed
2357
- nextStep === 'COMPLETED' && styles.topZoneTextSuccess,
2358
- // 2. Error (red) - wrong side - with flash opacity
2359
- status === 'INCORRECT' && styles.topZoneTextError,
2360
- status === 'INCORRECT' && {
2361
- opacity: errorFlashAnim,
2362
- },
2363
- // 3. Warning (yellow) - quality issues
2364
- (isBrightnessLow || isFrameBlurry) && styles.topZoneTextWarning,
2365
- // 4. Scanning (green) - all elements detected AND inside scan area
2366
- status === 'SCANNING' &&
2367
- allElementsDetected &&
2368
- elementsOutsideScanArea.length === 0 &&
2369
- !isBrightnessLow &&
2370
- !isFrameBlurry &&
2371
- styles.topZoneTextScanning,
2372
- // 5. Default (white) - aligning (not all detected OR elements outside scan area)
2373
- ]}
2374
- >
2375
- {getStatusMessage(
2376
- nextStep,
2377
- status,
2378
- detectedDocumentType,
2379
- isBrightnessLow,
2380
- isFrameBlurry,
2381
- allElementsDetected,
2382
- elementsOutsideScanArea,
2383
- t
2384
- )}
2385
- </AnimatedText>
2386
- </View>
2387
- <View style={styles.leftZone} />
2388
- <View style={styles.rightZone} />
2389
- <View style={styles.bottomZone} />
2390
- <View
2383
+ : nextStep === 'SCAN_ID_BACK'
2384
+ ? `${t('identityDocumentCamera.backSide')} • ${t('identityDocumentCamera.stepProgress', { current: 3, total: 3 })}`
2385
+ : ''}
2386
+ </TextView>
2387
+ )}
2388
+
2389
+ <AnimatedText
2391
2390
  style={[
2392
- styles.scanArea,
2393
- {
2394
- borderColor:
2395
- nextStep === 'COMPLETED'
2396
- ? '#4CAF50'
2397
- : status === 'INCORRECT'
2398
- ? '#f44336'
2399
- : status === 'SCANNING'
2400
- ? '#2196F3'
2401
- : isBrightnessLow || isFrameBlurry
2402
- ? '#FFC107'
2403
- : 'white',
2404
- borderWidth: status === 'SCANNING' ? 3 : 2,
2391
+ styles.topZoneText,
2392
+ // Priority order for coloring (later styles override earlier ones)
2393
+ // 1. Success (green) - scan completed
2394
+ nextStep === 'COMPLETED' && styles.topZoneTextSuccess,
2395
+ // 2. Error (red) - wrong side - with flash opacity
2396
+ status === 'INCORRECT' && styles.topZoneTextError,
2397
+ status === 'INCORRECT' && {
2398
+ opacity: errorFlashAnim,
2405
2399
  },
2400
+ // 3. Warning (yellow) - quality issues
2401
+ (isBrightnessLow || isFrameBlurry) && styles.topZoneTextWarning,
2402
+ // 4. Scanning (green) - all elements detected AND inside scan area
2403
+ status === 'SCANNING' &&
2404
+ allElementsDetected &&
2405
+ elementsOutsideScanArea.length === 0 &&
2406
+ !isBrightnessLow &&
2407
+ !isFrameBlurry &&
2408
+ styles.topZoneTextScanning,
2409
+ // 5. Default (white) - aligning (not all detected OR elements outside scan area)
2406
2410
  ]}
2407
2411
  >
2408
- {nextStep === 'COMPLETED' ? (
2409
- <LottieView
2410
- source={require('../../Shared/Animations/success.json')}
2411
- style={styles.animation}
2412
- loop={false}
2413
- autoPlay
2414
- />
2415
- ) : isBrightnessLow ? (
2416
- <LottieView
2417
- source={require('../../Shared/Animations/light.json')}
2418
- style={styles.animation}
2419
- loop={true}
2420
- autoPlay
2421
- />
2422
- ) : nextStep === 'SCAN_HOLOGRAM' && isTorchOn ? (
2423
- <LottieView
2424
- source={require('../../Shared/Animations/hologram-scan.json')}
2425
- style={styles.animation}
2426
- loop={true}
2427
- autoPlay
2428
- />
2429
- ) : null}
2430
- </View>
2431
- {isDebugEnabled() && (
2432
- <DebugOverlay
2433
- nextStep={nextStep}
2434
- status={status}
2435
- detectedDocumentType={detectedDocumentType}
2436
- isBrightnessLow={isBrightnessLow}
2437
- isFrameBlurry={isFrameBlurry}
2438
- isTorchOn={isTorchOn}
2439
- documentPlaneBounds={documentPlaneBounds}
2440
- secondaryFaceBounds={secondaryFaceBounds}
2441
- barcodeBounds={barcodeBounds}
2442
- mrzBounds={mrzBounds}
2443
- signatureBounds={signatureBounds}
2444
- currentFaceImage={currentFaceImage}
2445
- currentSecondaryFaceImage={currentSecondaryFaceImage}
2446
- currentHologramImage={currentHologramImage}
2447
- currentHologramMaskImage={_currentHologramMaskImage}
2448
- latestHologramFaceImage={latestHologramFaceImage}
2449
- hologramImageCount={hologramImageCount}
2450
- allElementsDetected={allElementsDetected}
2451
- elementsOutsideScanArea={elementsOutsideScanArea}
2412
+ {getStatusMessage(
2413
+ nextStep,
2414
+ status,
2415
+ detectedDocumentType,
2416
+ isBrightnessLow,
2417
+ isFrameBlurry,
2418
+ allElementsDetected,
2419
+ elementsOutsideScanArea,
2420
+ t
2421
+ )}
2422
+ </AnimatedText>
2423
+ </View>
2424
+ <View style={styles.leftZone} />
2425
+ <View style={styles.rightZone} />
2426
+ <View style={styles.bottomZone} />
2427
+ <View
2428
+ style={[
2429
+ styles.scanArea,
2430
+ {
2431
+ borderColor:
2432
+ nextStep === 'COMPLETED'
2433
+ ? '#4CAF50'
2434
+ : status === 'INCORRECT'
2435
+ ? '#f44336'
2436
+ : status === 'SCANNING'
2437
+ ? '#2196F3'
2438
+ : isBrightnessLow || isFrameBlurry
2439
+ ? '#FFC107'
2440
+ : 'white',
2441
+ borderWidth: status === 'SCANNING' ? 3 : 2,
2442
+ },
2443
+ ]}
2444
+ >
2445
+ {nextStep === 'COMPLETED' ? (
2446
+ <LottieView
2447
+ source={require('../../Shared/Animations/success.json')}
2448
+ style={styles.animation}
2449
+ loop={false}
2450
+ autoPlay
2451
+ />
2452
+ ) : isBrightnessLow ? (
2453
+ <LottieView
2454
+ source={require('../../Shared/Animations/light.json')}
2455
+ style={styles.animation}
2456
+ loop={true}
2457
+ autoPlay
2452
2458
  />
2453
- )}
2454
- {testMode && testModeData && (
2455
- <TestModePanel mrzText={testModeData.mrzText} />
2456
- )}
2457
- </>
2458
- )}
2459
+ ) : nextStep === 'SCAN_HOLOGRAM' && isTorchOn ? (
2460
+ <LottieView
2461
+ source={require('../../Shared/Animations/hologram-scan.json')}
2462
+ style={styles.animation}
2463
+ loop={true}
2464
+ autoPlay
2465
+ />
2466
+ ) : null}
2467
+ </View>
2468
+ {isDebugEnabled() && (
2469
+ <DebugOverlay
2470
+ nextStep={nextStep}
2471
+ status={status}
2472
+ detectedDocumentType={detectedDocumentType}
2473
+ isBrightnessLow={isBrightnessLow}
2474
+ isFrameBlurry={isFrameBlurry}
2475
+ isTorchOn={isTorchOn}
2476
+ documentPlaneBounds={documentPlaneBounds}
2477
+ secondaryFaceBounds={secondaryFaceBounds}
2478
+ barcodeBounds={barcodeBounds}
2479
+ mrzBounds={mrzBounds}
2480
+ signatureBounds={signatureBounds}
2481
+ currentFaceImage={currentFaceImage}
2482
+ currentSecondaryFaceImage={currentSecondaryFaceImage}
2483
+ currentHologramImage={currentHologramImage}
2484
+ currentHologramMaskImage={_currentHologramMaskImage}
2485
+ latestHologramFaceImage={latestHologramFaceImage}
2486
+ hologramImageCount={hologramImageCount}
2487
+ allElementsDetected={allElementsDetected}
2488
+ elementsOutsideScanArea={elementsOutsideScanArea}
2489
+ />
2490
+ )}
2491
+ {testMode && testModeData && (
2492
+ <TestModePanel mrzText={testModeData.mrzText} />
2493
+ )}
2494
+ </>
2459
2495
  </View>
2460
2496
  );
2461
2497
  };
@@ -12,6 +12,15 @@ import {
12
12
  } from './IdentityDocumentCamera.constants';
13
13
  import { debugLog, isDebugEnabled } from '../Libs/debug.utils';
14
14
 
15
+ /**
16
+ * Checks if a document code represents an ID card (TD1/TD2).
17
+ * Per ICAO 9303, valid ID card codes start with 'I', 'A', or 'C'.
18
+ */
19
+ export function isIDCardDocumentCode(code: string | null | undefined): boolean {
20
+ if (!code) return false;
21
+ return code.startsWith('I') || code.startsWith('A') || code.startsWith('C');
22
+ }
23
+
15
24
  /**
16
25
  * Frame-to-screen coordinate transform using FILL_CENTER scaling
17
26
  */
@@ -225,8 +234,8 @@ export function detectDocumentType(
225
234
  });
226
235
  }
227
236
 
228
- // ID Back: no face + ID MRZ
229
- if (faces.length === 0 && mrzFields?.documentCode === 'I') {
237
+ // ID Back: no face + ID MRZ (codes starting with I, A, or C per ICAO 9303)
238
+ if (faces.length === 0 && isIDCardDocumentCode(mrzFields?.documentCode)) {
230
239
  return 'ID_BACK';
231
240
  }
232
241
 
@@ -265,8 +274,8 @@ export function detectDocumentType(
265
274
  : faces;
266
275
 
267
276
  if (cardSizedFaces.length > 0) {
268
- // If we have MRZ code 'I', it's definitely an ID card
269
- if (mrzFields?.documentCode === 'I') {
277
+ // If we have an ID card MRZ code (I, A, or C), it's definitely an ID card
278
+ if (isIDCardDocumentCode(mrzFields?.documentCode)) {
270
279
  return 'ID_FRONT';
271
280
  }
272
281