@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
@@ -10,9 +10,12 @@ import { getI18n, useTranslation } from 'react-i18next';
10
10
  import StyledButton from "../../Shared/Components/StyledButton.js";
11
11
  import NativeDeviceInfo from "../../Shared/Libs/native-device-info.utils.js";
12
12
  import { speakWithDebounce } from "../../Shared/Libs/tts.utils.js";
13
+ import { useStatusBarWhiteBackground } from "../../Shared/Libs/status-bar.utils.js";
13
14
  import { trackFunnelStep, useScreenTracking, trackConsentGiven, trackVerificationStart, trackVerificationComplete, trackError } from "../../Shared/Libs/analytics.utils.js";
15
+ import { useKeepAwake } from "../../Shared/Libs/native-keep-awake.utils.js";
14
16
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
17
  const ContractAcceptanceScreen = () => {
18
+ useKeepAwake();
16
19
  const [isEnabled, setIsEnabled] = useState(false);
17
20
  const [isReady, setIsReady] = useState(false);
18
21
  const appContext = useContext(AppContext);
@@ -27,6 +30,9 @@ const ContractAcceptanceScreen = () => {
27
30
 
28
31
  // Track screen view and exit
29
32
  useScreenTracking('contract_acceptance');
33
+
34
+ // Configure status bar for white background
35
+ useStatusBarWhiteBackground();
30
36
  useEffect(() => {
31
37
  const contracts = appContext.currentWorkflowStep?.data?.contracts;
32
38
  if (!contracts) {
@@ -65,38 +71,49 @@ const ContractAcceptanceScreen = () => {
65
71
  const generateHumanReadableIdentifier = useCallback(async () => {
66
72
  return await NativeDeviceInfo.generateHumanReadableIdentifier();
67
73
  }, []);
74
+
75
+ // Early return if workflow step data is not available (after all hooks)
76
+ if (!appContext.currentWorkflowStep || !appContext.currentWorkflowStep.data) {
77
+ return null;
78
+ }
68
79
  return /*#__PURE__*/_jsxs(SafeAreaView, {
69
80
  style: styles.container,
70
- children: [/*#__PURE__*/_jsx(WebView, {
71
- source: {
72
- uri: contractUrl || ''
73
- },
74
- javaScriptEnabled: true,
75
- domStorageEnabled: false,
76
- scalesPageToFit: false,
77
- scrollEnabled: true,
78
- style: styles.webView,
79
- onError: syntheticEvent => {
80
- const {
81
- nativeEvent
82
- } = syntheticEvent;
83
- trackError('CONTRACT_WEBVIEW_ERROR', nativeEvent.description || 'Failed to load contract', 'contract_acceptance', 'medium', {
84
- recoverable: true,
85
- userAction: 'load_contract'
86
- });
87
- },
88
- onLoadEnd: event => {
89
- if (event.nativeEvent.url === contractUrl) {
90
- setIsReady(true);
81
+ children: [/*#__PURE__*/_jsx(View, {
82
+ style: [styles.webViewContainer, {
83
+ paddingHorizontal: Math.max(insets.left, insets.right),
84
+ paddingTop: insets.top
85
+ }],
86
+ children: /*#__PURE__*/_jsx(WebView, {
87
+ source: {
88
+ uri: contractUrl || ''
89
+ },
90
+ javaScriptEnabled: true,
91
+ domStorageEnabled: false,
92
+ scalesPageToFit: false,
93
+ scrollEnabled: true,
94
+ style: styles.webView,
95
+ onError: syntheticEvent => {
96
+ const {
97
+ nativeEvent
98
+ } = syntheticEvent;
99
+ trackError('CONTRACT_WEBVIEW_ERROR', nativeEvent.description || 'Failed to load contract', 'contract_acceptance', 'medium', {
100
+ recoverable: true,
101
+ userAction: 'load_contract'
102
+ });
103
+ },
104
+ onLoadEnd: event => {
105
+ if (event.nativeEvent.url === contractUrl) {
106
+ setIsReady(true);
91
107
 
92
- // Track contract acceptance started
93
- trackVerificationStart('CONTRACT_ACCEPTANCE');
94
- if (appContext.currentWorkflowStep?.data?.voiceGuidanceActive) {
95
- speakWithDebounce(t('termsOfUseAndDataPrivacyScreen.footerText'));
108
+ // Track contract acceptance started
109
+ trackVerificationStart('CONTRACT_ACCEPTANCE');
110
+ if (appContext.currentWorkflowStep?.data?.voiceGuidanceActive) {
111
+ speakWithDebounce(t('termsOfUseAndDataPrivacyScreen.footerText'));
112
+ }
96
113
  }
97
- }
98
- },
99
- onScroll: hasReachedEnd
114
+ },
115
+ onScroll: hasReachedEnd
116
+ })
100
117
  }), /*#__PURE__*/_jsxs(View, {
101
118
  style: [styles.footer, {
102
119
  paddingBottom: insets.bottom
@@ -146,17 +163,17 @@ const ContractAcceptanceScreen = () => {
146
163
  });
147
164
  };
148
165
  const styles = StyleSheet.create({
149
- safeAreaContainer: {
166
+ container: {
150
167
  flex: 1,
151
168
  backgroundColor: 'white'
152
169
  },
153
- container: {
154
- flex: 1
170
+ webViewContainer: {
171
+ flex: 1,
172
+ width: '100%'
155
173
  },
156
174
  webView: {
157
175
  flex: 1,
158
176
  width: '100%',
159
- height: '100%',
160
177
  resizeMode: 'contain'
161
178
  },
162
179
  footer: {
@@ -9,18 +9,33 @@ import AppContext from "../../Shared/Contexts/AppContext.js";
9
9
  import IdentityDocumentCamera from "../../Shared/Components/IdentityDocumentCamera.js";
10
10
  import { useTranslation } from 'react-i18next';
11
11
  import { trackFunnelStep, useScreenTracking, trackVerificationStart, trackVerificationComplete } from "../../Shared/Libs/analytics.utils.js";
12
+ import { useKeepAwake } from "../../Shared/Libs/native-keep-awake.utils.js";
12
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
14
  const IdentityDocumentEIDScanningScreen = () => {
15
+ useKeepAwake();
14
16
  const appContext = useContext(AppContext);
15
17
  const navigationManagerRef = React.useRef(null);
16
18
  const insets = useSafeAreaInsets();
17
19
  const [idFrontSideData, setIDFrontSideData] = useState(null);
18
20
  const [idBackSideData, setIDBackSideData] = useState(null);
19
21
  const [passportData, setPassportData] = useState();
20
- const [documentNumber, setDocumentNumber] = useState();
21
- const [dateOfBirth, setDateOfBirth] = useState();
22
- const [dateOfExpiry, setDateOfExpiry] = useState();
23
- const [documentType, setDocumentType] = useState();
22
+ const [documentNumber, setDocumentNumber] = useState(() => {
23
+ const mrzFields = appContext.identificationInfo.scannedDocument?.mrzFields;
24
+ return mrzFields?.documentNumber ?? undefined;
25
+ });
26
+ const [dateOfBirth, setDateOfBirth] = useState(() => {
27
+ const mrzFields = appContext.identificationInfo.scannedDocument?.mrzFields;
28
+ return mrzFields?.birthDate ?? undefined;
29
+ });
30
+ const [dateOfExpiry, setDateOfExpiry] = useState(() => {
31
+ const mrzFields = appContext.identificationInfo.scannedDocument?.mrzFields;
32
+ return mrzFields?.expirationDate ?? undefined;
33
+ });
34
+ const [documentType, setDocumentType] = useState(() => {
35
+ const dc = appContext.identificationInfo.scannedDocument?.mrzFields?.documentCode;
36
+ if (!dc) return undefined;
37
+ return dc === 'I' ? 'ID' : dc === 'P' ? 'PASSPORT' : 'UNKNOWN';
38
+ });
24
39
  const [isNFCSupported, setIsNFCSupported] = useState(false);
25
40
  const {
26
41
  t
@@ -55,6 +70,9 @@ const IdentityDocumentEIDScanningScreen = () => {
55
70
  setAllowedDocumentTypes(appContext.currentWorkflowStep?.data?.allowedDocumentTypes ?? null);
56
71
  setAllowedCountries(appContext.currentWorkflowStep?.data?.allowedCountries ?? null);
57
72
  }, [appContext.currentWorkflowStep]);
73
+ if (!appContext.currentWorkflowStep) {
74
+ return null;
75
+ }
58
76
  return /*#__PURE__*/_jsxs(SafeAreaView, {
59
77
  style: styles.safeAreaContainer,
60
78
  children: [documentNumber && dateOfBirth && dateOfExpiry ? /*#__PURE__*/_jsx(View, {
@@ -8,8 +8,10 @@ import AppContext from "../../Shared/Contexts/AppContext.js";
8
8
  import NavigationManager from "../../Shared/Components/NavigationManager.js";
9
9
  import { useTranslation } from 'react-i18next';
10
10
  import { trackFunnelStep, useScreenTracking, trackVerificationStart, trackVerificationComplete } from "../../Shared/Libs/analytics.utils.js";
11
+ import { useKeepAwake } from "../../Shared/Libs/native-keep-awake.utils.js";
11
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
13
  const IdentityDocumentScanningScreen = () => {
14
+ useKeepAwake();
13
15
  const [idFrontSideData, setIDFrontSideData] = useState(null);
14
16
  const [idBackSideData, setIDBackSideData] = useState(null);
15
17
  const [passportData, setPassportData] = useState();
@@ -83,6 +85,9 @@ const IdentityDocumentScanningScreen = () => {
83
85
  setAllowedDocumentTypes(appContext.currentWorkflowStep?.data?.allowedDocumentTypes ?? null);
84
86
  setAllowedCountries(appContext.currentWorkflowStep?.data?.allowedCountries ?? null);
85
87
  }, [appContext.currentWorkflowStep]);
88
+ if (!appContext.currentWorkflowStep) {
89
+ return null;
90
+ }
86
91
  return /*#__PURE__*/_jsxs(SafeAreaView, {
87
92
  style: styles.container,
88
93
  children: [/*#__PURE__*/_jsx(IdentityDocumentCamera, {
@@ -3,24 +3,25 @@
3
3
  import Svg, { Rect as SvgRect, Circle, Mask } from 'react-native-svg';
4
4
  import { useNavigation } from '@react-navigation/native';
5
5
  import React, { useState, useReducer, useContext, useEffect, useCallback, useRef } from 'react';
6
- import { StyleSheet, Text, View, Dimensions, Vibration } from 'react-native';
6
+ import { Animated, Easing, StyleSheet, Text, View, Dimensions, Platform, Vibration, StatusBar } from 'react-native';
7
7
  import { useSafeAreaInsets, SafeAreaView } from 'react-native-safe-area-context';
8
8
  import NativeCircularProgress from "../../Shared/Components/NativeCircularProgress.js";
9
9
  import FaceCamera from "../../Shared/Components/FaceCamera.js";
10
10
  import NavigationManager from "../../Shared/Components/NavigationManager.js";
11
11
  import AppContext from "../../Shared/Contexts/AppContext.js";
12
- import { contains } from "../../Shared/Libs/contains.js";
13
12
  import { useTranslation } from 'react-i18next';
14
13
  import StyledButton from "../../Shared/Components/StyledButton.js";
15
14
  import LottieView from 'lottie-react-native';
16
15
  import { speak, resetLastMessage } from "../../Shared/Libs/tts.utils.js";
16
+ import { useStatusBarWhiteBackground } from "../../Shared/Libs/status-bar.utils.js";
17
17
  import { trackFunnelStep, useScreenTracking, trackVerificationStart, trackVerificationComplete } from "../../Shared/Libs/analytics.utils.js";
18
+ import { useKeepAwake } from "../../Shared/Libs/native-keep-awake.utils.js";
18
19
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
19
20
  const {
20
21
  width: windowWidth,
21
22
  height: windowHeight
22
23
  } = Dimensions.get('window');
23
- const PREVIEW_SIZE = windowWidth * 0.8;
24
+ const PREVIEW_SIZE = windowWidth * 0.95;
24
25
  const PREVIEW_RECT = {
25
26
  minX: (windowWidth - PREVIEW_SIZE) / 2,
26
27
  minY: (windowHeight - PREVIEW_SIZE) / 2,
@@ -31,6 +32,7 @@ const PREVIEW_EDGE_OFFSET = 10;
31
32
  const TURN_ANGLE_LIMIT = 15;
32
33
  const LOOK_STRAIGHT_ANGLE_LIMIT = 10;
33
34
  const LivenessDetectionScreen = () => {
35
+ useKeepAwake();
34
36
  const [camera, setCamera] = useState(null);
35
37
  const navigation = useNavigation();
36
38
  const appContext = useContext(AppContext);
@@ -41,9 +43,32 @@ const LivenessDetectionScreen = () => {
41
43
  const [isRecording, setIsRecording] = useState(false);
42
44
  const insets = useSafeAreaInsets();
43
45
  const referenceFaceTrackingId = useRef(null);
46
+ const recordingDotOpacity = useRef(new Animated.Value(1)).current;
44
47
 
45
48
  // Track screen view and exit
46
49
  useScreenTracking('liveness_detection');
50
+ useEffect(() => {
51
+ if (isRecording) {
52
+ const pulse = Animated.loop(Animated.sequence([Animated.timing(recordingDotOpacity, {
53
+ toValue: 0.2,
54
+ duration: 600,
55
+ easing: Easing.inOut(Easing.ease),
56
+ useNativeDriver: true
57
+ }), Animated.timing(recordingDotOpacity, {
58
+ toValue: 1,
59
+ duration: 600,
60
+ easing: Easing.inOut(Easing.ease),
61
+ useNativeDriver: true
62
+ })]));
63
+ pulse.start();
64
+ return () => pulse.stop();
65
+ } else {
66
+ recordingDotOpacity.setValue(1);
67
+ }
68
+ }, [isRecording, recordingDotOpacity]);
69
+
70
+ // Configure status bar for white background
71
+ useStatusBarWhiteBackground();
47
72
  const [initialState, setInitialState] = useState({
48
73
  brightnessLow: false,
49
74
  faceDetected: false,
@@ -95,7 +120,23 @@ const LivenessDetectionScreen = () => {
95
120
  const [instructionList, setInstructionList] = useState([]);
96
121
  const [hasGuideShown, setHasGuideShown] = useState(false);
97
122
  const stoppingRecordingRef = useRef(false); // Track if we're already stopping to prevent multiple calls
98
- const lastVoiceGuidanceMessage = useRef('');
123
+
124
+ // Configure status bar for white background
125
+ useStatusBarWhiteBackground();
126
+
127
+ // Update status bar when guide visibility changes
128
+ useEffect(() => {
129
+ if (hasGuideShown) {
130
+ // Camera view - use light icons
131
+ StatusBar.setBarStyle('light-content', true);
132
+ } else {
133
+ // Guide screen with white background - use dark icons
134
+ StatusBar.setBarStyle('dark-content', true);
135
+ if (Platform.OS === 'android') {
136
+ StatusBar.setBackgroundColor('#ffffff', true);
137
+ }
138
+ }
139
+ }, [hasGuideShown]);
99
140
  useEffect(() => {
100
141
  const il = Object.keys(instructions).filter(instruction => !['START', 'FINISH'].includes(instruction) && (
101
142
  // Look straight and blink is always included
@@ -115,7 +156,6 @@ const LivenessDetectionScreen = () => {
115
156
  processComplete: false,
116
157
  videoPath: ''
117
158
  });
118
- lastVoiceGuidanceMessage.current = '';
119
159
  resetLastMessage();
120
160
  }, [instructions, appContext.currentWorkflowStep?.data?.allowedLivenessInstructionTypes]);
121
161
  const isCommandInProgress = useRef(false);
@@ -176,6 +216,13 @@ const LivenessDetectionScreen = () => {
176
216
  const rightOpen = face.rightEyeOpenProbability ?? 0;
177
217
  return leftOpen >= 0.8 && rightOpen >= 0.8;
178
218
  };
219
+ const areEyesVisible = face => {
220
+ // Relaxed check: eyes just need to be detected (not fully closed).
221
+ // Smiling naturally causes squinting, so a lower threshold is used.
222
+ const leftOpen = face.leftEyeOpenProbability ?? 0;
223
+ const rightOpen = face.rightEyeOpenProbability ?? 0;
224
+ return leftOpen >= 0.3 && rightOpen >= 0.3;
225
+ };
179
226
  const instructionReducer = (state, action) => {
180
227
  switch (action.type) {
181
228
  case 'RESET':
@@ -251,7 +298,6 @@ const LivenessDetectionScreen = () => {
251
298
  const nextInstruction = state.instructionList[nextInstructionIndex];
252
299
 
253
300
  // Reset TTS state when moving to any new instruction to ensure it speaks
254
- lastVoiceGuidanceMessage.current = '';
255
301
  resetLastMessage();
256
302
 
257
303
  // Calculate progress based on actual action steps (excluding START and FINISH)
@@ -295,8 +341,7 @@ const LivenessDetectionScreen = () => {
295
341
  // Let the instruction advance first, then speak the next instruction
296
342
 
297
343
  // Only speak if message changed and is not empty
298
- if (text && text !== lastVoiceGuidanceMessage.current) {
299
- lastVoiceGuidanceMessage.current = text;
344
+ if (text) {
300
345
  // Bypass interval for liveness instructions to ensure all instructions are spoken
301
346
  speak(text, true);
302
347
  }
@@ -369,25 +414,33 @@ const LivenessDetectionScreen = () => {
369
414
  });
370
415
  }
371
416
 
372
- // Calculate preview rect in frame coordinates (not screen coordinates)
373
- // Preview circle is 80% of frame width, centered
374
- const previewSizeInFrame = frameWidth * 0.8;
417
+ // Map the on-screen circle into frame coordinates.
418
+ // Camera uses FILL_CENTER / resizeAspectFill (cover): uniform scale filling
419
+ // the view, cropping overflow symmetrically.
420
+ const coverScale = Math.max(windowWidth / frameWidth, windowHeight / frameHeight);
421
+ const offsetX = (frameWidth - windowWidth / coverScale) / 2;
422
+ const offsetY = (frameHeight - windowHeight / coverScale) / 2;
375
423
  const previewRectInFrame = {
376
- minX: (frameWidth - previewSizeInFrame) / 2,
377
- minY: (frameHeight - previewSizeInFrame) / 2,
378
- width: previewSizeInFrame,
379
- height: previewSizeInFrame
380
- };
381
- const faceRectSmaller = {
382
- width: face.bounds.width - PREVIEW_EDGE_OFFSET,
383
- height: face.bounds.height - PREVIEW_EDGE_OFFSET,
384
- minY: face.bounds.y + PREVIEW_EDGE_OFFSET / 2,
385
- minX: face.bounds.x + PREVIEW_EDGE_OFFSET / 2
424
+ minX: PREVIEW_RECT.minX / coverScale + offsetX,
425
+ minY: PREVIEW_RECT.minY / coverScale + offsetY,
426
+ width: PREVIEW_RECT.width / coverScale,
427
+ height: PREVIEW_RECT.height / coverScale
386
428
  };
387
- const previewContainsFace = contains({
388
- outside: previewRectInFrame,
389
- inside: faceRectSmaller
390
- });
429
+ const previewSizeInFrame = PREVIEW_RECT.width / coverScale;
430
+
431
+ // Check containment using face center + yaw-stable core radius.
432
+ // When the head turns (yaw), the bounding box grows wider but height stays
433
+ // constant — so min(width, height)/2 gives a stable size that doesn't
434
+ // falsely trigger an outside-circle reset during TURN_HEAD_LEFT/RIGHT.
435
+ const faceCenterX = face.bounds.x + face.bounds.width / 2;
436
+ const faceCenterY = face.bounds.y + face.bounds.height / 2;
437
+ const faceCoreRadius = Math.max(0, Math.min(face.bounds.width, face.bounds.height) / 2 - PREVIEW_EDGE_OFFSET / 2);
438
+ const circleCX = previewRectInFrame.minX + previewRectInFrame.width / 2;
439
+ const circleCY = previewRectInFrame.minY + previewRectInFrame.height / 2;
440
+ const circleR = previewSizeInFrame / 2;
441
+ const faceDx = faceCenterX - circleCX;
442
+ const faceDy = faceCenterY - circleCY;
443
+ const previewContainsFace = faceDx * faceDx + faceDy * faceDy <= (circleR - faceCoreRadius) * (circleR - faceCoreRadius);
391
444
  const multipleFacesDetected = faces.length > 1;
392
445
  if (!isImageBright) {
393
446
  // Brightness too low - reset progress if we've started the flow
@@ -547,8 +600,9 @@ const LivenessDetectionScreen = () => {
547
600
  // Ensure user is looking at camera (face direction check)
548
601
  const isFacingCamera = instructions.SMILE.minAngle < face.yawAngle && face.yawAngle < instructions.SMILE.maxAngle && instructions.SMILE.minAngle < face.pitchAngle && face.pitchAngle < instructions.SMILE.maxAngle;
549
602
 
550
- // Check if smiling with sufficient probability AND looking at camera AND eyes open
551
- if (smilingProb >= instructions.SMILE.minProbability && isFacingCamera && areEyesOpen(face)) {
603
+ // Check if smiling with sufficient probability AND looking at camera AND eyes visible
604
+ // Use relaxed eye check smiling naturally causes squinting
605
+ if (smilingProb >= instructions.SMILE.minProbability && isFacingCamera && areEyesVisible(face)) {
552
606
  instructions.SMILE.photo = image;
553
607
  dispatch({
554
608
  type: 'NEXT_INSTRUCTION',
@@ -652,6 +706,9 @@ const LivenessDetectionScreen = () => {
652
706
  // eslint-disable-next-line react-hooks/exhaustive-deps
653
707
  }, []); // Empty array = only run on mount/unmount
654
708
 
709
+ if (!appContext.currentWorkflowStep || !appContext.currentWorkflowStep.data) {
710
+ return null;
711
+ }
655
712
  return /*#__PURE__*/_jsxs(_Fragment, {
656
713
  children: [hasGuideShown ? /*#__PURE__*/_jsxs(_Fragment, {
657
714
  children: [/*#__PURE__*/_jsx(FaceCamera, {
@@ -691,6 +748,21 @@ const LivenessDetectionScreen = () => {
691
748
  fill: "white",
692
749
  mask: "url(#hole-mask)"
693
750
  })]
751
+ }), isRecording && /*#__PURE__*/_jsx(View, {
752
+ style: [styles.recordingIndicatorContainer, {
753
+ top: PREVIEW_RECT.minY - 40
754
+ }],
755
+ children: /*#__PURE__*/_jsxs(View, {
756
+ style: styles.recordingIndicator,
757
+ children: [/*#__PURE__*/_jsx(Animated.View, {
758
+ style: [styles.recordingDot, {
759
+ opacity: recordingDotOpacity
760
+ }]
761
+ }), /*#__PURE__*/_jsx(Text, {
762
+ style: styles.recordingText,
763
+ children: "REC"
764
+ })]
765
+ })
694
766
  }), /*#__PURE__*/_jsx(View, {
695
767
  style: [styles.instructionsContainerBottom, {
696
768
  top: PREVIEW_RECT.minY + PREVIEW_SIZE + 20
@@ -816,6 +888,33 @@ const styles = StyleSheet.create({
816
888
  width: '100%',
817
889
  zIndex: 1
818
890
  },
891
+ recordingIndicatorContainer: {
892
+ position: 'absolute',
893
+ width: '100%',
894
+ alignItems: 'center',
895
+ zIndex: 2
896
+ },
897
+ recordingIndicator: {
898
+ flexDirection: 'row',
899
+ alignItems: 'center',
900
+ gap: 8,
901
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
902
+ paddingVertical: 6,
903
+ paddingHorizontal: 14,
904
+ borderRadius: 20
905
+ },
906
+ recordingDot: {
907
+ width: 10,
908
+ height: 10,
909
+ borderRadius: 5,
910
+ backgroundColor: '#ef4444'
911
+ },
912
+ recordingText: {
913
+ color: '#ffffff',
914
+ fontSize: 14,
915
+ fontWeight: '700',
916
+ letterSpacing: 1
917
+ },
819
918
  guide: {
820
919
  flex: 1,
821
920
  display: 'flex',