From c02762ae157d167ae27bf34f6014abcb49deecc1 Mon Sep 17 00:00:00 2001
From: Mqdd <ahmadmiqdad27@gmail.com>
Date: Mon, 15 Dec 2025 09:58:17 +0700
Subject: <Miqdad> scanner using zxing

---
 app/lib/camera/component/scannerBarcode.tsx | 95 ++++++++++++++++++++---------
 1 file changed, 65 insertions(+), 30 deletions(-)

(limited to 'app/lib/camera/component/scannerBarcode.tsx')

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>
-- 
cgit v1.2.3

