@trustchex/react-native-sdk 1.409.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.
- package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +59 -1
- package/ios/Camera/TrustchexCameraView.swift +9 -1
- package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
- package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
- package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
- package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +102 -23
- package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
- package/lib/module/Screens/Dynamic/VideoCallScreen.js +3 -1
- package/lib/module/Screens/Static/ResultScreen.js +128 -22
- package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
- package/lib/module/Shared/Animations/recording.json +1 -0
- package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
- package/lib/module/Shared/Components/EIDScanner.js +212 -108
- package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +53 -36
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
- package/lib/module/Shared/Components/NavigationManager.js +24 -16
- package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
- package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
- package/lib/module/Shared/EIDReader/bacKey.js +16 -2
- package/lib/module/Shared/EIDReader/eidReader.js +354 -13
- package/lib/module/Shared/EIDReader/eidService.js +25 -1
- package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
- package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
- package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
- package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
- package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
- package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
- package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
- package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
- package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
- package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
- package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
- package/lib/module/Shared/Libs/analytics.utils.js +4 -0
- package/lib/module/Shared/Libs/contains.js +1 -40
- package/lib/module/Shared/Libs/country-display.utils.js +34 -0
- package/lib/module/Shared/Libs/demo.utils.js +8 -0
- package/lib/module/Shared/Libs/mrz.utils.js +3 -2
- package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
- package/lib/module/Shared/Types/analytics.types.js +2 -0
- package/lib/module/Translation/Resources/en.js +41 -2
- package/lib/module/Translation/Resources/tr.js +41 -2
- package/lib/module/Trustchex.js +54 -20
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
- package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
- package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
- package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
- package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
- package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
- package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
- package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
- package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
- package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
- package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
- package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
- package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +40 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +40 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/Trustchex.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +7 -4
- package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
- package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
- package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
- package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +124 -23
- package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
- package/src/Screens/Dynamic/VideoCallScreen.tsx +3 -1
- package/src/Screens/Static/ResultScreen.tsx +183 -31
- package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
- package/src/Shared/Animations/recording.json +1 -0
- package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
- package/src/Shared/Components/EIDScanner.tsx +222 -111
- package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
- package/src/Shared/Components/IdentityDocumentCamera.tsx +199 -184
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
- package/src/Shared/Components/NavigationManager.tsx +27 -18
- package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
- package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
- package/src/Shared/EIDReader/bacKey.ts +24 -8
- package/src/Shared/EIDReader/eidReader.ts +398 -12
- package/src/Shared/EIDReader/eidService.ts +49 -1
- package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
- package/src/Shared/EIDReader/paceInfo.ts +159 -0
- package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
- package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
- package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
- package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
- package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
- package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
- package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
- package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
- package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
- package/src/Shared/Libs/analytics.utils.ts +4 -0
- package/src/Shared/Libs/contains.ts +0 -53
- package/src/Shared/Libs/country-display.utils.ts +55 -0
- package/src/Shared/Libs/crypto.utils.ts +2 -2
- package/src/Shared/Libs/demo.utils.ts +10 -0
- package/src/Shared/Libs/http-client.ts +12 -4
- package/src/Shared/Libs/mrz.utils.ts +3 -2
- package/src/Shared/Libs/status-bar.utils.ts +4 -2
- package/src/Shared/Services/VideoSessionService.ts +1 -1
- package/src/Shared/Types/analytics.types.ts +2 -0
- package/src/Shared/Types/identificationInfo.ts +11 -0
- package/src/Translation/Resources/en.ts +63 -3
- package/src/Translation/Resources/tr.ts +62 -3
- package/src/Trustchex.tsx +53 -17
- package/src/version.ts +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* KEY DISTINGUISHING FEATURES:
|
|
7
7
|
* =============================
|
|
8
8
|
* PASSPORT: Has MRZ on FRONT with pattern P<XXX (e.g., P<TUR, P<USA)
|
|
9
|
-
* ID CARD: Has NO MRZ on front; MRZ only on BACK with code
|
|
9
|
+
* ID CARD: Has NO MRZ on front; MRZ only on BACK with code starting with I, A, or C
|
|
10
10
|
*
|
|
11
11
|
* IMPORTANT: Both passports and ID cards have signature sections!
|
|
12
12
|
* Signature presence is NOT a distinguishing feature between document types.
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
import type { Face } from './IdentityDocumentCamera.types';
|
|
32
32
|
import type { MRZFields } from '../Types/mrzFields';
|
|
33
33
|
import { PASSPORT_MRZ_PATTERN } from './IdentityDocumentCamera.constants';
|
|
34
|
-
import {
|
|
34
|
+
import { isIDCardDocumentCode } from './IdentityDocumentCamera.utils';
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* After this many retry attempts for ID_FRONT flow, proceed with face detection alone
|
|
@@ -222,10 +222,13 @@ export function handleIDFrontFlow(
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
// ============================================================================
|
|
225
|
-
// STEP 4: Final MRZ code check (if present, must be
|
|
225
|
+
// STEP 4: Final MRZ code check (if present, must be an ID card code, not P)
|
|
226
226
|
// ============================================================================
|
|
227
227
|
// ID cards should NOT have MRZ on front, but if detected, verify it's not passport
|
|
228
|
-
if (
|
|
228
|
+
if (
|
|
229
|
+
mrzFields?.documentCode &&
|
|
230
|
+
!isIDCardDocumentCode(mrzFields.documentCode)
|
|
231
|
+
) {
|
|
229
232
|
return {
|
|
230
233
|
shouldProceed: false,
|
|
231
234
|
reason: `MRZ shows unexpected document code: ${mrzFields.documentCode}`,
|
|
@@ -382,7 +382,9 @@ const IdentityDocumentCamera = ({
|
|
|
382
382
|
} else {
|
|
383
383
|
// Guide screen with white background - use dark icons
|
|
384
384
|
StatusBar.setBarStyle('dark-content', true);
|
|
385
|
-
|
|
385
|
+
if (Platform.OS === 'android') {
|
|
386
|
+
StatusBar.setBackgroundColor('#ffffff', true);
|
|
387
|
+
}
|
|
386
388
|
}
|
|
387
389
|
}, [hasGuideShown]);
|
|
388
390
|
|
|
@@ -2251,42 +2253,18 @@ const IdentityDocumentCamera = ({
|
|
|
2251
2253
|
[]
|
|
2252
2254
|
);
|
|
2253
2255
|
|
|
2254
|
-
|
|
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) {
|
|
2255
2261
|
return (
|
|
2256
|
-
<
|
|
2257
|
-
<StatusBar
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
if (!hasPermission) {
|
|
2264
|
-
return (
|
|
2265
|
-
<SafeAreaView style={styles.permissionContainer}>
|
|
2266
|
-
<StatusBar barStyle="dark-content" />
|
|
2267
|
-
<TextView style={styles.permissionText}>
|
|
2268
|
-
{t('general.noCameraPermissionGiven')}
|
|
2269
|
-
</TextView>
|
|
2270
|
-
<StyledButton
|
|
2271
|
-
mode="contained"
|
|
2272
|
-
onPress={() => {
|
|
2273
|
-
Linking.openSettings();
|
|
2274
|
-
}}
|
|
2275
|
-
>
|
|
2276
|
-
{t('general.openSettings')}
|
|
2277
|
-
</StyledButton>
|
|
2278
|
-
</SafeAreaView>
|
|
2279
|
-
);
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
return (
|
|
2283
|
-
<View style={StyleSheet.absoluteFill}>
|
|
2284
|
-
<StatusBar
|
|
2285
|
-
barStyle={hasGuideShown ? 'light-content' : 'dark-content'}
|
|
2286
|
-
backgroundColor={hasGuideShown ? 'transparent' : '#ffffff'}
|
|
2287
|
-
translucent
|
|
2288
|
-
/>
|
|
2289
|
-
{!hasGuideShown ? (
|
|
2262
|
+
<View style={StyleSheet.absoluteFill}>
|
|
2263
|
+
<StatusBar
|
|
2264
|
+
barStyle="dark-content"
|
|
2265
|
+
backgroundColor="#ffffff"
|
|
2266
|
+
translucent
|
|
2267
|
+
/>
|
|
2290
2268
|
<SafeAreaView style={styles.guide}>
|
|
2291
2269
|
<LottieView
|
|
2292
2270
|
source={require('../../Shared/Animations/id-or-passport.json')}
|
|
@@ -2320,163 +2298,200 @@ const IdentityDocumentCamera = ({
|
|
|
2320
2298
|
{t('general.letsGo')}
|
|
2321
2299
|
</StyledButton>
|
|
2322
2300
|
</SafeAreaView>
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2301
|
+
</View>
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
if (!permissionsRequested) {
|
|
2306
|
+
return (
|
|
2307
|
+
<SafeAreaView style={styles.permissionContainer}>
|
|
2308
|
+
<StatusBar barStyle="dark-content" />
|
|
2309
|
+
<ActivityIndicator size="large" color={theme.colors.primary} />
|
|
2310
|
+
</SafeAreaView>
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
if (!hasPermission) {
|
|
2315
|
+
return (
|
|
2316
|
+
<SafeAreaView style={styles.permissionContainer}>
|
|
2317
|
+
<StatusBar barStyle="dark-content" />
|
|
2318
|
+
<TextView style={styles.permissionText}>
|
|
2319
|
+
{t('general.noCameraPermissionGiven')}
|
|
2320
|
+
</TextView>
|
|
2321
|
+
<StyledButton
|
|
2322
|
+
mode="contained"
|
|
2323
|
+
onPress={() => {
|
|
2324
|
+
Linking.openSettings();
|
|
2325
|
+
}}
|
|
2326
|
+
>
|
|
2327
|
+
{t('general.openSettings')}
|
|
2328
|
+
</StyledButton>
|
|
2329
|
+
</SafeAreaView>
|
|
2330
|
+
);
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
return (
|
|
2334
|
+
<View style={StyleSheet.absoluteFill}>
|
|
2335
|
+
<StatusBar
|
|
2336
|
+
barStyle="light-content"
|
|
2337
|
+
backgroundColor="transparent"
|
|
2338
|
+
translucent
|
|
2339
|
+
/>
|
|
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(
|
|
2347
2377
|
'identityDocumentCamera.stepProgress',
|
|
2348
2378
|
{
|
|
2349
|
-
current:
|
|
2350
|
-
total:
|
|
2351
|
-
? detectedDocumentType === 'PASSPORT'
|
|
2352
|
-
? 1
|
|
2353
|
-
: 2
|
|
2354
|
-
: detectedDocumentType === 'PASSPORT'
|
|
2355
|
-
? 2
|
|
2356
|
-
: 3,
|
|
2379
|
+
current: 2,
|
|
2380
|
+
total: detectedDocumentType === 'PASSPORT' ? 2 : 3,
|
|
2357
2381
|
}
|
|
2358
2382
|
)}`
|
|
2359
|
-
: nextStep === '
|
|
2360
|
-
? `${t('identityDocumentCamera.
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
)}`
|
|
2367
|
-
: nextStep === 'SCAN_ID_BACK'
|
|
2368
|
-
? `${t('identityDocumentCamera.backSide')} • ${t('identityDocumentCamera.stepProgress', { current: 3, total: 3 })}`
|
|
2369
|
-
: ''}
|
|
2370
|
-
</TextView>
|
|
2371
|
-
)}
|
|
2372
|
-
|
|
2373
|
-
<AnimatedText
|
|
2374
|
-
style={[
|
|
2375
|
-
styles.topZoneText,
|
|
2376
|
-
// Priority order for coloring (later styles override earlier ones)
|
|
2377
|
-
// 1. Success (green) - scan completed
|
|
2378
|
-
nextStep === 'COMPLETED' && styles.topZoneTextSuccess,
|
|
2379
|
-
// 2. Error (red) - wrong side - with flash opacity
|
|
2380
|
-
status === 'INCORRECT' && styles.topZoneTextError,
|
|
2381
|
-
status === 'INCORRECT' && {
|
|
2382
|
-
opacity: errorFlashAnim,
|
|
2383
|
-
},
|
|
2384
|
-
// 3. Warning (yellow) - quality issues
|
|
2385
|
-
(isBrightnessLow || isFrameBlurry) && styles.topZoneTextWarning,
|
|
2386
|
-
// 4. Scanning (green) - all elements detected AND inside scan area
|
|
2387
|
-
status === 'SCANNING' &&
|
|
2388
|
-
allElementsDetected &&
|
|
2389
|
-
elementsOutsideScanArea.length === 0 &&
|
|
2390
|
-
!isBrightnessLow &&
|
|
2391
|
-
!isFrameBlurry &&
|
|
2392
|
-
styles.topZoneTextScanning,
|
|
2393
|
-
// 5. Default (white) - aligning (not all detected OR elements outside scan area)
|
|
2394
|
-
]}
|
|
2395
|
-
>
|
|
2396
|
-
{getStatusMessage(
|
|
2397
|
-
nextStep,
|
|
2398
|
-
status,
|
|
2399
|
-
detectedDocumentType,
|
|
2400
|
-
isBrightnessLow,
|
|
2401
|
-
isFrameBlurry,
|
|
2402
|
-
allElementsDetected,
|
|
2403
|
-
elementsOutsideScanArea,
|
|
2404
|
-
t
|
|
2405
|
-
)}
|
|
2406
|
-
</AnimatedText>
|
|
2407
|
-
</View>
|
|
2408
|
-
<View style={styles.leftZone} />
|
|
2409
|
-
<View style={styles.rightZone} />
|
|
2410
|
-
<View style={styles.bottomZone} />
|
|
2411
|
-
<View
|
|
2383
|
+
: nextStep === 'SCAN_ID_BACK'
|
|
2384
|
+
? `${t('identityDocumentCamera.backSide')} • ${t('identityDocumentCamera.stepProgress', { current: 3, total: 3 })}`
|
|
2385
|
+
: ''}
|
|
2386
|
+
</TextView>
|
|
2387
|
+
)}
|
|
2388
|
+
|
|
2389
|
+
<AnimatedText
|
|
2412
2390
|
style={[
|
|
2413
|
-
styles.
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
? '#2196F3'
|
|
2422
|
-
: isBrightnessLow || isFrameBlurry
|
|
2423
|
-
? '#FFC107'
|
|
2424
|
-
: 'white',
|
|
2425
|
-
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,
|
|
2426
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)
|
|
2427
2410
|
]}
|
|
2428
2411
|
>
|
|
2429
|
-
{
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
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
|
|
2473
2458
|
/>
|
|
2474
|
-
)
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
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
|
+
</>
|
|
2480
2495
|
</View>
|
|
2481
2496
|
);
|
|
2482
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
|
|
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
|
|
269
|
-
if (mrzFields?.documentCode
|
|
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
|
|
|
@@ -18,9 +18,10 @@ import i18n from '../../Translation';
|
|
|
18
18
|
import StyledButton from './StyledButton';
|
|
19
19
|
import { analyticsService } from '../Services/AnalyticsService';
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// Navigation lock - use a ref-like pattern so unmounting resets state.
|
|
22
|
+
// The module-level object is shared across all instances but the
|
|
23
|
+
// cleanup effect in the component resets it on unmount.
|
|
24
|
+
const navigationLock = { isNavigating: false, lastNavigationTime: 0 };
|
|
24
25
|
|
|
25
26
|
export type NavigationManagerRef = {
|
|
26
27
|
navigateToNextStep: () => void;
|
|
@@ -45,6 +46,7 @@ const NavigationManager = forwardRef(
|
|
|
45
46
|
IDENTITY_DOCUMENT_SCAN: 'IdentityDocumentScanningScreen',
|
|
46
47
|
IDENTITY_DOCUMENT_EID_SCAN: 'IdentityDocumentEIDScanningScreen',
|
|
47
48
|
LIVENESS_CHECK: 'LivenessDetectionScreen',
|
|
49
|
+
VERBAL_CONSENT: 'VerbalConsentScreen',
|
|
48
50
|
VIDEO_CALL: 'VideoCallScreen',
|
|
49
51
|
},
|
|
50
52
|
RESULT: 'ResultScreen',
|
|
@@ -52,14 +54,14 @@ const NavigationManager = forwardRef(
|
|
|
52
54
|
|
|
53
55
|
React.useEffect(() => {
|
|
54
56
|
const handleFocus = () => {
|
|
55
|
-
isNavigating = false;
|
|
57
|
+
navigationLock.isNavigating = false;
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
navigation.addListener('focus', handleFocus);
|
|
59
61
|
|
|
60
62
|
return () => {
|
|
61
63
|
navigation.removeListener('focus', handleFocus);
|
|
62
|
-
isNavigating = false;
|
|
64
|
+
navigationLock.isNavigating = false;
|
|
63
65
|
};
|
|
64
66
|
}, [navigation]);
|
|
65
67
|
|
|
@@ -114,16 +116,22 @@ const NavigationManager = forwardRef(
|
|
|
114
116
|
return routes.DYNAMIC_ROUTES.VIDEO_CALL;
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
if (nextStep.type === 'VERBAL_CONSENT') {
|
|
120
|
+
return routes.DYNAMIC_ROUTES.VERBAL_CONSENT;
|
|
121
|
+
}
|
|
122
|
+
|
|
117
123
|
return routes.VERIFICATION_SESSION_CHECK;
|
|
118
124
|
},
|
|
119
125
|
[
|
|
120
126
|
appContext,
|
|
121
127
|
routes.VERIFICATION_SESSION_CHECK,
|
|
128
|
+
routes.RESULT,
|
|
122
129
|
routes.DYNAMIC_ROUTES.CONTRACT_ACCEPTANCE,
|
|
123
|
-
routes.DYNAMIC_ROUTES.IDENTITY_DOCUMENT_EID_SCAN,
|
|
124
130
|
routes.DYNAMIC_ROUTES.IDENTITY_DOCUMENT_SCAN,
|
|
131
|
+
routes.DYNAMIC_ROUTES.IDENTITY_DOCUMENT_EID_SCAN,
|
|
125
132
|
routes.DYNAMIC_ROUTES.LIVENESS_CHECK,
|
|
126
|
-
routes.
|
|
133
|
+
routes.DYNAMIC_ROUTES.VIDEO_CALL,
|
|
134
|
+
routes.DYNAMIC_ROUTES.VERBAL_CONSENT,
|
|
127
135
|
]
|
|
128
136
|
);
|
|
129
137
|
|
|
@@ -132,14 +140,15 @@ const NavigationManager = forwardRef(
|
|
|
132
140
|
const minTimeBetweenNavigation = 1000;
|
|
133
141
|
|
|
134
142
|
if (
|
|
135
|
-
isNavigating ||
|
|
136
|
-
currentTime - lastNavigationTime <
|
|
143
|
+
navigationLock.isNavigating ||
|
|
144
|
+
currentTime - navigationLock.lastNavigationTime <
|
|
145
|
+
minTimeBetweenNavigation
|
|
137
146
|
) {
|
|
138
147
|
return;
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
isNavigating = true;
|
|
142
|
-
lastNavigationTime = currentTime;
|
|
150
|
+
navigationLock.isNavigating = true;
|
|
151
|
+
navigationLock.lastNavigationTime = currentTime;
|
|
143
152
|
|
|
144
153
|
try {
|
|
145
154
|
const nextRoute = getNextRoute(
|
|
@@ -156,12 +165,12 @@ const NavigationManager = forwardRef(
|
|
|
156
165
|
})
|
|
157
166
|
);
|
|
158
167
|
} catch (error) {
|
|
159
|
-
isNavigating = false;
|
|
168
|
+
navigationLock.isNavigating = false;
|
|
160
169
|
throw error;
|
|
161
170
|
}
|
|
162
171
|
|
|
163
172
|
setTimeout(() => {
|
|
164
|
-
isNavigating = false;
|
|
173
|
+
navigationLock.isNavigating = false;
|
|
165
174
|
}, 1000);
|
|
166
175
|
}, [
|
|
167
176
|
getNextRoute,
|
|
@@ -171,7 +180,7 @@ const NavigationManager = forwardRef(
|
|
|
171
180
|
]);
|
|
172
181
|
|
|
173
182
|
const goToNextRouteWithAlert = useCallback(() => {
|
|
174
|
-
if (isNavigating) {
|
|
183
|
+
if (navigationLock.isNavigating) {
|
|
175
184
|
return;
|
|
176
185
|
}
|
|
177
186
|
|
|
@@ -192,11 +201,11 @@ const NavigationManager = forwardRef(
|
|
|
192
201
|
}, [goToNextRoute, t]);
|
|
193
202
|
|
|
194
203
|
const reset = useCallback(() => {
|
|
195
|
-
if (isNavigating) {
|
|
204
|
+
if (navigationLock.isNavigating) {
|
|
196
205
|
return;
|
|
197
206
|
}
|
|
198
207
|
|
|
199
|
-
isNavigating = true;
|
|
208
|
+
navigationLock.isNavigating = true;
|
|
200
209
|
|
|
201
210
|
try {
|
|
202
211
|
// Preserve demo session state when resetting
|
|
@@ -241,12 +250,12 @@ const NavigationManager = forwardRef(
|
|
|
241
250
|
})
|
|
242
251
|
);
|
|
243
252
|
} catch (error) {
|
|
244
|
-
isNavigating = false;
|
|
253
|
+
navigationLock.isNavigating = false;
|
|
245
254
|
throw error;
|
|
246
255
|
}
|
|
247
256
|
|
|
248
257
|
setTimeout(() => {
|
|
249
|
-
isNavigating = false;
|
|
258
|
+
navigationLock.isNavigating = false;
|
|
250
259
|
}, 1000);
|
|
251
260
|
}, [appContext, navigation, routes.VERIFICATION_SESSION_CHECK]);
|
|
252
261
|
|