diff options
Diffstat (limited to 'app/lib/camera/component/scannerBarcode.tsx')
| -rw-r--r-- | app/lib/camera/component/scannerBarcode.tsx | 95 |
1 files changed, 65 insertions, 30 deletions
diff --git a/app/lib/camera/component/scannerBarcode.tsx b/app/lib/camera/component/scannerBarcode.tsx index 6319a84..18f953d 100644 --- a/app/lib/camera/component/scannerBarcode.tsx +++ b/app/lib/camera/component/scannerBarcode.tsx @@ -1,52 +1,87 @@ import { QrCode2 } from "@mui/icons-material"; import { Button, TextField } from "@mui/material"; -import dynamic from "next/dynamic"; -import React, { useState } from "react"; +import { BrowserMultiFormatReader } from "@zxing/browser"; +import React, { useEffect, useRef, useState } from "react"; import useCameraStore from "../hooks/useCameraStore"; -const BarcodeScannerComponent = dynamic( - () => import("react-qr-barcode-scanner"), - { ssr: false } -); const BarcodeScanner: React.FC = () => { const { barcode, setBarcode } = useCameraStore(); const [isCameraActive, setIsCameraActive] = useState(false); + const videoRef = useRef<HTMLVideoElement>(null); + const inputRef = useRef<HTMLInputElement>(null); + + const stopCamera = () => { + const video = videoRef.current; + if (!video || !video.srcObject) return; + + const stream = video.srcObject as MediaStream; + stream.getTracks().forEach((track) => track.stop()); + video.srcObject = null; + }; + + useEffect(() => { + if (!isCameraActive || !videoRef.current) return; + + const reader = new BrowserMultiFormatReader(); + let cancelled = false; + + reader + .decodeOnceFromVideoDevice(undefined, videoRef.current) + .then((result) => { + if (cancelled) return; + + setBarcode(result.getText()); + setIsCameraActive(false); + stopCamera(); + + // 🔥 fokus ke input biar bisa diedit + setTimeout(() => { + inputRef.current?.focus(); + }, 100); + }) + .catch(() => { + // ignore cancel / permission stop + }); + + return () => { + cancelled = true; + stopCamera(); + }; + }, [isCameraActive, setBarcode]); + return ( <div> - <Button - variant="outlined" - onClick={() => setIsCameraActive(!isCameraActive)} - startIcon={<QrCode2 />} - color="error" - className="mb-2" - > - {isCameraActive ? "Cancel" : "Scan Code"} - </Button> + <Button + variant="outlined" + color="error" + startIcon={<QrCode2 />} + className="mb-2" + onClick={() => { + if (isCameraActive) stopCamera(); + setIsCameraActive((v) => !v); + }} + > + {isCameraActive ? "Cancel" : "Scan Code"} + </Button> {isCameraActive && ( - <BarcodeScannerComponent - width={500} // Tingkatkan ukuran untuk memperjelas gambar - height={300} - onUpdate={(err, result) => { - if (result) { - setBarcode(result.getText()); - setIsCameraActive(false); - } - }} - /> + <> + <p className="text-xs text-gray-500 mb-1"> + Arahkan barcode ke tengah layar + </p> + <video ref={videoRef} className="w-full h-[300px] border rounded" /> + </> )} <div className="mt-4"> <TextField fullWidth label="Detected Picking Code" - id="outlined-basic" value={barcode} - onChange={ (e) => setBarcode(e.target.value) } - InputLabelProps={{ - shrink: true, // Label akan selalu berada di atas (outline) - }} + inputRef={inputRef} + onChange={(e) => setBarcode(e.target.value)} + InputLabelProps={{ shrink: true }} /> </div> </div> |
