@hexar/biometric-identity-sdk-react-native 1.0.12 → 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 +19 -66
- 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 +26 -70
- 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,18 +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
|
-
console.log('handleVideoComplete called with video:', video?.path, 'current phase:', phase, 'isRecording:', isRecordingRef.current);
|
|
279
|
-
// Don't process if we're already done (result screen or error)
|
|
280
278
|
if (phase === 'loading' && !video) {
|
|
281
|
-
console.log('Video completion in loading phase with no video, ignoring');
|
|
282
279
|
return;
|
|
283
280
|
}
|
|
284
281
|
try {
|
|
285
|
-
console.log('Setting phase to processing');
|
|
286
282
|
setPhase('processing');
|
|
287
283
|
setOverallProgress(100);
|
|
288
284
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
289
|
-
console.log('Video Processing - Duration:', (actualDuration / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's, Frames:', frames.length);
|
|
290
285
|
if (actualDuration < minDurationMs) {
|
|
291
286
|
setPhase('recording');
|
|
292
287
|
setOverallProgress(0);
|
|
@@ -298,15 +293,17 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
298
293
|
try {
|
|
299
294
|
const RNFS = require('react-native-fs');
|
|
300
295
|
videoBase64 = await RNFS.readFile(video.path, 'base64');
|
|
301
|
-
console.log('Video file read successfully, size:', videoBase64.length, 'bytes');
|
|
302
296
|
}
|
|
303
297
|
catch (fsError) {
|
|
304
|
-
console.warn('Could not read video file, using captured frames
|
|
298
|
+
console.warn('Could not read video file, using captured frames');
|
|
305
299
|
}
|
|
306
300
|
}
|
|
307
|
-
|
|
301
|
+
let finalFrames = frames.length > 0 ? frames : [];
|
|
302
|
+
if (finalFrames.length === 0 && videoBase64) {
|
|
303
|
+
finalFrames = [videoBase64];
|
|
304
|
+
}
|
|
308
305
|
if (finalFrames.length === 0) {
|
|
309
|
-
console.error('No frames available, cannot complete');
|
|
306
|
+
console.error('No frames or video available, cannot complete');
|
|
310
307
|
setPhase('recording');
|
|
311
308
|
handleRecordingError(new Error('No video frames captured'));
|
|
312
309
|
return;
|
|
@@ -319,13 +316,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
319
316
|
challengesCompleted: completedChallenges,
|
|
320
317
|
sessionId,
|
|
321
318
|
};
|
|
322
|
-
console.log('Video recording completed
|
|
323
|
-
duration: (actualDuration / 1000).toFixed(1) + 's',
|
|
324
|
-
frames: result.frames.length,
|
|
325
|
-
challenges: `${completedChallenges.length}/${challenges.length}`,
|
|
326
|
-
instructionsFollowed: result.instructionsFollowed,
|
|
327
|
-
quality: result.qualityScore.toFixed(0) + '%'
|
|
328
|
-
});
|
|
319
|
+
console.log('Video recording completed:', result.frames.length, 'frames,', (actualDuration / 1000).toFixed(1) + 's');
|
|
329
320
|
isRecordingRef.current = false;
|
|
330
321
|
onComplete(result);
|
|
331
322
|
}
|
|
@@ -338,7 +329,6 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
338
329
|
}, [frames, completedChallenges, challenges, sessionId, onComplete, resetAndRetry, handleRecordingError, strings, minDurationMs, phase]);
|
|
339
330
|
const startFrameCapture = (0, react_1.useCallback)(() => {
|
|
340
331
|
if (cameraRef.current && device) {
|
|
341
|
-
console.log('Starting frame capture mode');
|
|
342
332
|
frameCaptureInterval.current = setInterval(async () => {
|
|
343
333
|
try {
|
|
344
334
|
const photo = await cameraRef.current?.takePhoto({
|
|
@@ -366,14 +356,12 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
366
356
|
}
|
|
367
357
|
}
|
|
368
358
|
catch (error) {
|
|
369
|
-
|
|
359
|
+
// Silent frame capture errors
|
|
370
360
|
}
|
|
371
361
|
}, 100);
|
|
372
362
|
}
|
|
373
363
|
}, [device]);
|
|
374
364
|
const stopRecording = (0, react_1.useCallback)(async () => {
|
|
375
|
-
console.log('stopRecording called, isRecording:', isRecordingRef.current, 'hasVideoRef:', !!videoRecordingRef.current);
|
|
376
|
-
// Clear any pending timeouts
|
|
377
365
|
if (recordingTimeoutRef.current) {
|
|
378
366
|
clearTimeout(recordingTimeoutRef.current);
|
|
379
367
|
recordingTimeoutRef.current = null;
|
|
@@ -382,28 +370,20 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
382
370
|
clearInterval(frameCaptureInterval.current);
|
|
383
371
|
frameCaptureInterval.current = null;
|
|
384
372
|
}
|
|
385
|
-
// Prevent multiple calls
|
|
386
373
|
if (!isRecordingRef.current) {
|
|
387
|
-
console.log('Recording already stopped, ignoring');
|
|
388
374
|
return;
|
|
389
375
|
}
|
|
390
|
-
// Mark as not recording first to prevent re-entry
|
|
391
376
|
isRecordingRef.current = false;
|
|
392
377
|
if (videoRecordingRef.current) {
|
|
393
378
|
try {
|
|
394
|
-
console.log('Stopping video recording, current ref exists');
|
|
395
379
|
const recording = videoRecordingRef.current;
|
|
396
380
|
videoRecordingRef.current = null;
|
|
397
381
|
await recording.stop();
|
|
398
|
-
console.log('Video recording stopped - waiting for onRecordingFinished callback');
|
|
399
|
-
// onRecordingFinished callback will handle completion
|
|
400
382
|
}
|
|
401
383
|
catch (error) {
|
|
402
384
|
console.error('Error stopping video recording:', error);
|
|
403
385
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
404
|
-
console.log('Error duration check:', actualDuration, 'minDurationMs:', minDurationMs, 'frames:', frames.length);
|
|
405
386
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
406
|
-
console.log('Video stopped with error, using captured frames');
|
|
407
387
|
const result = {
|
|
408
388
|
frames,
|
|
409
389
|
duration: actualDuration,
|
|
@@ -415,8 +395,6 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
415
395
|
onComplete(result);
|
|
416
396
|
}
|
|
417
397
|
else {
|
|
418
|
-
// Even if we don't have enough frames, try to complete with what we have
|
|
419
|
-
console.log('Completing with available data despite error');
|
|
420
398
|
const result = {
|
|
421
399
|
frames: frames.length > 0 ? frames : [],
|
|
422
400
|
duration: actualDuration,
|
|
@@ -430,12 +408,15 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
430
408
|
}
|
|
431
409
|
}
|
|
432
410
|
else {
|
|
433
|
-
console.log('No video recording ref - completing with captured frames');
|
|
434
411
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
435
|
-
|
|
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
|
+
}
|
|
436
418
|
setPhase('processing');
|
|
437
419
|
setOverallProgress(100);
|
|
438
|
-
// Complete with frames we have
|
|
439
420
|
const result = {
|
|
440
421
|
frames: frames.length > 0 ? frames : [],
|
|
441
422
|
duration: actualDuration,
|
|
@@ -444,49 +425,34 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
444
425
|
challengesCompleted: completedChallenges,
|
|
445
426
|
sessionId,
|
|
446
427
|
};
|
|
447
|
-
console.log('Completing without video ref:', {
|
|
448
|
-
frames: result.frames.length,
|
|
449
|
-
duration: (actualDuration / 1000).toFixed(1) + 's',
|
|
450
|
-
challenges: completedChallenges.length
|
|
451
|
-
});
|
|
452
|
-
// Small delay to ensure UI updates
|
|
453
428
|
setTimeout(() => {
|
|
454
429
|
onComplete(result);
|
|
455
430
|
}, 100);
|
|
456
431
|
}
|
|
457
|
-
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs]);
|
|
432
|
+
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs, resetAndRetry, strings]);
|
|
458
433
|
const runChallenge = (0, react_1.useCallback)((index) => {
|
|
459
434
|
if (index >= challenges.length) {
|
|
460
|
-
console.log('All challenges completed, checking duration');
|
|
461
435
|
setOverallProgress(100);
|
|
462
|
-
// Clear the totalDuration timeout since we're handling it manually
|
|
463
436
|
if (recordingTimeoutRef.current) {
|
|
464
437
|
clearTimeout(recordingTimeoutRef.current);
|
|
465
438
|
recordingTimeoutRef.current = null;
|
|
466
|
-
console.log('Cleared totalDuration timeout');
|
|
467
439
|
}
|
|
468
440
|
if (isRecordingRef.current) {
|
|
469
441
|
const elapsed = Date.now() - recordingStartTime.current;
|
|
470
|
-
console.log('Checking duration - Elapsed:', (elapsed / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's');
|
|
471
442
|
if (elapsed < minDurationMs) {
|
|
472
443
|
const remaining = minDurationMs - elapsed;
|
|
473
|
-
console.log('Waiting additional', (remaining / 1000).toFixed(1), 's to meet minimum duration');
|
|
474
444
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
475
|
-
console.log('Minimum duration wait completed, stopping recording');
|
|
476
445
|
if (isRecordingRef.current) {
|
|
477
446
|
stopRecording();
|
|
478
447
|
}
|
|
479
448
|
}, remaining);
|
|
480
449
|
return;
|
|
481
450
|
}
|
|
482
|
-
console.log('Duration requirement met, stopping immediately');
|
|
483
451
|
stopRecording();
|
|
484
452
|
}
|
|
485
453
|
else {
|
|
486
|
-
console.log('Recording already stopped, checking if we can complete');
|
|
487
454
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
488
455
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
489
|
-
console.log('Recording already stopped, completing with frames');
|
|
490
456
|
const result = {
|
|
491
457
|
frames,
|
|
492
458
|
duration: actualDuration,
|
|
@@ -542,44 +508,31 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
|
|
|
542
508
|
setPhase('recording');
|
|
543
509
|
recordingStartTime.current = Date.now();
|
|
544
510
|
isRecordingRef.current = true;
|
|
545
|
-
console.log('Starting video recording, total duration:', (totalDuration / 1000).toFixed(1), 's');
|
|
546
511
|
if (cameraRef.current && device) {
|
|
547
512
|
try {
|
|
548
513
|
videoRecordingRef.current = await cameraRef.current.startRecording({
|
|
549
514
|
flash: 'off',
|
|
550
515
|
onRecordingFinished: (video) => {
|
|
551
|
-
|
|
552
|
-
// Ensure we're in the right state to process
|
|
553
|
-
if (phase === 'recording' || phase === 'processing') {
|
|
554
|
-
handleVideoComplete(video);
|
|
555
|
-
}
|
|
556
|
-
else {
|
|
557
|
-
console.warn('Received onRecordingFinished but phase is', phase, '- calling handleVideoComplete anyway');
|
|
558
|
-
handleVideoComplete(video);
|
|
559
|
-
}
|
|
516
|
+
handleVideoComplete(video);
|
|
560
517
|
},
|
|
561
518
|
onRecordingError: (error) => {
|
|
562
519
|
console.error('Recording error:', error);
|
|
563
520
|
handleRecordingError(error);
|
|
564
521
|
},
|
|
565
522
|
});
|
|
566
|
-
|
|
523
|
+
startFrameCapture();
|
|
567
524
|
}
|
|
568
525
|
catch (error) {
|
|
569
|
-
console.warn('Video recording not available, falling back to frame capture
|
|
526
|
+
console.warn('Video recording not available, falling back to frame capture');
|
|
570
527
|
startFrameCapture();
|
|
571
528
|
}
|
|
572
529
|
}
|
|
573
530
|
else {
|
|
574
|
-
console.log('Camera not available, using frame capture');
|
|
575
531
|
startFrameCapture();
|
|
576
532
|
}
|
|
577
533
|
runChallenge(0);
|
|
578
|
-
|
|
579
|
-
// This will be cleared if challenges complete early
|
|
580
|
-
const maxDuration = Math.max(totalDuration, minDurationMs + 2000); // Add 2s buffer
|
|
534
|
+
const maxDuration = Math.max(totalDuration, minDurationMs + 2000);
|
|
581
535
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
582
|
-
console.log('Safety timeout reached (max duration), stopping recording');
|
|
583
536
|
if (isRecordingRef.current) {
|
|
584
537
|
stopRecording().catch(err => {
|
|
585
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,21 +329,15 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
329
329
|
}, [onCancel]);
|
|
330
330
|
|
|
331
331
|
const handleVideoComplete = useCallback(async (video: any) => {
|
|
332
|
-
console.log('handleVideoComplete called with video:', video?.path, 'current phase:', phase, 'isRecording:', isRecordingRef.current);
|
|
333
|
-
|
|
334
|
-
// Don't process if we're already done (result screen or error)
|
|
335
332
|
if (phase === 'loading' && !video) {
|
|
336
|
-
console.log('Video completion in loading phase with no video, ignoring');
|
|
337
333
|
return;
|
|
338
334
|
}
|
|
339
335
|
|
|
340
336
|
try {
|
|
341
|
-
console.log('Setting phase to processing');
|
|
342
337
|
setPhase('processing');
|
|
343
338
|
setOverallProgress(100);
|
|
344
339
|
|
|
345
340
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
346
|
-
console.log('Video Processing - Duration:', (actualDuration / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's, Frames:', frames.length);
|
|
347
341
|
|
|
348
342
|
if (actualDuration < minDurationMs) {
|
|
349
343
|
setPhase('recording');
|
|
@@ -361,16 +355,19 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
361
355
|
try {
|
|
362
356
|
const RNFS = require('react-native-fs');
|
|
363
357
|
videoBase64 = await RNFS.readFile(video.path, 'base64');
|
|
364
|
-
console.log('Video file read successfully, size:', videoBase64.length, 'bytes');
|
|
365
358
|
} catch (fsError) {
|
|
366
|
-
console.warn('Could not read video file, using captured frames
|
|
359
|
+
console.warn('Could not read video file, using captured frames');
|
|
367
360
|
}
|
|
368
361
|
}
|
|
369
362
|
|
|
370
|
-
|
|
363
|
+
let finalFrames = frames.length > 0 ? frames : [];
|
|
364
|
+
|
|
365
|
+
if (finalFrames.length === 0 && videoBase64) {
|
|
366
|
+
finalFrames = [videoBase64];
|
|
367
|
+
}
|
|
371
368
|
|
|
372
369
|
if (finalFrames.length === 0) {
|
|
373
|
-
console.error('No frames available, cannot complete');
|
|
370
|
+
console.error('No frames or video available, cannot complete');
|
|
374
371
|
setPhase('recording');
|
|
375
372
|
handleRecordingError(new Error('No video frames captured'));
|
|
376
373
|
return;
|
|
@@ -385,13 +382,7 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
385
382
|
sessionId,
|
|
386
383
|
};
|
|
387
384
|
|
|
388
|
-
console.log('Video recording completed
|
|
389
|
-
duration: (actualDuration / 1000).toFixed(1) + 's',
|
|
390
|
-
frames: result.frames.length,
|
|
391
|
-
challenges: `${completedChallenges.length}/${challenges.length}`,
|
|
392
|
-
instructionsFollowed: result.instructionsFollowed,
|
|
393
|
-
quality: result.qualityScore.toFixed(0) + '%'
|
|
394
|
-
});
|
|
385
|
+
console.log('Video recording completed:', result.frames.length, 'frames,', (actualDuration / 1000).toFixed(1) + 's');
|
|
395
386
|
|
|
396
387
|
isRecordingRef.current = false;
|
|
397
388
|
onComplete(result);
|
|
@@ -405,7 +396,6 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
405
396
|
|
|
406
397
|
const startFrameCapture = useCallback(() => {
|
|
407
398
|
if (cameraRef.current && device) {
|
|
408
|
-
console.log('Starting frame capture mode');
|
|
409
399
|
frameCaptureInterval.current = setInterval(async () => {
|
|
410
400
|
try {
|
|
411
401
|
const photo = await cameraRef.current?.takePhoto({
|
|
@@ -432,16 +422,13 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
432
422
|
}
|
|
433
423
|
}
|
|
434
424
|
} catch (error) {
|
|
435
|
-
|
|
425
|
+
// Silent frame capture errors
|
|
436
426
|
}
|
|
437
427
|
}, 100);
|
|
438
428
|
}
|
|
439
429
|
}, [device]);
|
|
440
430
|
|
|
441
431
|
const stopRecording = useCallback(async () => {
|
|
442
|
-
console.log('stopRecording called, isRecording:', isRecordingRef.current, 'hasVideoRef:', !!videoRecordingRef.current);
|
|
443
|
-
|
|
444
|
-
// Clear any pending timeouts
|
|
445
432
|
if (recordingTimeoutRef.current) {
|
|
446
433
|
clearTimeout(recordingTimeoutRef.current);
|
|
447
434
|
recordingTimeoutRef.current = null;
|
|
@@ -452,31 +439,22 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
452
439
|
frameCaptureInterval.current = null;
|
|
453
440
|
}
|
|
454
441
|
|
|
455
|
-
// Prevent multiple calls
|
|
456
442
|
if (!isRecordingRef.current) {
|
|
457
|
-
console.log('Recording already stopped, ignoring');
|
|
458
443
|
return;
|
|
459
444
|
}
|
|
460
445
|
|
|
461
|
-
// Mark as not recording first to prevent re-entry
|
|
462
446
|
isRecordingRef.current = false;
|
|
463
447
|
|
|
464
448
|
if (videoRecordingRef.current) {
|
|
465
449
|
try {
|
|
466
|
-
console.log('Stopping video recording, current ref exists');
|
|
467
450
|
const recording = videoRecordingRef.current;
|
|
468
451
|
videoRecordingRef.current = null;
|
|
469
|
-
|
|
470
452
|
await recording.stop();
|
|
471
|
-
console.log('Video recording stopped - waiting for onRecordingFinished callback');
|
|
472
|
-
// onRecordingFinished callback will handle completion
|
|
473
453
|
} catch (error) {
|
|
474
454
|
console.error('Error stopping video recording:', error);
|
|
475
455
|
|
|
476
456
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
477
|
-
console.log('Error duration check:', actualDuration, 'minDurationMs:', minDurationMs, 'frames:', frames.length);
|
|
478
457
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
479
|
-
console.log('Video stopped with error, using captured frames');
|
|
480
458
|
const result: VideoRecordingResult = {
|
|
481
459
|
frames,
|
|
482
460
|
duration: actualDuration,
|
|
@@ -487,8 +465,6 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
487
465
|
};
|
|
488
466
|
onComplete(result);
|
|
489
467
|
} else {
|
|
490
|
-
// Even if we don't have enough frames, try to complete with what we have
|
|
491
|
-
console.log('Completing with available data despite error');
|
|
492
468
|
const result: VideoRecordingResult = {
|
|
493
469
|
frames: frames.length > 0 ? frames : [],
|
|
494
470
|
duration: actualDuration,
|
|
@@ -501,14 +477,22 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
501
477
|
}
|
|
502
478
|
}
|
|
503
479
|
} else {
|
|
504
|
-
console.log('No video recording ref - completing with captured frames');
|
|
505
480
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
506
481
|
|
|
507
|
-
|
|
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
|
+
|
|
508
493
|
setPhase('processing');
|
|
509
494
|
setOverallProgress(100);
|
|
510
495
|
|
|
511
|
-
// Complete with frames we have
|
|
512
496
|
const result: VideoRecordingResult = {
|
|
513
497
|
frames: frames.length > 0 ? frames : [],
|
|
514
498
|
duration: actualDuration,
|
|
@@ -518,40 +502,27 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
518
502
|
sessionId,
|
|
519
503
|
};
|
|
520
504
|
|
|
521
|
-
console.log('Completing without video ref:', {
|
|
522
|
-
frames: result.frames.length,
|
|
523
|
-
duration: (actualDuration / 1000).toFixed(1) + 's',
|
|
524
|
-
challenges: completedChallenges.length
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
// Small delay to ensure UI updates
|
|
528
505
|
setTimeout(() => {
|
|
529
506
|
onComplete(result);
|
|
530
507
|
}, 100);
|
|
531
508
|
}
|
|
532
|
-
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs]);
|
|
509
|
+
}, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs, resetAndRetry, strings]);
|
|
533
510
|
|
|
534
511
|
const runChallenge = useCallback((index: number) => {
|
|
535
512
|
if (index >= challenges.length) {
|
|
536
|
-
console.log('All challenges completed, checking duration');
|
|
537
513
|
setOverallProgress(100);
|
|
538
514
|
|
|
539
|
-
// Clear the totalDuration timeout since we're handling it manually
|
|
540
515
|
if (recordingTimeoutRef.current) {
|
|
541
516
|
clearTimeout(recordingTimeoutRef.current);
|
|
542
517
|
recordingTimeoutRef.current = null;
|
|
543
|
-
console.log('Cleared totalDuration timeout');
|
|
544
518
|
}
|
|
545
519
|
|
|
546
520
|
if (isRecordingRef.current) {
|
|
547
521
|
const elapsed = Date.now() - recordingStartTime.current;
|
|
548
|
-
console.log('Checking duration - Elapsed:', (elapsed / 1000).toFixed(1), 's, Min required:', (minDurationMs / 1000).toFixed(1), 's');
|
|
549
522
|
|
|
550
523
|
if (elapsed < minDurationMs) {
|
|
551
524
|
const remaining = minDurationMs - elapsed;
|
|
552
|
-
console.log('Waiting additional', (remaining / 1000).toFixed(1), 's to meet minimum duration');
|
|
553
525
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
554
|
-
console.log('Minimum duration wait completed, stopping recording');
|
|
555
526
|
if (isRecordingRef.current) {
|
|
556
527
|
stopRecording();
|
|
557
528
|
}
|
|
@@ -559,13 +530,10 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
559
530
|
return;
|
|
560
531
|
}
|
|
561
532
|
|
|
562
|
-
console.log('Duration requirement met, stopping immediately');
|
|
563
533
|
stopRecording();
|
|
564
534
|
} else {
|
|
565
|
-
console.log('Recording already stopped, checking if we can complete');
|
|
566
535
|
const actualDuration = Date.now() - recordingStartTime.current;
|
|
567
536
|
if (actualDuration >= minDurationMs && frames.length > 0) {
|
|
568
|
-
console.log('Recording already stopped, completing with frames');
|
|
569
537
|
const result: VideoRecordingResult = {
|
|
570
538
|
frames,
|
|
571
539
|
duration: actualDuration,
|
|
@@ -632,44 +600,32 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
|
|
|
632
600
|
recordingStartTime.current = Date.now();
|
|
633
601
|
isRecordingRef.current = true;
|
|
634
602
|
|
|
635
|
-
console.log('Starting video recording, total duration:', (totalDuration / 1000).toFixed(1), 's');
|
|
636
|
-
|
|
637
603
|
if (cameraRef.current && device) {
|
|
638
604
|
try {
|
|
639
605
|
videoRecordingRef.current = await cameraRef.current.startRecording({
|
|
640
606
|
flash: 'off',
|
|
641
607
|
onRecordingFinished: (video: any) => {
|
|
642
|
-
|
|
643
|
-
// Ensure we're in the right state to process
|
|
644
|
-
if (phase === 'recording' || phase === 'processing') {
|
|
645
|
-
handleVideoComplete(video);
|
|
646
|
-
} else {
|
|
647
|
-
console.warn('Received onRecordingFinished but phase is', phase, '- calling handleVideoComplete anyway');
|
|
648
|
-
handleVideoComplete(video);
|
|
649
|
-
}
|
|
608
|
+
handleVideoComplete(video);
|
|
650
609
|
},
|
|
651
610
|
onRecordingError: (error: any) => {
|
|
652
611
|
console.error('Recording error:', error);
|
|
653
612
|
handleRecordingError(error);
|
|
654
613
|
},
|
|
655
614
|
});
|
|
656
|
-
|
|
615
|
+
|
|
616
|
+
startFrameCapture();
|
|
657
617
|
} catch (error) {
|
|
658
|
-
console.warn('Video recording not available, falling back to frame capture
|
|
618
|
+
console.warn('Video recording not available, falling back to frame capture');
|
|
659
619
|
startFrameCapture();
|
|
660
620
|
}
|
|
661
621
|
} else {
|
|
662
|
-
console.log('Camera not available, using frame capture');
|
|
663
622
|
startFrameCapture();
|
|
664
623
|
}
|
|
665
624
|
|
|
666
625
|
runChallenge(0);
|
|
667
626
|
|
|
668
|
-
|
|
669
|
-
// This will be cleared if challenges complete early
|
|
670
|
-
const maxDuration = Math.max(totalDuration, minDurationMs + 2000); // Add 2s buffer
|
|
627
|
+
const maxDuration = Math.max(totalDuration, minDurationMs + 2000);
|
|
671
628
|
recordingTimeoutRef.current = setTimeout(() => {
|
|
672
|
-
console.log('Safety timeout reached (max duration), stopping recording');
|
|
673
629
|
if (isRecordingRef.current) {
|
|
674
630
|
stopRecording().catch(err => {
|
|
675
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) {
|