@trustchex/react-native-sdk 1.215.0 → 1.248.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/ContractAcceptanceScreen.js +2 -2
- package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +2 -2
- package/lib/module/Screens/Static/ResultScreen.js +4 -9
- package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +150 -106
- package/lib/module/Shared/Components/EIDScanner.js +4 -4
- package/lib/module/Shared/Components/FaceCamera.js +4 -3
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +4 -3
- package/lib/module/Shared/Components/QrCodeScannerCamera.js +2 -2
- package/lib/module/Shared/Components/StyledButton.js +30 -0
- package/lib/module/Shared/Constants/index.js +3 -0
- package/lib/module/Shared/Constants/validation.constants.js +24 -0
- package/lib/module/Shared/Libs/demo.utils.js +5 -3
- package/lib/module/Translation/Resources/en.js +50 -52
- package/lib/module/Translation/Resources/tr.js +48 -53
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/FaceCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/StyledButton.d.ts +6 -0
- package/lib/typescript/src/Shared/Components/StyledButton.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Constants/index.d.ts +2 -0
- package/lib/typescript/src/Shared/Constants/index.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Constants/validation.constants.d.ts +20 -0
- package/lib/typescript/src/Shared/Constants/validation.constants.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/demo.utils.d.ts +2 -2
- package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +1 -3
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +1 -6
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +3 -3
- package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +3 -3
- package/src/Screens/Static/ResultScreen.tsx +14 -12
- package/src/Screens/Static/VerificationSessionCheckScreen.tsx +184 -131
- package/src/Shared/Components/EIDScanner.tsx +7 -7
- package/src/Shared/Components/FaceCamera.tsx +6 -5
- package/src/Shared/Components/IdentityDocumentCamera.tsx +6 -5
- package/src/Shared/Components/QrCodeScannerCamera.tsx +3 -3
- package/src/Shared/Components/StyledButton.tsx +35 -0
- package/src/Shared/Constants/index.ts +1 -0
- package/src/Shared/Constants/validation.constants.ts +24 -0
- package/src/Shared/Libs/demo.utils.ts +5 -4
- package/src/Translation/Resources/en.ts +51 -54
- package/src/Translation/Resources/tr.ts +50 -55
- package/lib/module/Shared/Components/OTPCodeInput.js +0 -74
- package/lib/typescript/src/Shared/Components/OTPCodeInput.d.ts +0 -10
- package/lib/typescript/src/Shared/Components/OTPCodeInput.d.ts.map +0 -1
- package/src/Shared/Components/OTPCodeInput.tsx +0 -93
|
@@ -2,6 +2,7 @@ import React, {
|
|
|
2
2
|
useCallback,
|
|
3
3
|
useContext,
|
|
4
4
|
useEffect,
|
|
5
|
+
useMemo,
|
|
5
6
|
useRef,
|
|
6
7
|
useState,
|
|
7
8
|
} from 'react';
|
|
@@ -20,25 +21,28 @@ import {
|
|
|
20
21
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
21
22
|
import AppContext from '../../Shared/Contexts/AppContext';
|
|
22
23
|
import httpClient, { NotFoundError } from '../../Shared/Libs/http-client';
|
|
23
|
-
import OTPCodeInput from '../../Shared/Components/OTPCodeInput';
|
|
24
24
|
import { useTranslation } from 'react-i18next';
|
|
25
25
|
import LanguageSelector from '../../Shared/Components/LanguageSelector';
|
|
26
26
|
import NavigationManager, {
|
|
27
27
|
type NavigationManagerRef,
|
|
28
28
|
} from '../../Shared/Components/NavigationManager';
|
|
29
29
|
import type { VerificationSession } from '../../Shared/Types/verificationSession';
|
|
30
|
-
import {
|
|
30
|
+
import { TextInput, useTheme } from 'react-native-paper';
|
|
31
|
+
import StyledButton from '../../Shared/Components/StyledButton';
|
|
31
32
|
import LottieView from 'lottie-react-native';
|
|
32
33
|
import {
|
|
33
34
|
getSimulatedDemoData,
|
|
34
35
|
isDemoSession,
|
|
35
36
|
} from '../../Shared/Libs/demo.utils';
|
|
36
37
|
import { useNavigation } from '@react-navigation/native';
|
|
38
|
+
import {
|
|
39
|
+
SESSION_CODE_CHARSET_PATTERN,
|
|
40
|
+
SESSION_CODE_VALIDATION_PATTERN,
|
|
41
|
+
} from '../../Shared/Constants/validation.constants';
|
|
37
42
|
|
|
38
43
|
const VerificationSessionCheckScreen = () => {
|
|
39
|
-
const [
|
|
44
|
+
const [sessionCode, setSessionCode] = useState('');
|
|
40
45
|
const [code, setCode] = useState('');
|
|
41
|
-
const [isEnabled, setIsEnabled] = useState(false);
|
|
42
46
|
const [isCheckingSession, setIsCheckingSession] = useState(false);
|
|
43
47
|
const [isSendAgainEnabled, setIsSendAgainEnabled] = useState(false);
|
|
44
48
|
const [isCodeSent, setIsCodeSent] = useState(false);
|
|
@@ -47,27 +51,17 @@ const VerificationSessionCheckScreen = () => {
|
|
|
47
51
|
const { t } = useTranslation();
|
|
48
52
|
const navigationManagerRef = React.useRef<NavigationManagerRef>(null);
|
|
49
53
|
const navigation = useNavigation();
|
|
50
|
-
const [apiUrl, setApiUrl] = useState<string>(
|
|
51
|
-
`${appContext.baseUrl}/api/app/mobile`
|
|
52
|
-
);
|
|
53
54
|
const theme = useTheme();
|
|
54
55
|
const initialized = useRef(false);
|
|
55
56
|
const insets = useSafeAreaInsets();
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}, [appContext.baseUrl]);
|
|
62
|
-
|
|
63
|
-
const validateEmail = useCallback((value: string) => {
|
|
64
|
-
const re = /\S+@\S+\.\S+/;
|
|
65
|
-
return re.test(value);
|
|
66
|
-
}, []);
|
|
58
|
+
const apiUrl = useMemo(
|
|
59
|
+
() => `${appContext.baseUrl}/api/app/mobile`,
|
|
60
|
+
[appContext.baseUrl]
|
|
61
|
+
);
|
|
67
62
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
return re.test(value);
|
|
63
|
+
const validateSessionCode = useCallback((value: string) => {
|
|
64
|
+
return SESSION_CODE_VALIDATION_PATTERN.test(value.toUpperCase());
|
|
71
65
|
}, []);
|
|
72
66
|
|
|
73
67
|
const getSession = useCallback(
|
|
@@ -94,29 +88,20 @@ const VerificationSessionCheckScreen = () => {
|
|
|
94
88
|
[apiUrl, appContext.isDemoSession, t]
|
|
95
89
|
);
|
|
96
90
|
|
|
97
|
-
const
|
|
98
|
-
async (
|
|
91
|
+
const getSessionByCode = useCallback(
|
|
92
|
+
async (inputCode: string) => {
|
|
99
93
|
try {
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
'VERIFICATION_SESSIONS'
|
|
110
|
-
)
|
|
111
|
-
: undefined
|
|
112
|
-
);
|
|
113
|
-
} else if (isPhoneNumber) {
|
|
114
|
-
response = await httpClient.get<VerificationSession[]>(
|
|
115
|
-
`${apiUrl}/verification-sessions?phoneNumber=${value}`
|
|
116
|
-
);
|
|
117
|
-
}
|
|
94
|
+
appContext.isDemoSession = isDemoSession(inputCode);
|
|
95
|
+
const response = await httpClient.get<{ id: string }>(
|
|
96
|
+
`${apiUrl}/verification-sessions?sessionCode=${inputCode.toUpperCase()}`,
|
|
97
|
+
appContext.isDemoSession
|
|
98
|
+
? getSimulatedDemoData<{ id: string } | undefined, void>(
|
|
99
|
+
'GET_SESSION_BY_CODE'
|
|
100
|
+
)
|
|
101
|
+
: undefined
|
|
102
|
+
);
|
|
118
103
|
|
|
119
|
-
if (!response || response.
|
|
104
|
+
if (!response || !response.id) {
|
|
120
105
|
throw new NotFoundError();
|
|
121
106
|
}
|
|
122
107
|
|
|
@@ -130,7 +115,7 @@ const VerificationSessionCheckScreen = () => {
|
|
|
130
115
|
}
|
|
131
116
|
}
|
|
132
117
|
},
|
|
133
|
-
[apiUrl, appContext, t
|
|
118
|
+
[apiUrl, appContext, t]
|
|
134
119
|
);
|
|
135
120
|
|
|
136
121
|
const sendVerificationCode = useCallback(
|
|
@@ -194,7 +179,7 @@ const VerificationSessionCheckScreen = () => {
|
|
|
194
179
|
[apiUrl, appContext.isDemoSession, t]
|
|
195
180
|
);
|
|
196
181
|
|
|
197
|
-
const
|
|
182
|
+
const sendOTPCode = useCallback(
|
|
198
183
|
async (sessionId: string) => {
|
|
199
184
|
if (!sessionId) {
|
|
200
185
|
return false;
|
|
@@ -237,7 +222,7 @@ const VerificationSessionCheckScreen = () => {
|
|
|
237
222
|
}
|
|
238
223
|
|
|
239
224
|
if (session?.sendOTP) {
|
|
240
|
-
return
|
|
225
|
+
return sendOTPCode(session.id);
|
|
241
226
|
} else if (session?.identificationId) {
|
|
242
227
|
appContext.identificationInfo.identificationId =
|
|
243
228
|
session?.identificationId;
|
|
@@ -254,7 +239,7 @@ const VerificationSessionCheckScreen = () => {
|
|
|
254
239
|
appContext,
|
|
255
240
|
appContext.identificationInfo.sessionId,
|
|
256
241
|
getSession,
|
|
257
|
-
|
|
242
|
+
sendOTPCode,
|
|
258
243
|
theme.colors,
|
|
259
244
|
theme.colors.primary,
|
|
260
245
|
theme.colors.secondary,
|
|
@@ -302,107 +287,138 @@ const VerificationSessionCheckScreen = () => {
|
|
|
302
287
|
<Text style={styles.mainText}>
|
|
303
288
|
{t('verificationSessionCheckScreen.mainText')}
|
|
304
289
|
</Text>
|
|
305
|
-
<
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
290
|
+
<View style={styles.inputContainer}>
|
|
291
|
+
<TextInput
|
|
292
|
+
mode="outlined"
|
|
293
|
+
autoCapitalize="characters"
|
|
294
|
+
placeholder=""
|
|
295
|
+
outlineColor={theme.colors.primary}
|
|
296
|
+
activeOutlineColor={theme.colors.primary}
|
|
297
|
+
style={styles.sessionCodeTextInput}
|
|
298
|
+
contentStyle={styles.sessionCodeInputWithText}
|
|
299
|
+
onChangeText={async (text) => {
|
|
300
|
+
const alphanumericText = text
|
|
301
|
+
.toUpperCase()
|
|
302
|
+
.replace(SESSION_CODE_CHARSET_PATTERN, '');
|
|
303
|
+
if (alphanumericText.length <= 8) {
|
|
304
|
+
setSessionCode(alphanumericText);
|
|
305
|
+
if (
|
|
306
|
+
validateSessionCode(alphanumericText) &&
|
|
307
|
+
alphanumericText.length === 8
|
|
308
|
+
) {
|
|
309
|
+
try {
|
|
310
|
+
setIsCheckingSession(true);
|
|
311
|
+
const session =
|
|
312
|
+
await getSessionByCode(alphanumericText);
|
|
313
|
+
if (session?.id) {
|
|
314
|
+
appContext.identificationInfo.sessionId =
|
|
315
|
+
session.id;
|
|
316
|
+
} else {
|
|
317
|
+
setSessionCode('');
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
setSessionCode('');
|
|
321
|
+
} finally {
|
|
322
|
+
setTimeout(() => {
|
|
323
|
+
setIsCheckingSession(false);
|
|
324
|
+
}, 1000);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}}
|
|
329
|
+
value={sessionCode.toUpperCase()}
|
|
330
|
+
maxLength={8}
|
|
331
|
+
/>
|
|
332
|
+
{!sessionCode && (
|
|
333
|
+
<Text style={styles.placeholderText}>
|
|
334
|
+
{t('verificationSessionCheckScreen.enterSessionCode')}
|
|
335
|
+
</Text>
|
|
310
336
|
)}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
337
|
+
</View>
|
|
338
|
+
<View style={styles.horizontalLineContainer}>
|
|
339
|
+
<View
|
|
340
|
+
style={[
|
|
341
|
+
styles.horizontalLine,
|
|
342
|
+
{ backgroundColor: theme.colors.primary },
|
|
343
|
+
]}
|
|
344
|
+
/>
|
|
345
|
+
<Text style={styles.mainText}>
|
|
346
|
+
{t('verificationSessionCheckScreen.or')}
|
|
347
|
+
</Text>
|
|
348
|
+
<View
|
|
349
|
+
style={[
|
|
350
|
+
styles.horizontalLine,
|
|
351
|
+
{ backgroundColor: theme.colors.primary },
|
|
352
|
+
]}
|
|
353
|
+
/>
|
|
354
|
+
</View>
|
|
355
|
+
<StyledButton
|
|
321
356
|
mode="contained"
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
setIsCheckingSession(true);
|
|
326
|
-
const sessions = await getSessions(emailOrPhone);
|
|
327
|
-
if (sessions && sessions.length > 0) {
|
|
328
|
-
appContext.identificationInfo.sessionId =
|
|
329
|
-
sessions[0].id;
|
|
330
|
-
}
|
|
331
|
-
} catch {
|
|
332
|
-
// Do nothing
|
|
333
|
-
} finally {
|
|
334
|
-
setTimeout(() => {
|
|
335
|
-
setIsCheckingSession(false);
|
|
336
|
-
setIsEnabled(false);
|
|
337
|
-
}, 1000);
|
|
338
|
-
}
|
|
357
|
+
onPress={() => {
|
|
358
|
+
navigation.navigate('QrCodeScanningScreen' as never);
|
|
339
359
|
}}
|
|
340
360
|
>
|
|
341
|
-
{t('verificationSessionCheckScreen.
|
|
342
|
-
</
|
|
343
|
-
{!isEnabled && (
|
|
344
|
-
<>
|
|
345
|
-
<View style={styles.horizontalLineContainer}>
|
|
346
|
-
<View style={styles.horizontalLine} />
|
|
347
|
-
<Text style={styles.mainText}>
|
|
348
|
-
{t('verificationSessionCheckScreen.or')}
|
|
349
|
-
</Text>
|
|
350
|
-
<View style={styles.horizontalLine} />
|
|
351
|
-
</View>
|
|
352
|
-
<Button
|
|
353
|
-
mode="contained"
|
|
354
|
-
onPress={() => {
|
|
355
|
-
navigation.navigate('QrCodeScanningScreen' as never);
|
|
356
|
-
}}
|
|
357
|
-
>
|
|
358
|
-
{t('verificationSessionCheckScreen.scanQRCode')}
|
|
359
|
-
</Button>
|
|
360
|
-
</>
|
|
361
|
-
)}
|
|
361
|
+
{t('verificationSessionCheckScreen.scanQRCode')}
|
|
362
|
+
</StyledButton>
|
|
362
363
|
</>
|
|
363
364
|
) : (
|
|
364
365
|
<>
|
|
365
366
|
<Text style={styles.mainText}>
|
|
366
367
|
{t('verificationSessionCheckScreen.codeText')}
|
|
367
368
|
</Text>
|
|
368
|
-
<
|
|
369
|
-
|
|
369
|
+
<TextInput
|
|
370
|
+
mode="outlined"
|
|
371
|
+
autoFocus={true}
|
|
372
|
+
placeholder=""
|
|
373
|
+
outlineColor={theme.colors.primary}
|
|
374
|
+
activeOutlineColor={theme.colors.primary}
|
|
375
|
+
style={styles.otpCodeTextInput}
|
|
376
|
+
contentStyle={styles.otpCodeInputWithText}
|
|
377
|
+
keyboardType="number-pad"
|
|
378
|
+
textContentType="oneTimeCode"
|
|
379
|
+
autoComplete="sms-otp"
|
|
380
|
+
maxLength={6}
|
|
370
381
|
onChangeText={(text) => {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
382
|
+
const numericText = text.replace(/[^0-9]/g, '');
|
|
383
|
+
if (numericText.length <= 6) {
|
|
384
|
+
setCode(numericText);
|
|
385
|
+
if (numericText.length === 6) {
|
|
386
|
+
(async () => {
|
|
387
|
+
setIsCodeGettingVerified(true);
|
|
388
|
+
const verifiedSession = await getVerifiedSession(
|
|
389
|
+
appContext.identificationInfo.sessionId,
|
|
390
|
+
numericText
|
|
391
|
+
);
|
|
392
|
+
if (verifiedSession?.identificationId) {
|
|
393
|
+
appContext.identificationInfo.identificationId =
|
|
394
|
+
verifiedSession?.identificationId;
|
|
395
|
+
setCode('');
|
|
396
|
+
setIsCodeSent(false);
|
|
397
|
+
navigationManagerRef.current?.navigateToNextStep();
|
|
398
|
+
} else {
|
|
399
|
+
appContext.onError?.('Invalid OTP code');
|
|
400
|
+
Alert.alert(
|
|
401
|
+
t('general.error'),
|
|
402
|
+
t('verificationSessionCheckScreen.codeError')
|
|
403
|
+
);
|
|
404
|
+
setCode('');
|
|
405
|
+
setIsCodeGettingVerified(false);
|
|
406
|
+
}
|
|
407
|
+
})();
|
|
408
|
+
}
|
|
394
409
|
}
|
|
395
410
|
}}
|
|
411
|
+
value={code}
|
|
396
412
|
/>
|
|
397
|
-
<
|
|
413
|
+
<StyledButton
|
|
398
414
|
mode="contained"
|
|
399
415
|
disabled={!isSendAgainEnabled}
|
|
400
416
|
onPress={() => {
|
|
401
|
-
|
|
417
|
+
sendOTPCode(appContext.identificationInfo.sessionId);
|
|
402
418
|
}}
|
|
403
419
|
>
|
|
404
420
|
{t('verificationSessionCheckScreen.sendCodeAgain')}
|
|
405
|
-
</
|
|
421
|
+
</StyledButton>
|
|
406
422
|
</>
|
|
407
423
|
)}
|
|
408
424
|
</View>
|
|
@@ -440,17 +456,15 @@ const styles = StyleSheet.create({
|
|
|
440
456
|
justifyContent: 'center',
|
|
441
457
|
},
|
|
442
458
|
horizontalLineContainer: {
|
|
443
|
-
display: 'flex',
|
|
444
459
|
flexDirection: 'row',
|
|
445
460
|
alignItems: 'center',
|
|
446
|
-
justifyContent: '
|
|
461
|
+
justifyContent: 'space-between',
|
|
447
462
|
gap: 10,
|
|
448
|
-
|
|
463
|
+
paddingVertical: 10,
|
|
449
464
|
},
|
|
450
465
|
horizontalLine: {
|
|
451
466
|
flex: 1,
|
|
452
|
-
height:
|
|
453
|
-
backgroundColor: '#aaa',
|
|
467
|
+
height: 2,
|
|
454
468
|
},
|
|
455
469
|
loadingAnimation: {
|
|
456
470
|
width: '100%',
|
|
@@ -519,6 +533,45 @@ const styles = StyleSheet.create({
|
|
|
519
533
|
alignItems: 'center',
|
|
520
534
|
position: 'absolute',
|
|
521
535
|
},
|
|
536
|
+
inputContainer: {
|
|
537
|
+
position: 'relative',
|
|
538
|
+
width: '100%',
|
|
539
|
+
},
|
|
540
|
+
sessionCodeTextInput: {
|
|
541
|
+
backgroundColor: 'white',
|
|
542
|
+
},
|
|
543
|
+
sessionCodeInputWithText: {
|
|
544
|
+
textTransform: 'uppercase',
|
|
545
|
+
fontWeight: '800',
|
|
546
|
+
fontSize: 28,
|
|
547
|
+
textAlign: 'center',
|
|
548
|
+
letterSpacing: 8,
|
|
549
|
+
},
|
|
550
|
+
placeholderText: {
|
|
551
|
+
position: 'absolute',
|
|
552
|
+
top: 0,
|
|
553
|
+
left: 0,
|
|
554
|
+
right: 0,
|
|
555
|
+
height: '100%',
|
|
556
|
+
lineHeight: 56,
|
|
557
|
+
fontSize: 16,
|
|
558
|
+
color: '#666',
|
|
559
|
+
textAlign: 'center',
|
|
560
|
+
pointerEvents: 'none',
|
|
561
|
+
},
|
|
562
|
+
sessionCodeInputPlaceholder: {
|
|
563
|
+
fontSize: 16,
|
|
564
|
+
textAlign: 'center',
|
|
565
|
+
},
|
|
566
|
+
otpCodeTextInput: {
|
|
567
|
+
backgroundColor: 'white',
|
|
568
|
+
},
|
|
569
|
+
otpCodeInputWithText: {
|
|
570
|
+
fontWeight: '800',
|
|
571
|
+
fontSize: 28,
|
|
572
|
+
textAlign: 'center',
|
|
573
|
+
letterSpacing: 8,
|
|
574
|
+
},
|
|
522
575
|
});
|
|
523
576
|
|
|
524
577
|
export default VerificationSessionCheckScreen;
|
|
@@ -7,7 +7,7 @@ import NativeProgressBar from './NativeProgressBar';
|
|
|
7
7
|
import type { FieldRecords } from 'mrz';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
import AppContext from '../Contexts/AppContext';
|
|
10
|
-
import
|
|
10
|
+
import StyledButton from './StyledButton';
|
|
11
11
|
import LottieView from 'lottie-react-native';
|
|
12
12
|
import { useKeepAwake } from '../Libs/native-keep-awake.utils';
|
|
13
13
|
import { speakWithDebounce } from '../Libs/tts.utils';
|
|
@@ -183,7 +183,7 @@ const EIDScanner = ({
|
|
|
183
183
|
{t('eidScannerScreen.guideText')}
|
|
184
184
|
</Text>
|
|
185
185
|
</View>
|
|
186
|
-
<
|
|
186
|
+
<StyledButton
|
|
187
187
|
mode="contained"
|
|
188
188
|
onPress={() => {
|
|
189
189
|
setHasGuideShown(true);
|
|
@@ -191,7 +191,7 @@ const EIDScanner = ({
|
|
|
191
191
|
}}
|
|
192
192
|
>
|
|
193
193
|
{t('eidScannerScreen.startScanning')}
|
|
194
|
-
</
|
|
194
|
+
</StyledButton>
|
|
195
195
|
</View>
|
|
196
196
|
) : (
|
|
197
197
|
<>
|
|
@@ -309,7 +309,7 @@ const EIDScanner = ({
|
|
|
309
309
|
<Text style={styles.mainText}>
|
|
310
310
|
{t('eidScannerScreen.nfcNotEnabled')}
|
|
311
311
|
</Text>
|
|
312
|
-
<
|
|
312
|
+
<StyledButton
|
|
313
313
|
mode="contained"
|
|
314
314
|
onPress={async () => {
|
|
315
315
|
await NFCManager.goToNfcSetting();
|
|
@@ -317,7 +317,7 @@ const EIDScanner = ({
|
|
|
317
317
|
}}
|
|
318
318
|
>
|
|
319
319
|
{t('eidScannerScreen.enableNFC')}
|
|
320
|
-
</
|
|
320
|
+
</StyledButton>
|
|
321
321
|
</View>
|
|
322
322
|
)}
|
|
323
323
|
|
|
@@ -368,7 +368,7 @@ const EIDScanner = ({
|
|
|
368
368
|
|
|
369
369
|
{hasNfc && isEnabled && isScanned && (
|
|
370
370
|
<View style={styles.buttonsContainer}>
|
|
371
|
-
<
|
|
371
|
+
<StyledButton
|
|
372
372
|
mode="contained"
|
|
373
373
|
disabled={!documentFaceImage || !documentMRZInfo}
|
|
374
374
|
onPress={() => {
|
|
@@ -387,7 +387,7 @@ const EIDScanner = ({
|
|
|
387
387
|
}}
|
|
388
388
|
>
|
|
389
389
|
{t('eidScannerScreen.approveAndContinue')}
|
|
390
|
-
</
|
|
390
|
+
</StyledButton>
|
|
391
391
|
</View>
|
|
392
392
|
)}
|
|
393
393
|
</>
|
|
@@ -28,7 +28,8 @@ import { Worklets, useSharedValue } from 'react-native-worklets-core';
|
|
|
28
28
|
import { crop } from '../VisionCameraPlugins/Cropper';
|
|
29
29
|
import { isFrameBright } from '../Libs/camera.utils';
|
|
30
30
|
import { useTranslation } from 'react-i18next';
|
|
31
|
-
import { ActivityIndicator
|
|
31
|
+
import { ActivityIndicator } from 'react-native-paper';
|
|
32
|
+
import StyledButton from './StyledButton';
|
|
32
33
|
|
|
33
34
|
export type FaceCameraProps = {
|
|
34
35
|
onFacesDetected: (
|
|
@@ -174,14 +175,14 @@ const FaceCamera = ({
|
|
|
174
175
|
<Text style={styles.permissionText}>
|
|
175
176
|
{t('general.noCameraPermissionGiven')}
|
|
176
177
|
</Text>
|
|
177
|
-
<
|
|
178
|
+
<StyledButton
|
|
178
179
|
mode="contained"
|
|
179
180
|
onPress={() => {
|
|
180
181
|
Linking.openSettings();
|
|
181
182
|
}}
|
|
182
183
|
>
|
|
183
184
|
{t('general.openSettings')}
|
|
184
|
-
</
|
|
185
|
+
</StyledButton>
|
|
185
186
|
</View>
|
|
186
187
|
);
|
|
187
188
|
}
|
|
@@ -192,14 +193,14 @@ const FaceCamera = ({
|
|
|
192
193
|
<Text style={styles.permissionText}>
|
|
193
194
|
{t('general.noMicrophonePermissionGiven')}
|
|
194
195
|
</Text>
|
|
195
|
-
<
|
|
196
|
+
<StyledButton
|
|
196
197
|
mode="contained"
|
|
197
198
|
onPress={() => {
|
|
198
199
|
Linking.openSettings();
|
|
199
200
|
}}
|
|
200
201
|
>
|
|
201
202
|
{t('general.openSettings')}
|
|
202
|
-
</
|
|
203
|
+
</StyledButton>
|
|
203
204
|
</View>
|
|
204
205
|
);
|
|
205
206
|
}
|
|
@@ -46,7 +46,8 @@ import {
|
|
|
46
46
|
import { getAverageBrightness } from '../Libs/camera.utils';
|
|
47
47
|
import { useTranslation } from 'react-i18next';
|
|
48
48
|
import LottieView from 'lottie-react-native';
|
|
49
|
-
import { ActivityIndicator
|
|
49
|
+
import { ActivityIndicator } from 'react-native-paper';
|
|
50
|
+
import StyledButton from './StyledButton';
|
|
50
51
|
import { type Barcode, scanCodes } from '../VisionCameraPlugins/BarcodeScanner';
|
|
51
52
|
import { speakWithDebounce } from '../Libs/tts.utils';
|
|
52
53
|
import AppContext from '../Contexts/AppContext';
|
|
@@ -981,14 +982,14 @@ const IdentityDocumentCamera = ({
|
|
|
981
982
|
<Text style={styles.permissionText}>
|
|
982
983
|
{t('general.noCameraPermissionGiven')}
|
|
983
984
|
</Text>
|
|
984
|
-
<
|
|
985
|
+
<StyledButton
|
|
985
986
|
mode="contained"
|
|
986
987
|
onPress={() => {
|
|
987
988
|
Linking.openSettings();
|
|
988
989
|
}}
|
|
989
990
|
>
|
|
990
991
|
{t('general.openSettings')}
|
|
991
|
-
</
|
|
992
|
+
</StyledButton>
|
|
992
993
|
</View>
|
|
993
994
|
);
|
|
994
995
|
}
|
|
@@ -1044,14 +1045,14 @@ const IdentityDocumentCamera = ({
|
|
|
1044
1045
|
• {t('identityDocumentCamera.guidePoint3')}
|
|
1045
1046
|
</TextView>
|
|
1046
1047
|
</View>
|
|
1047
|
-
<
|
|
1048
|
+
<StyledButton
|
|
1048
1049
|
mode="contained"
|
|
1049
1050
|
onPress={() => {
|
|
1050
1051
|
setHasGuideShown(true);
|
|
1051
1052
|
}}
|
|
1052
1053
|
>
|
|
1053
1054
|
{t('general.letsGo')}
|
|
1054
|
-
</
|
|
1055
|
+
</StyledButton>
|
|
1055
1056
|
</View>
|
|
1056
1057
|
) : (
|
|
1057
1058
|
<>
|
|
@@ -22,7 +22,7 @@ import { useIsFocused } from '@react-navigation/native';
|
|
|
22
22
|
import { useTranslation } from 'react-i18next';
|
|
23
23
|
import LottieView from 'lottie-react-native';
|
|
24
24
|
import { type Barcode, scanCodes } from '../VisionCameraPlugins/BarcodeScanner';
|
|
25
|
-
import
|
|
25
|
+
import StyledButton from './StyledButton';
|
|
26
26
|
|
|
27
27
|
export interface QrCodeScannerCameraProps {
|
|
28
28
|
onQrCodeScanned: (data: string) => void;
|
|
@@ -175,14 +175,14 @@ const QrCodeScannerCamera = ({ onQrCodeScanned }: QrCodeScannerCameraProps) => {
|
|
|
175
175
|
<Text style={styles.permissionText}>
|
|
176
176
|
{t('general.noCameraPermissionGiven')}
|
|
177
177
|
</Text>
|
|
178
|
-
<
|
|
178
|
+
<StyledButton
|
|
179
179
|
mode="contained"
|
|
180
180
|
onPress={() => {
|
|
181
181
|
Linking.openSettings();
|
|
182
182
|
}}
|
|
183
183
|
>
|
|
184
184
|
{t('general.openSettings')}
|
|
185
|
-
</
|
|
185
|
+
</StyledButton>
|
|
186
186
|
</View>
|
|
187
187
|
);
|
|
188
188
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
import { Button } from 'react-native-paper';
|
|
4
|
+
import type { ButtonProps } from 'react-native-paper';
|
|
5
|
+
|
|
6
|
+
type StyledButtonProps = ButtonProps;
|
|
7
|
+
|
|
8
|
+
const StyledButton: React.FC<StyledButtonProps> = ({
|
|
9
|
+
style,
|
|
10
|
+
labelStyle,
|
|
11
|
+
...props
|
|
12
|
+
}) => {
|
|
13
|
+
return (
|
|
14
|
+
<Button
|
|
15
|
+
{...props}
|
|
16
|
+
style={[styles.button, style]}
|
|
17
|
+
labelStyle={[styles.label, labelStyle]}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const styles = StyleSheet.create({
|
|
23
|
+
button: {
|
|
24
|
+
borderRadius: 8,
|
|
25
|
+
height: 56,
|
|
26
|
+
justifyContent: 'center',
|
|
27
|
+
elevation: 2,
|
|
28
|
+
},
|
|
29
|
+
label: {
|
|
30
|
+
fontWeight: 'bold',
|
|
31
|
+
fontSize: 16,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default StyledButton;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './validation.constants';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation constants used throughout the SDK.
|
|
3
|
+
* These constants ensure consistency between frontend and backend validation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Character set for session codes.
|
|
8
|
+
* Excludes ambiguous characters (0, 1, I, O) to prevent confusion.
|
|
9
|
+
*/
|
|
10
|
+
export const SESSION_CODE_CHARSET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Regular expression pattern for validating session code characters.
|
|
14
|
+
* Matches only characters from SESSION_CODE_CHARSET.
|
|
15
|
+
*/
|
|
16
|
+
export const SESSION_CODE_CHARSET_PATTERN =
|
|
17
|
+
/[^ABCDEFGHJKLMNPQRSTUVWXYZ23456789]/g;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Regular expression for validating complete session codes.
|
|
21
|
+
* Session codes must be exactly 8 characters from SESSION_CODE_CHARSET.
|
|
22
|
+
*/
|
|
23
|
+
export const SESSION_CODE_VALIDATION_PATTERN =
|
|
24
|
+
/^[ABCDEFGHJKLMNPQRSTUVWXYZ23456789]{8}$/;
|