Android_Retail/src/Services/BarCodeScan.jsx

388 lines
11 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>
// );
// }
2026-02-24 17:19:56 +05:30
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';
2026-02-20 15:32:24 +05:30
QrScanner.WORKER_PATH = new URL(
2026-02-24 17:19:56 +05:30
'qr-scanner/qr-scanner-worker.min.js',
import.meta.url
2026-02-20 15:32:24 +05:30
).toString();
export default function BarCodeScan({ onScan }) {
2026-02-24 17:19:56 +05:30
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;
2026-02-20 15:32:24 +05:30
}
2026-02-24 17:19:56 +05:30
const { barcodes } = await BarcodeScanner.scan();
if (barcodes?.length > 0) {
onScan(barcodes[0].rawValue);
2026-02-20 15:32:24 +05:30
}
2026-02-24 17:19:56 +05:30
} catch (err) {
console.error(err);
} finally {
2026-02-20 15:32:24 +05:30
setScanning(false);
2026-02-24 17:19:56 +05:30
}
} 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) => {
2026-02-20 15:32:24 +05:30
stopWebScan();
2026-02-24 17:19:56 +05:30
onScan(result.data);
2026-02-20 15:32:24 +05:30
setModalOpen(false);
2026-02-24 17:19:56 +05:30
},
{
maxScansPerSecond: 25,
}
);
2026-02-20 15:32:24 +05:30
2026-02-24 17:19:56 +05:30
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);
2026-02-20 15:32:24 +05:30
}
2026-02-24 17:19:56 +05:30
}
);
};
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 (
2026-02-20 15:32:24 +05:30
<div
2026-02-24 17:19:56 +05:30
className="BarCodeScanMaster"
style={{ display: 'flex', justifyContent: 'center', padding: 20 }}
2026-02-20 15:32:24 +05:30
>
2026-02-24 17:19:56 +05:30
{!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={{
position: 'relative',
width: '100%',
maxWidth: 400,
margin: 'auto',
}}
>
{/* VIDEO */}
<video
2026-02-20 15:32:24 +05:30
ref={videoRef}
style={{
2026-02-24 17:19:56 +05:30
width: '100%',
borderRadius: 8,
2026-02-20 15:32:24 +05:30
}}
2026-02-24 17:19:56 +05:30
/>
2026-02-20 15:32:24 +05:30
2026-02-24 17:19:56 +05:30
{/* DARK OVERLAY */}
<div
2026-02-20 15:32:24 +05:30
style={{
2026-02-24 17:19:56 +05:30
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
background: 'rgba(0,0,0,0.5)',
borderRadius: 8,
2026-02-20 15:32:24 +05:30
}}
2026-02-24 17:19:56 +05:30
/>
2026-02-20 15:32:24 +05:30
2026-02-24 17:19:56 +05:30
{/* SCAN BOX */}
<div
2026-02-20 15:32:24 +05:30
style={{
2026-02-24 17:19:56 +05:30
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)',
2026-02-20 15:32:24 +05:30
}}
2026-02-24 17:19:56 +05:30
/>
2026-02-20 15:32:24 +05:30
2026-02-24 17:19:56 +05:30
{/* SCAN LINE */}
<div
2026-02-20 15:32:24 +05:30
style={{
2026-02-24 17:19:56 +05:30
position: 'absolute',
left: '15%',
width: '70%',
height: 2,
background: 'red',
animation: 'scanAnimation 2s infinite linear',
2026-02-20 15:32:24 +05:30
}}
2026-02-24 17:19:56 +05:30
/>
</div>
2026-02-20 15:32:24 +05:30
2026-02-24 17:19:56 +05:30
<button
onClick={closeModal}
style={{
2026-02-20 15:32:24 +05:30
marginTop: 20,
2026-02-24 17:19:56 +05:30
padding: '10px 20px',
2026-02-20 15:32:24 +05:30
fontSize: 16,
borderRadius: 8,
2026-02-24 17:19:56 +05:30
border: 'none',
cursor: 'pointer',
}}
>
Close
</button>
{/* Animation */}
<style>
{`
2026-02-20 15:32:24 +05:30
@keyframes scanAnimation {
0% { top: 25%; }
50% { top: 70%; }
100% { top: 25%; }
}
`}
2026-02-24 17:19:56 +05:30
</style>
</DefaultModal>
</div>
);
}