diff --git a/server/src/services/eventService.ts b/server/src/services/eventService.ts index 3069870..38156cb 100644 --- a/server/src/services/eventService.ts +++ b/server/src/services/eventService.ts @@ -392,6 +392,7 @@ export const eventService = { user: { select: { id: true, + clerkId: true, username: true, firstName: true, lastName: true, diff --git a/src/components/event/QRCodeScanner.tsx b/src/components/event/QRCodeScanner.tsx index cbb1cbf..af7b029 100644 --- a/src/components/event/QRCodeScanner.tsx +++ b/src/components/event/QRCodeScanner.tsx @@ -9,6 +9,8 @@ interface QRCodeScannerProps { export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { const [isScanning, setIsScanning] = useState(false); const [error, setError] = useState(null); + const [showManualInput, setShowManualInput] = useState(false); + const [manualInput, setManualInput] = useState(''); const scannerRef = useRef(null); const scannerIdRef = useRef('qr-reader'); @@ -49,17 +51,31 @@ export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { onError?.(errorMsg); } }, - (errorMessage) => { + () => { // Ignore scanning errors (happens continuously while scanning) } ); setIsScanning(true); } catch (err: any) { - const errorMsg = err.message || 'Failed to start camera'; + 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')) { + 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')) { + errorMsg = 'Camera is already in use by another application.'; + } else if (err.message?.includes('secure')) { + errorMsg = 'Camera access requires HTTPS. Use manual input instead.'; + } + setError(errorMsg); onError?.(errorMsg); setIsScanning(false); + setShowManualInput(true); // Show manual input as fallback } }; @@ -75,6 +91,24 @@ export function QRCodeScanner({ onScan, onError }: QRCodeScannerProps) { } }; + const handleManualSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!manualInput.trim()) return; + + try { + const data = JSON.parse(manualInput); + if (data.type === 'attendee-checkin' && data.userId) { + onScan(data.userId); + setManualInput(''); + setShowManualInput(false); + } else { + setError('Invalid QR code data format'); + } + } catch (err) { + setError('Invalid JSON format. Please scan the QR code or paste valid data.'); + } + }; + return (
- {error} +

{error}

+ {error.includes('HTTPS') && ( +

+ 💡 Tip: Camera access requires a secure connection (HTTPS) in most browsers. Use manual input below as an alternative. +

+ )} + {error.includes('permission') && ( +

+ 💡 Tip: Check your browser's address bar for camera permission settings, or use manual input below. +

+ )}
)}
{!isScanning ? ( - + <> + + + ) : (