diff --git a/src/Services/BarCodeScan.jsx b/src/Services/BarCodeScan.jsx new file mode 100644 index 0000000..4e2c71c --- /dev/null +++ b/src/Services/BarCodeScan.jsx @@ -0,0 +1,419 @@ +// import React, { useRef, useState, useEffect } from "react"; +// import { BarcodeScanner } from "@capacitor-mlkit/barcode-scanning"; +// import { BsUpcScan } from "react-icons/bs"; +// import { BrowserMultiFormatReader } from "@zxing/library"; +// import { Capacitor } from "@capacitor/core"; +// import { DefaultModal } from "../Components/Modal/DefaultModal"; + +// export default function BarCodeScan({ onScan }) { +// const isMobileApp = Capacitor.getPlatform() !== "web"; +// const [scanning, setScanning] = useState(false); +// const [modalOpen, setModalOpen] = useState(false); +// const videoRef = useRef(null); +// const codeReaderRef = useRef(null); +// const streamRef = useRef(null); + +// const startScan = async () => { +// if (scanning) return; +// setScanning(true); + +// if (isMobileApp) { +// // Mobile: MLKit scanner +// try { +// const perm = await BarcodeScanner.requestPermissions(); +// if (perm.camera !== "granted") { +// alert("Camera permission not granted"); +// setScanning(false); +// return; +// } + +// const { barcodes } = await BarcodeScanner.scan(); +// if (barcodes && barcodes.length > 0) { +// onScan(barcodes[0].rawValue); +// } +// } catch (err) { +// alert("Error scanning barcode: " + err.message); +// } finally { +// setScanning(false); +// } +// } else { +// // Web: open modal and start camera +// setModalOpen(true); +// setTimeout(() => startWebScan(), 50); // wait for modal DOM +// } +// }; + +// const startWebScan = async () => { +// try { +// codeReaderRef.current = new BrowserMultiFormatReader(); +// streamRef.current = await navigator.mediaDevices.getUserMedia({ +// video: { facingMode: "environment" }, +// }); +// if (videoRef.current) { +// videoRef.current.srcObject = streamRef.current; +// videoRef.current.play(); +// } + +// codeReaderRef.current.decodeFromVideoDevice( +// null, +// videoRef.current, +// (result) => { +// if (result) { +// onScan(result.getText()); +// stopWebScan(); +// setModalOpen(false); +// } +// } +// ); +// } catch (err) { +// alert("Error accessing camera: " + err.message); +// setScanning(false); +// setModalOpen(false); +// } +// }; + +// const stopWebScan = () => { +// if (streamRef.current) { +// streamRef.current.getTracks().forEach((track) => track.stop()); +// streamRef.current = null; +// } +// if (codeReaderRef.current) { +// codeReaderRef.current.reset(); +// codeReaderRef.current = null; +// } +// setScanning(false); +// }; + +// const closeModal = () => { +// stopWebScan(); +// setModalOpen(false); +// }; + +// // Stop camera if component unmounts +// useEffect(() => () => stopWebScan(), []); + +// return ( +//
+// {!scanning && ( +// +// )} + +// { +// closeModal(); +// }} +// > +//
+//
+//
+ +//
+// ); +// } + +import React, { useRef, useState, useEffect } from "react"; +import { BarcodeScanner } from "@capacitor-mlkit/barcode-scanning"; +import { BsUpcScan } from "react-icons/bs"; +import { Capacitor } from "@capacitor/core"; +import { DefaultModal } from "../Components/Modal/DefaultModal"; +import QrScanner from "qr-scanner/qr-scanner.min.js"; +import { + BrowserMultiFormatReader, + BarcodeFormat, +} from "@zxing/library"; + +QrScanner.WORKER_PATH = new URL( + "qr-scanner/qr-scanner-worker.min.js", + import.meta.url +).toString(); + +export default function BarCodeScan({ onScan }) { + const isMobileApp = Capacitor.getPlatform() !== "web"; + const [scanning, setScanning] = useState(false); + const [modalOpen, setModalOpen] = useState(false); + + const videoRef = useRef(null); + const qrScannerRef = useRef(null); + const barcodeReaderRef = useRef(null); + + // ------------------------- + // START SCAN + // ------------------------- + const startScan = async () => { + if (scanning) return; + setScanning(true); + + if (isMobileApp) { + try { + const perm = await BarcodeScanner.requestPermissions(); + if (perm.camera !== "granted") { + alert("Camera permission not granted"); + setScanning(false); + return; + } + + const { barcodes } = await BarcodeScanner.scan(); + if (barcodes?.length > 0) { + onScan(barcodes[0].rawValue); + } + } catch (err) { + console.error(err); + } finally { + setScanning(false); + } + } else { + setModalOpen(true); + } + }; + + // ------------------------- + // START WEB SCAN (HYBRID) + // ------------------------- + const startWebScan = async () => { + if (!videoRef.current) return; + + // Start QR scanner (fast) + qrScannerRef.current = new QrScanner( + videoRef.current, + (result) => { + stopWebScan(); + onScan(result.data); + setModalOpen(false); + }, + { + maxScansPerSecond: 25, + } + ); + + await qrScannerRef.current.start(); + + // Start Barcode scanner (ZXing) + barcodeReaderRef.current = new BrowserMultiFormatReader(undefined, { + possibleFormats: [ + BarcodeFormat.CODE_128, + BarcodeFormat.EAN_13, + BarcodeFormat.UPC_A, + BarcodeFormat.UPC_E, + ], + }); + + barcodeReaderRef.current.timeBetweenDecodingAttempts = 50; + + barcodeReaderRef.current.decodeFromVideoDevice( + null, + videoRef.current, + (result) => { + if (result) { + stopWebScan(); + onScan(result.getText()); + setModalOpen(false); + } + } + ); + }; + + const stopWebScan = () => { + if (qrScannerRef.current) { + qrScannerRef.current.stop(); + qrScannerRef.current.destroy(); + qrScannerRef.current = null; + } + + if (barcodeReaderRef.current) { + barcodeReaderRef.current.reset(); + barcodeReaderRef.current = null; + } + + setScanning(false); + }; + + const closeModal = () => { + stopWebScan(); + setModalOpen(false); + }; + + useEffect(() => { + if (modalOpen) { + startWebScan(); + } + }, [modalOpen]); + + useEffect(() => { + return () => stopWebScan(); + }, []); + + return ( +
+ {!scanning && ( + + )} + + {/* +
+
+ + +
*/} + +
+ {/* VIDEO */} +