summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/lib/camera/component/scannerBarcode.tsx95
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>