import { Autocomplete, Box, Button, Card, CardContent, Grid, Modal, ModalProps, Stack, SxProps, TextField, Typography, } from "@mui/material"; import { CameraDevice, Html5Qrcode, Html5QrcodeCameraScanConfig, Html5QrcodeFullConfig, Html5QrcodeResult, Html5QrcodeScanner, Html5QrcodeScannerState, QrcodeErrorCallback, QrcodeSuccessCallback, } from "html5-qrcode"; import { Html5QrcodeError } from "html5-qrcode/esm/core"; import { Html5QrcodeScannerConfig } from "html5-qrcode/esm/html5-qrcode-scanner"; import React, { RefObject, useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { useTranslation } from "react-i18next"; import QrCodeScannerIcon from "@mui/icons-material/QrCodeScanner"; import StopCircleOutlinedIcon from "@mui/icons-material/StopCircleOutlined"; import CloseOutlinedIcon from "@mui/icons-material/CloseOutlined"; import { QrCodeInfo } from "@/app/api/qrcode"; const scannerSx: React.CSSProperties = { position: "absolute", // top: "50%", // left: "50%", // transform: "translate(-50%, -50%)", width: "90%", maxHeight: "10%", maxWidth: 1400, }; type QrCodeScannerProps = { cameras: CameraDevice[]; title?: string; contents?: string[]; onScanSuccess: (qrCodeInfo: QrCodeInfo) => void; onScanError?: (error: string) => void; isOpen: boolean; onClose: () => void; }; const QrCodeScanner: React.FC = ({ title, contents, onScanSuccess, onScanError, isOpen, onClose, }) => { const { t } = useTranslation(); const [isScanned, setIsScanned] = useState(false); const [scanner, setScanner] = useState(null); const [cameraList, setCameraList] = useState([]); const [selectedCameraId, setSelectedCameraId] = useState(null); const stringList = [ "ABC: abc", "123:123", "ABC: abc", "123:123", "ABC: abc", "123:123", ]; const scannerConfig: Html5QrcodeFullConfig = { verbose: false, }; const cameraConfig: Html5QrcodeCameraScanConfig = { fps: 10, qrbox: { width: 250, height: 250 }, // aspectRatio: cardRef.current ? (cardRef.current.offsetWidth / cardRef.current.offsetHeight) : 1.78, aspectRatio: (window.innerWidth / window.innerHeight) * 1.5, // can be better }; // MediaTrackConstraintSet const mediaTrackConstraintSet = { facingMode: "environment", }; const handleScanStart = useCallback(() => { if (scanner && selectedCameraId) { if (scanner.getState() === Html5QrcodeScannerState.SCANNING) { console.log("first"); scanner.stop(); } scanner.start( selectedCameraId, cameraConfig, handleScanSuccess, handleScanError ); } }, [selectedCameraId, scanner]); const handleCameraList = useCallback(async () => { const cameras = await Html5Qrcode.getCameras(); setCameraList(cameras); if (cameras.length > 0) { handleCameraChange(cameras[cameras.length - 1].id); } }, []); const handleCameraChange = useCallback((id: string) => { setSelectedCameraId(id); }, []); const switchScanStatus = useCallback(() => { if (scanner) { console.log(isScanned); switch (isScanned) { case true: setIsScanned(false); scanner.resume(); break; case false: setIsScanned(true); scanner.pause(true); break; } } }, [scanner, isScanned]); const handleScanSuccess = useCallback( (decodedText, result) => { if (scanner) { console.log(`Decoded text: ${decodedText}`); const parseData: QrCodeInfo = JSON.parse(decodedText); console.log(parseData); // Handle the decoded text as needed switchScanStatus(); onScanSuccess(parseData); } }, [scanner, onScanSuccess] ); const handleScanError = useCallback( (errorMessage, error) => { // console.log(`Error: ${errorMessage}`); if (onScanError) { onScanError(errorMessage); } }, [scanner, onScanError] ); const handleScanCloseButton = useCallback(async () => { if (scanner) { console.log("Cleaning up scanner..."); await scanner.stop(); scanner.clear(); onClose(); } }, [scanner]); // close modal without using Cancel Button const handleScanClose = useCallback(async () => { if (scanner && !isOpen) { handleScanCloseButton(); } }, [scanner, isOpen, handleScanCloseButton]); // -------------------------------------------------------// useEffect(() => { setScanner(new Html5Qrcode("qr-reader", scannerConfig)); handleCameraList(); }, []); useEffect(() => { handleScanStart(); }, [scanner, selectedCameraId]); useEffect(() => { handleScanClose(); }, [isOpen]); return ( <> {title && ( {"Title"} )}