@transfergratis/react-native-sdk 0.1.24 → 0.1.26
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/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
- package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
- package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
- package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
- package/android/src/main/AndroidManifest.xml +22 -7
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +76 -21
- package/build/components/EnhancedCameraView.web.js.map +1 -1
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js +212 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +216 -14
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js +2 -2
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +7 -3
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/WelcomeTemplate.js +2 -1
- package/build/components/KYCElements/WelcomeTemplate.js.map +1 -1
- package/build/components/OverLay/type.d.ts +2 -0
- package/build/components/OverLay/type.d.ts.map +1 -1
- package/build/components/OverLay/type.js.map +1 -1
- package/build/components/TemplateKYCExample.d.ts +10 -0
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +7 -30
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +12 -0
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +25 -3
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/config/KYCConfig.d.ts +14 -0
- package/build/config/KYCConfig.d.ts.map +1 -0
- package/build/config/KYCConfig.js +26 -0
- package/build/config/KYCConfig.js.map +1 -0
- package/build/config/allowedDomains.d.ts.map +1 -1
- package/build/config/allowedDomains.js +4 -19
- package/build/config/allowedDomains.js.map +1 -1
- package/build/hooks/useOrientationVideo.d.ts +2 -1
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +3 -3
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.d.ts +18 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +410 -56
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +42 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +44 -2
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +28 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +30 -2
- package/build/i18n/fr/index.js.map +1 -1
- package/build/i18n/types.d.ts +2 -0
- package/build/i18n/types.d.ts.map +1 -1
- package/build/i18n/types.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts +24 -3
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +90 -12
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +17 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +125 -37
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -1
- package/build/modules/api/SelfieVerification.d.ts.map +1 -1
- package/build/modules/api/SelfieVerification.js +17 -1
- package/build/modules/api/SelfieVerification.js.map +1 -1
- package/build/modules/api/TemplateService.d.ts +0 -1
- package/build/modules/api/TemplateService.d.ts.map +1 -1
- package/build/modules/api/TemplateService.js +3 -3
- package/build/modules/api/TemplateService.js.map +1 -1
- package/build/modules/camera/VisionCameraModule.web.d.ts.map +1 -1
- package/build/modules/camera/VisionCameraModule.web.js +27 -8
- package/build/modules/camera/VisionCameraModule.web.js.map +1 -1
- package/build/types/KYC.types.d.ts +130 -5
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js.map +1 -1
- package/build/types/env.types.d.ts +13 -0
- package/build/types/env.types.d.ts.map +1 -0
- package/build/types/env.types.js +2 -0
- package/build/types/env.types.js.map +1 -0
- package/build/utils/cropByObb.d.ts +7 -0
- package/build/utils/cropByObb.d.ts.map +1 -1
- package/build/utils/cropByObb.js +20 -1
- package/build/utils/cropByObb.js.map +1 -1
- package/build/utils/deviceDetection.d.ts +6 -0
- package/build/utils/deviceDetection.d.ts.map +1 -0
- package/build/utils/deviceDetection.js +12 -0
- package/build/utils/deviceDetection.js.map +1 -0
- package/build/utils/platformAlert.d.ts.map +1 -1
- package/build/utils/platformAlert.js.map +1 -1
- package/build/utils/template-transformer.d.ts.map +1 -1
- package/build/utils/template-transformer.js +12 -0
- package/build/utils/template-transformer.js.map +1 -1
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +88 -38
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/index.d.ts +1 -0
- package/plugin/build/index.js +3 -1
- package/plugin/build/withRemovePermissions.d.ts +3 -0
- package/plugin/build/withRemovePermissions.js +67 -0
- package/plugin/build/withVisionCamera.js +3 -4
- package/plugin/src/index.ts +2 -1
- package/plugin/src/withRemovePermissions.js +85 -0
- package/plugin/src/withRemovePermissions.ts +83 -0
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/plugin.js +6 -1
- package/src/components/EnhancedCameraView.web.tsx +76 -21
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +278 -0
- package/src/components/KYCElements/IDCardCapture.tsx +253 -21
- package/src/components/KYCElements/OrientationVideoCapture.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +4 -1
- package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +6 -3
- package/src/components/KYCElements/WelcomeTemplate.tsx +2 -1
- package/src/components/OverLay/type.ts +2 -0
- package/src/components/TemplateKYCExample.tsx +35 -46
- package/src/components/TemplateKYCFlowRefactored.tsx +46 -2
- package/src/config/KYCConfig.ts +34 -0
- package/src/config/allowedDomains.ts +7 -26
- package/src/hooks/useOrientationVideo.ts +5 -4
- package/src/hooks/useTemplateKYCFlow.tsx +443 -56
- package/src/i18n/en/index.ts +46 -3
- package/src/i18n/fr/index.ts +31 -2
- package/src/i18n/types.ts +2 -0
- package/src/index.ts +3 -0
- package/src/modules/api/CardAuthentification.ts +98 -12
- package/src/modules/api/KYCService.ts +158 -37
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +4 -4
- package/src/modules/camera/VisionCameraModule.web.ts +30 -12
- package/src/types/KYC.types.ts +153 -6
- package/src/types/env.types.ts +13 -0
- package/src/utils/cropByObb.ts +20 -1
- package/src/utils/deviceDetection.ts +11 -0
- package/src/utils/platformAlert.ts +1 -0
- package/src/utils/template-transformer.ts +20 -8
- package/src/web/WebKYCEntry.tsx +123 -61
|
@@ -11,6 +11,7 @@ import { showAlert } from '../../utils/platformAlert';
|
|
|
11
11
|
import Svg, { Rect, Path, Mask, Defs } from 'react-native-svg';
|
|
12
12
|
import { Camera, useCameraDevice } from 'react-native-vision-camera';
|
|
13
13
|
import { OrientationVideoConfig, OrientationVideoState } from '../../types/KYC.types';
|
|
14
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
14
15
|
import kycService from '../../modules/api/KYCService';
|
|
15
16
|
import VisionCameraModule from '../../modules/camera/VisionCameraModule';
|
|
16
17
|
import SideSelfieIcon from '../Svgs/sideSelfieIcon';
|
|
@@ -20,6 +21,7 @@ interface OrientationVideoCaptureProps {
|
|
|
20
21
|
onComplete: (result: any) => void;
|
|
21
22
|
onError: (error: string) => void;
|
|
22
23
|
kycService: typeof kycService;
|
|
24
|
+
env?: KycEnvironment;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
const defaultConfig: OrientationVideoConfig = {
|
|
@@ -42,6 +44,7 @@ export const OrientationVideoCapture: React.FC<OrientationVideoCaptureProps> = (
|
|
|
42
44
|
onComplete,
|
|
43
45
|
onError,
|
|
44
46
|
kycService,
|
|
47
|
+
env = 'PRODUCTION',
|
|
45
48
|
}) => {
|
|
46
49
|
const finalConfig = { ...defaultConfig, ...config };
|
|
47
50
|
|
|
@@ -174,7 +177,7 @@ export const OrientationVideoCapture: React.FC<OrientationVideoCaptureProps> = (
|
|
|
174
177
|
setState(prev => ({ ...prev, isProcessing: true, error: null }));
|
|
175
178
|
|
|
176
179
|
try {
|
|
177
|
-
const result = await kycService.processOrientationVideo(videoUri);
|
|
180
|
+
const result = await kycService.processOrientationVideo(videoUri, env);
|
|
178
181
|
|
|
179
182
|
if (result.success && result.data) {
|
|
180
183
|
setState(prev => ({
|
|
@@ -12,6 +12,7 @@ import { showAlert } from '../../utils/platformAlert';
|
|
|
12
12
|
import Svg, { Rect, Path, Mask, Defs } from 'react-native-svg';
|
|
13
13
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
14
14
|
import { OrientationVideoConfig, OrientationVideoState } from '../../types/KYC.types';
|
|
15
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
15
16
|
import kycService from '../../modules/api/KYCService';
|
|
16
17
|
import FrontSelfieIcon from '../Svgs/frontSelfieIcon';
|
|
17
18
|
import ScanningLine from '../Svgs/scanningLine';
|
|
@@ -21,6 +22,7 @@ interface OrientationVideoCaptureEnhancedProps {
|
|
|
21
22
|
onComplete: (result: any) => void;
|
|
22
23
|
onError: (error: string) => void;
|
|
23
24
|
kycService: typeof kycService;
|
|
25
|
+
env?: KycEnvironment;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
const defaultConfig: OrientationVideoConfig = {
|
|
@@ -43,6 +45,7 @@ export const OrientationVideoCaptureEnhanced: React.FC<OrientationVideoCaptureEn
|
|
|
43
45
|
onComplete,
|
|
44
46
|
onError,
|
|
45
47
|
kycService,
|
|
48
|
+
env = 'PRODUCTION',
|
|
46
49
|
}) => {
|
|
47
50
|
const finalConfig = { ...defaultConfig, ...config };
|
|
48
51
|
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
|
@@ -153,7 +156,7 @@ export const OrientationVideoCaptureEnhanced: React.FC<OrientationVideoCaptureEn
|
|
|
153
156
|
setState(prev => ({ ...prev, isProcessing: true, error: null }));
|
|
154
157
|
|
|
155
158
|
try {
|
|
156
|
-
const result = await kycService.processOrientationVideo(videoUri);
|
|
159
|
+
const result = await kycService.processOrientationVideo(videoUri, env);
|
|
157
160
|
|
|
158
161
|
if (result.success && result.data) {
|
|
159
162
|
setState(prev => ({
|
|
@@ -11,6 +11,7 @@ import { showAlert } from '../../utils/platformAlert';
|
|
|
11
11
|
import Svg, { Rect, Path, Mask, Defs } from 'react-native-svg';
|
|
12
12
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
13
13
|
import { OrientationVideoConfig, OrientationVideoState } from '../../types/KYC.types';
|
|
14
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
14
15
|
import SideSelfieIcon from '../Svgs/sideSelfieIcon';
|
|
15
16
|
import kycService from '../../modules/api/KYCService';
|
|
16
17
|
|
|
@@ -19,6 +20,7 @@ interface OrientationVideoCaptureFinalProps {
|
|
|
19
20
|
onComplete: (result: any) => void;
|
|
20
21
|
onError: (error: string) => void;
|
|
21
22
|
kycService: typeof kycService;
|
|
23
|
+
env?: KycEnvironment;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const defaultConfig: OrientationVideoConfig = {
|
|
@@ -41,6 +43,7 @@ export const OrientationVideoCaptureFinal: React.FC<OrientationVideoCaptureFinal
|
|
|
41
43
|
onComplete,
|
|
42
44
|
onError,
|
|
43
45
|
kycService,
|
|
46
|
+
env = 'PRODUCTION',
|
|
44
47
|
}) => {
|
|
45
48
|
const finalConfig = { ...defaultConfig, ...config };
|
|
46
49
|
|
|
@@ -127,7 +130,7 @@ export const OrientationVideoCaptureFinal: React.FC<OrientationVideoCaptureFinal
|
|
|
127
130
|
setState(prev => ({ ...prev, isProcessing: true, error: null }));
|
|
128
131
|
|
|
129
132
|
try {
|
|
130
|
-
const result = await kycService.processOrientationVideo(videoUri);
|
|
133
|
+
const result = await kycService.processOrientationVideo(videoUri, env);
|
|
131
134
|
|
|
132
135
|
if (result.success && result.data) {
|
|
133
136
|
setState(prev => ({
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, TextInput, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
|
3
|
+
import { TemplateComponent, PersonalInformationConfig, LocalizedText } from '../../types/KYC.types';
|
|
4
|
+
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
5
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
6
|
+
import { Button } from '../ui/Button';
|
|
7
|
+
|
|
8
|
+
interface PersonalInformationTemplateProps {
|
|
9
|
+
component: TemplateComponent;
|
|
10
|
+
value?: any;
|
|
11
|
+
onValueChange: (data: any) => void;
|
|
12
|
+
error?: string;
|
|
13
|
+
language?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const PersonalInformationTemplate: React.FC<PersonalInformationTemplateProps> = ({
|
|
17
|
+
component,
|
|
18
|
+
value,
|
|
19
|
+
onValueChange,
|
|
20
|
+
error,
|
|
21
|
+
}) => {
|
|
22
|
+
const { actions, getLocalizedText } = useTemplateKYCFlowContext();
|
|
23
|
+
const { t } = useI18n();
|
|
24
|
+
const config = component.config as PersonalInformationConfig;
|
|
25
|
+
const [formData, setFormData] = useState<Record<string, string>>({});
|
|
26
|
+
|
|
27
|
+
const title = getLocalizedText(component.labels as LocalizedText);
|
|
28
|
+
const instructions = getLocalizedText(component.instructions as LocalizedText);
|
|
29
|
+
const buttonText = getLocalizedText((component.ui as any).buttonText) || t('common.submit');
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (value) {
|
|
33
|
+
setFormData(value);
|
|
34
|
+
}
|
|
35
|
+
}, [value]);
|
|
36
|
+
|
|
37
|
+
const handleChange = (fieldId: string, text: string) => {
|
|
38
|
+
const newData = { ...formData, [fieldId]: text };
|
|
39
|
+
setFormData(newData);
|
|
40
|
+
onValueChange(newData);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleCreate = () => {
|
|
44
|
+
actions.nextComponent();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const isFormValid = () => {
|
|
48
|
+
if (!config.fields) return true;
|
|
49
|
+
return config.fields.every(field => {
|
|
50
|
+
if (field.required && !formData[field.id]) return false;
|
|
51
|
+
return true;
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<KeyboardAvoidingView
|
|
57
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
58
|
+
style={styles.keyboardAvoidingView}
|
|
59
|
+
>
|
|
60
|
+
<ScrollView contentContainerStyle={styles.scrollContainer} showsVerticalScrollIndicator={false}>
|
|
61
|
+
<View style={styles.container}>
|
|
62
|
+
<Text style={styles.title}>{title}</Text>
|
|
63
|
+
<Text style={styles.instructions}>{instructions}</Text>
|
|
64
|
+
|
|
65
|
+
<View style={styles.formContainer}>
|
|
66
|
+
{config.fields && config.fields.map((field) => (
|
|
67
|
+
<View key={field.id} style={styles.fieldContainer}>
|
|
68
|
+
<Text style={styles.label}>
|
|
69
|
+
{field.label} {field.type === 'date' && field.dateFormat ? `(${field.dateFormat})` : ''} {field.required && '*'}
|
|
70
|
+
</Text>
|
|
71
|
+
<TextInput
|
|
72
|
+
style={styles.input}
|
|
73
|
+
placeholder={field.placeholder || field.label}
|
|
74
|
+
value={formData[field.id] || ''}
|
|
75
|
+
onChangeText={(text) => handleChange(field.id, text)}
|
|
76
|
+
autoCapitalize="words"
|
|
77
|
+
/>
|
|
78
|
+
</View>
|
|
79
|
+
))}
|
|
80
|
+
</View>
|
|
81
|
+
|
|
82
|
+
{error && <Text style={styles.errorText}>{error}</Text>}
|
|
83
|
+
|
|
84
|
+
<Button
|
|
85
|
+
title={buttonText}
|
|
86
|
+
onPress={handleCreate}
|
|
87
|
+
fullWidth
|
|
88
|
+
style={styles.button}
|
|
89
|
+
disabled={!isFormValid()}
|
|
90
|
+
/>
|
|
91
|
+
</View>
|
|
92
|
+
</ScrollView>
|
|
93
|
+
</KeyboardAvoidingView>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const styles = StyleSheet.create({
|
|
98
|
+
keyboardAvoidingView: {
|
|
99
|
+
flex: 1,
|
|
100
|
+
width: '100%',
|
|
101
|
+
},
|
|
102
|
+
scrollContainer: {
|
|
103
|
+
flexGrow: 1,
|
|
104
|
+
justifyContent: 'center',
|
|
105
|
+
paddingBottom: 20,
|
|
106
|
+
},
|
|
107
|
+
container: {
|
|
108
|
+
padding: 20,
|
|
109
|
+
backgroundColor: 'white',
|
|
110
|
+
borderRadius: 12,
|
|
111
|
+
margin: 16,
|
|
112
|
+
shadowColor: '#000',
|
|
113
|
+
shadowOffset: { width: 0, height: 2 },
|
|
114
|
+
shadowOpacity: 0.1,
|
|
115
|
+
shadowRadius: 4,
|
|
116
|
+
elevation: 3,
|
|
117
|
+
width: '95%',
|
|
118
|
+
},
|
|
119
|
+
title: {
|
|
120
|
+
fontSize: 22,
|
|
121
|
+
fontWeight: 'bold',
|
|
122
|
+
marginBottom: 10,
|
|
123
|
+
color: '#333',
|
|
124
|
+
},
|
|
125
|
+
instructions: {
|
|
126
|
+
fontSize: 16,
|
|
127
|
+
color: '#666',
|
|
128
|
+
marginBottom: 20,
|
|
129
|
+
lineHeight: 22,
|
|
130
|
+
},
|
|
131
|
+
formContainer: {
|
|
132
|
+
marginBottom: 20,
|
|
133
|
+
},
|
|
134
|
+
fieldContainer: {
|
|
135
|
+
marginBottom: 16,
|
|
136
|
+
},
|
|
137
|
+
label: {
|
|
138
|
+
fontSize: 14,
|
|
139
|
+
fontWeight: '600',
|
|
140
|
+
color: '#333',
|
|
141
|
+
marginBottom: 6,
|
|
142
|
+
},
|
|
143
|
+
input: {
|
|
144
|
+
borderWidth: 1,
|
|
145
|
+
borderColor: '#ddd',
|
|
146
|
+
padding: 12,
|
|
147
|
+
borderRadius: 8,
|
|
148
|
+
fontSize: 16,
|
|
149
|
+
backgroundColor: '#f9f9f9',
|
|
150
|
+
},
|
|
151
|
+
errorText: {
|
|
152
|
+
color: 'red',
|
|
153
|
+
marginBottom: 10,
|
|
154
|
+
},
|
|
155
|
+
button: {
|
|
156
|
+
marginTop: 10,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert } from 'react-native';
|
|
3
|
+
import { TemplateComponent, LocalizedText } from '../../types/KYC.types';
|
|
4
|
+
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
5
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
6
|
+
import { Button } from '../ui/Button';
|
|
7
|
+
|
|
8
|
+
interface PhoneVerificationTemplateProps {
|
|
9
|
+
component: TemplateComponent;
|
|
10
|
+
value?: any;
|
|
11
|
+
onValueChange: (data: any) => void;
|
|
12
|
+
error?: string;
|
|
13
|
+
language?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type VerificationStep = 'phone' | 'otp';
|
|
17
|
+
|
|
18
|
+
export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps> = ({
|
|
19
|
+
component,
|
|
20
|
+
value,
|
|
21
|
+
onValueChange,
|
|
22
|
+
error: propError,
|
|
23
|
+
}) => {
|
|
24
|
+
const { actions, getLocalizedText } = useTemplateKYCFlowContext();
|
|
25
|
+
const { t } = useI18n();
|
|
26
|
+
// const config = component.config as PhoneVerificationConfig;
|
|
27
|
+
|
|
28
|
+
// State
|
|
29
|
+
const [step, setStep] = useState<VerificationStep>('phone');
|
|
30
|
+
const [phone, setPhone] = useState('');
|
|
31
|
+
const [otp, setOtp] = useState('');
|
|
32
|
+
const [localError, setLocalError] = useState<string | null>(null);
|
|
33
|
+
const [isSimulating, setIsSimulating] = useState(false);
|
|
34
|
+
|
|
35
|
+
const title = getLocalizedText(component.labels as LocalizedText);
|
|
36
|
+
const instructions = getLocalizedText(component.instructions as LocalizedText);
|
|
37
|
+
|
|
38
|
+
// Determine button text based on step
|
|
39
|
+
const verifyButtonText = getLocalizedText((component.ui as any).buttonText) || t('common.verify') || 'Verify';
|
|
40
|
+
const sendButtonText = t('common.sendCode') || 'Send Verification Code';
|
|
41
|
+
const buttonText = step === 'phone' ? sendButtonText : verifyButtonText;
|
|
42
|
+
|
|
43
|
+
const handleSendCode = () => {
|
|
44
|
+
if (!phone || phone.length < 5) {
|
|
45
|
+
setLocalError(t('errors.invalidPhone') || 'Please enter a valid phone number');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setLocalError(null);
|
|
50
|
+
setIsSimulating(true);
|
|
51
|
+
|
|
52
|
+
// Simulate API call to send code
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
setIsSimulating(false);
|
|
55
|
+
setStep('otp');
|
|
56
|
+
}, 1500);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleVerifyCode = () => {
|
|
60
|
+
if (!otp || otp.length < 4) {
|
|
61
|
+
setLocalError(t('errors.invalidCode') || 'Please enter the 6-digit code');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setLocalError(null);
|
|
66
|
+
setIsSimulating(true);
|
|
67
|
+
|
|
68
|
+
// Simulate verification API
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
setIsSimulating(false);
|
|
71
|
+
|
|
72
|
+
// Mock validation logic
|
|
73
|
+
if (otp === '123456') {
|
|
74
|
+
onValueChange({ phone, otp, verified: true });
|
|
75
|
+
actions.nextComponent();
|
|
76
|
+
} else {
|
|
77
|
+
setLocalError(t('errors.wrongCode') || 'Invalid verification code. Try 123456');
|
|
78
|
+
}
|
|
79
|
+
}, 1500);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const onChangePhone = (text: string) => {
|
|
83
|
+
setPhone(text);
|
|
84
|
+
if (localError) setLocalError(null);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const onChangeOtp = (text: string) => {
|
|
88
|
+
setOtp(text);
|
|
89
|
+
if (localError) setLocalError(null);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const handleBackToPhone = () => {
|
|
93
|
+
setStep('phone');
|
|
94
|
+
setOtp('');
|
|
95
|
+
setLocalError(null);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<View style={styles.container}>
|
|
100
|
+
<Text style={styles.title}>{title}</Text>
|
|
101
|
+
<Text style={styles.instructions}>
|
|
102
|
+
{step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${phone}`)}
|
|
103
|
+
</Text>
|
|
104
|
+
|
|
105
|
+
<View style={styles.contentContainer}>
|
|
106
|
+
{step === 'phone' ? (
|
|
107
|
+
<View style={styles.inputContainer}>
|
|
108
|
+
<Text style={styles.label}>{t('common.phone') || 'Phone Number'}</Text>
|
|
109
|
+
<TextInput
|
|
110
|
+
style={styles.input}
|
|
111
|
+
placeholder="+1234567890"
|
|
112
|
+
value={phone}
|
|
113
|
+
onChangeText={onChangePhone}
|
|
114
|
+
keyboardType="phone-pad"
|
|
115
|
+
autoComplete="tel"
|
|
116
|
+
editable={!isSimulating}
|
|
117
|
+
/>
|
|
118
|
+
</View>
|
|
119
|
+
) : (
|
|
120
|
+
<View style={styles.inputContainer}>
|
|
121
|
+
<Text style={styles.label}>{t('common.verificationCode') || 'Verification Code'}</Text>
|
|
122
|
+
<TextInput
|
|
123
|
+
style={styles.input}
|
|
124
|
+
placeholder="123456"
|
|
125
|
+
value={otp}
|
|
126
|
+
onChangeText={onChangeOtp}
|
|
127
|
+
keyboardType="number-pad"
|
|
128
|
+
maxLength={6}
|
|
129
|
+
editable={!isSimulating}
|
|
130
|
+
/>
|
|
131
|
+
<TouchableOpacity onPress={handleBackToPhone} style={styles.changeLink}>
|
|
132
|
+
<Text style={styles.changeText}>{t('common.back') || 'Change number'}</Text>
|
|
133
|
+
</TouchableOpacity>
|
|
134
|
+
</View>
|
|
135
|
+
)}
|
|
136
|
+
|
|
137
|
+
{(localError || propError) && (
|
|
138
|
+
<Text style={styles.errorText}>{localError || propError}</Text>
|
|
139
|
+
)}
|
|
140
|
+
|
|
141
|
+
<Button
|
|
142
|
+
title={isSimulating ? (t('common.processing') || 'Processing...') : buttonText}
|
|
143
|
+
onPress={step === 'phone' ? handleSendCode : handleVerifyCode}
|
|
144
|
+
style={styles.button}
|
|
145
|
+
disabled={
|
|
146
|
+
isSimulating ||
|
|
147
|
+
(step === 'phone' ? !phone : !otp)
|
|
148
|
+
}
|
|
149
|
+
/>
|
|
150
|
+
|
|
151
|
+
{step === 'otp' && (
|
|
152
|
+
<TouchableOpacity
|
|
153
|
+
onPress={() => {
|
|
154
|
+
// Resend logic
|
|
155
|
+
Alert.alert(
|
|
156
|
+
t('common.codeResent') || 'Code Resent',
|
|
157
|
+
t('common.codeResentMessage', { email: phone }) || 'Code resent to ' + phone
|
|
158
|
+
);
|
|
159
|
+
}}
|
|
160
|
+
style={styles.resendButton}
|
|
161
|
+
disabled={isSimulating}
|
|
162
|
+
>
|
|
163
|
+
<Text style={styles.resendText}>{t('common.resendCode') || 'Resend Code'}</Text>
|
|
164
|
+
</TouchableOpacity>
|
|
165
|
+
)}
|
|
166
|
+
</View>
|
|
167
|
+
</View>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const styles = StyleSheet.create({
|
|
172
|
+
container: {
|
|
173
|
+
padding: 24,
|
|
174
|
+
backgroundColor: 'white',
|
|
175
|
+
borderRadius: 16,
|
|
176
|
+
margin: 16,
|
|
177
|
+
shadowColor: '#000',
|
|
178
|
+
shadowOffset: { width: 0, height: 4 },
|
|
179
|
+
shadowOpacity: 0.1,
|
|
180
|
+
shadowRadius: 12,
|
|
181
|
+
elevation: 5,
|
|
182
|
+
width: '95%',
|
|
183
|
+
},
|
|
184
|
+
title: {
|
|
185
|
+
fontSize: 24,
|
|
186
|
+
fontWeight: '700',
|
|
187
|
+
marginBottom: 8,
|
|
188
|
+
color: '#1a1a1a',
|
|
189
|
+
textAlign: 'center',
|
|
190
|
+
},
|
|
191
|
+
instructions: {
|
|
192
|
+
fontSize: 16,
|
|
193
|
+
color: '#666',
|
|
194
|
+
marginBottom: 32,
|
|
195
|
+
lineHeight: 24,
|
|
196
|
+
textAlign: 'center',
|
|
197
|
+
},
|
|
198
|
+
contentContainer: {
|
|
199
|
+
// width: '100%',
|
|
200
|
+
},
|
|
201
|
+
inputContainer: {
|
|
202
|
+
marginBottom: 24,
|
|
203
|
+
},
|
|
204
|
+
label: {
|
|
205
|
+
fontSize: 14,
|
|
206
|
+
fontWeight: '600',
|
|
207
|
+
color: '#333',
|
|
208
|
+
marginBottom: 8,
|
|
209
|
+
marginLeft: 4,
|
|
210
|
+
},
|
|
211
|
+
input: {
|
|
212
|
+
borderWidth: 1,
|
|
213
|
+
borderColor: '#e0e0e0',
|
|
214
|
+
padding: 16,
|
|
215
|
+
borderRadius: 12,
|
|
216
|
+
fontSize: 16,
|
|
217
|
+
backgroundColor: '#f8f9fa',
|
|
218
|
+
color: '#333',
|
|
219
|
+
},
|
|
220
|
+
errorText: {
|
|
221
|
+
color: '#dc2626',
|
|
222
|
+
marginBottom: 16,
|
|
223
|
+
fontSize: 14,
|
|
224
|
+
textAlign: 'center',
|
|
225
|
+
backgroundColor: '#fee2e2',
|
|
226
|
+
padding: 8,
|
|
227
|
+
borderRadius: 8,
|
|
228
|
+
overflow: 'hidden',
|
|
229
|
+
},
|
|
230
|
+
button: {
|
|
231
|
+
height: 50,
|
|
232
|
+
borderRadius: 12,
|
|
233
|
+
width: "100%"
|
|
234
|
+
},
|
|
235
|
+
changeLink: {
|
|
236
|
+
alignSelf: 'flex-end',
|
|
237
|
+
marginTop: 8,
|
|
238
|
+
},
|
|
239
|
+
changeText: {
|
|
240
|
+
color: '#2DBD60',
|
|
241
|
+
fontSize: 14,
|
|
242
|
+
fontWeight: '500',
|
|
243
|
+
},
|
|
244
|
+
resendButton: {
|
|
245
|
+
marginTop: 16,
|
|
246
|
+
alignItems: 'center',
|
|
247
|
+
},
|
|
248
|
+
resendText: {
|
|
249
|
+
color: '#666',
|
|
250
|
+
fontSize: 14,
|
|
251
|
+
textDecorationLine: 'underline',
|
|
252
|
+
},
|
|
253
|
+
});
|
|
@@ -33,7 +33,7 @@ export const SelfieCaptureTemplate: React.FC<SelfieCaptureTemplateProps> = ({
|
|
|
33
33
|
const { t } = useI18n();
|
|
34
34
|
// const config = component.config as SelfieConfig;
|
|
35
35
|
const orientations: OrientationType[] = (['center','left','right']) as OrientationType[];
|
|
36
|
-
const { actions, state, } = useTemplateKYCFlowContext();
|
|
36
|
+
const { actions, state, env } = useTemplateKYCFlowContext();
|
|
37
37
|
|
|
38
38
|
const [silentCaptureResult, setSilentCaptureResult] = useState<ISilentCaptureResult>({ success: false, isAnalyzing: false });
|
|
39
39
|
|
|
@@ -152,10 +152,13 @@ export const SelfieCaptureTemplate: React.FC<SelfieCaptureTemplateProps> = ({
|
|
|
152
152
|
}
|
|
153
153
|
if (result.success && result.path) {
|
|
154
154
|
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: true, success: false, error: '' }));
|
|
155
|
-
selfieVerification(result.path).then((response) => {
|
|
155
|
+
selfieVerification(result.path, env).then((response) => {
|
|
156
156
|
if (response.length > 0) {
|
|
157
157
|
const res = response[0];
|
|
158
|
-
|
|
158
|
+
// In SANDBOX mode, always accept the result regardless of orientation
|
|
159
|
+
if (env === 'SANDBOX' && res?.capture) {
|
|
160
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: true, error: '', path: result.path }));
|
|
161
|
+
} else if (res?.orientation_direction === getOrientationOpposite(currentOrientation) && res?.capture) {
|
|
159
162
|
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: true, error: '', path: result.path }));
|
|
160
163
|
} else {
|
|
161
164
|
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: 'Le selfie n\'est pas correct' }));
|
|
@@ -150,7 +150,7 @@ export const WelcomeTemplate: React.FC<WelcomeTemplateProps> = ({
|
|
|
150
150
|
|
|
151
151
|
{/* Get Started Button */}
|
|
152
152
|
<Button
|
|
153
|
-
title={buttonText}
|
|
153
|
+
title={buttonText?.length === 0 ? t('kyc.welcome.getStarted') || 'Get Started' : buttonText}
|
|
154
154
|
fullWidth
|
|
155
155
|
onPress={handleGetStarted}
|
|
156
156
|
style={{ paddingVertical: 20, marginTop: 36 }}
|
|
@@ -175,6 +175,7 @@ const styles = StyleSheet.create({
|
|
|
175
175
|
shadowRadius: 1.84,
|
|
176
176
|
elevation: 3,
|
|
177
177
|
maxWidth: 760,
|
|
178
|
+
width: '94%',
|
|
178
179
|
},
|
|
179
180
|
title: {
|
|
180
181
|
fontSize: 24,
|
|
@@ -81,6 +81,8 @@ export interface EnhancedCameraViewProps {
|
|
|
81
81
|
onVideoRecordingStart?: () => void;
|
|
82
82
|
onVideoRecordingStop?: (result: { success: boolean; path?: string; error?: string }) => void;
|
|
83
83
|
videoDuration?: number;
|
|
84
|
+
/** Delay in ms before first auto-capture (lets camera focus and user position document). Recommended 2500–3000 for ID/document capture. */
|
|
85
|
+
captureStabilizationDelayMs?: number;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
export interface CheckTemplateTypeResponse {
|
|
@@ -2,8 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import { View, SafeAreaView } from 'react-native';
|
|
3
3
|
import { TemplateKYCFlow } from './TemplateKYCFlowRefactored';
|
|
4
4
|
import { KYCTemplate, VerificationState } from '../types/KYC.types';
|
|
5
|
+
import { KycEnvironment, BackendEnvironment } from '../types/env.types';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
|
|
6
|
-
// Template JSON basé sur votre exemple
|
|
7
10
|
const advancedVerificationTemplate: KYCTemplate = {
|
|
8
11
|
id: 1,
|
|
9
12
|
name: {
|
|
@@ -103,7 +106,7 @@ const advancedVerificationTemplate: KYCTemplate = {
|
|
|
103
106
|
allowed_formats: ["jpg", "png"],
|
|
104
107
|
max_size_mb: 5,
|
|
105
108
|
document_types: ["drivers_licence", "passport", "drivers_licence", "national_id"],
|
|
106
|
-
|
|
109
|
+
|
|
107
110
|
} as const
|
|
108
111
|
},
|
|
109
112
|
{
|
|
@@ -130,42 +133,23 @@ const advancedVerificationTemplate: KYCTemplate = {
|
|
|
130
133
|
orientations: ["center", "left", "right"]
|
|
131
134
|
} as const
|
|
132
135
|
},
|
|
133
|
-
// {
|
|
134
|
-
// id: 4,
|
|
135
|
-
// type: "file_upload" as const,
|
|
136
|
-
// order: 6,
|
|
137
|
-
// labels: {
|
|
138
|
-
// en: "Upload proof of address",
|
|
139
|
-
// fr: "Téléversez un justificatif de domicile"
|
|
140
|
-
// },
|
|
141
|
-
// instructions: {
|
|
142
|
-
// en: "Upload a recent utility bill or bank statement (PDF, JPG, PNG).",
|
|
143
|
-
// fr: "Téléversez une facture récente ou un relevé bancaire (PDF, JPG, PNG)."
|
|
144
|
-
// },
|
|
145
|
-
// ui: {
|
|
146
|
-
// icon: "file-upload-icon.png",
|
|
147
|
-
// themeColor: "#2DBD60",
|
|
148
|
-
// buttonText: { en: "Upload", fr: "Téléverser" }
|
|
149
|
-
// },
|
|
150
|
-
// config: {
|
|
151
|
-
// allowed_formats: ["pdf", "jpg", "png"],
|
|
152
|
-
// max_size_mb: 10,
|
|
153
|
-
// required: true
|
|
154
|
-
// } as const
|
|
155
|
-
// },
|
|
156
|
-
|
|
157
136
|
]
|
|
158
137
|
};
|
|
159
138
|
|
|
160
|
-
export const TemplateKYCExample: React.FC<{
|
|
161
|
-
onComplete: (data: VerificationState) => void;
|
|
162
|
-
onCancel: () => void;
|
|
163
|
-
onError: (error: string) => void;
|
|
164
|
-
language: string;
|
|
139
|
+
export const TemplateKYCExample: React.FC<{
|
|
140
|
+
onComplete: (data: VerificationState) => void;
|
|
141
|
+
onCancel: () => void;
|
|
142
|
+
onError: (error: string) => void;
|
|
143
|
+
language: string;
|
|
165
144
|
API_KEY?: string;
|
|
166
145
|
templateId?: string;
|
|
167
146
|
template?: KYCTemplate;
|
|
168
|
-
|
|
147
|
+
env?: KycEnvironment; // Flow execution: PRODUCTION (full AI) or SANDBOX (skip AI)
|
|
148
|
+
serverEnv?: BackendEnvironment; // Backend to call: PRODUCTION or TEST (API URL)
|
|
149
|
+
existingSessionId?: string;
|
|
150
|
+
initialComponentIndex?: number;
|
|
151
|
+
initialCountryResume?: { code: string; documentType: string; region?: string };
|
|
152
|
+
}> = ({ onComplete, onCancel, onError, language, API_KEY, templateId, template, env = 'PRODUCTION', serverEnv, existingSessionId, initialComponentIndex, initialCountryResume }) => {
|
|
169
153
|
const handleComplete = (data: VerificationState) => {
|
|
170
154
|
console.log('KYC Template completed with data:', data);
|
|
171
155
|
onComplete(data);
|
|
@@ -182,24 +166,29 @@ export const TemplateKYCExample: React.FC<{
|
|
|
182
166
|
onError(error);
|
|
183
167
|
};
|
|
184
168
|
|
|
169
|
+
// Transform backend template to SDK format
|
|
185
170
|
// Determine which template to use: prefer templateId for dynamic loading, then template prop, then fallback to hardcoded
|
|
186
171
|
const templateToUse = templateId ? undefined : (template || advancedVerificationTemplate);
|
|
187
172
|
|
|
188
173
|
return (
|
|
189
|
-
<SafeAreaView style={{ flex: 1
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
174
|
+
<SafeAreaView style={{ flex: 1, paddingVertical: 25 }}>
|
|
175
|
+
<View style={{ flex: 1 }}>
|
|
176
|
+
<TemplateKYCFlow
|
|
177
|
+
template={templateToUse}
|
|
178
|
+
templateId={templateId}
|
|
179
|
+
onComplete={handleComplete}
|
|
180
|
+
onError={handleError}
|
|
181
|
+
onCancel={handleCancel}
|
|
182
|
+
language={language} // ou "en" pour l'anglais
|
|
183
|
+
API_KEY={API_KEY}
|
|
184
|
+
env={env}
|
|
185
|
+
serverEnv={serverEnv}
|
|
186
|
+
existingSessionId={existingSessionId}
|
|
187
|
+
initialComponentIndex={initialComponentIndex}
|
|
188
|
+
initialCountryResume={initialCountryResume}
|
|
189
|
+
/>
|
|
190
|
+
</View>
|
|
191
|
+
</SafeAreaView>
|
|
202
192
|
);
|
|
203
193
|
};
|
|
204
194
|
|
|
205
|
-
|