'use client'; import React, { useState, useRef, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, Camera, Trash2, Send, Loader2, Check, AlertCircle, Zap } from 'lucide-react'; import { useBulkScanner } from '@/hooks/useBulkScanner'; interface BulkScanSheetProps { isOpen: boolean; onClose: () => void; sessionId: string; sessionName: string; onSuccess?: (bottleIds: string[]) => void; } export default function BulkScanSheet({ isOpen, onClose, sessionId, sessionName, onSuccess }: BulkScanSheetProps) { const { queue, addToQueue, removeFromQueue, clearQueue, submitToSession, isSubmitting, progress } = useBulkScanner(); const videoRef = useRef(null); const canvasRef = useRef(null); const streamRef = useRef(null); const [isCameraReady, setIsCameraReady] = useState(false); const [cameraError, setCameraError] = useState(null); const [submitError, setSubmitError] = useState(null); // Start camera when sheet opens React.useEffect(() => { if (isOpen) { startCamera(); } else { stopCamera(); } return () => stopCamera(); }, [isOpen]); const startCamera = async () => { try { setCameraError(null); const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment', width: { ideal: 1920 }, height: { ideal: 1080 } } }); if (videoRef.current) { videoRef.current.srcObject = stream; streamRef.current = stream; setIsCameraReady(true); } } catch (error) { console.error('Camera error:', error); setCameraError('Kamera konnte nicht gestartet werden'); } }; const stopCamera = () => { if (streamRef.current) { streamRef.current.getTracks().forEach(track => track.stop()); streamRef.current = null; } setIsCameraReady(false); }; const captureImage = useCallback(() => { if (!videoRef.current || !canvasRef.current) return; const video = videoRef.current; const canvas = canvasRef.current; canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); if (!ctx) return; ctx.drawImage(video, 0, 0); canvas.toBlob((blob) => { if (blob) { addToQueue(blob, `Flasche #${queue.length + 1}`); } }, 'image/webp', 0.85); }, [addToQueue, queue.length]); const handleSubmit = async () => { setSubmitError(null); const result = await submitToSession(sessionId); if (result.success && result.bottleIds) { onSuccess?.(result.bottleIds); setTimeout(() => { onClose(); }, 500); } else { setSubmitError(result.error || 'Fehler beim Hochladen'); } }; const handleClose = () => { if (queue.length > 0 && !isSubmitting) { if (!confirm('Warteschlange verwerfen?')) return; } clearQueue(); onClose(); }; if (!isOpen) return null; return ( {/* Header */}

Bulk Scan

{sessionName}

{/* Camera View */}
{cameraError ? (

{cameraError}

) : ( <>
{/* Queue Strip */} {queue.length > 0 && ( {/* Thumbnails */}
{queue.map((item, i) => (
{`Bottle {item.status === 'uploading' && (
)} {item.status === 'done' && (
)}
{!isSubmitting && item.status === 'queued' && ( )} #{i + 1}
))}
{/* Error Message */} {submitError && (
{submitError}
)} {/* Submit Button */}
)}
); }