summaryrefslogtreecommitdiff
path: root/app/lib/camera/component/scannerBarcode.tsx
blob: 18f953d7aa0c3d8c141c052aa0365602a44fe3e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { QrCode2 } from "@mui/icons-material";
import { Button, TextField } from "@mui/material";
import { BrowserMultiFormatReader } from "@zxing/browser";
import React, { useEffect, useRef, useState } from "react";
import useCameraStore from "../hooks/useCameraStore";

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"
        color="error"
        startIcon={<QrCode2 />}
        className="mb-2"
        onClick={() => {
          if (isCameraActive) stopCamera();
          setIsCameraActive((v) => !v);
        }}
      >
        {isCameraActive ? "Cancel" : "Scan Code"}
      </Button>

      {isCameraActive && (
        <>
          <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"
          value={barcode}
          inputRef={inputRef}
          onChange={(e) => setBarcode(e.target.value)}
          InputLabelProps={{ shrink: true }}
        />
      </div>
    </div>
  );
};

export default BarcodeScanner;