@hexar/biometric-identity-sdk-react-native 1.0.11 → 1.0.13
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/BiometricIdentityFlow.d.ts.map +1 -1
- package/dist/components/BiometricIdentityFlow.js +2 -18
- package/dist/components/VideoRecorder.d.ts.map +1 -1
- package/dist/components/VideoRecorder.js +46 -56
- package/dist/hooks/useBiometricSDK.d.ts.map +1 -1
- package/dist/hooks/useBiometricSDK.js +2 -9
- package/package.json +1 -1
- package/src/components/BiometricIdentityFlow.tsx +2 -19
- package/src/components/VideoRecorder.tsx +56 -59
- package/src/hooks/useBiometricSDK.ts +2 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BiometricIdentityFlow.d.ts","sourceRoot":"","sources":["../../src/components/BiometricIdentityFlow.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAOL,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,cAAc,EAKd,iBAAiB,EAClB,MAAM,oCAAoC,CAAC;AAU5C,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,OAAO,CAAC,EAAE,SAAS,CAAC;KACrB,CAAC;CACH;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,
|
|
1
|
+
{"version":3,"file":"BiometricIdentityFlow.d.ts","sourceRoot":"","sources":["../../src/components/BiometricIdentityFlow.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAOL,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,cAAc,EAKd,iBAAiB,EAClB,MAAM,oCAAoC,CAAC;AAU5C,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,OAAO,CAAC,EAAE,SAAS,CAAC;KACrB,CAAC;CACH;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAgTtE,CAAC;AAiOF,eAAe,qBAAqB,CAAC"}
|
|
@@ -109,28 +109,16 @@ const BiometricIdentityFlow = ({ onValidationComplete, onError, theme, language,
|
|
|
109
109
|
* Handle capture completion
|
|
110
110
|
*/
|
|
111
111
|
const handleCaptureComplete = (0, react_1.useCallback)(async (data) => {
|
|
112
|
-
console.log('handleCaptureComplete called, cameraMode:', cameraMode);
|
|
113
112
|
setShowCamera(false);
|
|
114
113
|
try {
|
|
115
114
|
if (cameraMode === 'front') {
|
|
116
|
-
console.log('Uploading front ID');
|
|
117
115
|
await uploadFrontID(data);
|
|
118
|
-
console.log('Front ID uploaded successfully');
|
|
119
116
|
}
|
|
120
117
|
else if (cameraMode === 'back') {
|
|
121
|
-
console.log('Uploading back ID');
|
|
122
118
|
await uploadBackID(data);
|
|
123
|
-
console.log('Back ID uploaded successfully');
|
|
124
119
|
}
|
|
125
120
|
else if (cameraMode === 'video') {
|
|
126
|
-
console.log('Processing video recording result');
|
|
127
|
-
// Handle video recording result
|
|
128
121
|
const videoResult = data;
|
|
129
|
-
console.log('Storing video recording:', {
|
|
130
|
-
frames: videoResult.frames.length,
|
|
131
|
-
duration: videoResult.duration,
|
|
132
|
-
challengesCompleted: videoResult.challengesCompleted.length
|
|
133
|
-
});
|
|
134
122
|
await storeVideoRecording({
|
|
135
123
|
frames: videoResult.frames,
|
|
136
124
|
duration: videoResult.duration,
|
|
@@ -139,10 +127,8 @@ const BiometricIdentityFlow = ({ onValidationComplete, onError, theme, language,
|
|
|
139
127
|
challengesCompleted: videoResult.challengesCompleted,
|
|
140
128
|
sessionId: videoResult.sessionId,
|
|
141
129
|
});
|
|
142
|
-
console.log('
|
|
143
|
-
|
|
144
|
-
const result = await validateIdentity();
|
|
145
|
-
console.log('Validation complete, result:', result);
|
|
130
|
+
console.log('Starting validation...');
|
|
131
|
+
await validateIdentity();
|
|
146
132
|
}
|
|
147
133
|
}
|
|
148
134
|
catch (error) {
|
|
@@ -185,12 +171,10 @@ const BiometricIdentityFlow = ({ onValidationComplete, onError, theme, language,
|
|
|
185
171
|
}
|
|
186
172
|
// Show validation progress
|
|
187
173
|
if (state.currentStep === biometric_identity_sdk_core_1.SDKStep.VALIDATING) {
|
|
188
|
-
console.log('Rendering ValidationProgress, progress:', state.progress);
|
|
189
174
|
return (react_1.default.createElement(ValidationProgress_1.ValidationProgress, { progress: state.progress, theme: theme, language: language }));
|
|
190
175
|
}
|
|
191
176
|
// Show result
|
|
192
177
|
if (state.currentStep === biometric_identity_sdk_core_1.SDKStep.RESULT && state.validationResult) {
|
|
193
|
-
console.log('Rendering ResultScreen, result:', state.validationResult);
|
|
194
178
|
return (react_1.default.createElement(ResultScreen_1.ResultScreen, { result: state.validationResult, theme: theme, language: language, onClose: () => onValidationComplete(state.validationResult) }));
|
|
195
179
|
}
|
|
196
180
|
// Show error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoRecorder.d.ts","sourceRoot":"","sources":["../../src/components/VideoRecorder.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAaxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,iBAAiB,EAA2B,MAAM,oCAAoC,CAAC;AAGlI,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,YAAY,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACrC,0CAA0C;IAC1C,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,UAAU,EAAE,CAAC,SAAS,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,iCAAiC;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+CD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"VideoRecorder.d.ts","sourceRoot":"","sources":["../../src/components/VideoRecorder.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAaxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,iBAAiB,EAA2B,MAAM,oCAAoC,CAAC;AAGlI,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,YAAY,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACrC,0CAA0C;IAC1C,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,UAAU,EAAE,CAAC,SAAS,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,iCAAiC;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+CD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkyBtD,CAAC;AA4OF,eAAe,aAAa,CAAC"}
|
|
@@ -275,16 +275,13 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
275
275
|
react_native_1.Alert.alert('Recording Error', 'Failed to record video. Please try again.', [{ text: 'OK', onPress: onCancel }]);
|
|
276
276
|
}, [onCancel]);
|
|
277
277
|
const handleVideoComplete = (0, react_1.useCallback)(async (video) => {
|
|
278
|
-
|
|
279
|
-
if (!isRecordingRef.current && phase !== 'processing') {
|
|
280
|
-
console.log('Video already processed, ignoring duplicate callback');
|
|
278
|
+
if (phase === 'loading' && !video) {
|
|
281
279
|
return;
|
|
282
280
|
}
|
|
283
281
|
try {
|
|
284
282
|
setPhase('processing');
|
|
285
283
|
setOverallProgress(100);
|
|
286
284
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
287
|
-
console.log('Video Processing - Duration:', (actualDuration / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's, Frames:', frames.length);
|
|
288
285
|
if (actualDuration < minDurationMs) {
|
|
289
286
|
setPhase('recording');
|
|
290
287
|
setOverallProgress(0);
|
|
@@ -296,15 +293,17 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
296
293
|
try {
|
|
297
294
|
const RNFS = require('react-native-fs');
|
|
298
295
|
videoBase64 = await RNFS.readFile(video.path, 'base64');
|
|
299
|
-
console.log('Video file read successfully, size:', videoBase64.length, 'bytes');
|
|
300
296
|
}
|
|
301
297
|
catch (fsError) {
|
|
302
|
-
console.warn('Could not read video file, using captured frames
|
|
298
|
+
console.warn('Could not read video file, using captured frames');
|
|
303
299
|
}
|
|
304
300
|
}
|
|
305
|
-
|
|
301
|
+
let finalFrames = frames.length > 0 ? frames : [];
|
|
302
|
+
if (finalFrames.length === 0 && videoBase64) {
|
|
303
|
+
finalFrames = [videoBase64];
|
|
304
|
+
}
|
|
306
305
|
if (finalFrames.length === 0) {
|
|
307
|
-
console.error('No frames available, cannot complete');
|
|
306
|
+
console.error('No frames or video available, cannot complete');
|
|
308
307
|
setPhase('recording');
|
|
309
308
|
handleRecordingError(new Error('No video frames captured'));
|
|
310
309
|
return;
|
|
@@ -317,13 +316,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
317
316
|
challengesCompleted: completedChallenges,
|
|
318
317
|
sessionId,
|
|
319
318
|
};
|
|
320
|
-
console.log('Video recording completed
|
|
321
|
-
duration: (actualDuration / 1000).toFixed(1) + 's',
|
|
322
|
-
frames: result.frames.length,
|
|
323
|
-
challenges: `${completedChallenges.length}/${challenges.length}`,
|
|
324
|
-
instructionsFollowed: result.instructionsFollowed,
|
|
325
|
-
quality: result.qualityScore.toFixed(0) + '%'
|
|
326
|
-
});
|
|
319
|
+
console.log('Video recording completed:', result.frames.length, 'frames,', (actualDuration / 1000).toFixed(1) + 's');
|
|
327
320
|
isRecordingRef.current = false;
|
|
328
321
|
onComplete(result);
|
|
329
322
|
}
|
|
@@ -336,7 +329,6 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
336
329
|
}, [frames, completedChallenges, challenges, sessionId, onComplete, resetAndRetry, handleRecordingError, strings, minDurationMs, phase]);
|
|
337
330
|
const startFrameCapture = (0, react_1.useCallback)(() => {
|
|
338
331
|
if (cameraRef.current && device) {
|
|
339
|
-
console.log('Starting frame capture mode');
|
|
340
332
|
frameCaptureInterval.current = setInterval(async () => {
|
|
341
333
|
try {
|
|
342
334
|
const photo = await cameraRef.current?.takePhoto({
|
|
@@ -364,14 +356,12 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
364
356
|
}
|
|
365
357
|
}
|
|
366
358
|
catch (error) {
|
|
367
|
-
|
|
359
|
+
// Silent frame capture errors
|
|
368
360
|
}
|
|
369
361
|
}, 100);
|
|
370
362
|
}
|
|
371
363
|
}, [device]);
|
|
372
364
|
const stopRecording = (0, react_1.useCallback)(async () => {
|
|
373
|
-
console.log('stopRecording called, isRecording:', isRecordingRef.current);
|
|
374
|
-
// Clear any pending timeouts
|
|
375
365
|
if (recordingTimeoutRef.current) {
|
|
376
366
|
clearTimeout(recordingTimeoutRef.current);
|
|
377
367
|
recordingTimeoutRef.current = null;
|
|
@@ -380,27 +370,20 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
380
370
|
clearInterval(frameCaptureInterval.current);
|
|
381
371
|
frameCaptureInterval.current = null;
|
|
382
372
|
}
|
|
383
|
-
// Prevent multiple calls
|
|
384
373
|
if (!isRecordingRef.current) {
|
|
385
|
-
console.log('Recording already stopped, ignoring');
|
|
386
374
|
return;
|
|
387
375
|
}
|
|
376
|
+
isRecordingRef.current = false;
|
|
388
377
|
if (videoRecordingRef.current) {
|
|
389
378
|
try {
|
|
390
|
-
console.log('Stopping video recording, current ref:', !!videoRecordingRef.current);
|
|
391
379
|
const recording = videoRecordingRef.current;
|
|
392
380
|
videoRecordingRef.current = null;
|
|
393
|
-
isRecordingRef.current = false;
|
|
394
381
|
await recording.stop();
|
|
395
|
-
console.log('Video recording stopped - waiting for onRecordingFinished callback');
|
|
396
382
|
}
|
|
397
383
|
catch (error) {
|
|
398
384
|
console.error('Error stopping video recording:', error);
|
|
399
|
-
isRecordingRef.current = false;
|
|
400
385
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
401
|
-
console.log('Error duration check:', actualDuration, 'minDurationMs:', minDurationMs, 'frames:', frames.length);
|
|
402
386
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
403
|
-
console.log('Video stopped with error, using captured frames');
|
|
404
387
|
const result = {
|
|
405
388
|
frames,
|
|
406
389
|
duration: actualDuration,
|
|
@@ -411,45 +394,65 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
411
394
|
};
|
|
412
395
|
onComplete(result);
|
|
413
396
|
}
|
|
397
|
+
else {
|
|
398
|
+
const result = {
|
|
399
|
+
frames: frames.length > 0 ? frames : [],
|
|
400
|
+
duration: actualDuration,
|
|
401
|
+
instructionsFollowed: completedChallenges.length === challenges.length,
|
|
402
|
+
qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
|
|
403
|
+
challengesCompleted: completedChallenges,
|
|
404
|
+
sessionId,
|
|
405
|
+
};
|
|
406
|
+
onComplete(result);
|
|
407
|
+
}
|
|
414
408
|
}
|
|
415
409
|
}
|
|
416
410
|
else {
|
|
417
|
-
|
|
418
|
-
|
|
411
|
+
const actualDuration = Date.now() - recordingStartTime.current;
|
|
412
|
+
if (frames.length === 0 && actualDuration < minDurationMs) {
|
|
413
|
+
console.error('No frames and duration too short, cannot complete');
|
|
414
|
+
setPhase('recording');
|
|
415
|
+
react_native_1.Alert.alert(strings.errors.videoTooShort?.title || 'Recording Too Short', strings.errors.videoTooShort?.message || `Video must be at least ${minDurationMs / 1000} seconds. Please try again.`, [{ text: strings.common.retry || 'OK', onPress: resetAndRetry }]);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
setPhase('processing');
|
|
419
|
+
setOverallProgress(100);
|
|
420
|
+
const result = {
|
|
421
|
+
frames: frames.length > 0 ? frames : [],
|
|
422
|
+
duration: actualDuration,
|
|
423
|
+
instructionsFollowed: completedChallenges.length === challenges.length,
|
|
424
|
+
qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
|
|
425
|
+
challengesCompleted: completedChallenges,
|
|
426
|
+
sessionId,
|
|
427
|
+
};
|
|
428
|
+
setTimeout(() => {
|
|
429
|
+
onComplete(result);
|
|
430
|
+
}, 100);
|
|
419
431
|
}
|
|
420
|
-
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs]);
|
|
432
|
+
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs, resetAndRetry, strings]);
|
|
421
433
|
const runChallenge = (0, react_1.useCallback)((index) => {
|
|
422
434
|
if (index >= challenges.length) {
|
|
423
|
-
console.log('All challenges completed, checking duration');
|
|
424
435
|
setOverallProgress(100);
|
|
425
|
-
// Clear the totalDuration timeout since we're handling it manually
|
|
426
436
|
if (recordingTimeoutRef.current) {
|
|
427
437
|
clearTimeout(recordingTimeoutRef.current);
|
|
428
438
|
recordingTimeoutRef.current = null;
|
|
429
|
-
console.log('Cleared totalDuration timeout');
|
|
430
439
|
}
|
|
431
440
|
if (isRecordingRef.current) {
|
|
432
441
|
const elapsed = Date.now() - recordingStartTime.current;
|
|
433
|
-
console.log('Checking duration - Elapsed:', (elapsed / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's');
|
|
434
442
|
if (elapsed < minDurationMs) {
|
|
435
443
|
const remaining = minDurationMs - elapsed;
|
|
436
|
-
console.log('Waiting additional', (remaining / 1000).toFixed(1), 's to meet minimum duration');
|
|
437
444
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
438
|
-
console.log('Minimum duration wait completed, stopping recording');
|
|
439
445
|
if (isRecordingRef.current) {
|
|
440
446
|
stopRecording();
|
|
441
447
|
}
|
|
442
448
|
}, remaining);
|
|
443
449
|
return;
|
|
444
450
|
}
|
|
445
|
-
console.log('Duration requirement met, stopping immediately');
|
|
446
451
|
stopRecording();
|
|
447
452
|
}
|
|
448
453
|
else {
|
|
449
|
-
console.log('Recording already stopped, checking if we can complete');
|
|
450
454
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
451
455
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
452
|
-
console.log('Recording already stopped, completing with frames');
|
|
453
456
|
const result = {
|
|
454
457
|
frames,
|
|
455
458
|
duration: actualDuration,
|
|
@@ -505,44 +508,31 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
505
508
|
setPhase('recording');
|
|
506
509
|
recordingStartTime.current = Date.now();
|
|
507
510
|
isRecordingRef.current = true;
|
|
508
|
-
console.log('Starting video recording, total duration:', (totalDuration / 1000).toFixed(1), 's');
|
|
509
511
|
if (cameraRef.current && device) {
|
|
510
512
|
try {
|
|
511
513
|
videoRecordingRef.current = await cameraRef.current.startRecording({
|
|
512
514
|
flash: 'off',
|
|
513
515
|
onRecordingFinished: (video) => {
|
|
514
|
-
|
|
515
|
-
// Ensure we're in the right state to process
|
|
516
|
-
if (phase === 'recording' || phase === 'processing') {
|
|
517
|
-
handleVideoComplete(video);
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
console.warn('Received onRecordingFinished but phase is', phase, '- calling handleVideoComplete anyway');
|
|
521
|
-
handleVideoComplete(video);
|
|
522
|
-
}
|
|
516
|
+
handleVideoComplete(video);
|
|
523
517
|
},
|
|
524
518
|
onRecordingError: (error) => {
|
|
525
519
|
console.error('Recording error:', error);
|
|
526
520
|
handleRecordingError(error);
|
|
527
521
|
},
|
|
528
522
|
});
|
|
529
|
-
|
|
523
|
+
startFrameCapture();
|
|
530
524
|
}
|
|
531
525
|
catch (error) {
|
|
532
|
-
console.warn('Video recording not available, falling back to frame capture
|
|
526
|
+
console.warn('Video recording not available, falling back to frame capture');
|
|
533
527
|
startFrameCapture();
|
|
534
528
|
}
|
|
535
529
|
}
|
|
536
530
|
else {
|
|
537
|
-
console.log('Camera not available, using frame capture');
|
|
538
531
|
startFrameCapture();
|
|
539
532
|
}
|
|
540
533
|
runChallenge(0);
|
|
541
|
-
|
|
542
|
-
// This will be cleared if challenges complete early
|
|
543
|
-
const maxDuration = Math.max(totalDuration, minDurationMs + 2000); // Add 2s buffer
|
|
534
|
+
const maxDuration = Math.max(totalDuration, minDurationMs + 2000);
|
|
544
535
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
545
|
-
console.log('Safety timeout reached (max duration), stopping recording');
|
|
546
536
|
if (isRecordingRef.current) {
|
|
547
537
|
stopRecording().catch(err => {
|
|
548
538
|
console.error('Error stopping recording on safety timeout:', err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBiometricSDK.d.ts","sourceRoot":"","sources":["../../src/hooks/useBiometricSDK.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACZ,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,oBAAoB,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,mBAAmB,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,eAAO,MAAM,eAAe,QAAO,
|
|
1
|
+
{"version":3,"file":"useBiometricSDK.d.ts","sourceRoot":"","sources":["../../src/hooks/useBiometricSDK.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACZ,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,oBAAoB,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,mBAAmB,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,eAAO,MAAM,eAAe,QAAO,qBAuNlC,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -137,24 +137,17 @@ const useBiometricSDK = () => {
|
|
|
137
137
|
* Validate identity with all collected data
|
|
138
138
|
*/
|
|
139
139
|
const validateIdentity = (0, react_1.useCallback)(async () => {
|
|
140
|
-
console.log('validateIdentity called, current state:', sdk.getState().currentStep);
|
|
141
|
-
// Update state immediately to show validation screen
|
|
142
140
|
setState(sdk.getState());
|
|
143
|
-
// Poll state during validation to catch intermediate updates
|
|
144
141
|
const pollInterval = setInterval(() => {
|
|
145
142
|
if (isMounted.current) {
|
|
146
|
-
|
|
147
|
-
setState(currentState);
|
|
148
|
-
console.log('State polled - step:', currentState.currentStep, 'progress:', currentState.progress);
|
|
143
|
+
setState(sdk.getState());
|
|
149
144
|
}
|
|
150
145
|
}, 200);
|
|
151
146
|
try {
|
|
152
147
|
const result = await sdk.validateIdentity();
|
|
153
148
|
clearInterval(pollInterval);
|
|
154
149
|
if (isMounted.current) {
|
|
155
|
-
|
|
156
|
-
setState(finalState);
|
|
157
|
-
console.log('Validation complete, final state:', finalState.currentStep, 'result:', result);
|
|
150
|
+
setState(sdk.getState());
|
|
158
151
|
}
|
|
159
152
|
return result;
|
|
160
153
|
}
|
package/package.json
CHANGED
|
@@ -135,29 +135,16 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
|
|
|
135
135
|
* Handle capture completion
|
|
136
136
|
*/
|
|
137
137
|
const handleCaptureComplete = useCallback(async (data: any) => {
|
|
138
|
-
console.log('handleCaptureComplete called, cameraMode:', cameraMode);
|
|
139
138
|
setShowCamera(false);
|
|
140
139
|
|
|
141
140
|
try {
|
|
142
141
|
if (cameraMode === 'front') {
|
|
143
|
-
console.log('Uploading front ID');
|
|
144
142
|
await uploadFrontID(data);
|
|
145
|
-
console.log('Front ID uploaded successfully');
|
|
146
143
|
} else if (cameraMode === 'back') {
|
|
147
|
-
console.log('Uploading back ID');
|
|
148
144
|
await uploadBackID(data);
|
|
149
|
-
console.log('Back ID uploaded successfully');
|
|
150
145
|
} else if (cameraMode === 'video') {
|
|
151
|
-
console.log('Processing video recording result');
|
|
152
|
-
// Handle video recording result
|
|
153
146
|
const videoResult: VideoRecordingResult = data;
|
|
154
147
|
|
|
155
|
-
console.log('Storing video recording:', {
|
|
156
|
-
frames: videoResult.frames.length,
|
|
157
|
-
duration: videoResult.duration,
|
|
158
|
-
challengesCompleted: videoResult.challengesCompleted.length
|
|
159
|
-
});
|
|
160
|
-
|
|
161
148
|
await storeVideoRecording({
|
|
162
149
|
frames: videoResult.frames,
|
|
163
150
|
duration: videoResult.duration,
|
|
@@ -167,10 +154,8 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
|
|
|
167
154
|
sessionId: videoResult.sessionId,
|
|
168
155
|
});
|
|
169
156
|
|
|
170
|
-
console.log('
|
|
171
|
-
|
|
172
|
-
const result = await validateIdentity();
|
|
173
|
-
console.log('Validation complete, result:', result);
|
|
157
|
+
console.log('Starting validation...');
|
|
158
|
+
await validateIdentity();
|
|
174
159
|
}
|
|
175
160
|
} catch (error) {
|
|
176
161
|
console.error('Capture error:', error);
|
|
@@ -249,7 +234,6 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
|
|
|
249
234
|
|
|
250
235
|
// Show validation progress
|
|
251
236
|
if (state.currentStep === SDKStep.VALIDATING) {
|
|
252
|
-
console.log('Rendering ValidationProgress, progress:', state.progress);
|
|
253
237
|
return (
|
|
254
238
|
<ValidationProgress
|
|
255
239
|
progress={state.progress}
|
|
@@ -261,7 +245,6 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
|
|
|
261
245
|
|
|
262
246
|
// Show result
|
|
263
247
|
if (state.currentStep === SDKStep.RESULT && state.validationResult) {
|
|
264
|
-
console.log('Rendering ResultScreen, result:', state.validationResult);
|
|
265
248
|
return (
|
|
266
249
|
<ResultScreen
|
|
267
250
|
result={state.validationResult}
|
|
@@ -329,10 +329,7 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
329
329
|
}, [onCancel]);
|
|
330
330
|
|
|
331
331
|
const handleVideoComplete = useCallback(async (video: any) => {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (!isRecordingRef.current && phase !== 'processing') {
|
|
335
|
-
console.log('Video already processed, ignoring duplicate callback');
|
|
332
|
+
if (phase === 'loading' && !video) {
|
|
336
333
|
return;
|
|
337
334
|
}
|
|
338
335
|
|
|
@@ -341,7 +338,6 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
341
338
|
setOverallProgress(100);
|
|
342
339
|
|
|
343
340
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
344
|
-
console.log('Video Processing - Duration:', (actualDuration / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's, Frames:', frames.length);
|
|
345
341
|
|
|
346
342
|
if (actualDuration < minDurationMs) {
|
|
347
343
|
setPhase('recording');
|
|
@@ -359,16 +355,19 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
359
355
|
try {
|
|
360
356
|
const RNFS = require('react-native-fs');
|
|
361
357
|
videoBase64 = await RNFS.readFile(video.path, 'base64');
|
|
362
|
-
console.log('Video file read successfully, size:', videoBase64.length, 'bytes');
|
|
363
358
|
} catch (fsError) {
|
|
364
|
-
console.warn('Could not read video file, using captured frames
|
|
359
|
+
console.warn('Could not read video file, using captured frames');
|
|
365
360
|
}
|
|
366
361
|
}
|
|
367
362
|
|
|
368
|
-
|
|
363
|
+
let finalFrames = frames.length > 0 ? frames : [];
|
|
364
|
+
|
|
365
|
+
if (finalFrames.length === 0 && videoBase64) {
|
|
366
|
+
finalFrames = [videoBase64];
|
|
367
|
+
}
|
|
369
368
|
|
|
370
369
|
if (finalFrames.length === 0) {
|
|
371
|
-
console.error('No frames available, cannot complete');
|
|
370
|
+
console.error('No frames or video available, cannot complete');
|
|
372
371
|
setPhase('recording');
|
|
373
372
|
handleRecordingError(new Error('No video frames captured'));
|
|
374
373
|
return;
|
|
@@ -383,13 +382,7 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
383
382
|
sessionId,
|
|
384
383
|
};
|
|
385
384
|
|
|
386
|
-
console.log('Video recording completed
|
|
387
|
-
duration: (actualDuration / 1000).toFixed(1) + 's',
|
|
388
|
-
frames: result.frames.length,
|
|
389
|
-
challenges: `${completedChallenges.length}/${challenges.length}`,
|
|
390
|
-
instructionsFollowed: result.instructionsFollowed,
|
|
391
|
-
quality: result.qualityScore.toFixed(0) + '%'
|
|
392
|
-
});
|
|
385
|
+
console.log('Video recording completed:', result.frames.length, 'frames,', (actualDuration / 1000).toFixed(1) + 's');
|
|
393
386
|
|
|
394
387
|
isRecordingRef.current = false;
|
|
395
388
|
onComplete(result);
|
|
@@ -403,7 +396,6 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
403
396
|
|
|
404
397
|
const startFrameCapture = useCallback(() => {
|
|
405
398
|
if (cameraRef.current && device) {
|
|
406
|
-
console.log('Starting frame capture mode');
|
|
407
399
|
frameCaptureInterval.current = setInterval(async () => {
|
|
408
400
|
try {
|
|
409
401
|
const photo = await cameraRef.current?.takePhoto({
|
|
@@ -430,16 +422,13 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
430
422
|
}
|
|
431
423
|
}
|
|
432
424
|
} catch (error) {
|
|
433
|
-
|
|
425
|
+
// Silent frame capture errors
|
|
434
426
|
}
|
|
435
427
|
}, 100);
|
|
436
428
|
}
|
|
437
429
|
}, [device]);
|
|
438
430
|
|
|
439
431
|
const stopRecording = useCallback(async () => {
|
|
440
|
-
console.log('stopRecording called, isRecording:', isRecordingRef.current);
|
|
441
|
-
|
|
442
|
-
// Clear any pending timeouts
|
|
443
432
|
if (recordingTimeoutRef.current) {
|
|
444
433
|
clearTimeout(recordingTimeoutRef.current);
|
|
445
434
|
recordingTimeoutRef.current = null;
|
|
@@ -450,29 +439,22 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
450
439
|
frameCaptureInterval.current = null;
|
|
451
440
|
}
|
|
452
441
|
|
|
453
|
-
// Prevent multiple calls
|
|
454
442
|
if (!isRecordingRef.current) {
|
|
455
|
-
console.log('Recording already stopped, ignoring');
|
|
456
443
|
return;
|
|
457
444
|
}
|
|
458
445
|
|
|
446
|
+
isRecordingRef.current = false;
|
|
447
|
+
|
|
459
448
|
if (videoRecordingRef.current) {
|
|
460
449
|
try {
|
|
461
|
-
console.log('Stopping video recording, current ref:', !!videoRecordingRef.current);
|
|
462
450
|
const recording = videoRecordingRef.current;
|
|
463
451
|
videoRecordingRef.current = null;
|
|
464
|
-
isRecordingRef.current = false;
|
|
465
|
-
|
|
466
452
|
await recording.stop();
|
|
467
|
-
console.log('Video recording stopped - waiting for onRecordingFinished callback');
|
|
468
453
|
} catch (error) {
|
|
469
454
|
console.error('Error stopping video recording:', error);
|
|
470
|
-
isRecordingRef.current = false;
|
|
471
455
|
|
|
472
456
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
473
|
-
console.log('Error duration check:', actualDuration, 'minDurationMs:', minDurationMs, 'frames:', frames.length);
|
|
474
457
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
475
|
-
console.log('Video stopped with error, using captured frames');
|
|
476
458
|
const result: VideoRecordingResult = {
|
|
477
459
|
frames,
|
|
478
460
|
duration: actualDuration,
|
|
@@ -482,35 +464,65 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
482
464
|
sessionId,
|
|
483
465
|
};
|
|
484
466
|
onComplete(result);
|
|
467
|
+
} else {
|
|
468
|
+
const result: VideoRecordingResult = {
|
|
469
|
+
frames: frames.length > 0 ? frames : [],
|
|
470
|
+
duration: actualDuration,
|
|
471
|
+
instructionsFollowed: completedChallenges.length === challenges.length,
|
|
472
|
+
qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
|
|
473
|
+
challengesCompleted: completedChallenges,
|
|
474
|
+
sessionId,
|
|
475
|
+
};
|
|
476
|
+
onComplete(result);
|
|
485
477
|
}
|
|
486
478
|
}
|
|
487
479
|
} else {
|
|
488
|
-
|
|
489
|
-
|
|
480
|
+
const actualDuration = Date.now() - recordingStartTime.current;
|
|
481
|
+
|
|
482
|
+
if (frames.length === 0 && actualDuration < minDurationMs) {
|
|
483
|
+
console.error('No frames and duration too short, cannot complete');
|
|
484
|
+
setPhase('recording');
|
|
485
|
+
Alert.alert(
|
|
486
|
+
strings.errors.videoTooShort?.title || 'Recording Too Short',
|
|
487
|
+
strings.errors.videoTooShort?.message || `Video must be at least ${minDurationMs / 1000} seconds. Please try again.`,
|
|
488
|
+
[{ text: strings.common.retry || 'OK', onPress: resetAndRetry }]
|
|
489
|
+
);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
setPhase('processing');
|
|
494
|
+
setOverallProgress(100);
|
|
495
|
+
|
|
496
|
+
const result: VideoRecordingResult = {
|
|
497
|
+
frames: frames.length > 0 ? frames : [],
|
|
498
|
+
duration: actualDuration,
|
|
499
|
+
instructionsFollowed: completedChallenges.length === challenges.length,
|
|
500
|
+
qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
|
|
501
|
+
challengesCompleted: completedChallenges,
|
|
502
|
+
sessionId,
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
setTimeout(() => {
|
|
506
|
+
onComplete(result);
|
|
507
|
+
}, 100);
|
|
490
508
|
}
|
|
491
|
-
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs]);
|
|
509
|
+
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs, resetAndRetry, strings]);
|
|
492
510
|
|
|
493
511
|
const runChallenge = useCallback((index: number) => {
|
|
494
512
|
if (index >= challenges.length) {
|
|
495
|
-
console.log('All challenges completed, checking duration');
|
|
496
513
|
setOverallProgress(100);
|
|
497
514
|
|
|
498
|
-
// Clear the totalDuration timeout since we're handling it manually
|
|
499
515
|
if (recordingTimeoutRef.current) {
|
|
500
516
|
clearTimeout(recordingTimeoutRef.current);
|
|
501
517
|
recordingTimeoutRef.current = null;
|
|
502
|
-
console.log('Cleared totalDuration timeout');
|
|
503
518
|
}
|
|
504
519
|
|
|
505
520
|
if (isRecordingRef.current) {
|
|
506
521
|
const elapsed = Date.now() - recordingStartTime.current;
|
|
507
|
-
console.log('Checking duration - Elapsed:', (elapsed / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's');
|
|
508
522
|
|
|
509
523
|
if (elapsed < minDurationMs) {
|
|
510
524
|
const remaining = minDurationMs - elapsed;
|
|
511
|
-
console.log('Waiting additional', (remaining / 1000).toFixed(1), 's to meet minimum duration');
|
|
512
525
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
513
|
-
console.log('Minimum duration wait completed, stopping recording');
|
|
514
526
|
if (isRecordingRef.current) {
|
|
515
527
|
stopRecording();
|
|
516
528
|
}
|
|
@@ -518,13 +530,10 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
518
530
|
return;
|
|
519
531
|
}
|
|
520
532
|
|
|
521
|
-
console.log('Duration requirement met, stopping immediately');
|
|
522
533
|
stopRecording();
|
|
523
534
|
} else {
|
|
524
|
-
console.log('Recording already stopped, checking if we can complete');
|
|
525
535
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
526
536
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
527
|
-
console.log('Recording already stopped, completing with frames');
|
|
528
537
|
const result: VideoRecordingResult = {
|
|
529
538
|
frames,
|
|
530
539
|
duration: actualDuration,
|
|
@@ -591,44 +600,32 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
591
600
|
recordingStartTime.current = Date.now();
|
|
592
601
|
isRecordingRef.current = true;
|
|
593
602
|
|
|
594
|
-
console.log('Starting video recording, total duration:', (totalDuration / 1000).toFixed(1), 's');
|
|
595
|
-
|
|
596
603
|
if (cameraRef.current && device) {
|
|
597
604
|
try {
|
|
598
605
|
videoRecordingRef.current = await cameraRef.current.startRecording({
|
|
599
606
|
flash: 'off',
|
|
600
607
|
onRecordingFinished: (video: any) => {
|
|
601
|
-
|
|
602
|
-
// Ensure we're in the right state to process
|
|
603
|
-
if (phase === 'recording' || phase === 'processing') {
|
|
604
|
-
handleVideoComplete(video);
|
|
605
|
-
} else {
|
|
606
|
-
console.warn('Received onRecordingFinished but phase is', phase, '- calling handleVideoComplete anyway');
|
|
607
|
-
handleVideoComplete(video);
|
|
608
|
-
}
|
|
608
|
+
handleVideoComplete(video);
|
|
609
609
|
},
|
|
610
610
|
onRecordingError: (error: any) => {
|
|
611
611
|
console.error('Recording error:', error);
|
|
612
612
|
handleRecordingError(error);
|
|
613
613
|
},
|
|
614
614
|
});
|
|
615
|
-
|
|
615
|
+
|
|
616
|
+
startFrameCapture();
|
|
616
617
|
} catch (error) {
|
|
617
|
-
console.warn('Video recording not available, falling back to frame capture
|
|
618
|
+
console.warn('Video recording not available, falling back to frame capture');
|
|
618
619
|
startFrameCapture();
|
|
619
620
|
}
|
|
620
621
|
} else {
|
|
621
|
-
console.log('Camera not available, using frame capture');
|
|
622
622
|
startFrameCapture();
|
|
623
623
|
}
|
|
624
624
|
|
|
625
625
|
runChallenge(0);
|
|
626
626
|
|
|
627
|
-
|
|
628
|
-
// This will be cleared if challenges complete early
|
|
629
|
-
const maxDuration = Math.max(totalDuration, minDurationMs + 2000); // Add 2s buffer
|
|
627
|
+
const maxDuration = Math.max(totalDuration, minDurationMs + 2000);
|
|
630
628
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
631
|
-
console.log('Safety timeout reached (max duration), stopping recording');
|
|
632
629
|
if (isRecordingRef.current) {
|
|
633
630
|
stopRecording().catch(err => {
|
|
634
631
|
console.error('Error stopping recording on safety timeout:', err);
|
|
@@ -192,17 +192,11 @@ export const useBiometricSDK = (): UseBiometricSDKResult => {
|
|
|
192
192
|
* Validate identity with all collected data
|
|
193
193
|
*/
|
|
194
194
|
const validateIdentity = useCallback(async () => {
|
|
195
|
-
console.log('validateIdentity called, current state:', sdk.getState().currentStep);
|
|
196
|
-
|
|
197
|
-
// Update state immediately to show validation screen
|
|
198
195
|
setState(sdk.getState());
|
|
199
196
|
|
|
200
|
-
// Poll state during validation to catch intermediate updates
|
|
201
197
|
const pollInterval = setInterval(() => {
|
|
202
198
|
if (isMounted.current) {
|
|
203
|
-
|
|
204
|
-
setState(currentState);
|
|
205
|
-
console.log('State polled - step:', currentState.currentStep, 'progress:', currentState.progress);
|
|
199
|
+
setState(sdk.getState());
|
|
206
200
|
}
|
|
207
201
|
}, 200);
|
|
208
202
|
|
|
@@ -211,9 +205,7 @@ export const useBiometricSDK = (): UseBiometricSDKResult => {
|
|
|
211
205
|
clearInterval(pollInterval);
|
|
212
206
|
|
|
213
207
|
if (isMounted.current) {
|
|
214
|
-
|
|
215
|
-
setState(finalState);
|
|
216
|
-
console.log('Validation complete, final state:', finalState.currentStep, 'result:', result);
|
|
208
|
+
setState(sdk.getState());
|
|
217
209
|
}
|
|
218
210
|
return result;
|
|
219
211
|
} catch (error) {
|