"use client"; import { useEffect, useRef, useState } from "react"; import { useTranslations } from "next-intl"; import { Loader2 } from "lucide-react"; export function BarcodeScanner({ onDetected, onError, }: { onDetected: (barcode: string) => void; onError?: (message: string) => void; }) { const t = useTranslations("pantry"); const videoRef = useRef(null); const [starting, setStarting] = useState(true); const detectedRef = useRef(false); useEffect(() => { let cancelled = false; let controls: { stop: () => void } | null = null; async function start() { try { const { BrowserMultiFormatReader } = await import("@zxing/browser"); const reader = new BrowserMultiFormatReader(); if (cancelled || !videoRef.current) return; controls = await reader.decodeFromVideoDevice( undefined, videoRef.current, (result) => { if (result && !detectedRef.current) { detectedRef.current = true; onDetected(result.getText()); controls?.stop(); } } ); if (!cancelled) setStarting(false); } catch (err) { if (!cancelled) { onError?.(err instanceof Error ? err.message : t("cameraError")); setStarting(false); } } } void start(); return () => { cancelled = true; controls?.stop(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (