@trustchex/react-native-sdk 1.478.7 → 1.483.4

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 (112) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +57 -3
  2. package/ios/Camera/TrustchexCameraView.swift +20 -15
  3. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +0 -3
  4. package/lib/module/Screens/Dynamic/IdentityDocumentScanningScreen.js +21 -0
  5. package/lib/module/Screens/Dynamic/VideoCallScreen.js +1 -1
  6. package/lib/module/Screens/Static/ResultScreen.js +75 -16
  7. package/lib/module/Shared/Components/DiagnosticReportButton.js +64 -0
  8. package/lib/module/Shared/Components/EIDScanner.js +52 -19
  9. package/lib/module/Shared/Components/IdentityDocumentCamera.js +132 -8
  10. package/lib/module/Shared/Components/NavigationManager.js +7 -9
  11. package/lib/module/Shared/Contexts/AppContext.js +3 -0
  12. package/lib/module/Shared/EIDReader/eidReader.js +167 -30
  13. package/lib/module/Shared/EIDReader/lds/icao/dg11File.js +77 -0
  14. package/lib/module/Shared/Libs/MRZ_KNOWN_ISSUES.md +7 -0
  15. package/lib/module/Shared/Libs/diagnosticReport.js +133 -0
  16. package/lib/module/Shared/Libs/diagnostics.js +171 -0
  17. package/lib/module/Shared/Libs/documentDataNormalizer.js +104 -0
  18. package/lib/module/Shared/Libs/mrz.utils.js +0 -5
  19. package/lib/module/Shared/Libs/mrzFrameAggregator.js +32 -5
  20. package/lib/module/Shared/Libs/mrzTransliteration.js +80 -0
  21. package/lib/module/Shared/Libs/native-device-info.utils.js +67 -0
  22. package/lib/module/Shared/Libs/sendDiagnosticReport.js +130 -0
  23. package/lib/module/Shared/Services/DataUploadService.js +6 -3
  24. package/lib/module/Shared/Types/documentData.js +1 -0
  25. package/lib/module/Shared/Types/documentReadResult.js +3 -0
  26. package/lib/module/Translation/Resources/en.js +5 -0
  27. package/lib/module/Translation/Resources/tr.js +5 -0
  28. package/lib/module/Trustchex.js +31 -4
  29. package/lib/module/version.js +1 -1
  30. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  31. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentScanningScreen.d.ts.map +1 -1
  32. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
  33. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  34. package/lib/typescript/src/Shared/Components/DiagnosticReportButton.d.ts +20 -0
  35. package/lib/typescript/src/Shared/Components/DiagnosticReportButton.d.ts.map +1 -0
  36. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  37. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  38. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.types.d.ts +10 -0
  39. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.types.d.ts.map +1 -1
  40. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  41. package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts +10 -0
  42. package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts.map +1 -1
  43. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts +5 -0
  44. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts.map +1 -1
  45. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts +2 -0
  46. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  47. package/lib/typescript/src/Shared/EIDReader/lds/icao/dg11File.d.ts +35 -0
  48. package/lib/typescript/src/Shared/EIDReader/lds/icao/dg11File.d.ts.map +1 -0
  49. package/lib/typescript/src/Shared/Libs/diagnosticReport.d.ts +48 -0
  50. package/lib/typescript/src/Shared/Libs/diagnosticReport.d.ts.map +1 -0
  51. package/lib/typescript/src/Shared/Libs/diagnostics.d.ts +145 -0
  52. package/lib/typescript/src/Shared/Libs/diagnostics.d.ts.map +1 -0
  53. package/lib/typescript/src/Shared/Libs/documentDataNormalizer.d.ts +12 -0
  54. package/lib/typescript/src/Shared/Libs/documentDataNormalizer.d.ts.map +1 -0
  55. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  56. package/lib/typescript/src/Shared/Libs/mrzFrameAggregator.d.ts +33 -0
  57. package/lib/typescript/src/Shared/Libs/mrzFrameAggregator.d.ts.map +1 -1
  58. package/lib/typescript/src/Shared/Libs/mrzTransliteration.d.ts +3 -0
  59. package/lib/typescript/src/Shared/Libs/mrzTransliteration.d.ts.map +1 -0
  60. package/lib/typescript/src/Shared/Libs/native-device-info.utils.d.ts +33 -0
  61. package/lib/typescript/src/Shared/Libs/native-device-info.utils.d.ts.map +1 -1
  62. package/lib/typescript/src/Shared/Libs/sendDiagnosticReport.d.ts +30 -0
  63. package/lib/typescript/src/Shared/Libs/sendDiagnosticReport.d.ts.map +1 -0
  64. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts +3 -2
  65. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts.map +1 -1
  66. package/lib/typescript/src/Shared/Types/documentData.d.ts +44 -0
  67. package/lib/typescript/src/Shared/Types/documentData.d.ts.map +1 -0
  68. package/lib/typescript/src/Shared/Types/documentReadResult.d.ts +44 -0
  69. package/lib/typescript/src/Shared/Types/documentReadResult.d.ts.map +1 -0
  70. package/lib/typescript/src/Shared/Types/mrzFields.d.ts +1 -1
  71. package/lib/typescript/src/Shared/Types/mrzFields.d.ts.map +1 -1
  72. package/lib/typescript/src/Translation/Resources/en.d.ts +5 -0
  73. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  74. package/lib/typescript/src/Translation/Resources/tr.d.ts +5 -0
  75. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  76. package/lib/typescript/src/Trustchex.d.ts +9 -0
  77. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  78. package/lib/typescript/src/index.d.ts +2 -0
  79. package/lib/typescript/src/index.d.ts.map +1 -1
  80. package/lib/typescript/src/version.d.ts +1 -1
  81. package/package.json +5 -1
  82. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +0 -4
  83. package/src/Screens/Dynamic/IdentityDocumentScanningScreen.tsx +23 -0
  84. package/src/Screens/Dynamic/VideoCallScreen.tsx +5 -1
  85. package/src/Screens/Static/ResultScreen.tsx +85 -16
  86. package/src/Shared/Components/DiagnosticReportButton.tsx +77 -0
  87. package/src/Shared/Components/EIDScanner.tsx +67 -18
  88. package/src/Shared/Components/IdentityDocumentCamera.tsx +145 -7
  89. package/src/Shared/Components/IdentityDocumentCamera.types.ts +6 -0
  90. package/src/Shared/Components/NavigationManager.tsx +7 -7
  91. package/src/Shared/Components/TrustchexCamera.tsx +6 -0
  92. package/src/Shared/Contexts/AppContext.ts +8 -0
  93. package/src/Shared/EIDReader/eidReader.ts +193 -47
  94. package/src/Shared/EIDReader/lds/icao/dg11File.ts +94 -0
  95. package/src/Shared/Libs/MRZ_KNOWN_ISSUES.md +7 -0
  96. package/src/Shared/Libs/diagnosticReport.ts +206 -0
  97. package/src/Shared/Libs/diagnostics.ts +251 -0
  98. package/src/Shared/Libs/documentDataNormalizer.ts +108 -0
  99. package/src/Shared/Libs/mrz.utils.ts +0 -5
  100. package/src/Shared/Libs/mrzFrameAggregator.ts +61 -3
  101. package/src/Shared/Libs/mrzTransliteration.ts +131 -0
  102. package/src/Shared/Libs/native-device-info.utils.ts +116 -0
  103. package/src/Shared/Libs/sendDiagnosticReport.ts +165 -0
  104. package/src/Shared/Services/DataUploadService.ts +9 -3
  105. package/src/Shared/Types/documentData.ts +52 -0
  106. package/src/Shared/Types/documentReadResult.ts +47 -0
  107. package/src/Shared/Types/mrzFields.ts +0 -5
  108. package/src/Translation/Resources/en.ts +6 -0
  109. package/src/Translation/Resources/tr.ts +6 -0
  110. package/src/Trustchex.tsx +48 -3
  111. package/src/index.tsx +7 -0
  112. package/src/version.ts +1 -1
@@ -1,6 +1,8 @@
1
1
  import React, { useContext, useEffect, useState } from 'react';
2
2
 
3
3
  import type { MRZFields } from '../../Shared/Types/mrzFields';
4
+ import { buildDocumentName } from '../../Shared/Libs/mrzTransliteration';
5
+ import { normalizeFromMRZFields } from '../../Shared/Libs/documentDataNormalizer';
4
6
  import { Alert, SafeAreaView, StyleSheet, View } from 'react-native';
5
7
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
6
8
  import IdentityDocumentCamera, {
@@ -122,6 +124,27 @@ const IdentityDocumentScanningScreen = () => {
122
124
  true
123
125
  );
124
126
 
127
+ {
128
+ const documentData = normalizeFromMRZFields(mrzFields);
129
+ const faceImg = idFrontSideData?.faceImage || passportData?.faceImage;
130
+ const builtName = buildDocumentName(
131
+ documentData.firstName,
132
+ documentData.lastName,
133
+ documentData.issuingCountry
134
+ );
135
+ const documentReadResult = {
136
+ document: {
137
+ ...documentData,
138
+ firstName: builtName.displayFirst,
139
+ lastName: builtName.displayLast,
140
+ },
141
+ name: builtName,
142
+ face: faceImg ? { data: faceImg, mimeType: 'image/jpeg' } : undefined,
143
+ };
144
+ appContext.setLastDocumentRead?.(documentReadResult);
145
+ appContext.onDocumentRead?.(documentReadResult);
146
+ }
147
+
125
148
  setTimeout(
126
149
  () => navigationManagerRef.current?.navigateToNextStep(),
127
150
  1000
@@ -147,7 +147,11 @@ const VideoCallScreen = ({ navigation }: any) => {
147
147
  const uploadService = new DataUploadService(baseUrl);
148
148
  dataUploadServiceRef.current = uploadService;
149
149
  const uploaded =
150
- await uploadService.uploadCollectedData(identificationInfo);
150
+ await uploadService.uploadCollectedData(
151
+ identificationInfo,
152
+ undefined,
153
+ appContext.lastDocumentRead?.name
154
+ );
151
155
  if (!uploaded) {
152
156
  console.warn('[VideoCallScreen] Upload service returned false');
153
157
  if (mounted) {
@@ -39,7 +39,32 @@ import { Video as VideoCompressor } from 'react-native-compressor';
39
39
  import { encryptWithAes, getSessionKey } from '../../Shared/Libs/crypto.utils';
40
40
  import Video from 'react-native-video';
41
41
  import StyledButton from '../../Shared/Components/StyledButton';
42
+ import DiagnosticReportButton from '../../Shared/Components/DiagnosticReportButton';
43
+ import type { DiagnosticImage } from '../../Shared/Libs/sendDiagnosticReport';
42
44
  import NativeDeviceInfo from '../../Shared/Libs/native-device-info.utils';
45
+
46
+ /**
47
+ * Collect the captured document/face images (base64) as attachments for a
48
+ * diagnostic report. On an ID card the BACK image is the MRZ side; on a passport
49
+ * the front carries the MRZ. The NFC chip face arrives as `faceImage` with its
50
+ * own mime type, which may be png.
51
+ */
52
+ const collectDiagnosticImages = (
53
+ doc?: ScannedIdentityDocument
54
+ ): DiagnosticImage[] => {
55
+ if (!doc) return [];
56
+ const out: DiagnosticImage[] = [];
57
+ const push = (name: string, b64?: string, mime: 'jpg' | 'png' = 'jpg') => {
58
+ if (b64 && b64 !== '') out.push({ name, base64: b64, mime });
59
+ };
60
+ push('mrz-side', doc.backImage);
61
+ push('front', doc.frontImage);
62
+ const faceMime = doc.faceImageMimeType === 'image/png' ? 'png' : 'jpg';
63
+ push('face', doc.faceImage, faceMime);
64
+ push('secondary-face', doc.secondaryFaceImage);
65
+ push('hologram', doc.hologramImage);
66
+ return out;
67
+ };
43
68
  import {
44
69
  trackError,
45
70
  trackFunnelStep,
@@ -234,14 +259,16 @@ const ResultScreen = () => {
234
259
  throw new Error('MRZ fields not found');
235
260
  }
236
261
 
237
- // Backend payload must contain raw MRZ data only.
238
- // Human-friendly formatting is strictly for UI rendering paths.
239
262
  const rawMrzFields = scannedDocument.mrzFields;
263
+ const docName = appContext.lastDocumentRead?.name;
240
264
 
241
265
  const identificationDocument = {
242
266
  type: rawMrzFields.documentCode,
243
267
  name: rawMrzFields.firstName,
244
268
  surname: rawMrzFields.lastName,
269
+ displayName: docName?.source === 'dg11' ? docName.displayFirst : undefined,
270
+ displaySurname: docName?.source === 'dg11' ? docName.displayLast : undefined,
271
+ nameSource: docName?.source === 'dg11' ? docName.source : undefined,
245
272
  gender: getGenderEnumType(rawMrzFields.sex),
246
273
  number: rawMrzFields.documentNumber,
247
274
  country: rawMrzFields.issuingState,
@@ -267,7 +294,7 @@ const ResultScreen = () => {
267
294
  }
268
295
  );
269
296
  },
270
- [apiUrl, getGenderEnumType]
297
+ [apiUrl, appContext.lastDocumentRead, getGenderEnumType]
271
298
  );
272
299
 
273
300
  const uploadIdentificationMedia = useCallback(
@@ -765,23 +792,35 @@ const ResultScreen = () => {
765
792
  <Text style={styles.mrzInfoLabel}>
766
793
  {t('eidScannerScreen.name')}:
767
794
  </Text>
768
- <Text style={styles.mrzInfoText}>
769
- {
770
- appContext.identificationInfo.scannedDocument
771
- .mrzFields?.firstName
772
- }
773
- </Text>
795
+ <View style={styles.mrzInfoValueGroup}>
796
+ <Text style={styles.mrzInfoText}>
797
+ {appContext.lastDocumentRead?.name.source === 'dg11'
798
+ ? appContext.lastDocumentRead.name.displayFirst
799
+ : appContext.identificationInfo.scannedDocument.mrzFields?.firstName}
800
+ </Text>
801
+ {appContext.lastDocumentRead?.name.source === 'dg11' && (
802
+ <Text style={styles.mrzInfoSubText}>
803
+ {appContext.identificationInfo.scannedDocument.mrzFields?.firstName}
804
+ </Text>
805
+ )}
806
+ </View>
774
807
  </View>
775
808
  <View style={styles.mrzInfoItem}>
776
809
  <Text style={styles.mrzInfoLabel}>
777
810
  {t('eidScannerScreen.surname')}:
778
811
  </Text>
779
- <Text style={styles.mrzInfoText}>
780
- {
781
- appContext.identificationInfo.scannedDocument
782
- .mrzFields?.lastName
783
- }
784
- </Text>
812
+ <View style={styles.mrzInfoValueGroup}>
813
+ <Text style={styles.mrzInfoText}>
814
+ {appContext.lastDocumentRead?.name.source === 'dg11'
815
+ ? appContext.lastDocumentRead.name.displayLast
816
+ : appContext.identificationInfo.scannedDocument.mrzFields?.lastName}
817
+ </Text>
818
+ {appContext.lastDocumentRead?.name.source === 'dg11' && (
819
+ <Text style={styles.mrzInfoSubText}>
820
+ {appContext.identificationInfo.scannedDocument.mrzFields?.lastName}
821
+ </Text>
822
+ )}
823
+ </View>
785
824
  </View>
786
825
  <View style={styles.mrzInfoItem}>
787
826
  <Text style={styles.mrzInfoLabel}>
@@ -1045,7 +1084,7 @@ const ResultScreen = () => {
1045
1084
  )}
1046
1085
  </View>
1047
1086
  </ScrollView>
1048
- <View style={{ paddingBottom: insets.bottom }}>
1087
+ <View style={[styles.footer, { paddingBottom: insets.bottom + 20 }]}>
1049
1088
  <StyledButton
1050
1089
  mode="contained"
1051
1090
  onPress={() => {
@@ -1055,6 +1094,26 @@ const ResultScreen = () => {
1055
1094
  >
1056
1095
  {t('resultScreen.demoStartOver')}
1057
1096
  </StyledButton>
1097
+ <DiagnosticReportButton
1098
+ sessionId={appContext.identificationInfo?.sessionId}
1099
+ scan={{
1100
+ documentType:
1101
+ appContext.identificationInfo?.scannedDocument
1102
+ ?.documentType,
1103
+ dataSource:
1104
+ appContext.identificationInfo?.scannedDocument?.dataSource,
1105
+ mrzText:
1106
+ appContext.identificationInfo?.scannedDocument?.mrzText,
1107
+ mrzFields:
1108
+ appContext.identificationInfo?.scannedDocument?.mrzFields,
1109
+ barcodeValue:
1110
+ appContext.identificationInfo?.scannedDocument
1111
+ ?.barcodeValue,
1112
+ }}
1113
+ images={collectDiagnosticImages(
1114
+ appContext.identificationInfo?.scannedDocument
1115
+ )}
1116
+ />
1058
1117
  </View>
1059
1118
  </>
1060
1119
  ) : (
@@ -1182,6 +1241,16 @@ const styles = StyleSheet.create({
1182
1241
  fontSize: 10,
1183
1242
  fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace',
1184
1243
  },
1244
+ mrzInfoValueGroup: {
1245
+ flexDirection: 'column',
1246
+ alignItems: 'flex-end',
1247
+ },
1248
+ mrzInfoSubText: {
1249
+ color: '#aaa',
1250
+ fontSize: 9,
1251
+ fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace',
1252
+ marginTop: 1,
1253
+ },
1185
1254
  mrzTextContainer: {
1186
1255
  padding: 12,
1187
1256
  backgroundColor: '#F3F4F6',
@@ -0,0 +1,77 @@
1
+ import React, { useState } from 'react';
2
+ import { Alert } from 'react-native';
3
+ import { useTranslation } from 'react-i18next';
4
+ import StyledButton from './StyledButton';
5
+ import {
6
+ sendDiagnosticReport,
7
+ isDiagnosticSharingAvailable,
8
+ type DiagnosticImage,
9
+ } from '../Libs/sendDiagnosticReport';
10
+ import type { ScanDataForReport } from '../Libs/diagnosticReport';
11
+ import { SDK_VERSION } from '../../version';
12
+
13
+ export interface DiagnosticReportButtonProps {
14
+ scan: ScanDataForReport;
15
+ sessionId?: string;
16
+ images?: DiagnosticImage[];
17
+ }
18
+
19
+ /**
20
+ * "Report a scanning issue" button for the result screen.
21
+ *
22
+ * Shows a brief notice describing what will be shared (the draft itself is the
23
+ * user's review/consent step), then opens the OS share sheet — the user picks
24
+ * email / WhatsApp / Drive / etc. and sends the diagnostic bundle to support.
25
+ * Self-contained so the result screen only needs to render it with the scan
26
+ * data + captured images.
27
+ */
28
+ const DiagnosticReportButton: React.FC<DiagnosticReportButtonProps> = ({
29
+ scan,
30
+ sessionId,
31
+ images,
32
+ }) => {
33
+ const { t } = useTranslation();
34
+ const [sending, setSending] = useState(false);
35
+
36
+ // `react-native-share` is optional — hide the button entirely when the host
37
+ // app hasn't installed it, so apps that don't want diagnostics see no UI.
38
+ if (!isDiagnosticSharingAvailable()) {
39
+ return null;
40
+ }
41
+
42
+ const onPress = () => {
43
+ if (sending) return;
44
+ // Brief notice — the share draft is the actual review/consent step.
45
+ Alert.alert(
46
+ t('diagnosticReport.noticeTitle'),
47
+ t('diagnosticReport.noticeBody'),
48
+ [
49
+ { text: t('diagnosticReport.cancel'), style: 'cancel' },
50
+ {
51
+ text: t('diagnosticReport.continue'),
52
+ onPress: async () => {
53
+ setSending(true);
54
+ try {
55
+ await sendDiagnosticReport({
56
+ scan,
57
+ sdkVersion: SDK_VERSION,
58
+ sessionId,
59
+ images,
60
+ });
61
+ } finally {
62
+ setSending(false);
63
+ }
64
+ },
65
+ },
66
+ ]
67
+ );
68
+ };
69
+
70
+ return (
71
+ <StyledButton mode="outlined" onPress={onPress} disabled={sending}>
72
+ {t('diagnosticReport.button')}
73
+ </StyledButton>
74
+ );
75
+ };
76
+
77
+ export default DiagnosticReportButton;
@@ -9,6 +9,8 @@ import { MRZInfo } from '../EIDReader/lds/icao/mrzInfo';
9
9
  import { eidReader } from '../EIDReader/eidReader';
10
10
  import NativeProgressBar from './NativeProgressBar';
11
11
  import type { MRZFields } from '../Types/mrzFields';
12
+ import { buildDocumentName } from '../Libs/mrzTransliteration';
13
+ import { normalizeFromMRZInfo } from '../Libs/documentDataNormalizer';
12
14
  import { useTranslation } from 'react-i18next';
13
15
  import AppContext from '../Contexts/AppContext';
14
16
  import StyledButton from './StyledButton';
@@ -52,6 +54,7 @@ const EIDScanner = ({
52
54
  const [documentMRZInfo, setDocumentMRZInfo] = React.useState<MRZInfo>();
53
55
  const [documentFaceImageMimeType, setDocumentFaceImageMimeType] =
54
56
  React.useState<string>();
57
+ const [documentName, setDocumentName] = React.useState<import('../Types/documentReadResult').DocumentName>();
55
58
  const [progress, setProgress] = React.useState(0);
56
59
  const [progressStage, setProgressStage] = React.useState<string>('');
57
60
 
@@ -133,6 +136,21 @@ const EIDScanner = ({
133
136
  const [voiceGuidanceMessage, setVoiceGuidanceMessage] = useState<string>();
134
137
  const [attemptNumber, setAttemptNumber] = useState<number>(0);
135
138
 
139
+ const getFieldsFromMRZ = useCallback((mrz: MRZInfo) => {
140
+ return {
141
+ documentCode: mrz.getDocumentCode(),
142
+ personalNumber: mrz.getPersonalNumber() || mrz.getOptionalData1(),
143
+ documentNumber: mrz.getDocumentNumber(),
144
+ firstName: mrz.getSecondaryIdentifier(),
145
+ lastName: mrz.getPrimaryIdentifier(),
146
+ birthDate: mrz.getDateOfBirth(),
147
+ expirationDate: mrz.getDateOfExpiry(),
148
+ issuingState: mrz.getIssuingState(),
149
+ sex: mrz.getGender().getStrCode(),
150
+ nationality: mrz.getNationality(),
151
+ } satisfies MRZFields;
152
+ }, []);
153
+
136
154
  const readNFC = useCallback(async () => {
137
155
  const startTime = Date.now();
138
156
  const currentAttempt = attemptNumber + 1;
@@ -228,6 +246,32 @@ const EIDScanner = ({
228
246
  setDocumentMRZInfo(passportData.mrz);
229
247
  setDocumentFaceImageMimeType(passportData.mimeType);
230
248
  setIsScanned(true);
249
+
250
+ {
251
+ const documentData = normalizeFromMRZInfo(passportData.mrz);
252
+ const builtName = buildDocumentName(
253
+ documentData.firstName,
254
+ documentData.lastName,
255
+ documentData.issuingCountry,
256
+ passportData.dg11FirstName,
257
+ passportData.dg11LastName
258
+ );
259
+ setDocumentName(builtName);
260
+ const documentReadResult = {
261
+ document: {
262
+ ...documentData,
263
+ firstName: builtName.displayFirst,
264
+ lastName: builtName.displayLast,
265
+ },
266
+ name: builtName,
267
+ face: {
268
+ data: passportData.faceImage,
269
+ mimeType: passportData.mimeType,
270
+ },
271
+ };
272
+ appContext.setLastDocumentRead?.(documentReadResult);
273
+ appContext.onDocumentRead?.(documentReadResult);
274
+ }
231
275
  await trackEIDScanComplete(
232
276
  docType,
233
277
  scanDuration,
@@ -314,23 +358,10 @@ const EIDScanner = ({
314
358
  isEnabled,
315
359
  attemptNumber,
316
360
  t,
361
+ getFieldsFromMRZ,
362
+ appContext,
317
363
  ]);
318
364
 
319
- const getFieldsFromMRZ = useCallback((mrz: MRZInfo) => {
320
- return {
321
- documentCode: mrz.getDocumentCode(),
322
- personalNumber: mrz.getPersonalNumber() || mrz.getOptionalData1(),
323
- documentNumber: mrz.getDocumentNumber(),
324
- firstName: mrz.getSecondaryIdentifier(),
325
- lastName: mrz.getPrimaryIdentifier(),
326
- birthDate: mrz.getDateOfBirth(),
327
- expirationDate: mrz.getDateOfExpiry(),
328
- issuingState: mrz.getIssuingState(),
329
- sex: mrz.getGender().getStrCode(),
330
- nationality: mrz.getNationality(),
331
- } satisfies MRZFields;
332
- }, []);
333
-
334
365
  useEffect(() => {
335
366
  const checkIsSupported = async () => {
336
367
  const deviceIsSupported = await NFCManager.isSupported();
@@ -533,11 +564,13 @@ const EIDScanner = ({
533
564
  <View style={styles.idCardFields}>
534
565
  <IDCardField
535
566
  label={t('eidScannerScreen.surname')}
536
- value={documentMRZInfo.getPrimaryIdentifier()}
567
+ value={documentName?.displayLast ?? documentMRZInfo.getPrimaryIdentifier()}
568
+ subValue={documentName?.source === 'dg11' ? documentMRZInfo.getPrimaryIdentifier() : undefined}
537
569
  />
538
570
  <IDCardField
539
571
  label={t('eidScannerScreen.name')}
540
- value={documentMRZInfo.getSecondaryIdentifier()}
572
+ value={documentName?.displayFirst ?? documentMRZInfo.getSecondaryIdentifier()}
573
+ subValue={documentName?.source === 'dg11' ? documentMRZInfo.getSecondaryIdentifier() : undefined}
541
574
  />
542
575
  <IDCardField
543
576
  label={t('eidScannerScreen.documentNumber')}
@@ -866,6 +899,11 @@ const styles = StyleSheet.create({
866
899
  flexShrink: 1,
867
900
  flexWrap: 'wrap',
868
901
  },
902
+ idCardFieldSubValue: {
903
+ fontSize: 9,
904
+ color: '#aaa',
905
+ marginTop: 1,
906
+ },
869
907
  guide: {
870
908
  flex: 1,
871
909
  display: 'flex',
@@ -896,12 +934,23 @@ const styles = StyleSheet.create({
896
934
  },
897
935
  });
898
936
 
899
- const IDCardField = ({ label, value }: { label: string; value: string }) => (
937
+ const IDCardField = ({
938
+ label,
939
+ value,
940
+ subValue,
941
+ }: {
942
+ label: string;
943
+ value: string;
944
+ subValue?: string;
945
+ }) => (
900
946
  <View style={styles.idCardFieldItem}>
901
947
  <Text style={styles.idCardFieldLabel} numberOfLines={1}>
902
948
  {label}
903
949
  </Text>
904
950
  <Text style={styles.idCardFieldValue}>{value || '—'}</Text>
951
+ {subValue ? (
952
+ <Text style={styles.idCardFieldSubValue}>{subValue}</Text>
953
+ ) : null}
905
954
  </View>
906
955
  );
907
956