Android_Retail/src/Services/BarCodeScan.jsx

419 lines
12 KiB
React
Raw Normal View History

2026-02-20 15:32:24 +05:30
// 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 (
// <div style={{ display: "flex", justifyContent: "center", padding: 20 }}>
// {!scanning && (
// <BsUpcScan
// onClick={startScan}
// style={{ fontSize: 32, color: "#007bff", cursor: "pointer" }}
// />
// )}
// <DefaultModal
// title="Barcode Reader"
// width={500}
// open={modalOpen}
// footer={false}
// handleCancel={() => {
// closeModal();
// }}
// >
// <div
// style={{
// display: "flex",
// flexDirection: "column",
// alignItems: "center",
// justifyContent: "center",
// }}
// >
// <video
// ref={videoRef}
// style={{
// width: "100%",
// maxWidth: 400,
// borderRadius: 8,
// border: "2px solid #000",
// }}
// />
// <button
// onClick={closeModal}
// style={{
// marginTop: 20,
// padding: "10px 20px",
// fontSize: 16,
// borderRadius: 8,
// border: "none",
// cursor: "pointer",
// }}
// >
// Close
// </button>
// </div>
// </DefaultModal>
// </div>
// );
// }
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 (
<div style={{ display: "flex", justifyContent: "center", padding: 20 }}>
{!scanning && (
<BsUpcScan
onClick={startScan}
style={{
fontSize: 32,
color: "#007bff",
cursor: "pointer",
}}
/>
)}
{/* <DefaultModal
title="QR / Barcode Reader"
width={500}
open={modalOpen}
footer={false}
handleCancel={closeModal}
>
<div style={{ display: "flex", justifyContent: "center" }}>
<video
ref={videoRef}
style={{
width: "100%",
maxWidth: 400,
borderRadius: 8,
}}
/>
</div>
<button
onClick={closeModal}
style={{
marginTop: 20,
padding: "10px 20px",
fontSize: 16,
borderRadius: 8,
border: "none",
cursor: "pointer",
}}
>
Close
</button>
</DefaultModal> */}
<DefaultModal
title="QR / Barcode Reader"
width={500}
open={modalOpen}
footer={false}
handleCancel={closeModal}
>
<div
style={{
position: "relative",
width: "100%",
maxWidth: 400,
margin: "auto",
}}
>
{/* VIDEO */}
<video
ref={videoRef}
style={{
width: "100%",
borderRadius: 8,
}}
/>
{/* DARK OVERLAY */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background: "rgba(0,0,0,0.5)",
borderRadius: 8,
}}
/>
{/* SCAN BOX */}
<div
style={{
position: "absolute",
top: "50%",
left: "50%",
width: "70%",
height: "60%",
transform: "translate(-50%, -50%)",
border: "3px solid #00ff00",
borderRadius: 12,
boxShadow: "0 0 0 2000px rgba(0,0,0,0.4)",
}}
/>
{/* SCAN LINE */}
<div
style={{
position: "absolute",
left: "15%",
width: "70%",
height: 2,
background: "red",
animation: "scanAnimation 2s infinite linear",
}}
/>
</div>
<button
onClick={closeModal}
style={{
marginTop: 20,
padding: "10px 20px",
fontSize: 16,
borderRadius: 8,
border: "none",
cursor: "pointer",
}}
>
Close
</button>
{/* Animation */}
<style>
{`
@keyframes scanAnimation {
0% { top: 25%; }
50% { top: 70%; }
100% { top: 25%; }
}
`}
</style>
</DefaultModal>
</div>
);
}