diff --git a/src/components/event/QRCodeScanner.tsx b/src/components/event/QRCodeScanner.tsx index af7b029..9b3d174 100644 --- a/src/components/event/QRCodeScanner.tsx +++ b/src/components/event/QRCodeScanner.tsx @@ -26,6 +26,18 @@ export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { const startScanning = async () => { try { setError(null); + + // First, check if we can get camera devices (this will trigger permission prompt) + try { + const devices = await Html5Qrcode.getCameras(); + if (!devices || devices.length === 0) { + throw new Error('No camera found on this device.'); + } + } catch (permErr: any) { + // If we can't get cameras, it might be a permission issue + console.error('Camera access error:', permErr); + } + const scanner = new Html5Qrcode(scannerIdRef.current); scannerRef.current = scanner; @@ -60,16 +72,23 @@ export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { } catch (err: any) { let errorMsg = 'Failed to start camera'; - if (err.message?.includes('Permission')) { - errorMsg = 'Camera permission denied. Please allow camera access in your browser settings.'; - } else if (err.message?.includes('NotFoundError')) { + console.error('Scanner error:', err); + + if (err.name === 'NotAllowedError' || err.message?.includes('NotAllowedError')) { + errorMsg = 'Camera permission denied. Please click "Allow" when your browser asks for camera access.'; + } else if (err.name === 'NotFoundError' || err.message?.includes('NotFoundError')) { errorMsg = 'No camera found on this device.'; - } else if (err.message?.includes('NotAllowedError')) { - errorMsg = 'Camera access was denied. Please grant permission and try again.'; - } else if (err.message?.includes('NotReadableError')) { + } else if (err.name === 'NotReadableError' || err.message?.includes('NotReadableError')) { errorMsg = 'Camera is already in use by another application.'; - } else if (err.message?.includes('secure')) { + } else if (err.name === 'OverconstrainedError' || err.message?.includes('OverconstrainedError')) { + errorMsg = 'Camera constraints not supported. Trying with default camera...'; + // Try again without facingMode constraint + setTimeout(() => startScanningWithoutConstraints(), 1000); + return; + } else if (err.message?.includes('secure') || err.message?.includes('https')) { errorMsg = 'Camera access requires HTTPS. Use manual input instead.'; + } else if (err.message) { + errorMsg = `Camera error: ${err.message}`; } setError(errorMsg); @@ -79,6 +98,50 @@ export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { } }; + const startScanningWithoutConstraints = async () => { + try { + setError(null); + const scanner = new Html5Qrcode(scannerIdRef.current); + scannerRef.current = scanner; + + // Try with any available camera + const devices = await Html5Qrcode.getCameras(); + if (devices && devices.length > 0 && devices[0]) { + await scanner.start( + devices[0].id, // Use first available camera + { + fps: 10, + qrbox: { width: 250, height: 250 }, + }, + (decodedText) => { + try { + const data = JSON.parse(decodedText); + if (data.type === 'attendee-checkin' && data.userId) { + onScan(data.userId); + } else { + const errorMsg = 'Invalid QR code format'; + setError(errorMsg); + onError?.(errorMsg); + } + } catch (err) { + const errorMsg = 'Failed to parse QR code'; + setError(errorMsg); + onError?.(errorMsg); + } + }, + () => { + // Ignore scanning errors + } + ); + setIsScanning(true); + } + } catch (err: any) { + console.error('Fallback scanner error:', err); + setError('Unable to access camera. Please use manual check-in instead.'); + setShowManualInput(true); + } + }; + const stopScanning = async () => { if (scannerRef.current) { try { @@ -111,6 +174,21 @@ export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { return (
+ {/* Info message before scanning */} + {!isScanning && !error && ( +
+
+ + + +
+

Camera Permission Required

+

When you click "Start Camera Scan", your browser will ask for camera permission. Please click "Allow" to enable QR code scanning.

+
+
+
+ )} +