@hexar/biometric-identity-sdk-react-native 1.8.0 → 1.10.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/dist/components/ProfilePictureCapture.d.ts.map +1 -1
- package/dist/components/ProfilePictureCapture.js +32 -2
- package/dist/components/ValidationProgress.js +2 -2
- package/package.json +2 -2
- package/src/components/ProfilePictureCapture.tsx +52 -2
- package/src/components/ValidationProgress.tsx +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProfilePictureCapture.d.ts","sourceRoot":"","sources":["../../src/components/ProfilePictureCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ProfilePictureCapture.d.ts","sourceRoot":"","sources":["../../src/components/ProfilePictureCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAYxE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAmC,cAAc,EAAsB,MAAM,oCAAoC,CAAC;AAGzJ,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,CAAC,MAAM,EAAE,8BAA8B,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAyYtE,CAAC;AA4EF,eAAe,qBAAqB,CAAC"}
|
|
@@ -46,6 +46,7 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
46
46
|
const [isValidating, setIsValidating] = (0, react_1.useState)(false);
|
|
47
47
|
const [currentChallenges, setCurrentChallenges] = (0, react_1.useState)([]);
|
|
48
48
|
const [isLoadingChallenges, setIsLoadingChallenges] = (0, react_1.useState)(false);
|
|
49
|
+
const [loadingTimedOut, setLoadingTimedOut] = (0, react_1.useState)(false);
|
|
49
50
|
const animatedProgress = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
|
50
51
|
const [displayProgress, setDisplayProgress] = (0, react_1.useState)(0);
|
|
51
52
|
const animationRef = (0, react_1.useRef)(null);
|
|
@@ -58,6 +59,19 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
58
59
|
(0, biometric_identity_sdk_core_1.setLanguage)(language);
|
|
59
60
|
}
|
|
60
61
|
}, [language]);
|
|
62
|
+
// 15-second timeout on initial loading (challenge fetch / SDK init)
|
|
63
|
+
(0, react_1.useEffect)(() => {
|
|
64
|
+
const isLoading = !isInitialized || (isUsingBackend && isLoadingChallenges);
|
|
65
|
+
if (isLoading) {
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
setLoadingTimedOut(true);
|
|
68
|
+
}, 15000);
|
|
69
|
+
return () => clearTimeout(timer);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
setLoadingTimedOut(false);
|
|
73
|
+
}
|
|
74
|
+
}, [isInitialized, isUsingBackend, isLoadingChallenges]);
|
|
61
75
|
(0, react_1.useEffect)(() => {
|
|
62
76
|
if (isInitialized && isUsingBackend) {
|
|
63
77
|
const loadChallenges = async () => {
|
|
@@ -151,10 +165,10 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
151
165
|
hasStartedAnimation.current = true;
|
|
152
166
|
animatedProgress.setValue(0);
|
|
153
167
|
setDisplayProgress(0);
|
|
154
|
-
// Start animation to 90% over
|
|
168
|
+
// Start animation to 90% over 25 seconds
|
|
155
169
|
animationRef.current = react_native_1.Animated.timing(animatedProgress, {
|
|
156
170
|
toValue: 90,
|
|
157
|
-
duration:
|
|
171
|
+
duration: 25000, // 25 seconds
|
|
158
172
|
useNativeDriver: false,
|
|
159
173
|
});
|
|
160
174
|
animationRef.current.start();
|
|
@@ -284,6 +298,7 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
284
298
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#4f46e5' }),
|
|
285
299
|
react_1.default.createElement(react_native_1.Text, { style: [styles.progressTitle, { color: theme?.textColor || '#1e1b4b' }] }, strings.validation.title || strings.liveness.processing || strings.validation.checkingLiveness || 'Validating Profile Picture'),
|
|
286
300
|
react_1.default.createElement(react_native_1.Text, { style: [styles.progressStatusText, { color: theme?.secondaryTextColor || '#64748b' }] }, strings.validation.validatingFace || strings.liveness.processing || 'Validando rostro...'),
|
|
301
|
+
react_1.default.createElement(react_native_1.Text, { style: [styles.progressDoNotLockText, { color: theme?.secondaryTextColor || '#64748b' }] }, strings.validation.doNotLockScreen || 'No bloquees la pantalla'),
|
|
287
302
|
react_1.default.createElement(react_native_1.View, { style: styles.progressBarContainer },
|
|
288
303
|
react_1.default.createElement(react_native_1.View, { style: styles.progressBar },
|
|
289
304
|
react_1.default.createElement(react_native_1.Animated.View, { style: [
|
|
@@ -300,6 +315,15 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
300
315
|
}
|
|
301
316
|
// Wait for initialization and challenge loading before showing guide or VideoRecorder
|
|
302
317
|
if (!isInitialized || (isUsingBackend && isLoadingChallenges)) {
|
|
318
|
+
if (loadingTimedOut) {
|
|
319
|
+
return (react_1.default.createElement(react_native_1.SafeAreaView, { style: [styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }] },
|
|
320
|
+
react_1.default.createElement(react_native_1.View, { style: styles.loadingContainer },
|
|
321
|
+
react_1.default.createElement(react_native_1.Text, { style: { fontSize: 48, marginBottom: 16 } }, "\u23F3"),
|
|
322
|
+
react_1.default.createElement(react_native_1.Text, { style: [styles.loadingText, { color: theme?.textColor || '#1e1b4b', fontSize: 20, fontWeight: 'bold' }] }, strings.errors.systemBusy),
|
|
323
|
+
react_1.default.createElement(react_native_1.Text, { style: { fontSize: 15, color: theme?.secondaryTextColor || '#64748b', textAlign: 'center', marginTop: 12, paddingHorizontal: 24, lineHeight: 22 } }, strings.errors.systemBusyMessage),
|
|
324
|
+
onCancel && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: { backgroundColor: theme?.primaryColor || '#4f46e5', paddingVertical: 14, paddingHorizontal: 32, borderRadius: 12, marginTop: 32 }, onPress: onCancel },
|
|
325
|
+
react_1.default.createElement(react_native_1.Text, { style: { color: '#FFFFFF', fontSize: 16, fontWeight: '600' } }, strings.common?.back || 'Go back'))))));
|
|
326
|
+
}
|
|
303
327
|
return (react_1.default.createElement(react_native_1.SafeAreaView, { style: [styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }] },
|
|
304
328
|
react_1.default.createElement(react_native_1.View, { style: styles.loadingContainer },
|
|
305
329
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#4f46e5' }),
|
|
@@ -348,6 +372,12 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
348
372
|
},
|
|
349
373
|
progressStatusText: {
|
|
350
374
|
fontSize: 16,
|
|
375
|
+
marginBottom: 8,
|
|
376
|
+
textAlign: 'center',
|
|
377
|
+
},
|
|
378
|
+
progressDoNotLockText: {
|
|
379
|
+
fontSize: 14,
|
|
380
|
+
fontWeight: '600',
|
|
351
381
|
marginBottom: 32,
|
|
352
382
|
textAlign: 'center',
|
|
353
383
|
},
|
|
@@ -55,10 +55,10 @@ const ValidationProgress = ({ progress, theme, language = 'en', }) => {
|
|
|
55
55
|
// Start animation from 0 to 90% over 60 seconds (1 minute) - only once
|
|
56
56
|
if (!hasStartedAnimation.current) {
|
|
57
57
|
hasStartedAnimation.current = true;
|
|
58
|
-
// Start animation to 90% over
|
|
58
|
+
// Start animation to 90% over 35 seconds, regardless of backend progress
|
|
59
59
|
animationRef.current = react_native_1.Animated.timing(animatedProgress, {
|
|
60
60
|
toValue: 90,
|
|
61
|
-
duration:
|
|
61
|
+
duration: 35000, // 35 seconds
|
|
62
62
|
useNativeDriver: false,
|
|
63
63
|
});
|
|
64
64
|
animationRef.current.start();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hexar/biometric-identity-sdk-react-native",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "React Native wrapper for Biometric Identity SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"clean": "rm -rf dist"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"@hexar/biometric-identity-sdk-core": ">=1.
|
|
14
|
+
"@hexar/biometric-identity-sdk-core": ">=1.7.0",
|
|
15
15
|
"react": ">=18.0.0",
|
|
16
16
|
"react-native": ">=0.70.0",
|
|
17
17
|
"react-native-permissions": ">=4.0.0",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ActivityIndicator,
|
|
7
7
|
SafeAreaView,
|
|
8
8
|
Animated,
|
|
9
|
+
TouchableOpacity,
|
|
9
10
|
} from 'react-native';
|
|
10
11
|
import { VideoRecorder, VideoRecordingResult } from './VideoRecorder';
|
|
11
12
|
import { FacePositioningGuide } from './FacePositioningGuide';
|
|
@@ -47,6 +48,7 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
47
48
|
const [isValidating, setIsValidating] = useState(false);
|
|
48
49
|
const [currentChallenges, setCurrentChallenges] = useState<any[]>([]);
|
|
49
50
|
const [isLoadingChallenges, setIsLoadingChallenges] = useState(false);
|
|
51
|
+
const [loadingTimedOut, setLoadingTimedOut] = useState(false);
|
|
50
52
|
const animatedProgress = useRef(new Animated.Value(0)).current;
|
|
51
53
|
const [displayProgress, setDisplayProgress] = useState(0);
|
|
52
54
|
const animationRef = useRef<Animated.CompositeAnimation | null>(null);
|
|
@@ -62,6 +64,19 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
62
64
|
}
|
|
63
65
|
}, [language]);
|
|
64
66
|
|
|
67
|
+
// 15-second timeout on initial loading (challenge fetch / SDK init)
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
const isLoading = !isInitialized || (isUsingBackend && isLoadingChallenges);
|
|
70
|
+
if (isLoading) {
|
|
71
|
+
const timer = setTimeout(() => {
|
|
72
|
+
setLoadingTimedOut(true);
|
|
73
|
+
}, 15000);
|
|
74
|
+
return () => clearTimeout(timer);
|
|
75
|
+
} else {
|
|
76
|
+
setLoadingTimedOut(false);
|
|
77
|
+
}
|
|
78
|
+
}, [isInitialized, isUsingBackend, isLoadingChallenges]);
|
|
79
|
+
|
|
65
80
|
useEffect(() => {
|
|
66
81
|
if (isInitialized && isUsingBackend) {
|
|
67
82
|
const loadChallenges = async () => {
|
|
@@ -163,10 +178,10 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
163
178
|
animatedProgress.setValue(0);
|
|
164
179
|
setDisplayProgress(0);
|
|
165
180
|
|
|
166
|
-
// Start animation to 90% over
|
|
181
|
+
// Start animation to 90% over 25 seconds
|
|
167
182
|
animationRef.current = Animated.timing(animatedProgress, {
|
|
168
183
|
toValue: 90,
|
|
169
|
-
duration:
|
|
184
|
+
duration: 25000, // 25 seconds
|
|
170
185
|
useNativeDriver: false,
|
|
171
186
|
});
|
|
172
187
|
|
|
@@ -315,6 +330,10 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
315
330
|
{(strings.validation as any).validatingFace || strings.liveness.processing || 'Validando rostro...'}
|
|
316
331
|
</Text>
|
|
317
332
|
|
|
333
|
+
<Text style={[styles.progressDoNotLockText, { color: theme?.secondaryTextColor || '#64748b' }]}>
|
|
334
|
+
{strings.validation.doNotLockScreen || 'No bloquees la pantalla'}
|
|
335
|
+
</Text>
|
|
336
|
+
|
|
318
337
|
{/* Progress Bar */}
|
|
319
338
|
<View style={styles.progressBarContainer}>
|
|
320
339
|
<View style={styles.progressBar}>
|
|
@@ -343,6 +362,31 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
343
362
|
|
|
344
363
|
// Wait for initialization and challenge loading before showing guide or VideoRecorder
|
|
345
364
|
if (!isInitialized || (isUsingBackend && isLoadingChallenges)) {
|
|
365
|
+
if (loadingTimedOut) {
|
|
366
|
+
return (
|
|
367
|
+
<SafeAreaView style={[styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }]}>
|
|
368
|
+
<View style={styles.loadingContainer}>
|
|
369
|
+
<Text style={{ fontSize: 48, marginBottom: 16 }}>⏳</Text>
|
|
370
|
+
<Text style={[styles.loadingText, { color: theme?.textColor || '#1e1b4b', fontSize: 20, fontWeight: 'bold' }]}>
|
|
371
|
+
{strings.errors.systemBusy}
|
|
372
|
+
</Text>
|
|
373
|
+
<Text style={{ fontSize: 15, color: theme?.secondaryTextColor || '#64748b', textAlign: 'center', marginTop: 12, paddingHorizontal: 24, lineHeight: 22 }}>
|
|
374
|
+
{strings.errors.systemBusyMessage}
|
|
375
|
+
</Text>
|
|
376
|
+
{onCancel && (
|
|
377
|
+
<TouchableOpacity
|
|
378
|
+
style={{ backgroundColor: theme?.primaryColor || '#4f46e5', paddingVertical: 14, paddingHorizontal: 32, borderRadius: 12, marginTop: 32 }}
|
|
379
|
+
onPress={onCancel}
|
|
380
|
+
>
|
|
381
|
+
<Text style={{ color: '#FFFFFF', fontSize: 16, fontWeight: '600' }}>
|
|
382
|
+
{strings.common?.back || 'Go back'}
|
|
383
|
+
</Text>
|
|
384
|
+
</TouchableOpacity>
|
|
385
|
+
)}
|
|
386
|
+
</View>
|
|
387
|
+
</SafeAreaView>
|
|
388
|
+
);
|
|
389
|
+
}
|
|
346
390
|
return (
|
|
347
391
|
<SafeAreaView style={[styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }]}>
|
|
348
392
|
<View style={styles.loadingContainer}>
|
|
@@ -417,6 +461,12 @@ const styles = StyleSheet.create({
|
|
|
417
461
|
},
|
|
418
462
|
progressStatusText: {
|
|
419
463
|
fontSize: 16,
|
|
464
|
+
marginBottom: 8,
|
|
465
|
+
textAlign: 'center',
|
|
466
|
+
},
|
|
467
|
+
progressDoNotLockText: {
|
|
468
|
+
fontSize: 14,
|
|
469
|
+
fontWeight: '600',
|
|
420
470
|
marginBottom: 32,
|
|
421
471
|
textAlign: 'center',
|
|
422
472
|
},
|
|
@@ -40,10 +40,10 @@ export const ValidationProgress: React.FC<ValidationProgressProps> = ({
|
|
|
40
40
|
if (!hasStartedAnimation.current) {
|
|
41
41
|
hasStartedAnimation.current = true;
|
|
42
42
|
|
|
43
|
-
// Start animation to 90% over
|
|
43
|
+
// Start animation to 90% over 35 seconds, regardless of backend progress
|
|
44
44
|
animationRef.current = Animated.timing(animatedProgress, {
|
|
45
45
|
toValue: 90,
|
|
46
|
-
duration:
|
|
46
|
+
duration: 35000, // 35 seconds
|
|
47
47
|
useNativeDriver: false,
|
|
48
48
|
});
|
|
49
49
|
|