import Quagga, { QuaggaJSCodeReader, QuaggaJSResultObject, } from "@ericblade/quagga2"; import { useState, useCallback, useEffect } from "react"; import { getMedianOfCodeErrors } from "./getMedianOfCodeErrors"; import { drawQuaggaProcessing } from "./drawQuaggaProcessing"; const constraints = { width: 640, height: 480, }; const locator = { patchSize: "medium", halfSample: true, willReadFrequently: true, }; const readers: QuaggaJSCodeReader[] = ["ean_reader"]; export const useScanner = ({ onDetected, }: { onDetected?: (result: string) => void; }): { setScannerRef: (ref: HTMLDivElement | null) => void; scannerError: string | undefined; } => { const [scannerError, setScannerError] = useState<string | undefined>(); const [scannerRef, setScannerRef] = useState<HTMLDivElement | null>(null); const errorCheck = useCallback( (result: QuaggaJSResultObject) => { if (!onDetected) { return; } const err = getMedianOfCodeErrors(result); if (!err) { return; } if (err < 0.1 && result.codeResult.code) { onDetected(result.codeResult.code); } }, [onDetected] ); const getCameraId = useCallback(async () => { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" }, }); if ( stream && stream.getVideoTracks().length && stream.getVideoTracks()[0].getSettings().deviceId ) { return stream.getVideoTracks()[0].getSettings().deviceId; } const devices = await navigator.mediaDevices .enumerateDevices() .then((ds) => ds.filter((d) => d.kind === "videoinput")); const back = devices.filter((d) => d.label.toLowerCase().includes("back") )[0]; return !back ? devices[0].deviceId : back.deviceId; }, []); const initQuagga = useCallback(async () => { try { const cameraId = await getCameraId(); if (!scannerRef || !cameraId) { console.log("fehlt", scannerRef, cameraId); return; } await Quagga.init( { inputStream: { type: "LiveStream", constraints: { ...constraints, ...(cameraId && { deviceId: cameraId }), }, target: scannerRef, willReadFrequently: true, }, locator, decoder: { readers }, locate: true, }, async (err) => { Quagga.onProcessed(drawQuaggaProcessing); if (err) { return console.error("Error starting Quagga:", err); } if (scannerRef) { Quagga.start(); } } ); Quagga.onDetected(errorCheck); } catch (e: unknown) { setScannerError(JSON.stringify(e)); } }, [errorCheck, getCameraId, scannerRef]); const stopQuagga = useCallback(async () => { await Quagga.CameraAccess.release(); await Quagga.stop(); Quagga.offDetected(errorCheck); Quagga.offProcessed(drawQuaggaProcessing); }, [errorCheck]); useEffect(() => { const init = () => { initQuagga(); }; const disable = () => { stopQuagga(); }; if (scannerRef) { init(); } return disable(); }, [stopQuagga, initQuagga, scannerRef]); return { setScannerRef, scannerError, }; };