@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.
Files changed (156) 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 +59 -1
  3. package/ios/Camera/TrustchexCameraView.swift +9 -1
  4. package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
  5. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
  6. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
  7. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +102 -23
  8. package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
  9. package/lib/module/Screens/Dynamic/VideoCallScreen.js +3 -1
  10. package/lib/module/Screens/Static/ResultScreen.js +128 -22
  11. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
  12. package/lib/module/Shared/Animations/recording.json +1 -0
  13. package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
  14. package/lib/module/Shared/Components/EIDScanner.js +212 -108
  15. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
  16. package/lib/module/Shared/Components/IdentityDocumentCamera.js +53 -36
  17. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
  18. package/lib/module/Shared/Components/NavigationManager.js +24 -16
  19. package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
  20. package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
  21. package/lib/module/Shared/EIDReader/bacKey.js +16 -2
  22. package/lib/module/Shared/EIDReader/eidReader.js +354 -13
  23. package/lib/module/Shared/EIDReader/eidService.js +25 -1
  24. package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
  25. package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
  26. package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
  27. package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
  28. package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
  29. package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
  30. package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
  31. package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
  32. package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
  33. package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
  34. package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
  35. package/lib/module/Shared/Libs/analytics.utils.js +4 -0
  36. package/lib/module/Shared/Libs/contains.js +1 -40
  37. package/lib/module/Shared/Libs/country-display.utils.js +34 -0
  38. package/lib/module/Shared/Libs/demo.utils.js +8 -0
  39. package/lib/module/Shared/Libs/mrz.utils.js +3 -2
  40. package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
  41. package/lib/module/Shared/Types/analytics.types.js +2 -0
  42. package/lib/module/Translation/Resources/en.js +41 -2
  43. package/lib/module/Translation/Resources/tr.js +41 -2
  44. package/lib/module/Trustchex.js +54 -20
  45. package/lib/module/version.js +1 -1
  46. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
  47. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
  48. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  49. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  50. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  51. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
  52. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
  53. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
  54. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  55. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  56. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  57. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  58. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  59. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
  60. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
  61. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
  62. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  63. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  64. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
  65. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
  66. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
  67. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
  68. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
  69. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
  70. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  71. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
  72. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
  73. package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
  74. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
  75. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
  76. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
  77. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
  78. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
  79. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
  80. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
  81. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
  82. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
  83. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
  84. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
  85. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
  86. package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
  87. package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
  88. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
  89. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
  90. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  91. package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
  92. package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
  93. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
  94. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
  95. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  96. package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
  97. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  98. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  99. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
  100. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
  101. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  102. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
  103. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  104. package/lib/typescript/src/Translation/Resources/en.d.ts +40 -1
  105. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  106. package/lib/typescript/src/Translation/Resources/tr.d.ts +40 -1
  107. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  108. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  109. package/lib/typescript/src/version.d.ts +1 -1
  110. package/package.json +7 -4
  111. package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
  112. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
  113. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
  114. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +124 -23
  115. package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
  116. package/src/Screens/Dynamic/VideoCallScreen.tsx +3 -1
  117. package/src/Screens/Static/ResultScreen.tsx +183 -31
  118. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
  119. package/src/Shared/Animations/recording.json +1 -0
  120. package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
  121. package/src/Shared/Components/EIDScanner.tsx +222 -111
  122. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
  123. package/src/Shared/Components/IdentityDocumentCamera.tsx +199 -184
  124. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
  125. package/src/Shared/Components/NavigationManager.tsx +27 -18
  126. package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
  127. package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
  128. package/src/Shared/EIDReader/bacKey.ts +24 -8
  129. package/src/Shared/EIDReader/eidReader.ts +398 -12
  130. package/src/Shared/EIDReader/eidService.ts +49 -1
  131. package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
  132. package/src/Shared/EIDReader/paceInfo.ts +159 -0
  133. package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
  134. package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
  135. package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
  136. package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
  137. package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
  138. package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
  139. package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
  140. package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
  141. package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
  142. package/src/Shared/Libs/analytics.utils.ts +4 -0
  143. package/src/Shared/Libs/contains.ts +0 -53
  144. package/src/Shared/Libs/country-display.utils.ts +55 -0
  145. package/src/Shared/Libs/crypto.utils.ts +2 -2
  146. package/src/Shared/Libs/demo.utils.ts +10 -0
  147. package/src/Shared/Libs/http-client.ts +12 -4
  148. package/src/Shared/Libs/mrz.utils.ts +3 -2
  149. package/src/Shared/Libs/status-bar.utils.ts +4 -2
  150. package/src/Shared/Services/VideoSessionService.ts +1 -1
  151. package/src/Shared/Types/analytics.types.ts +2 -0
  152. package/src/Shared/Types/identificationInfo.ts +11 -0
  153. package/src/Translation/Resources/en.ts +63 -3
  154. package/src/Translation/Resources/tr.ts +62 -3
  155. package/src/Trustchex.tsx +53 -17
  156. package/src/version.ts +1 -1
@@ -10,16 +10,22 @@ import {
10
10
  } from 'react-native';
11
11
  import { useNavigation } from '@react-navigation/native';
12
12
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
13
+ import { useTranslation } from 'react-i18next';
13
14
  import AppContext from '../Contexts/AppContext';
14
15
  import { getSimulatedDemoData } from '../Libs/demo.utils';
15
16
  import type { VerificationSession } from '../Types/verificationSession';
16
17
 
17
18
  const DEV_BASE_URL = 'https://192.168.0.171:3000';
19
+ const DEBUG_VERBAL_CONSENT_TITLE_EN = 'Verbal Consent';
20
+ const DEBUG_VERBAL_CONSENT_TITLE_TR = 'Sözlü Onay';
21
+ const DEBUG_VERBAL_CONSENT_TEXT_EN =
22
+ 'I confirm my identity and give my explicit consent to the processing of my personal data for digital identity verification. I acknowledge that my biometric data will be used solely for this purpose. I understand that I can withdraw this consent at any time.';
23
+ const DEBUG_VERBAL_CONSENT_TEXT_TR =
24
+ 'Dijital kimlik doğrulama amacıyla kimliğimi teyit ediyor ve kişisel verilerimin işlenmesine açık rızamı veriyorum. Biyometrik verilerimin yalnızca kimlik doğrulama amacıyla işleneceğini kabul ediyorum. Bu onayı istediğim zaman geri çekebileceğimi biliyorum.';
18
25
 
19
26
  type ScreenOption = {
20
27
  screen: string;
21
28
  label: string;
22
- icon: string;
23
29
  isDebug?: boolean;
24
30
  hasOptions?: boolean;
25
31
  hasDocumentTypeOption?: boolean;
@@ -27,18 +33,6 @@ type ScreenOption = {
27
33
  params?: Record<string, unknown>;
28
34
  };
29
35
 
30
- // Icon mapping matching Flutter SDK Material Icons
31
- const ICONS = {
32
- LOGIN: '�', // Icons.login - Locked with key for session security
33
- HANDSHAKE: '📝', // Icons.handshake - Document for contract signing
34
- CREDIT_CARD: '🪪', // Icons.credit_card - ID card for document scan
35
- NFC: '💳', // Icons.nfc - Contactless card for eID
36
- FACE: '📸', // Icons.face - Camera for face detection
37
- CHECK_CIRCLE: '📋', // Icons.check_circle - Clipboard for results
38
- BUG_REPORT: '🔧', // Icons.bug_report - Wrench for debugging
39
- PHONE: '💬', // Icons.phone - Message for OTP code
40
- } as const;
41
-
42
36
  const DebugNavigationPanel = () => {
43
37
  const [isExpanded, setIsExpanded] = useState(false);
44
38
  const [selectedScreen, setSelectedScreen] = useState<ScreenOption | null>(
@@ -52,6 +46,8 @@ const DebugNavigationPanel = () => {
52
46
  const navigation = useNavigation();
53
47
  const appContext = useContext(AppContext);
54
48
  const insets = useSafeAreaInsets();
49
+ const { i18n } = useTranslation();
50
+ const isTurkish = (i18n.language || '').toLowerCase().startsWith('tr');
55
51
 
56
52
  const setupDemoSession = useCallback(
57
53
  (setDebugFlag: boolean = false) => {
@@ -114,12 +110,10 @@ const DebugNavigationPanel = () => {
114
110
  {
115
111
  screen: 'VerificationSessionCheckScreen',
116
112
  label: 'Session Check',
117
- icon: ICONS.LOGIN,
118
113
  },
119
114
  {
120
115
  screen: 'OTPVerificationScreen',
121
116
  label: 'OTP',
122
- icon: ICONS.PHONE,
123
117
  setupDemo: () => {
124
118
  setupDemoSession(true);
125
119
  },
@@ -128,7 +122,6 @@ const DebugNavigationPanel = () => {
128
122
  {
129
123
  screen: 'ContractAcceptanceScreen',
130
124
  label: 'Consent',
131
- icon: ICONS.HANDSHAKE,
132
125
  hasOptions: true,
133
126
  setupDemo: () => {
134
127
  setupDemoSession(true);
@@ -141,10 +134,55 @@ const DebugNavigationPanel = () => {
141
134
  }
142
135
  },
143
136
  },
137
+ {
138
+ screen: 'VerbalConsentScreen',
139
+ label: 'Verbal Consent',
140
+ hasOptions: true,
141
+ setupDemo: () => {
142
+ setupDemoSession(true);
143
+ const existingStep = appContext.workflowSteps?.find(
144
+ (s) => s.type === 'VERBAL_CONSENT'
145
+ );
146
+
147
+ const localizedConsentTitle = isTurkish
148
+ ? DEBUG_VERBAL_CONSENT_TITLE_TR
149
+ : DEBUG_VERBAL_CONSENT_TITLE_EN;
150
+ const localizedConsentText = isTurkish
151
+ ? DEBUG_VERBAL_CONSENT_TEXT_TR
152
+ : DEBUG_VERBAL_CONSENT_TEXT_EN;
153
+
154
+ const localizedStep = existingStep
155
+ ? {
156
+ ...existingStep,
157
+ data: {
158
+ ...existingStep.data,
159
+ verbalConsentTitle: localizedConsentTitle,
160
+ verbalConsentText: localizedConsentText,
161
+ voiceGuidanceActive: false,
162
+ },
163
+ }
164
+ : {
165
+ type: 'VERBAL_CONSENT' as const,
166
+ required: true,
167
+ data: {
168
+ verbalConsentTitle: localizedConsentTitle,
169
+ verbalConsentText: localizedConsentText,
170
+ voiceGuidanceActive: false,
171
+ },
172
+ };
173
+
174
+ if (appContext.workflowSteps) {
175
+ appContext.workflowSteps = appContext.workflowSteps.map((step) =>
176
+ step.type === 'VERBAL_CONSENT' ? localizedStep : step
177
+ );
178
+ }
179
+
180
+ appContext.currentWorkflowStep = localizedStep;
181
+ },
182
+ },
144
183
  {
145
184
  screen: 'IdentityDocumentScanningScreen',
146
185
  label: 'ID Scan',
147
- icon: ICONS.CREDIT_CARD,
148
186
  hasOptions: true,
149
187
  hasDocumentTypeOption: true,
150
188
  setupDemo: () => {
@@ -160,7 +198,6 @@ const DebugNavigationPanel = () => {
160
198
  {
161
199
  screen: 'IdentityDocumentEIDScanningScreen',
162
200
  label: 'eID Scan',
163
- icon: ICONS.NFC,
164
201
  hasOptions: true,
165
202
  hasDocumentTypeOption: true,
166
203
  setupDemo: () => {
@@ -176,7 +213,6 @@ const DebugNavigationPanel = () => {
176
213
  {
177
214
  screen: 'LivenessDetectionScreen',
178
215
  label: 'Liveness',
179
- icon: ICONS.FACE,
180
216
  hasOptions: true,
181
217
  setupDemo: () => {
182
218
  setupDemoSession(true);
@@ -191,7 +227,6 @@ const DebugNavigationPanel = () => {
191
227
  {
192
228
  screen: 'ResultScreen',
193
229
  label: 'Result',
194
- icon: ICONS.CHECK_CIRCLE,
195
230
  setupDemo: () => {
196
231
  setupDemoSession();
197
232
  },
@@ -199,13 +234,16 @@ const DebugNavigationPanel = () => {
199
234
  {
200
235
  screen: 'MRZTestScreen',
201
236
  label: 'MRZ Test',
202
- icon: ICONS.BUG_REPORT,
203
237
  isDebug: true,
204
238
  },
205
239
  {
206
240
  screen: 'BarcodeTestScreen',
207
241
  label: 'Barcode Test',
208
- icon: ICONS.BUG_REPORT,
242
+ isDebug: true,
243
+ },
244
+ {
245
+ screen: 'NFCScanTestScreen',
246
+ label: 'NFC Scan Test',
209
247
  isDebug: true,
210
248
  },
211
249
  ];
@@ -215,6 +253,7 @@ const DebugNavigationPanel = () => {
215
253
  if (!screen.hasOptions) {
216
254
  if (screen.setupDemo) {
217
255
  screen.setupDemo();
256
+ applyVoiceGuidance(voiceGuidanceEnabled);
218
257
  }
219
258
  (navigation as any).navigate(screen.screen, screen.params);
220
259
  setIsExpanded(false);
@@ -225,7 +264,7 @@ const DebugNavigationPanel = () => {
225
264
  setAllowIdCard(true);
226
265
  setAllowPassport(true);
227
266
  },
228
- [navigation]
267
+ [navigation, voiceGuidanceEnabled, applyVoiceGuidance]
229
268
  );
230
269
 
231
270
  const handleVideoCallTest = useCallback(async () => {
@@ -336,11 +375,9 @@ const DebugNavigationPanel = () => {
336
375
  <Text style={styles.title}>SDK JUMP TO SCREEN:</Text>
337
376
  {selectedScreen ? (
338
377
  <View>
339
- <Text style={styles.optionsTitle}>
340
- {selectedScreen.icon} {selectedScreen.label}
341
- </Text>
378
+ <Text style={styles.optionsTitle}>{selectedScreen.label}</Text>
342
379
  <View style={styles.optionRow}>
343
- <Text style={styles.optionLabel}>🔊 Voice Guidance</Text>
380
+ <Text style={styles.optionLabel}>Voice Guidance</Text>
344
381
  <Switch
345
382
  value={voiceGuidanceEnabled}
346
383
  onValueChange={setVoiceGuidanceEnabled}
@@ -351,7 +388,7 @@ const DebugNavigationPanel = () => {
351
388
  {selectedScreen.hasDocumentTypeOption && (
352
389
  <>
353
390
  <View style={styles.optionRow}>
354
- <Text style={styles.optionLabel}>🪪 Allow ID Card</Text>
391
+ <Text style={styles.optionLabel}>Allow ID Card</Text>
355
392
  <Switch
356
393
  value={allowIdCard}
357
394
  onValueChange={setAllowIdCard}
@@ -360,7 +397,7 @@ const DebugNavigationPanel = () => {
360
397
  />
361
398
  </View>
362
399
  <View style={styles.optionRow}>
363
- <Text style={styles.optionLabel}>🛂 Allow Passport</Text>
400
+ <Text style={styles.optionLabel}>Allow Passport</Text>
364
401
  <Switch
365
402
  value={allowPassport}
366
403
  onValueChange={setAllowPassport}
@@ -416,7 +453,6 @@ const DebugNavigationPanel = () => {
416
453
  style={styles.screenButton}
417
454
  onPress={() => selectScreen(screen)}
418
455
  >
419
- <Text style={styles.screenIcon}>{screen.icon}</Text>
420
456
  <Text style={styles.screenLabel}>{screen.label}</Text>
421
457
  </TouchableOpacity>
422
458
  ))}
@@ -433,7 +469,6 @@ const DebugNavigationPanel = () => {
433
469
  style={styles.debugScreenButton}
434
470
  onPress={() => selectScreen(screen)}
435
471
  >
436
- <Text style={styles.screenIcon}>{screen.icon}</Text>
437
472
  <Text style={styles.debugScreenLabel}>{screen.label}</Text>
438
473
  </TouchableOpacity>
439
474
  ))}
@@ -445,10 +480,8 @@ const DebugNavigationPanel = () => {
445
480
  onPress={handleVideoCallTest}
446
481
  disabled={isConnectingVideoCall}
447
482
  >
448
- {isConnectingVideoCall ? (
483
+ {isConnectingVideoCall && (
449
484
  <ActivityIndicator size="small" color="#4CAF50" />
450
- ) : (
451
- <Text style={styles.screenIcon}>📹</Text>
452
485
  )}
453
486
  <Text style={styles.videoCallTestLabel}>
454
487
  {isConnectingVideoCall ? 'Connecting...' : 'Video Call Test'}
@@ -471,14 +504,12 @@ const DebugNavigationPanel = () => {
471
504
  setAllowPassport(true);
472
505
  }}
473
506
  >
474
- <Text style={styles.bugIcon}>{ICONS.BUG_REPORT}</Text>
475
507
  {isExpanded && (
476
508
  <>
477
- <View style={styles.spacing} />
478
509
  <Text style={styles.toggleText}>DEBUG NAV</Text>
510
+ <View style={styles.spacing} />
479
511
  </>
480
512
  )}
481
- <View style={styles.spacing} />
482
513
  <Text style={styles.arrow}>{isExpanded ? '▼' : '▲'}</Text>
483
514
  </TouchableOpacity>
484
515
  </View>
@@ -496,9 +527,9 @@ const styles = StyleSheet.create({
496
527
  flexDirection: 'row',
497
528
  alignItems: 'center',
498
529
  backgroundColor: '#FF5252',
499
- paddingHorizontal: 12,
530
+ paddingHorizontal: 10,
500
531
  paddingVertical: 10,
501
- borderRadius: 10,
532
+ borderRadius: 8,
502
533
  borderWidth: 2,
503
534
  borderColor: 'white',
504
535
  ...Platform.select({
@@ -513,9 +544,6 @@ const styles = StyleSheet.create({
513
544
  },
514
545
  }),
515
546
  },
516
- bugIcon: {
517
- fontSize: 24,
518
- },
519
547
  spacing: {
520
548
  width: 8,
521
549
  },
@@ -527,6 +555,9 @@ const styles = StyleSheet.create({
527
555
  arrow: {
528
556
  color: 'white',
529
557
  fontSize: 20,
558
+ lineHeight: 20,
559
+ textAlignVertical: 'center',
560
+ includeFontPadding: false,
530
561
  },
531
562
  panel: {
532
563
  backgroundColor: 'rgba(0, 0, 0, 0.9)',
@@ -566,12 +597,6 @@ const styles = StyleSheet.create({
566
597
  borderRadius: 4,
567
598
  marginBottom: 6,
568
599
  },
569
- screenIcon: {
570
- fontSize: 16,
571
- marginRight: 8,
572
- width: 20,
573
- textAlign: 'center',
574
- },
575
600
  screenLabel: {
576
601
  color: 'white',
577
602
  fontSize: 12,
@@ -11,6 +11,7 @@ import { useTranslation } from 'react-i18next';
11
11
  import AppContext from '../Contexts/AppContext';
12
12
  import StyledButton from './StyledButton';
13
13
  import LottieView from 'lottie-react-native';
14
+ import { getLocalizedCountryName } from '../Libs/country-display.utils';
14
15
  import { useKeepAwake } from '../Libs/native-keep-awake.utils';
15
16
  import { speak, resetLastMessage } from '../Libs/tts.utils';
16
17
  import {
@@ -87,8 +88,46 @@ const EIDScanner = ({
87
88
  }, []);
88
89
  const [isScanned, setIsScanned] = React.useState(false);
89
90
  const [hasGuideShown, setHasGuideShown] = React.useState(false);
90
- const { t } = useTranslation();
91
+ const { t, i18n } = useTranslation();
91
92
  const appContext = React.useContext(AppContext);
93
+
94
+ const formatGender = useCallback(
95
+ (code?: string | null) => {
96
+ switch (code?.toUpperCase()) {
97
+ case 'M':
98
+ return t('eidScannerScreen.genderMale', 'Male');
99
+ case 'F':
100
+ return t('eidScannerScreen.genderFemale', 'Female');
101
+ default:
102
+ return t('eidScannerScreen.genderUnspecified', 'Unspecified');
103
+ }
104
+ },
105
+ [t]
106
+ );
107
+
108
+ const formatDocumentType = useCallback(
109
+ (code?: string | null) => {
110
+ if (!code) return '';
111
+ const upper = code.toUpperCase();
112
+ if (upper.startsWith('P'))
113
+ return t('eidScannerScreen.docTypePassport', 'Passport');
114
+ if (upper.startsWith('I'))
115
+ return t('eidScannerScreen.docTypeID', 'ID Card');
116
+ if (upper.startsWith('A'))
117
+ return t('eidScannerScreen.docTypeResidence', 'Residence Permit');
118
+ if (upper.startsWith('V'))
119
+ return t('eidScannerScreen.docTypeVisa', 'Visa');
120
+ return code;
121
+ },
122
+ [t]
123
+ );
124
+
125
+ const formatNationality = useCallback(
126
+ (code?: string | null) => {
127
+ return getLocalizedCountryName(code, i18n.language);
128
+ },
129
+ [i18n.language]
130
+ );
92
131
  const [voiceGuidanceMessage, setVoiceGuidanceMessage] = useState<string>();
93
132
  const [attemptNumber, setAttemptNumber] = useState<number>(0);
94
133
 
@@ -434,106 +473,118 @@ const EIDScanner = ({
434
473
  </View>
435
474
  ) : (
436
475
  <>
437
- {isScanned &&
438
- documentFaceImage &&
439
- documentFaceImageMimeType === 'image/jpeg' && (
440
- <Image
441
- source={{
442
- uri: `data:${documentFaceImageMimeType};base64,${documentFaceImage}`,
443
- }}
444
- style={styles.faceImage}
445
- />
446
- )}
447
-
448
- {isScanned &&
449
- documentFaceImage &&
450
- // TODO Add support for jp2 images
451
- documentFaceImageMimeType === 'image/jp2' && (
452
- <Text style={styles.mainText}>
453
- {t('eidScannerScreen.imageCannotBeShown')}
454
- </Text>
455
- )}
456
-
457
- {isScanned && !documentFaceImage && (
458
- <Text style={styles.mainText}>
459
- {t('eidScannerScreen.faceImageNotFound')}
460
- </Text>
461
- )}
462
-
463
- {isScanned && documentMRZInfo && (
464
- <View style={styles.mrzInfo}>
465
- <View style={styles.mrzInfoItem}>
466
- <Text style={styles.mrzInfoLabel}>
467
- {t('eidScannerScreen.documentCode')}:
468
- </Text>
469
- <Text style={styles.mrzInfoText}>
470
- {documentMRZInfo.getDocumentCode()}
471
- </Text>
472
- </View>
473
- <View style={styles.mrzInfoItem}>
474
- <Text style={styles.mrzInfoLabel}>
475
- {t('eidScannerScreen.nationality')}:
476
- </Text>
477
- <Text style={styles.mrzInfoText}>
478
- {documentMRZInfo.getNationality()}
479
- </Text>
480
- </View>
481
- <View style={styles.mrzInfoItem}>
482
- <Text style={styles.mrzInfoLabel}>
483
- {t('eidScannerScreen.personalNumber')}:
484
- </Text>
485
- <Text style={styles.mrzInfoText}>
486
- {documentMRZInfo.getOptionalData1()}
487
- </Text>
488
- </View>
489
- <View style={styles.mrzInfoItem}>
490
- <Text style={styles.mrzInfoLabel}>
491
- {t('eidScannerScreen.documentNumber')}:
492
- </Text>
493
- <Text style={styles.mrzInfoText}>
494
- {documentMRZInfo.getDocumentNumber()}
495
- </Text>
496
- </View>
497
- <View style={styles.mrzInfoItem}>
498
- <Text style={styles.mrzInfoLabel}>
499
- {t('eidScannerScreen.name')}:
500
- </Text>
501
- <Text style={styles.mrzInfoText}>
502
- {documentMRZInfo.getSecondaryIdentifier()}
503
- </Text>
504
- </View>
505
- <View style={styles.mrzInfoItem}>
506
- <Text style={styles.mrzInfoLabel}>
507
- {t('eidScannerScreen.surname')}:
508
- </Text>
509
- <Text style={styles.mrzInfoText}>
510
- {documentMRZInfo.getPrimaryIdentifier()}
511
- </Text>
512
- </View>
513
- <View style={styles.mrzInfoItem}>
514
- <Text style={styles.mrzInfoLabel}>
515
- {t('eidScannerScreen.birthDate')}:
516
- </Text>
517
- <Text style={styles.mrzInfoText}>
518
- {formatDate(documentMRZInfo.getDateOfBirth())}
519
- </Text>
520
- </View>
521
- <View style={styles.mrzInfoItem}>
522
- <Text style={styles.mrzInfoLabel}>
523
- {t('eidScannerScreen.gender')}:
524
- </Text>
525
- <Text style={styles.mrzInfoText}>
526
- {documentMRZInfo.getGender().getStrCode()}
527
- </Text>
528
- </View>
529
- <View style={styles.mrzInfoItem}>
530
- <Text style={styles.mrzInfoLabel}>
531
- {t('eidScannerScreen.expirationDate')}:
532
- </Text>
533
- <Text style={styles.mrzInfoText}>
534
- {formatDate(documentMRZInfo.getDateOfExpiry())}
535
- </Text>
476
+ {isScanned && (
477
+ <View style={styles.resultCard}>
478
+ <View style={styles.resultHeader}>
479
+ {documentFaceImage &&
480
+ (documentFaceImageMimeType === 'image/jpeg' ||
481
+ documentFaceImageMimeType === 'image/png') ? (
482
+ <Image
483
+ source={{
484
+ uri: `data:${documentFaceImageMimeType};base64,${documentFaceImage}`,
485
+ }}
486
+ style={styles.faceImage}
487
+ resizeMode="cover"
488
+ />
489
+ ) : (
490
+ <View style={styles.faceImagePlaceholder}>
491
+ <Text style={styles.faceImagePlaceholderText}>?</Text>
492
+ </View>
493
+ )}
494
+ {documentMRZInfo && (
495
+ <View style={styles.resultHeaderInfo}>
496
+ <Text style={styles.fullName} numberOfLines={2}>
497
+ {documentMRZInfo.getSecondaryIdentifier()}{' '}
498
+ {documentMRZInfo.getPrimaryIdentifier()}
499
+ </Text>
500
+ <Text style={styles.subInfo}>
501
+ {formatNationality(documentMRZInfo.getNationality())} ·{' '}
502
+ {formatDocumentType(documentMRZInfo.getDocumentCode())}
503
+ </Text>
504
+ <Text style={styles.subInfo}>
505
+ {formatGender(documentMRZInfo.getGender().getStrCode())} ·{' '}
506
+ {formatDate(documentMRZInfo.getDateOfBirth())}
507
+ </Text>
508
+ </View>
509
+ )}
536
510
  </View>
511
+
512
+ {documentMRZInfo && (
513
+ <View style={styles.mrzInfo}>
514
+ <View style={styles.mrzInfoItem}>
515
+ <Text style={styles.mrzInfoLabel}>
516
+ {t('eidScannerScreen.name')}
517
+ </Text>
518
+ <Text style={styles.mrzInfoText}>
519
+ {documentMRZInfo.getSecondaryIdentifier()}
520
+ </Text>
521
+ </View>
522
+ <View style={styles.mrzInfoItem}>
523
+ <Text style={styles.mrzInfoLabel}>
524
+ {t('eidScannerScreen.surname')}
525
+ </Text>
526
+ <Text style={styles.mrzInfoText}>
527
+ {documentMRZInfo.getPrimaryIdentifier()}
528
+ </Text>
529
+ </View>
530
+ <View style={styles.mrzInfoItem}>
531
+ <Text style={styles.mrzInfoLabel}>
532
+ {t('eidScannerScreen.documentCode')}
533
+ </Text>
534
+ <Text style={styles.mrzInfoText}>
535
+ {formatDocumentType(documentMRZInfo.getDocumentCode())}
536
+ </Text>
537
+ </View>
538
+ <View style={styles.mrzInfoItem}>
539
+ <Text style={styles.mrzInfoLabel}>
540
+ {t('eidScannerScreen.documentNumber')}
541
+ </Text>
542
+ <Text style={styles.mrzInfoText}>
543
+ {documentMRZInfo.getDocumentNumber()}
544
+ </Text>
545
+ </View>
546
+ <View style={styles.mrzInfoItem}>
547
+ <Text style={styles.mrzInfoLabel}>
548
+ {t('eidScannerScreen.personalNumber')}
549
+ </Text>
550
+ <Text style={styles.mrzInfoText}>
551
+ {documentMRZInfo.getOptionalData1()}
552
+ </Text>
553
+ </View>
554
+ <View style={styles.mrzInfoItem}>
555
+ <Text style={styles.mrzInfoLabel}>
556
+ {t('eidScannerScreen.nationality')}
557
+ </Text>
558
+ <Text style={styles.mrzInfoText}>
559
+ {formatNationality(documentMRZInfo.getNationality())}
560
+ </Text>
561
+ </View>
562
+ <View style={styles.mrzInfoItem}>
563
+ <Text style={styles.mrzInfoLabel}>
564
+ {t('eidScannerScreen.gender')}
565
+ </Text>
566
+ <Text style={styles.mrzInfoText}>
567
+ {formatGender(documentMRZInfo.getGender().getStrCode())}
568
+ </Text>
569
+ </View>
570
+ <View style={styles.mrzInfoItem}>
571
+ <Text style={styles.mrzInfoLabel}>
572
+ {t('eidScannerScreen.birthDate')}
573
+ </Text>
574
+ <Text style={styles.mrzInfoText}>
575
+ {formatDate(documentMRZInfo.getDateOfBirth())}
576
+ </Text>
577
+ </View>
578
+ <View style={styles.mrzInfoItem}>
579
+ <Text style={styles.mrzInfoLabel}>
580
+ {t('eidScannerScreen.expirationDate')}
581
+ </Text>
582
+ <Text style={styles.mrzInfoText}>
583
+ {formatDate(documentMRZInfo.getDateOfExpiry())}
584
+ </Text>
585
+ </View>
586
+ </View>
587
+ )}
537
588
  </View>
538
589
  )}
539
590
 
@@ -589,6 +640,14 @@ const EIDScanner = ({
589
640
  </Text>
590
641
  )))}
591
642
 
643
+ {hasNfc && isEnabled && !isScanning && !isScanned && (
644
+ <View style={styles.buttonsContainer}>
645
+ <StyledButton mode="contained" onPress={readNFC}>
646
+ {t('eidScannerScreen.startScanning')}
647
+ </StyledButton>
648
+ </View>
649
+ )}
650
+
592
651
  {hasNfc && isEnabled && isScanned && (
593
652
  <View style={styles.buttonsContainer}>
594
653
  <StyledButton
@@ -688,31 +747,83 @@ const styles = StyleSheet.create({
688
747
  color: 'black',
689
748
  textAlign: 'center',
690
749
  },
691
- faceImage: {
692
- width: 150,
693
- height: 150,
694
- borderRadius: 150,
695
- borderColor: 'lightgray',
750
+ resultCard: {
751
+ backgroundColor: '#fff',
752
+ borderRadius: 16,
753
+ padding: 16,
754
+ gap: 16,
755
+ shadowColor: '#000',
756
+ shadowOffset: { width: 0, height: 2 },
757
+ shadowOpacity: 0.08,
758
+ shadowRadius: 8,
759
+ elevation: 3,
696
760
  borderWidth: 1,
697
- alignSelf: 'center',
761
+ borderColor: '#f0f0f0',
762
+ },
763
+ resultHeader: {
764
+ flexDirection: 'row',
765
+ gap: 14,
766
+ alignItems: 'flex-start',
767
+ },
768
+ resultHeaderInfo: {
769
+ flex: 1,
770
+ gap: 4,
771
+ justifyContent: 'center',
772
+ },
773
+ fullName: {
774
+ fontSize: 17,
775
+ fontWeight: '700',
776
+ color: '#111',
777
+ letterSpacing: 0.2,
778
+ },
779
+ subInfo: {
780
+ fontSize: 13,
781
+ color: '#666',
782
+ fontWeight: '500',
783
+ },
784
+ faceImage: {
785
+ width: 90,
786
+ height: 115,
787
+ borderRadius: 10,
788
+ overflow: 'hidden',
789
+ },
790
+ faceImagePlaceholder: {
791
+ width: 90,
792
+ height: 115,
793
+ borderRadius: 10,
794
+ backgroundColor: '#f5f5f5',
795
+ alignItems: 'center',
796
+ justifyContent: 'center',
797
+ },
798
+ faceImagePlaceholderText: {
799
+ fontSize: 32,
800
+ color: '#ccc',
698
801
  },
699
802
  mrzInfo: {
700
803
  flexDirection: 'column',
701
804
  width: '100%',
805
+ gap: 2,
702
806
  },
703
807
  mrzInfoItem: {
704
808
  flexDirection: 'row',
705
809
  justifyContent: 'space-between',
706
- borderBottomColor: 'lightgray',
810
+ alignItems: 'center',
811
+ paddingVertical: 8,
812
+ borderBottomColor: '#f0f0f0',
707
813
  borderBottomWidth: 1,
708
- paddingVertical: 5,
709
814
  },
710
815
  mrzInfoLabel: {
711
- color: 'black',
712
- fontWeight: 'bold',
816
+ color: '#888',
817
+ fontSize: 13,
818
+ fontWeight: '500',
713
819
  },
714
820
  mrzInfoText: {
715
- color: 'black',
821
+ color: '#111',
822
+ fontSize: 13,
823
+ fontWeight: '600',
824
+ textAlign: 'right',
825
+ flexShrink: 1,
826
+ marginLeft: 8,
716
827
  },
717
828
  guide: {
718
829
  flex: 1,