@trustchex/react-native-sdk 1.501.0 → 1.502.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/Screens/Dynamic/AddressCaptureScreen.js +36 -28
- package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +8 -5
- package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
- package/lib/module/Shared/Components/QrCodeScannerCamera.js +19 -17
- package/lib/module/Shared/Libs/deeplink.utils.js +22 -2
- package/lib/module/Translation/Resources/en.js +3 -3
- package/lib/module/Translation/Resources/tr.js +3 -3
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Dynamic/AddressCaptureScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/QrCodeScannerCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/deeplink.utils.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Screens/Dynamic/AddressCaptureScreen.tsx +32 -32
- package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +8 -5
- package/src/Screens/Static/VerificationSessionCheckScreen.tsx +8 -0
- package/src/Shared/Components/QrCodeScannerCamera.tsx +29 -23
- package/src/Shared/Libs/deeplink.utils.ts +24 -2
- package/src/Translation/Resources/en.ts +3 -3
- package/src/Translation/Resources/tr.ts +3 -3
- package/src/version.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
4
|
-
import { SafeAreaView, View, Text,
|
|
4
|
+
import { SafeAreaView, View, Text, StyleSheet, ScrollView, Image, TouchableOpacity } from 'react-native';
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { TrustchexCamera } from "../../Shared/Components/TrustchexCamera.js";
|
|
@@ -18,7 +18,7 @@ import { useKeepAwake } from "../../Shared/Libs/native-keep-awake.utils.js";
|
|
|
18
18
|
* captures a proof document (residence cert / utility bill ≤3 months / public-
|
|
19
19
|
* authority doc). The address is verified later by an operator (manual review).
|
|
20
20
|
*/
|
|
21
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
21
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
22
22
|
const AddressCaptureScreen = () => {
|
|
23
23
|
useKeepAwake();
|
|
24
24
|
useStatusBarWhiteBackground();
|
|
@@ -30,16 +30,14 @@ const AddressCaptureScreen = () => {
|
|
|
30
30
|
} = useTranslation();
|
|
31
31
|
const insets = useSafeAreaInsets();
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// The address text is NOT collected here — the chip's DG11 address (read on
|
|
34
|
+
// the NFC step) is the source of truth and is always sent. This step only
|
|
35
|
+
// collects a PROOF-DOCUMENT photo for the operator's manual review. We show
|
|
36
|
+
// the chip address read-only for context when available.
|
|
37
|
+
const chipAddress = appContext.identificationInfo.address?.addressText ?? appContext.lastDocumentRead?.document.address ?? '';
|
|
37
38
|
const [proofImage, setProofImage] = useState();
|
|
38
39
|
const [isCameraOpen, setIsCameraOpen] = useState(false);
|
|
39
40
|
const captureNextFrame = useRef(false);
|
|
40
|
-
|
|
41
|
-
// Whether the proof document is required is configurable per workflow step.
|
|
42
|
-
const proofRequired = appContext.currentWorkflowStep?.data?.addressProofRequired !== false;
|
|
43
41
|
useEffect(() => {
|
|
44
42
|
trackVerificationStart('ADDRESS_CAPTURE');
|
|
45
43
|
}, []);
|
|
@@ -52,11 +50,17 @@ const AddressCaptureScreen = () => {
|
|
|
52
50
|
setIsCameraOpen(false);
|
|
53
51
|
}
|
|
54
52
|
};
|
|
55
|
-
|
|
53
|
+
|
|
54
|
+
// A proof photo is the whole point of this step.
|
|
55
|
+
const canContinue = !!proofImage;
|
|
56
56
|
const onContinue = () => {
|
|
57
|
+
// Attach the proof to the existing (chip-sourced) address without changing
|
|
58
|
+
// the address text or fromChip flag. If for some reason no address object
|
|
59
|
+
// exists yet, keep whatever chip text we have for display continuity.
|
|
60
|
+
const existing = appContext.identificationInfo.address;
|
|
57
61
|
appContext.identificationInfo.address = {
|
|
58
|
-
addressText: addressText
|
|
59
|
-
fromChip,
|
|
62
|
+
addressText: existing?.addressText ?? chipAddress,
|
|
63
|
+
fromChip: existing?.fromChip ?? !!chipAddress,
|
|
60
64
|
proofImage,
|
|
61
65
|
proofImageMimeType: proofImage ? 'image/jpeg' : undefined
|
|
62
66
|
};
|
|
@@ -103,20 +107,21 @@ const AddressCaptureScreen = () => {
|
|
|
103
107
|
}), /*#__PURE__*/_jsx(Text, {
|
|
104
108
|
style: styles.subtitle,
|
|
105
109
|
children: t('addressCaptureScreen.subtitle')
|
|
106
|
-
}),
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
}), chipAddress ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
111
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
112
|
+
style: styles.label,
|
|
113
|
+
children: t('addressCaptureScreen.addressLabel')
|
|
114
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
115
|
+
style: styles.readonlyAddress,
|
|
116
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
117
|
+
style: styles.readonlyAddressText,
|
|
118
|
+
children: chipAddress
|
|
119
|
+
})
|
|
120
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
121
|
+
style: styles.chipHint,
|
|
122
|
+
children: t('addressCaptureScreen.prefilledFromChip')
|
|
123
|
+
})]
|
|
109
124
|
}) : null, /*#__PURE__*/_jsx(Text, {
|
|
110
|
-
style: styles.label,
|
|
111
|
-
children: t('addressCaptureScreen.addressLabel')
|
|
112
|
-
}), /*#__PURE__*/_jsx(TextInput, {
|
|
113
|
-
style: styles.input,
|
|
114
|
-
value: addressText,
|
|
115
|
-
onChangeText: setAddressText,
|
|
116
|
-
placeholder: t('addressCaptureScreen.addressPlaceholder'),
|
|
117
|
-
multiline: true,
|
|
118
|
-
textAlignVertical: "top"
|
|
119
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
120
125
|
style: styles.label,
|
|
121
126
|
children: t('addressCaptureScreen.proofLabel')
|
|
122
127
|
}), /*#__PURE__*/_jsx(Text, {
|
|
@@ -177,12 +182,15 @@ const styles = StyleSheet.create({
|
|
|
177
182
|
marginTop: 16,
|
|
178
183
|
marginBottom: 6
|
|
179
184
|
},
|
|
180
|
-
|
|
185
|
+
readonlyAddress: {
|
|
181
186
|
borderWidth: 1,
|
|
182
|
-
borderColor: '#
|
|
187
|
+
borderColor: '#E0E0E0',
|
|
188
|
+
backgroundColor: '#F7F7F7',
|
|
183
189
|
borderRadius: 8,
|
|
184
190
|
padding: 12,
|
|
185
|
-
minHeight:
|
|
191
|
+
minHeight: 56
|
|
192
|
+
},
|
|
193
|
+
readonlyAddressText: {
|
|
186
194
|
fontSize: 15,
|
|
187
195
|
color: '#111'
|
|
188
196
|
},
|
|
@@ -104,13 +104,16 @@ const IdentityDocumentEIDScanningScreen = () => {
|
|
|
104
104
|
// Passive Auth artifacts for server-side verification.
|
|
105
105
|
appContext.identificationInfo.scannedDocument.paSodBase64 = appContext.lastDocumentRead?.passiveAuth?.sodBase64 ?? null;
|
|
106
106
|
appContext.identificationInfo.scannedDocument.paIntegrityStatus = appContext.lastDocumentRead?.passiveAuth?.integrityStatus ?? null;
|
|
107
|
-
// MASAK 4/C(1)(d):
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
// step
|
|
107
|
+
// MASAK 4/C(1)(d): the chip's DG11 address is the source of truth
|
|
108
|
+
// and is ALWAYS sent on the NFC read — independent of any
|
|
109
|
+
// ADDRESS_CAPTURE step. The address text is never user-edited; an
|
|
110
|
+
// ADDRESS_CAPTURE step only ADDS a proof-document photo for manual
|
|
111
|
+
// operator review (it does not change this address text).
|
|
111
112
|
const chipAddress = appContext.lastDocumentRead?.document.address;
|
|
112
|
-
if (chipAddress
|
|
113
|
+
if (chipAddress) {
|
|
113
114
|
appContext.identificationInfo.address = {
|
|
115
|
+
// Preserve any proof image already captured for this id.
|
|
116
|
+
...appContext.identificationInfo.address,
|
|
114
117
|
addressText: chipAddress,
|
|
115
118
|
fromChip: true
|
|
116
119
|
};
|
|
@@ -110,6 +110,11 @@ const VerificationSessionCheckScreen = () => {
|
|
|
110
110
|
getSessionRef.current(sid).then(session => {
|
|
111
111
|
const ctx = appContextRef.current;
|
|
112
112
|
ctx.workflowSteps = session.workflowSteps;
|
|
113
|
+
// Start the loaded workflow from its FIRST step. Without clearing this,
|
|
114
|
+
// a currentWorkflowStep left over from a prior flow makes the navigator
|
|
115
|
+
// resolve "next" past the last step and jump straight to the result
|
|
116
|
+
// screen (which uploads + completes the session immediately).
|
|
117
|
+
ctx.currentWorkflowStep = undefined;
|
|
113
118
|
if (session.branding) {
|
|
114
119
|
ctx.branding = ctx.branding || session.branding;
|
|
115
120
|
}
|
|
@@ -200,6 +205,9 @@ const VerificationSessionCheckScreen = () => {
|
|
|
200
205
|
}
|
|
201
206
|
const session = await getSession(sessionResponse.id, isDemoMode);
|
|
202
207
|
appContext.workflowSteps = session?.workflowSteps;
|
|
208
|
+
// Start from the first step (see note above) — clear
|
|
209
|
+
// any stale step so we don't jump straight to result.
|
|
210
|
+
appContext.currentWorkflowStep = undefined;
|
|
203
211
|
if (session?.branding) {
|
|
204
212
|
appContext.branding = appContext.branding || session.branding;
|
|
205
213
|
}
|
|
@@ -29,19 +29,21 @@ const QrCodeScannerCamera = ({
|
|
|
29
29
|
const lastScanTime = useRef(0);
|
|
30
30
|
const hasScanned = useRef(false);
|
|
31
31
|
const isInScanningFrame = (boundingBox, width, height) => {
|
|
32
|
-
// Match UI scanArea
|
|
33
|
-
//
|
|
34
|
-
|
|
32
|
+
// Match the UI scanArea (top/bottom 35%, left/right 3%) but accept a QR
|
|
33
|
+
// whose CENTER falls inside it rather than requiring the WHOLE bounding box.
|
|
34
|
+
// Requiring full containment silently rejected perfectly readable codes that
|
|
35
|
+
// were merely close to an edge or slightly larger than the band — the most
|
|
36
|
+
// common "QR won't scan" failure. The center test keeps the scan scoped to
|
|
37
|
+
// the framed area without being brittle about size/position.
|
|
35
38
|
const scanningFrame = {
|
|
36
|
-
left: width *
|
|
37
|
-
top: height *
|
|
38
|
-
right: width *
|
|
39
|
-
bottom: height *
|
|
39
|
+
left: width * 0.03,
|
|
40
|
+
top: height * 0.35,
|
|
41
|
+
right: width * 0.97,
|
|
42
|
+
bottom: height * 0.65
|
|
40
43
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return isInFrame;
|
|
44
|
+
const centerX = (boundingBox.left + boundingBox.right) / 2;
|
|
45
|
+
const centerY = (boundingBox.top + boundingBox.bottom) / 2;
|
|
46
|
+
return centerX >= scanningFrame.left && centerX <= scanningFrame.right && centerY >= scanningFrame.top && centerY <= scanningFrame.bottom;
|
|
45
47
|
};
|
|
46
48
|
const handleFrame = useCallback(async event => {
|
|
47
49
|
if (hasScanned.current) return;
|
|
@@ -55,13 +57,13 @@ const QrCodeScannerCamera = ({
|
|
|
55
57
|
frame
|
|
56
58
|
} = event.nativeEvent;
|
|
57
59
|
try {
|
|
58
|
-
// Barcodes are already detected natively — read directly from frame
|
|
60
|
+
// Barcodes are already detected natively — read directly from frame.
|
|
61
|
+
// Accept the first code that is readable AND framed; don't bail just
|
|
62
|
+
// because more than one code happens to be in view.
|
|
59
63
|
const barcodes = frame.barcodes;
|
|
60
|
-
if (!barcodes || barcodes.length
|
|
61
|
-
const code = barcodes
|
|
62
|
-
|
|
63
|
-
// Use frame checking on both platforms for consistent behavior
|
|
64
|
-
if (code.boundingBox && isInScanningFrame(code.boundingBox, frame.width, frame.height) && code.rawValue) {
|
|
64
|
+
if (!barcodes || barcodes.length === 0) return;
|
|
65
|
+
const code = barcodes.find(b => b.rawValue && b.boundingBox && isInScanningFrame(b.boundingBox, frame.width, frame.height));
|
|
66
|
+
if (code?.rawValue) {
|
|
65
67
|
hasScanned.current = true;
|
|
66
68
|
onQrCodeScanned(code.rawValue);
|
|
67
69
|
}
|
|
@@ -34,12 +34,32 @@ const handleDeepLink = ({
|
|
|
34
34
|
sessionId = segments[i + 1] ?? '';
|
|
35
35
|
debugLog('handleDeepLink', 'Found sessionId:', sessionId);
|
|
36
36
|
} else if (segments[i] === 'app-url') {
|
|
37
|
-
|
|
37
|
+
// The app-url value can be EITHER a bare host (`app-url/host[:port]`) OR a
|
|
38
|
+
// full embedded URL (`app-url/https://host/...`). The embedded form splits
|
|
39
|
+
// across multiple segments because the inner `https://` contains a `//`,
|
|
40
|
+
// e.g. ['app-url', 'https:', '', 'host', ...] — so segments[i+1] is the
|
|
41
|
+
// inner scheme, not the host. Detect that and derive the host from the
|
|
42
|
+
// first non-empty segment after the inner scheme.
|
|
43
|
+
let host = '';
|
|
44
|
+
let embeddedScheme = '';
|
|
45
|
+
const next = segments[i + 1] ?? '';
|
|
46
|
+
const schemeMatch = next.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):$/);
|
|
47
|
+
if (schemeMatch) {
|
|
48
|
+
// Embedded-URL form: skip the inner scheme + the empty segment from `//`.
|
|
49
|
+
embeddedScheme = schemeMatch[1].toLowerCase();
|
|
50
|
+
let j = i + 2;
|
|
51
|
+
while (j < segments.length && segments[j] === '') j += 1;
|
|
52
|
+
host = segments[j] ?? '';
|
|
53
|
+
} else {
|
|
54
|
+
// Bare-host form.
|
|
55
|
+
host = next;
|
|
56
|
+
}
|
|
38
57
|
if (!HOST_PATTERN.test(host)) {
|
|
39
58
|
logWarn('handleDeepLink', 'Rejected invalid app-url host');
|
|
40
59
|
continue;
|
|
41
60
|
}
|
|
42
|
-
|
|
61
|
+
// Prefer the embedded URL's own scheme; otherwise inherit the link's.
|
|
62
|
+
const hostScheme = embeddedScheme || (scheme === 'http' ? 'http' : 'https');
|
|
43
63
|
if (!isAllowedScheme(hostScheme)) {
|
|
44
64
|
logWarn('handleDeepLink', 'Rejected non-HTTPS app-url');
|
|
45
65
|
continue;
|
|
@@ -95,9 +95,9 @@ export default {
|
|
|
95
95
|
'eidScannerScreen.nfcAuthFailed': 'Could not establish a secure connection to the chip. Make sure the document number, date of birth and expiry date are correct, then try again.',
|
|
96
96
|
'eidScannerScreen.nfcTagLost': 'Connection to the document was lost. Keep the document still against the device and try again.',
|
|
97
97
|
'eidScannerScreen.nfcTimeout': 'Reading the chip timed out. Hold the document steady against the device and try again.',
|
|
98
|
-
'addressCaptureScreen.title': '
|
|
99
|
-
'addressCaptureScreen.subtitle': '
|
|
100
|
-
'addressCaptureScreen.prefilledFromChip': '
|
|
98
|
+
'addressCaptureScreen.title': 'Proof of address',
|
|
99
|
+
'addressCaptureScreen.subtitle': 'Take a clear photo of a document that shows your address. It will be reviewed by an operator.',
|
|
100
|
+
'addressCaptureScreen.prefilledFromChip': 'This address was read from your document chip and is used as-is.',
|
|
101
101
|
'addressCaptureScreen.addressLabel': 'Address',
|
|
102
102
|
'addressCaptureScreen.addressPlaceholder': 'Street, number, city, country',
|
|
103
103
|
'addressCaptureScreen.proofLabel': 'Proof of address',
|
|
@@ -95,9 +95,9 @@ export default {
|
|
|
95
95
|
'eidScannerScreen.nfcAuthFailed': 'Çip ile güvenli bağlantı kurulamadı. Belge numarası, doğum tarihi ve son geçerlilik tarihinin doğru olduğundan emin olup tekrar deneyin.',
|
|
96
96
|
'eidScannerScreen.nfcTagLost': 'Belge ile bağlantı kesildi. Belgeyi cihaza sabit tutun ve tekrar deneyin.',
|
|
97
97
|
'eidScannerScreen.nfcTimeout': 'Çip okuması zaman aşımına uğradı. Belgeyi cihaza sabit tutup tekrar deneyin.',
|
|
98
|
-
'addressCaptureScreen.title': '
|
|
99
|
-
'addressCaptureScreen.subtitle': '
|
|
100
|
-
'addressCaptureScreen.prefilledFromChip': '
|
|
98
|
+
'addressCaptureScreen.title': 'Adres kanıtı',
|
|
99
|
+
'addressCaptureScreen.subtitle': 'Adresinizi gösteren bir belgenin net bir fotoğrafını çekin. Bir operatör tarafından incelenecektir.',
|
|
100
|
+
'addressCaptureScreen.prefilledFromChip': 'Bu adres belge yongasından okundu ve olduğu gibi kullanılır.',
|
|
101
101
|
'addressCaptureScreen.addressLabel': 'Adres',
|
|
102
102
|
'addressCaptureScreen.addressPlaceholder': 'Cadde, numara, şehir, ülke',
|
|
103
103
|
'addressCaptureScreen.proofLabel': 'Adres kanıtı',
|
package/lib/module/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddressCaptureScreen.d.ts","sourceRoot":"","sources":["../../../../../src/Screens/Dynamic/AddressCaptureScreen.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AddressCaptureScreen.d.ts","sourceRoot":"","sources":["../../../../../src/Screens/Dynamic/AddressCaptureScreen.tsx"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,+CA8HzB,CAAC;AAkCF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentEIDScanningScreen.d.ts","sourceRoot":"","sources":["../../../../../src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx"],"names":[],"mappings":"AAsBA,QAAA,MAAM,iCAAiC,+
|
|
1
|
+
{"version":3,"file":"IdentityDocumentEIDScanningScreen.d.ts","sourceRoot":"","sources":["../../../../../src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx"],"names":[],"mappings":"AAsBA,QAAA,MAAM,iCAAiC,+CA0PtC,CAAC;AAoBF,eAAe,iCAAiC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerificationSessionCheckScreen.d.ts","sourceRoot":"","sources":["../../../../../src/Screens/Static/VerificationSessionCheckScreen.tsx"],"names":[],"mappings":"AAkDA,QAAA,MAAM,8BAA8B,+
|
|
1
|
+
{"version":3,"file":"VerificationSessionCheckScreen.d.ts","sourceRoot":"","sources":["../../../../../src/Screens/Static/VerificationSessionCheckScreen.tsx"],"names":[],"mappings":"AAkDA,QAAA,MAAM,8BAA8B,+CA2UnC,CAAC;AAiHF,eAAe,8BAA8B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QrCodeScannerCamera.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/QrCodeScannerCamera.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,+BAG1B,wBAAwB,
|
|
1
|
+
{"version":3,"file":"QrCodeScannerCamera.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/QrCodeScannerCamera.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,+BAG1B,wBAAwB,4CAmL1B,CAAC;AAwGF,eAAe,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deeplink.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/deeplink.utils.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MAGxC,CAAC;AAEF,QAAA,MAAM,cAAc,GAAI,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"deeplink.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/deeplink.utils.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MAGxC,CAAC;AAEF,QAAA,MAAM,cAAc,GAAI,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,aAkE/C,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "1.
|
|
1
|
+
export declare const SDK_VERSION = "1.502.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
SafeAreaView,
|
|
4
4
|
View,
|
|
5
5
|
Text,
|
|
6
|
-
TextInput,
|
|
7
6
|
StyleSheet,
|
|
8
7
|
ScrollView,
|
|
9
8
|
Image,
|
|
@@ -44,20 +43,19 @@ const AddressCaptureScreen = () => {
|
|
|
44
43
|
const { t } = useTranslation();
|
|
45
44
|
const insets = useSafeAreaInsets();
|
|
46
45
|
|
|
47
|
-
//
|
|
46
|
+
// The address text is NOT collected here — the chip's DG11 address (read on
|
|
47
|
+
// the NFC step) is the source of truth and is always sent. This step only
|
|
48
|
+
// collects a PROOF-DOCUMENT photo for the operator's manual review. We show
|
|
49
|
+
// the chip address read-only for context when available.
|
|
48
50
|
const chipAddress =
|
|
49
|
-
appContext.
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
appContext.identificationInfo.address?.addressText ??
|
|
52
|
+
appContext.lastDocumentRead?.document.address ??
|
|
53
|
+
'';
|
|
52
54
|
|
|
53
55
|
const [proofImage, setProofImage] = useState<string | undefined>();
|
|
54
56
|
const [isCameraOpen, setIsCameraOpen] = useState(false);
|
|
55
57
|
const captureNextFrame = useRef(false);
|
|
56
58
|
|
|
57
|
-
// Whether the proof document is required is configurable per workflow step.
|
|
58
|
-
const proofRequired =
|
|
59
|
-
appContext.currentWorkflowStep?.data?.addressProofRequired !== false;
|
|
60
|
-
|
|
61
59
|
useEffect(() => {
|
|
62
60
|
trackVerificationStart('ADDRESS_CAPTURE');
|
|
63
61
|
}, []);
|
|
@@ -72,13 +70,17 @@ const AddressCaptureScreen = () => {
|
|
|
72
70
|
}
|
|
73
71
|
};
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
// A proof photo is the whole point of this step.
|
|
74
|
+
const canContinue = !!proofImage;
|
|
77
75
|
|
|
78
76
|
const onContinue = () => {
|
|
77
|
+
// Attach the proof to the existing (chip-sourced) address without changing
|
|
78
|
+
// the address text or fromChip flag. If for some reason no address object
|
|
79
|
+
// exists yet, keep whatever chip text we have for display continuity.
|
|
80
|
+
const existing = appContext.identificationInfo.address;
|
|
79
81
|
appContext.identificationInfo.address = {
|
|
80
|
-
addressText: addressText
|
|
81
|
-
fromChip,
|
|
82
|
+
addressText: existing?.addressText ?? chipAddress,
|
|
83
|
+
fromChip: existing?.fromChip ?? !!chipAddress,
|
|
82
84
|
proofImage,
|
|
83
85
|
proofImageMimeType: proofImage ? 'image/jpeg' : undefined,
|
|
84
86
|
};
|
|
@@ -118,22 +120,20 @@ const AddressCaptureScreen = () => {
|
|
|
118
120
|
<Text style={styles.title}>{t('addressCaptureScreen.title')}</Text>
|
|
119
121
|
<Text style={styles.subtitle}>{t('addressCaptureScreen.subtitle')}</Text>
|
|
120
122
|
|
|
121
|
-
{
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
|
|
123
|
+
{chipAddress ? (
|
|
124
|
+
<>
|
|
125
|
+
<Text style={styles.label}>
|
|
126
|
+
{t('addressCaptureScreen.addressLabel')}
|
|
127
|
+
</Text>
|
|
128
|
+
<View style={styles.readonlyAddress}>
|
|
129
|
+
<Text style={styles.readonlyAddressText}>{chipAddress}</Text>
|
|
130
|
+
</View>
|
|
131
|
+
<Text style={styles.chipHint}>
|
|
132
|
+
{t('addressCaptureScreen.prefilledFromChip')}
|
|
133
|
+
</Text>
|
|
134
|
+
</>
|
|
125
135
|
) : null}
|
|
126
136
|
|
|
127
|
-
<Text style={styles.label}>{t('addressCaptureScreen.addressLabel')}</Text>
|
|
128
|
-
<TextInput
|
|
129
|
-
style={styles.input}
|
|
130
|
-
value={addressText}
|
|
131
|
-
onChangeText={setAddressText}
|
|
132
|
-
placeholder={t('addressCaptureScreen.addressPlaceholder')}
|
|
133
|
-
multiline
|
|
134
|
-
textAlignVertical="top"
|
|
135
|
-
/>
|
|
136
|
-
|
|
137
137
|
<Text style={styles.label}>{t('addressCaptureScreen.proofLabel')}</Text>
|
|
138
138
|
<Text style={styles.proofHint}>{t('addressCaptureScreen.proofHint')}</Text>
|
|
139
139
|
{proofImage ? (
|
|
@@ -168,15 +168,15 @@ const styles = StyleSheet.create({
|
|
|
168
168
|
subtitle: { fontSize: 15, color: '#555', marginBottom: 16 },
|
|
169
169
|
chipHint: { fontSize: 13, color: '#2E7D32', marginBottom: 12 },
|
|
170
170
|
label: { fontSize: 14, fontWeight: '600', color: '#222', marginTop: 16, marginBottom: 6 },
|
|
171
|
-
|
|
171
|
+
readonlyAddress: {
|
|
172
172
|
borderWidth: 1,
|
|
173
|
-
borderColor: '#
|
|
173
|
+
borderColor: '#E0E0E0',
|
|
174
|
+
backgroundColor: '#F7F7F7',
|
|
174
175
|
borderRadius: 8,
|
|
175
176
|
padding: 12,
|
|
176
|
-
minHeight:
|
|
177
|
-
fontSize: 15,
|
|
178
|
-
color: '#111',
|
|
177
|
+
minHeight: 56,
|
|
179
178
|
},
|
|
179
|
+
readonlyAddressText: { fontSize: 15, color: '#111' },
|
|
180
180
|
proofHint: { fontSize: 13, color: '#777', marginBottom: 10 },
|
|
181
181
|
proofPreview: {
|
|
182
182
|
width: '100%',
|
|
@@ -144,14 +144,17 @@ const IdentityDocumentEIDScanningScreen = () => {
|
|
|
144
144
|
appContext.identificationInfo.scannedDocument.paIntegrityStatus =
|
|
145
145
|
appContext.lastDocumentRead?.passiveAuth?.integrityStatus ??
|
|
146
146
|
null;
|
|
147
|
-
// MASAK 4/C(1)(d):
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// step
|
|
147
|
+
// MASAK 4/C(1)(d): the chip's DG11 address is the source of truth
|
|
148
|
+
// and is ALWAYS sent on the NFC read — independent of any
|
|
149
|
+
// ADDRESS_CAPTURE step. The address text is never user-edited; an
|
|
150
|
+
// ADDRESS_CAPTURE step only ADDS a proof-document photo for manual
|
|
151
|
+
// operator review (it does not change this address text).
|
|
151
152
|
const chipAddress =
|
|
152
153
|
appContext.lastDocumentRead?.document.address;
|
|
153
|
-
if (chipAddress
|
|
154
|
+
if (chipAddress) {
|
|
154
155
|
appContext.identificationInfo.address = {
|
|
156
|
+
// Preserve any proof image already captured for this id.
|
|
157
|
+
...appContext.identificationInfo.address,
|
|
155
158
|
addressText: chipAddress,
|
|
156
159
|
fromChip: true,
|
|
157
160
|
};
|
|
@@ -181,6 +181,11 @@ const VerificationSessionCheckScreen = () => {
|
|
|
181
181
|
.then((session) => {
|
|
182
182
|
const ctx = appContextRef.current;
|
|
183
183
|
ctx.workflowSteps = session.workflowSteps;
|
|
184
|
+
// Start the loaded workflow from its FIRST step. Without clearing this,
|
|
185
|
+
// a currentWorkflowStep left over from a prior flow makes the navigator
|
|
186
|
+
// resolve "next" past the last step and jump straight to the result
|
|
187
|
+
// screen (which uploads + completes the session immediately).
|
|
188
|
+
ctx.currentWorkflowStep = undefined;
|
|
184
189
|
if (session.branding) {
|
|
185
190
|
ctx.branding = ctx.branding || session.branding;
|
|
186
191
|
}
|
|
@@ -299,6 +304,9 @@ const VerificationSessionCheckScreen = () => {
|
|
|
299
304
|
isDemoMode
|
|
300
305
|
);
|
|
301
306
|
appContext.workflowSteps = session?.workflowSteps;
|
|
307
|
+
// Start from the first step (see note above) — clear
|
|
308
|
+
// any stale step so we don't jump straight to result.
|
|
309
|
+
appContext.currentWorkflowStep = undefined;
|
|
302
310
|
if (session?.branding) {
|
|
303
311
|
appContext.branding =
|
|
304
312
|
appContext.branding || session.branding;
|
|
@@ -50,24 +50,28 @@ const QrCodeScannerCamera = ({
|
|
|
50
50
|
width: number,
|
|
51
51
|
height: number
|
|
52
52
|
) => {
|
|
53
|
-
// Match UI scanArea
|
|
54
|
-
//
|
|
55
|
-
|
|
53
|
+
// Match the UI scanArea (top/bottom 35%, left/right 3%) but accept a QR
|
|
54
|
+
// whose CENTER falls inside it rather than requiring the WHOLE bounding box.
|
|
55
|
+
// Requiring full containment silently rejected perfectly readable codes that
|
|
56
|
+
// were merely close to an edge or slightly larger than the band — the most
|
|
57
|
+
// common "QR won't scan" failure. The center test keeps the scan scoped to
|
|
58
|
+
// the framed area without being brittle about size/position.
|
|
56
59
|
const scanningFrame = {
|
|
57
|
-
left: width *
|
|
58
|
-
top: height *
|
|
59
|
-
right: width *
|
|
60
|
-
bottom: height *
|
|
60
|
+
left: width * 0.03,
|
|
61
|
+
top: height * 0.35,
|
|
62
|
+
right: width * 0.97,
|
|
63
|
+
bottom: height * 0.65,
|
|
61
64
|
};
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
boundingBox.left >= scanningFrame.left &&
|
|
66
|
-
boundingBox.top >= scanningFrame.top &&
|
|
67
|
-
boundingBox.right <= scanningFrame.right &&
|
|
68
|
-
boundingBox.bottom <= scanningFrame.bottom;
|
|
66
|
+
const centerX = (boundingBox.left + boundingBox.right) / 2;
|
|
67
|
+
const centerY = (boundingBox.top + boundingBox.bottom) / 2;
|
|
69
68
|
|
|
70
|
-
return
|
|
69
|
+
return (
|
|
70
|
+
centerX >= scanningFrame.left &&
|
|
71
|
+
centerX <= scanningFrame.right &&
|
|
72
|
+
centerY >= scanningFrame.top &&
|
|
73
|
+
centerY <= scanningFrame.bottom
|
|
74
|
+
);
|
|
71
75
|
};
|
|
72
76
|
|
|
73
77
|
const handleFrame = useCallback(
|
|
@@ -84,18 +88,20 @@ const QrCodeScannerCamera = ({
|
|
|
84
88
|
const { frame } = event.nativeEvent;
|
|
85
89
|
|
|
86
90
|
try {
|
|
87
|
-
// Barcodes are already detected natively — read directly from frame
|
|
91
|
+
// Barcodes are already detected natively — read directly from frame.
|
|
92
|
+
// Accept the first code that is readable AND framed; don't bail just
|
|
93
|
+
// because more than one code happens to be in view.
|
|
88
94
|
const barcodes = frame.barcodes;
|
|
89
|
-
if (!barcodes || barcodes.length
|
|
95
|
+
if (!barcodes || barcodes.length === 0) return;
|
|
90
96
|
|
|
91
|
-
const code = barcodes
|
|
97
|
+
const code = barcodes.find(
|
|
98
|
+
(b) =>
|
|
99
|
+
b.rawValue &&
|
|
100
|
+
b.boundingBox &&
|
|
101
|
+
isInScanningFrame(b.boundingBox, frame.width, frame.height)
|
|
102
|
+
);
|
|
92
103
|
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
code.boundingBox &&
|
|
96
|
-
isInScanningFrame(code.boundingBox, frame.width, frame.height) &&
|
|
97
|
-
code.rawValue
|
|
98
|
-
) {
|
|
104
|
+
if (code?.rawValue) {
|
|
99
105
|
hasScanned.current = true;
|
|
100
106
|
onQrCodeScanned(code.rawValue);
|
|
101
107
|
}
|
|
@@ -37,12 +37,34 @@ const handleDeepLink = ({ url }: { url: string }) => {
|
|
|
37
37
|
sessionId = segments[i + 1] ?? '';
|
|
38
38
|
debugLog('handleDeepLink', 'Found sessionId:', sessionId);
|
|
39
39
|
} else if (segments[i] === 'app-url') {
|
|
40
|
-
|
|
40
|
+
// The app-url value can be EITHER a bare host (`app-url/host[:port]`) OR a
|
|
41
|
+
// full embedded URL (`app-url/https://host/...`). The embedded form splits
|
|
42
|
+
// across multiple segments because the inner `https://` contains a `//`,
|
|
43
|
+
// e.g. ['app-url', 'https:', '', 'host', ...] — so segments[i+1] is the
|
|
44
|
+
// inner scheme, not the host. Detect that and derive the host from the
|
|
45
|
+
// first non-empty segment after the inner scheme.
|
|
46
|
+
let host = '';
|
|
47
|
+
let embeddedScheme = '';
|
|
48
|
+
const next = segments[i + 1] ?? '';
|
|
49
|
+
const schemeMatch = next.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):$/);
|
|
50
|
+
if (schemeMatch) {
|
|
51
|
+
// Embedded-URL form: skip the inner scheme + the empty segment from `//`.
|
|
52
|
+
embeddedScheme = schemeMatch[1].toLowerCase();
|
|
53
|
+
let j = i + 2;
|
|
54
|
+
while (j < segments.length && segments[j] === '') j += 1;
|
|
55
|
+
host = segments[j] ?? '';
|
|
56
|
+
} else {
|
|
57
|
+
// Bare-host form.
|
|
58
|
+
host = next;
|
|
59
|
+
}
|
|
60
|
+
|
|
41
61
|
if (!HOST_PATTERN.test(host)) {
|
|
42
62
|
logWarn('handleDeepLink', 'Rejected invalid app-url host');
|
|
43
63
|
continue;
|
|
44
64
|
}
|
|
45
|
-
|
|
65
|
+
// Prefer the embedded URL's own scheme; otherwise inherit the link's.
|
|
66
|
+
const hostScheme =
|
|
67
|
+
embeddedScheme || (scheme === 'http' ? 'http' : 'https');
|
|
46
68
|
if (!isAllowedScheme(hostScheme)) {
|
|
47
69
|
logWarn('handleDeepLink', 'Rejected non-HTTPS app-url');
|
|
48
70
|
continue;
|
|
@@ -124,11 +124,11 @@ export default {
|
|
|
124
124
|
'Connection to the document was lost. Keep the document still against the device and try again.',
|
|
125
125
|
'eidScannerScreen.nfcTimeout':
|
|
126
126
|
'Reading the chip timed out. Hold the document steady against the device and try again.',
|
|
127
|
-
'addressCaptureScreen.title': '
|
|
127
|
+
'addressCaptureScreen.title': 'Proof of address',
|
|
128
128
|
'addressCaptureScreen.subtitle':
|
|
129
|
-
'
|
|
129
|
+
'Take a clear photo of a document that shows your address. It will be reviewed by an operator.',
|
|
130
130
|
'addressCaptureScreen.prefilledFromChip':
|
|
131
|
-
'
|
|
131
|
+
'This address was read from your document chip and is used as-is.',
|
|
132
132
|
'addressCaptureScreen.addressLabel': 'Address',
|
|
133
133
|
'addressCaptureScreen.addressPlaceholder': 'Street, number, city, country',
|
|
134
134
|
'addressCaptureScreen.proofLabel': 'Proof of address',
|
|
@@ -124,11 +124,11 @@ export default {
|
|
|
124
124
|
'Belge ile bağlantı kesildi. Belgeyi cihaza sabit tutun ve tekrar deneyin.',
|
|
125
125
|
'eidScannerScreen.nfcTimeout':
|
|
126
126
|
'Çip okuması zaman aşımına uğradı. Belgeyi cihaza sabit tutup tekrar deneyin.',
|
|
127
|
-
'addressCaptureScreen.title': '
|
|
127
|
+
'addressCaptureScreen.title': 'Adres kanıtı',
|
|
128
128
|
'addressCaptureScreen.subtitle':
|
|
129
|
-
'
|
|
129
|
+
'Adresinizi gösteren bir belgenin net bir fotoğrafını çekin. Bir operatör tarafından incelenecektir.',
|
|
130
130
|
'addressCaptureScreen.prefilledFromChip':
|
|
131
|
-
'
|
|
131
|
+
'Bu adres belge yongasından okundu ve olduğu gibi kullanılır.',
|
|
132
132
|
'addressCaptureScreen.addressLabel': 'Adres',
|
|
133
133
|
'addressCaptureScreen.addressPlaceholder': 'Cadde, numara, şehir, ülke',
|
|
134
134
|
'addressCaptureScreen.proofLabel': 'Adres kanıtı',
|
package/src/version.ts
CHANGED