omnipay-reactnative-sdk 1.2.2-beta.9 → 1.2.3-beta.10
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/README.md +58 -48
- package/android/build.gradle +4 -7
- package/android/src/main/AndroidManifest.xml +0 -5
- package/android/src/main/java/com/omniretail/omnipay/FaceVerificationFrameProcessor.kt +111 -0
- package/android/src/main/java/com/omniretail/omnipay/OmnipayActivityPackage.java +6 -4
- package/ios/FaceVerificationFrameProcessor.swift +138 -0
- package/ios/FaceVerificationFrameProcessorPlugin.m +4 -0
- package/ios/OmnipayReactnativeSdk.m +5 -0
- package/ios/OmnipayReactnativeSdk.swift +10 -0
- package/ios/omnipay_reactnative_sdk.h +6 -0
- package/lib/commonjs/components/Button.js +68 -0
- package/lib/commonjs/components/Button.js.map +1 -0
- package/lib/commonjs/components/OmnipayProvider.js +7 -23
- package/lib/commonjs/components/OmnipayProvider.js.map +1 -1
- package/lib/commonjs/components/biometrics/FaceVerification.js +294 -270
- package/lib/commonjs/components/biometrics/FaceVerification.js.map +1 -1
- package/lib/commonjs/components/biometrics/useFaceVerification.js +85 -0
- package/lib/commonjs/components/biometrics/useFaceVerification.js.map +1 -0
- package/lib/commonjs/components/biometrics/useFaceVerificationFlow.js +157 -0
- package/lib/commonjs/components/biometrics/useFaceVerificationFlow.js.map +1 -0
- package/lib/commonjs/index.js +0 -33
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/Button.js +61 -0
- package/lib/module/components/Button.js.map +1 -0
- package/lib/module/components/OmnipayProvider.js +7 -23
- package/lib/module/components/OmnipayProvider.js.map +1 -1
- package/lib/module/components/biometrics/FaceVerification.js +294 -271
- package/lib/module/components/biometrics/FaceVerification.js.map +1 -1
- package/lib/module/components/biometrics/useFaceVerification.js +78 -0
- package/lib/module/components/biometrics/useFaceVerification.js.map +1 -0
- package/lib/module/components/biometrics/useFaceVerificationFlow.js +150 -0
- package/lib/module/components/biometrics/useFaceVerificationFlow.js.map +1 -0
- package/lib/module/index.js +0 -6
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/components/Button.d.ts +17 -0
- package/lib/typescript/components/Button.d.ts.map +1 -0
- package/lib/typescript/components/OmnipayProvider.d.ts.map +1 -1
- package/lib/typescript/components/biometrics/FaceVerification.d.ts +1 -3
- package/lib/typescript/components/biometrics/FaceVerification.d.ts.map +1 -1
- package/lib/typescript/components/biometrics/useFaceVerification.d.ts +38 -0
- package/lib/typescript/components/biometrics/useFaceVerification.d.ts.map +1 -0
- package/lib/typescript/components/biometrics/useFaceVerificationFlow.d.ts +29 -0
- package/lib/typescript/components/biometrics/useFaceVerificationFlow.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +0 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/omnipay_reactnative_sdk.podspec +46 -0
- package/package.json +5 -8
- package/src/components/Button.tsx +86 -0
- package/src/components/OmnipayProvider.tsx +7 -24
- package/src/components/biometrics/FaceVerification.tsx +315 -309
- package/src/components/biometrics/useFaceVerification.ts +120 -0
- package/src/components/biometrics/useFaceVerificationFlow.ts +224 -0
- package/src/index.tsx +0 -7
- package/android/src/main/java/com/omniretail/omnipay/OmnipayLivenessCameraView.java +0 -153
- package/android/src/main/java/com/omniretail/omnipay/OmnipayLivenessCameraViewManager.java +0 -49
- package/android/src/main/java/com/omniretail/omnipay/OmnipayLivenessModule.java +0 -557
- package/ios/OmnipayLivenessCameraView.h +0 -15
- package/ios/OmnipayLivenessCameraView.m +0 -80
- package/ios/OmnipayLivenessCameraViewManager.m +0 -19
- package/ios/OmnipayLivenessModule.h +0 -38
- package/ios/OmnipayLivenessModule.m +0 -615
- package/lib/commonjs/components/biometrics/LivenessDetection.js +0 -149
- package/lib/commonjs/components/biometrics/LivenessDetection.js.map +0 -1
- package/lib/commonjs/components/biometrics/OmnipayLivenessCameraView.js +0 -15
- package/lib/commonjs/components/biometrics/OmnipayLivenessCameraView.js.map +0 -1
- package/lib/commonjs/components/biometrics/PermissionManager.js +0 -279
- package/lib/commonjs/components/biometrics/PermissionManager.js.map +0 -1
- package/lib/commonjs/components/biometrics/index.js +0 -45
- package/lib/commonjs/components/biometrics/index.js.map +0 -1
- package/lib/commonjs/components/biometrics/types.js +0 -17
- package/lib/commonjs/components/biometrics/types.js.map +0 -1
- package/lib/module/components/biometrics/LivenessDetection.js +0 -129
- package/lib/module/components/biometrics/LivenessDetection.js.map +0 -1
- package/lib/module/components/biometrics/OmnipayLivenessCameraView.js +0 -7
- package/lib/module/components/biometrics/OmnipayLivenessCameraView.js.map +0 -1
- package/lib/module/components/biometrics/PermissionManager.js +0 -272
- package/lib/module/components/biometrics/PermissionManager.js.map +0 -1
- package/lib/module/components/biometrics/index.js +0 -12
- package/lib/module/components/biometrics/index.js.map +0 -1
- package/lib/module/components/biometrics/types.js +0 -16
- package/lib/module/components/biometrics/types.js.map +0 -1
- package/lib/typescript/components/biometrics/LivenessDetection.d.ts +0 -33
- package/lib/typescript/components/biometrics/LivenessDetection.d.ts.map +0 -1
- package/lib/typescript/components/biometrics/OmnipayLivenessCameraView.d.ts +0 -18
- package/lib/typescript/components/biometrics/OmnipayLivenessCameraView.d.ts.map +0 -1
- package/lib/typescript/components/biometrics/PermissionManager.d.ts +0 -58
- package/lib/typescript/components/biometrics/PermissionManager.d.ts.map +0 -1
- package/lib/typescript/components/biometrics/index.d.ts +0 -5
- package/lib/typescript/components/biometrics/index.d.ts.map +0 -1
- package/lib/typescript/components/biometrics/types.d.ts +0 -73
- package/lib/typescript/components/biometrics/types.d.ts.map +0 -1
- package/omnipay-reactnative-sdk.podspec +0 -50
- package/src/components/biometrics/LivenessDetection.ts +0 -178
- package/src/components/biometrics/OmnipayLivenessCameraView.tsx +0 -19
- package/src/components/biometrics/PermissionManager.ts +0 -317
- package/src/components/biometrics/index.ts +0 -11
- package/src/components/biometrics/types.ts +0 -86
|
@@ -3,209 +3,161 @@ import {
|
|
|
3
3
|
View,
|
|
4
4
|
Modal,
|
|
5
5
|
Dimensions,
|
|
6
|
+
Platform,
|
|
6
7
|
StyleSheet,
|
|
7
8
|
TouchableOpacity,
|
|
8
9
|
Image,
|
|
9
10
|
Text,
|
|
10
|
-
ActivityIndicator,
|
|
11
11
|
} from 'react-native';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
import {
|
|
13
|
+
Camera,
|
|
14
|
+
useCameraDevice,
|
|
15
|
+
useCameraPermission,
|
|
16
|
+
} from 'react-native-vision-camera';
|
|
17
|
+
import Button from '../Button';
|
|
18
|
+
import { useFaceVerification } from './useFaceVerification';
|
|
19
|
+
import { useFaceVerificationFlow } from './useFaceVerificationFlow';
|
|
16
20
|
|
|
17
21
|
type FaceVerificationProps = {
|
|
18
22
|
onClose: () => void;
|
|
19
|
-
onSuccess: (
|
|
23
|
+
onSuccess: () => void;
|
|
20
24
|
primaryColor: string;
|
|
21
|
-
config?: Partial<LivenessConfig>;
|
|
22
25
|
};
|
|
23
26
|
|
|
24
|
-
type DetectionState =
|
|
25
|
-
| 'initializing'
|
|
26
|
-
| 'starting'
|
|
27
|
-
| 'running'
|
|
28
|
-
| 'completed'
|
|
29
|
-
| 'failed';
|
|
30
|
-
|
|
31
27
|
const FaceVerification: React.FC<FaceVerificationProps> = ({
|
|
32
28
|
onClose,
|
|
33
29
|
onSuccess,
|
|
34
30
|
primaryColor,
|
|
35
|
-
config,
|
|
36
31
|
}) => {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const [
|
|
40
|
-
const [currentChallenge, setCurrentChallenge] =
|
|
41
|
-
useState<LivenessChallenge | null>(null);
|
|
42
|
-
const [challengeProgress, setChallengeProgress] = useState<string>('');
|
|
32
|
+
const device = useCameraDevice('front');
|
|
33
|
+
const { hasPermission, requestPermission } = useCameraPermission();
|
|
34
|
+
const [isRequestingPermission, setIsRequestingPermission] = useState(false);
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
console.log('🔍 Starting liveness detection initialization...');
|
|
36
|
+
// Face verification flow
|
|
37
|
+
const {
|
|
38
|
+
state: flowState,
|
|
39
|
+
resetFlow,
|
|
40
|
+
isCompleted,
|
|
41
|
+
isFailed,
|
|
42
|
+
} = useFaceVerificationFlow();
|
|
52
43
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const permissionResponse =
|
|
56
|
-
await CameraPermissionManager.requestCameraPermission();
|
|
44
|
+
// Frame processor
|
|
45
|
+
const frameProcessor = useFaceVerification();
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
: 'Camera permission is required for face verification.'
|
|
65
|
-
);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
console.log('✅ Camera permission granted');
|
|
70
|
-
|
|
71
|
-
// Step 2: Check device support (hardware/framework capability)
|
|
72
|
-
console.log('🔍 Checking device capabilities...');
|
|
73
|
-
const supported = await LivenessDetection.isSupported();
|
|
74
|
-
console.log('📱 Device support result:', supported);
|
|
75
|
-
|
|
76
|
-
setIsSupported(supported);
|
|
77
|
-
if (supported) {
|
|
78
|
-
console.log('✅ Device supports liveness detection, starting...');
|
|
79
|
-
await startDetection();
|
|
80
|
-
} else {
|
|
81
|
-
console.log('❌ Device does not support liveness detection');
|
|
82
|
-
setState('failed');
|
|
83
|
-
setError('Liveness detection is not supported on this device');
|
|
84
|
-
}
|
|
85
|
-
} catch (err) {
|
|
86
|
-
console.error('💥 Error during initialization:', err);
|
|
87
|
-
setState('failed');
|
|
88
|
-
setError('Failed to initialize liveness detection');
|
|
47
|
+
// Handle completion
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (isCompleted) {
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
onSuccess();
|
|
52
|
+
}, 1000); // Show success message briefly
|
|
89
53
|
}
|
|
90
|
-
};
|
|
54
|
+
}, [isCompleted, onSuccess]);
|
|
91
55
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
56
|
+
const handleRequestPermission = async () => {
|
|
57
|
+
setIsRequestingPermission(true);
|
|
58
|
+
try {
|
|
59
|
+
await requestPermission();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Error requesting camera permission:', error);
|
|
62
|
+
} finally {
|
|
63
|
+
setIsRequestingPermission(false);
|
|
95
64
|
}
|
|
65
|
+
};
|
|
96
66
|
|
|
97
|
-
|
|
98
|
-
|
|
67
|
+
const renderPermissionRequest = () => (
|
|
68
|
+
<View style={styles.permissionContainer}>
|
|
69
|
+
<View style={styles.permissionIconContainer}>
|
|
70
|
+
<Text style={styles.permissionIcon}>📷</Text>
|
|
71
|
+
</View>
|
|
72
|
+
<Text style={styles.permissionTitle}>Camera Permission Required</Text>
|
|
73
|
+
<Text style={styles.permissionDescription}>
|
|
74
|
+
To verify your identity, we need access to your camera. This allows us
|
|
75
|
+
to capture your face for secure verification.
|
|
76
|
+
</Text>
|
|
77
|
+
<Button
|
|
78
|
+
title="Allow Camera Access"
|
|
79
|
+
onPress={handleRequestPermission}
|
|
80
|
+
backgroundColor={primaryColor}
|
|
81
|
+
loading={isRequestingPermission}
|
|
82
|
+
/>
|
|
83
|
+
</View>
|
|
84
|
+
);
|
|
99
85
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
const renderNoDevice = () => (
|
|
87
|
+
<View style={styles.errorContainer}>
|
|
88
|
+
<Text style={styles.errorTitle}>Camera Not Available</Text>
|
|
89
|
+
<Text style={styles.errorSubtitle}>
|
|
90
|
+
No front camera detected on this device. Face verification requires a
|
|
91
|
+
front-facing camera.
|
|
92
|
+
</Text>
|
|
93
|
+
</View>
|
|
94
|
+
);
|
|
103
95
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
...config,
|
|
107
|
-
};
|
|
96
|
+
const renderCamera = () => {
|
|
97
|
+
if (!device) return null;
|
|
108
98
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
},
|
|
120
|
-
onChallengeFailure: (challenge, reason) => {
|
|
121
|
-
setError(`Failed: ${reason}, ${challenge}`);
|
|
122
|
-
},
|
|
123
|
-
onAllChallengesComplete: () => {
|
|
124
|
-
setChallengeProgress(
|
|
125
|
-
'All challenges completed! Taking final photo...'
|
|
126
|
-
);
|
|
127
|
-
},
|
|
128
|
-
onScreenshotCaptured: (_screenshot) => {
|
|
129
|
-
// Screenshot captured, detection will complete soon
|
|
130
|
-
},
|
|
131
|
-
onDetectionFailed: (reason) => {
|
|
132
|
-
setError(reason);
|
|
133
|
-
setState('failed');
|
|
134
|
-
},
|
|
135
|
-
});
|
|
99
|
+
return (
|
|
100
|
+
<View style={styles.cameraContainer}>
|
|
101
|
+
<Camera
|
|
102
|
+
device={device}
|
|
103
|
+
style={styles.camera}
|
|
104
|
+
isActive={true}
|
|
105
|
+
frameProcessor={frameProcessor}
|
|
106
|
+
/>
|
|
107
|
+
<View style={styles.cameraOverlay}>
|
|
108
|
+
<View style={styles.faceFrame} />
|
|
136
109
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
};
|
|
110
|
+
{/* Progress indicator */}
|
|
111
|
+
<View style={styles.progressContainer}>
|
|
112
|
+
<View
|
|
113
|
+
style={[
|
|
114
|
+
styles.progressBar,
|
|
115
|
+
{
|
|
116
|
+
width: `${flowState.progress}%`,
|
|
117
|
+
backgroundColor: primaryColor,
|
|
118
|
+
},
|
|
119
|
+
]}
|
|
120
|
+
/>
|
|
121
|
+
</View>
|
|
151
122
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
case LivenessChallenge.SMILE:
|
|
155
|
-
return 'Please smile';
|
|
156
|
-
case LivenessChallenge.BLINK:
|
|
157
|
-
return 'Please blink';
|
|
158
|
-
case LivenessChallenge.TURN_LEFT:
|
|
159
|
-
return 'Please turn your head left';
|
|
160
|
-
case LivenessChallenge.TURN_RIGHT:
|
|
161
|
-
return 'Please turn your head right';
|
|
162
|
-
default:
|
|
163
|
-
return 'Follow the instruction';
|
|
164
|
-
}
|
|
165
|
-
};
|
|
123
|
+
{/* Current instruction */}
|
|
124
|
+
<Text style={styles.instructionText}>{flowState.instruction}</Text>
|
|
166
125
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
case 'starting':
|
|
172
|
-
return 'Starting face verification...';
|
|
173
|
-
case 'running':
|
|
174
|
-
return challengeProgress || 'Look at the camera';
|
|
175
|
-
case 'completed':
|
|
176
|
-
return 'Face verification completed!';
|
|
177
|
-
case 'failed':
|
|
178
|
-
return error || 'Face verification failed';
|
|
179
|
-
default:
|
|
180
|
-
return 'Please wait...';
|
|
181
|
-
}
|
|
182
|
-
};
|
|
126
|
+
{/* Step indicator */}
|
|
127
|
+
<Text style={styles.stepIndicator}>
|
|
128
|
+
Step {flowState.completedSteps.length + 1} of 5
|
|
129
|
+
</Text>
|
|
183
130
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
};
|
|
131
|
+
{/* Success/Failure messages */}
|
|
132
|
+
{isCompleted && (
|
|
133
|
+
<View
|
|
134
|
+
style={[
|
|
135
|
+
styles.statusContainer,
|
|
136
|
+
{ backgroundColor: primaryColor },
|
|
137
|
+
]}
|
|
138
|
+
>
|
|
139
|
+
<Text style={styles.statusText}>✓ Verification Complete!</Text>
|
|
140
|
+
</View>
|
|
141
|
+
)}
|
|
196
142
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
143
|
+
{isFailed && (
|
|
144
|
+
<View style={[styles.statusContainer, styles.statusContainerError]}>
|
|
145
|
+
<Text style={styles.statusText}>✗ Verification Failed</Text>
|
|
146
|
+
<Button
|
|
147
|
+
title="Try Again"
|
|
148
|
+
onPress={resetFlow}
|
|
149
|
+
backgroundColor="white"
|
|
150
|
+
textColor="#ff4444"
|
|
151
|
+
style={styles.retryButton}
|
|
152
|
+
/>
|
|
153
|
+
</View>
|
|
154
|
+
)}
|
|
155
|
+
</View>
|
|
156
|
+
</View>
|
|
157
|
+
);
|
|
203
158
|
};
|
|
204
159
|
|
|
205
|
-
|
|
206
|
-
state === 'failed' &&
|
|
207
|
-
error !==
|
|
208
|
-
'Camera permission is blocked. Please enable it in device settings.';
|
|
160
|
+
console.log(onSuccess, primaryColor);
|
|
209
161
|
|
|
210
162
|
return (
|
|
211
163
|
<Modal
|
|
@@ -217,7 +169,7 @@ const FaceVerification: React.FC<FaceVerificationProps> = ({
|
|
|
217
169
|
<TouchableOpacity
|
|
218
170
|
style={styles.backdrop}
|
|
219
171
|
activeOpacity={1}
|
|
220
|
-
onPress={
|
|
172
|
+
onPress={onClose}
|
|
221
173
|
>
|
|
222
174
|
<View style={[styles.container]}>
|
|
223
175
|
<TouchableOpacity style={styles.close} onPress={onClose}>
|
|
@@ -226,61 +178,10 @@ const FaceVerification: React.FC<FaceVerificationProps> = ({
|
|
|
226
178
|
style={styles.closeIcon}
|
|
227
179
|
/>
|
|
228
180
|
</TouchableOpacity>
|
|
229
|
-
|
|
230
181
|
<View style={styles.contentContainer}>
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
{
|
|
234
|
-
<View style={styles.cameraContainer}>
|
|
235
|
-
{state === 'running' && isSupported ? (
|
|
236
|
-
<OmnipayLivenessCameraView style={styles.camera} />
|
|
237
|
-
) : (
|
|
238
|
-
<View style={[styles.camera, styles.cameraPlaceholder]}>
|
|
239
|
-
{state === 'initializing' || state === 'starting' ? (
|
|
240
|
-
<ActivityIndicator size="large" color={primaryColor} />
|
|
241
|
-
) : state === 'completed' ? (
|
|
242
|
-
<View style={styles.successIcon}>
|
|
243
|
-
<Text style={styles.successText}>✓</Text>
|
|
244
|
-
</View>
|
|
245
|
-
) : (
|
|
246
|
-
<View style={styles.errorIcon}>
|
|
247
|
-
<Text style={styles.errorText}>!</Text>
|
|
248
|
-
</View>
|
|
249
|
-
)}
|
|
250
|
-
</View>
|
|
251
|
-
)}
|
|
252
|
-
|
|
253
|
-
{/* Overlay with instructions */}
|
|
254
|
-
<View style={styles.overlay}>
|
|
255
|
-
<Text style={[styles.instruction, { color: getStateColor() }]}>
|
|
256
|
-
{getStateMessage()}
|
|
257
|
-
</Text>
|
|
258
|
-
</View>
|
|
259
|
-
</View>
|
|
260
|
-
|
|
261
|
-
{/* Progress indicator for challenges */}
|
|
262
|
-
{state === 'running' && currentChallenge && (
|
|
263
|
-
<View style={styles.progressContainer}>
|
|
264
|
-
<Text style={styles.challengeText}>
|
|
265
|
-
{getChallengeInstruction(currentChallenge)}
|
|
266
|
-
</Text>
|
|
267
|
-
</View>
|
|
268
|
-
)}
|
|
269
|
-
|
|
270
|
-
{/* Action buttons */}
|
|
271
|
-
<View style={styles.buttonContainer}>
|
|
272
|
-
{showRetryButton && (
|
|
273
|
-
<TouchableOpacity
|
|
274
|
-
style={[
|
|
275
|
-
styles.retryButton,
|
|
276
|
-
{ backgroundColor: primaryColor },
|
|
277
|
-
]}
|
|
278
|
-
onPress={handleRetry}
|
|
279
|
-
>
|
|
280
|
-
<Text style={styles.retryButtonText}>Try Again</Text>
|
|
281
|
-
</TouchableOpacity>
|
|
282
|
-
)}
|
|
283
|
-
</View>
|
|
182
|
+
{!hasPermission && renderPermissionRequest()}
|
|
183
|
+
{hasPermission && !device && renderNoDevice()}
|
|
184
|
+
{hasPermission && device && renderCamera()}
|
|
284
185
|
</View>
|
|
285
186
|
</View>
|
|
286
187
|
</TouchableOpacity>
|
|
@@ -288,136 +189,241 @@ const FaceVerification: React.FC<FaceVerificationProps> = ({
|
|
|
288
189
|
);
|
|
289
190
|
};
|
|
290
191
|
|
|
291
|
-
|
|
192
|
+
export default FaceVerification;
|
|
292
193
|
|
|
293
194
|
const styles = StyleSheet.create({
|
|
294
|
-
|
|
295
|
-
|
|
195
|
+
hide: {
|
|
196
|
+
display: 'none',
|
|
296
197
|
},
|
|
297
|
-
|
|
198
|
+
full: {
|
|
298
199
|
flex: 1,
|
|
299
|
-
|
|
300
|
-
|
|
200
|
+
width: '100%',
|
|
201
|
+
height: '100%',
|
|
202
|
+
},
|
|
203
|
+
webview: {
|
|
204
|
+
flex: 1,
|
|
205
|
+
width: '100%',
|
|
206
|
+
height: Dimensions.get('window').height - 40,
|
|
207
|
+
backgroundColor: 'white',
|
|
208
|
+
borderTopRightRadius: 20,
|
|
209
|
+
borderTopLeftRadius: 20,
|
|
210
|
+
paddingTop: 150,
|
|
211
|
+
},
|
|
212
|
+
webviewLoader: {
|
|
213
|
+
zIndex: 3,
|
|
214
|
+
backgroundColor: 'white',
|
|
301
215
|
alignItems: 'center',
|
|
216
|
+
justifyContent: 'center',
|
|
217
|
+
flex: 1,
|
|
218
|
+
width: '100%',
|
|
219
|
+
height: '100%',
|
|
220
|
+
position: 'absolute',
|
|
221
|
+
top: 0,
|
|
222
|
+
left: 0,
|
|
223
|
+
borderTopRightRadius: 20,
|
|
224
|
+
borderTopLeftRadius: 20,
|
|
225
|
+
},
|
|
226
|
+
backdrop: {
|
|
227
|
+
backgroundColor: 'rgba(0,0,0,0.3)',
|
|
228
|
+
flex: 1,
|
|
229
|
+
justifyContent: 'flex-end',
|
|
230
|
+
position: 'relative',
|
|
231
|
+
height: '100%',
|
|
302
232
|
},
|
|
303
233
|
container: {
|
|
304
|
-
width: screenWidth * 0.9,
|
|
305
|
-
maxHeight: screenHeight * 0.8,
|
|
306
234
|
backgroundColor: 'white',
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
235
|
+
borderTopRightRadius: 20,
|
|
236
|
+
borderTopLeftRadius: 20,
|
|
237
|
+
maxHeight: Dimensions.get('window').height - 120,
|
|
238
|
+
flex: 1,
|
|
239
|
+
position: 'relative',
|
|
240
|
+
...(Platform.OS === 'android' && { overflow: 'hidden' }),
|
|
241
|
+
},
|
|
242
|
+
modal: {
|
|
243
|
+
flex: 1,
|
|
244
|
+
backgroundColor: 'rgba(0,0,0,0.48)',
|
|
245
|
+
height: '100%',
|
|
246
|
+
width: '100%',
|
|
310
247
|
},
|
|
311
248
|
close: {
|
|
312
249
|
position: 'absolute',
|
|
313
|
-
top:
|
|
314
|
-
right:
|
|
315
|
-
|
|
316
|
-
|
|
250
|
+
top: 10,
|
|
251
|
+
right: 10,
|
|
252
|
+
backgroundColor: 'white',
|
|
253
|
+
height: 24,
|
|
254
|
+
width: 24,
|
|
255
|
+
borderRadius: 1000,
|
|
256
|
+
alignItems: 'center',
|
|
257
|
+
justifyContent: 'center',
|
|
258
|
+
zIndex: 2,
|
|
317
259
|
},
|
|
318
260
|
closeIcon: {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
tintColor: '#666',
|
|
261
|
+
height: 12,
|
|
262
|
+
width: 12,
|
|
322
263
|
},
|
|
323
264
|
contentContainer: {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
265
|
+
height: '100%',
|
|
266
|
+
position: 'relative',
|
|
267
|
+
borderTopRightRadius: 20,
|
|
268
|
+
borderTopLeftRadius: 20,
|
|
269
|
+
padding: 16,
|
|
327
270
|
},
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
color: '#333',
|
|
332
|
-
marginBottom: 20,
|
|
333
|
-
textAlign: 'center',
|
|
271
|
+
testContent: {
|
|
272
|
+
paddingTop: 30,
|
|
273
|
+
paddingLeft: 16,
|
|
334
274
|
},
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
275
|
+
testTwoContent: {
|
|
276
|
+
paddingTop: 10,
|
|
277
|
+
paddingLeft: 16,
|
|
278
|
+
},
|
|
279
|
+
errorSubtitle: {
|
|
280
|
+
textAlign: 'center',
|
|
281
|
+
fontSize: 14,
|
|
282
|
+
color: '#5e7079',
|
|
342
283
|
marginBottom: 20,
|
|
284
|
+
paddingHorizontal: 8,
|
|
285
|
+
marginTop: 14,
|
|
343
286
|
},
|
|
344
|
-
|
|
287
|
+
errorContainer: {
|
|
345
288
|
flex: 1,
|
|
289
|
+
justifyContent: 'center',
|
|
290
|
+
alignItems: 'center',
|
|
291
|
+
width: Dimensions.get('window').width,
|
|
292
|
+
height: Dimensions.get('window').height,
|
|
293
|
+
zIndex: 2,
|
|
294
|
+
backgroundColor: 'white',
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
camera: {
|
|
346
298
|
width: '100%',
|
|
347
|
-
height:
|
|
299
|
+
height: 400,
|
|
348
300
|
},
|
|
349
|
-
|
|
301
|
+
// Permission request styles
|
|
302
|
+
permissionContainer: {
|
|
303
|
+
flex: 1,
|
|
350
304
|
justifyContent: 'center',
|
|
351
305
|
alignItems: 'center',
|
|
352
|
-
|
|
306
|
+
paddingHorizontal: 24,
|
|
307
|
+
paddingVertical: 40,
|
|
353
308
|
},
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
padding: 15,
|
|
309
|
+
permissionIconContainer: {
|
|
310
|
+
width: 80,
|
|
311
|
+
height: 80,
|
|
312
|
+
borderRadius: 40,
|
|
313
|
+
backgroundColor: '#f0f0f0',
|
|
314
|
+
justifyContent: 'center',
|
|
361
315
|
alignItems: 'center',
|
|
316
|
+
marginBottom: 24,
|
|
362
317
|
},
|
|
363
|
-
|
|
364
|
-
fontSize:
|
|
318
|
+
permissionIcon: {
|
|
319
|
+
fontSize: 40,
|
|
320
|
+
},
|
|
321
|
+
permissionTitle: {
|
|
322
|
+
fontSize: 20,
|
|
365
323
|
fontWeight: '600',
|
|
324
|
+
color: '#1a1a1a',
|
|
366
325
|
textAlign: 'center',
|
|
367
|
-
|
|
326
|
+
marginBottom: 12,
|
|
368
327
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
328
|
+
permissionDescription: {
|
|
329
|
+
fontSize: 16,
|
|
330
|
+
color: '#666',
|
|
331
|
+
textAlign: 'center',
|
|
332
|
+
lineHeight: 22,
|
|
333
|
+
marginBottom: 32,
|
|
372
334
|
},
|
|
373
|
-
|
|
335
|
+
|
|
336
|
+
// Error styles
|
|
337
|
+
errorTitle: {
|
|
374
338
|
fontSize: 18,
|
|
375
339
|
fontWeight: '600',
|
|
376
|
-
color: '#
|
|
340
|
+
color: '#1a1a1a',
|
|
377
341
|
textAlign: 'center',
|
|
342
|
+
marginBottom: 8,
|
|
378
343
|
},
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
344
|
+
// Camera styles
|
|
345
|
+
cameraContainer: {
|
|
346
|
+
flex: 1,
|
|
347
|
+
position: 'relative',
|
|
348
|
+
marginTop: 60,
|
|
383
349
|
},
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
350
|
+
cameraOverlay: {
|
|
351
|
+
position: 'absolute',
|
|
352
|
+
top: 0,
|
|
353
|
+
left: 0,
|
|
354
|
+
right: 0,
|
|
355
|
+
bottom: 0,
|
|
356
|
+
justifyContent: 'center',
|
|
388
357
|
alignItems: 'center',
|
|
389
358
|
},
|
|
390
|
-
|
|
359
|
+
faceFrame: {
|
|
360
|
+
width: 200,
|
|
361
|
+
height: 250,
|
|
362
|
+
borderWidth: 3,
|
|
363
|
+
borderColor: 'white',
|
|
364
|
+
borderRadius: 100,
|
|
365
|
+
borderStyle: 'dashed',
|
|
366
|
+
backgroundColor: 'transparent',
|
|
367
|
+
},
|
|
368
|
+
instructionText: {
|
|
391
369
|
color: 'white',
|
|
392
370
|
fontSize: 16,
|
|
393
|
-
fontWeight: '
|
|
371
|
+
fontWeight: '500',
|
|
372
|
+
textAlign: 'center',
|
|
373
|
+
marginTop: 20,
|
|
374
|
+
backgroundColor: 'rgba(0,0,0,0.7)',
|
|
375
|
+
paddingHorizontal: 16,
|
|
376
|
+
paddingVertical: 8,
|
|
377
|
+
borderRadius: 20,
|
|
394
378
|
},
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
379
|
+
// Verification flow styles
|
|
380
|
+
progressContainer: {
|
|
381
|
+
position: 'absolute',
|
|
382
|
+
top: 20,
|
|
383
|
+
left: 20,
|
|
384
|
+
right: 20,
|
|
385
|
+
height: 4,
|
|
386
|
+
backgroundColor: 'rgba(255,255,255,0.3)',
|
|
387
|
+
borderRadius: 2,
|
|
388
|
+
overflow: 'hidden',
|
|
389
|
+
},
|
|
390
|
+
progressBar: {
|
|
391
|
+
height: '100%',
|
|
392
|
+
borderRadius: 2,
|
|
402
393
|
},
|
|
403
|
-
|
|
404
|
-
fontSize: 30,
|
|
394
|
+
stepIndicator: {
|
|
405
395
|
color: 'white',
|
|
406
|
-
|
|
396
|
+
fontSize: 14,
|
|
397
|
+
fontWeight: '400',
|
|
398
|
+
textAlign: 'center',
|
|
399
|
+
marginTop: 8,
|
|
400
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
401
|
+
paddingHorizontal: 12,
|
|
402
|
+
paddingVertical: 4,
|
|
403
|
+
borderRadius: 12,
|
|
404
|
+
alignSelf: 'center',
|
|
407
405
|
},
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
406
|
+
statusContainer: {
|
|
407
|
+
position: 'absolute',
|
|
408
|
+
bottom: 40,
|
|
409
|
+
left: 20,
|
|
410
|
+
right: 20,
|
|
411
|
+
padding: 20,
|
|
412
|
+
borderRadius: 12,
|
|
414
413
|
alignItems: 'center',
|
|
415
414
|
},
|
|
416
|
-
|
|
417
|
-
|
|
415
|
+
statusContainerError: {
|
|
416
|
+
backgroundColor: '#ff4444',
|
|
417
|
+
},
|
|
418
|
+
statusText: {
|
|
418
419
|
color: 'white',
|
|
419
|
-
|
|
420
|
+
fontSize: 18,
|
|
421
|
+
fontWeight: '600',
|
|
422
|
+
textAlign: 'center',
|
|
423
|
+
marginBottom: 8,
|
|
424
|
+
},
|
|
425
|
+
retryButton: {
|
|
426
|
+
marginTop: 12,
|
|
427
|
+
minWidth: 120,
|
|
420
428
|
},
|
|
421
429
|
});
|
|
422
|
-
|
|
423
|
-
export default FaceVerification;
|