mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-07 09:57:50 +08:00
fix(qr): resolve scanner race condition and crashes
This commit addresses several issues related to the QR code scanner: - Fixes a build failure by defining stable handlers (`handleRestoreClose`, `handleRestoreError`) for the QRScanner component in `App.tsx` using `useCallback`. - Resolves a race condition that caused an `AbortError` when the scanner was initialized, particularly in React Strict Mode. This was fixed by ensuring all props passed to the scanner are stable. - Implements more robust error handling within the `QRScanner` component to prevent crashes when `null` or `undefined` errors are caught. - Updates documentation (`README.md`, `GEMINI.md`) to version 1.4.5.
This commit is contained in:
@@ -70,22 +70,14 @@ export default function QRScanner({ onScanSuccess, onClose, onError }: QRScanner
|
||||
// jsQR gives us raw bytes!
|
||||
const rawBytes = code.binaryData;
|
||||
|
||||
console.log('🔍 Raw QR bytes:', rawBytes);
|
||||
console.log(' - Length:', rawBytes.length);
|
||||
console.log(' - Hex:', Array.from(rawBytes).map((b: number) => b.toString(16).padStart(2, '0')).join(''));
|
||||
|
||||
// Detect binary (16 or 32 bytes with non-printable chars)
|
||||
const isBinary = (rawBytes.length === 16 || rawBytes.length === 32) &&
|
||||
/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]/.test(String.fromCharCode(...Array.from(rawBytes)));
|
||||
|
||||
console.log('📊 Is binary?', isBinary);
|
||||
|
||||
if (isBinary) {
|
||||
console.log('✅ Passing Uint8Array');
|
||||
onScanSuccess(new Uint8Array(rawBytes));
|
||||
} else {
|
||||
// Text QR - use the text property
|
||||
console.log('✅ Passing string:', code.data.slice(0, 50));
|
||||
onScanSuccess(code.data);
|
||||
}
|
||||
|
||||
@@ -94,9 +86,33 @@ export default function QRScanner({ onScanSuccess, onClose, onError }: QRScanner
|
||||
}, 300);
|
||||
}
|
||||
} catch (err: any) {
|
||||
// IMPORTANT: Check for null/undefined err object first.
|
||||
if (!err) {
|
||||
console.error('Caught a null or undefined error inside QRScanner.');
|
||||
return; // Exit if error is falsy
|
||||
}
|
||||
|
||||
if (isCancelled || err.name === 'AbortError') {
|
||||
console.log('Camera operation was cancelled or aborted, which is expected on unmount.');
|
||||
return; // Ignore abort errors, they are expected on cleanup
|
||||
}
|
||||
|
||||
console.error('Camera error:', err);
|
||||
setHasPermission(false);
|
||||
const errorMsg = 'Camera access was denied.';
|
||||
|
||||
let errorMsg = 'An unknown camera error occurred.';
|
||||
if (err.name === 'NotAllowedError') {
|
||||
errorMsg = 'Camera access was denied. Please grant permission in your browser settings.';
|
||||
} else if (err.name === 'NotFoundError') {
|
||||
errorMsg = 'No camera found on this device.';
|
||||
} else if (err.name === 'NotReadableError') {
|
||||
errorMsg = 'Cannot access the camera. It may be in use by another application or browser tab.';
|
||||
} else if (err.name === 'OverconstrainedError') {
|
||||
errorMsg = 'The camera does not meet the required constraints.';
|
||||
} else if (err instanceof Error) {
|
||||
errorMsg = `Camera error: ${err.message}`;
|
||||
}
|
||||
|
||||
setInternalError(errorMsg);
|
||||
onError?.(errorMsg);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user