qrCodeScanner.tsx
1 import { CameraOutlined } from "@ant-design/icons"; 2 import { useTranslate } from "@refinedev/core"; 3 import { IDetectedBarcode, Scanner } from "@yudiel/react-qr-scanner"; 4 import { FloatButton, Modal, Space } from "antd"; 5 import { useState } from "react"; 6 import { useNavigate } from "react-router"; 7 8 const QRCodeScannerModal = () => { 9 const [visible, setVisible] = useState(false); 10 const [lastError, setLastError] = useState<string | null>(null); 11 const t = useTranslate(); 12 const navigate = useNavigate(); 13 14 const onScan = (detectedCodes: IDetectedBarcode[]) => { 15 if (detectedCodes.length === 0) { 16 return; 17 } 18 const result = detectedCodes[0].rawValue; 19 20 // Check for the spoolman ID format 21 const match = result.match(/^web\+spoolman:s-(?<id>[0-9]+)$/i); 22 if (match && match.groups) { 23 setVisible(false); 24 navigate(`/spool/show/${match.groups.id}`); 25 } 26 const fullURLmatch = result.match(/^https?:\/\/[^/]+\/spool\/show\/(?<id>[0-9]+)$/i); 27 if (fullURLmatch && fullURLmatch.groups) { 28 setVisible(false); 29 navigate(`/spool/show/${fullURLmatch.groups.id}`); 30 } 31 }; 32 33 return ( 34 <> 35 <FloatButton type="primary" onClick={() => setVisible(true)} icon={<CameraOutlined />} shape="circle" /> 36 <Modal open={visible} destroyOnHidden onCancel={() => setVisible(false)} footer={null} title={t("scanner.title")}> 37 <Space direction="vertical" style={{ width: "100%" }}> 38 <p>{t("scanner.description")}</p> 39 <Scanner 40 constraints={{ 41 facingMode: "environment", 42 }} 43 onScan={onScan} 44 formats={["qr_code"]} 45 onError={(err: unknown) => { 46 const error = err as Error; 47 console.error(error); 48 if (error.name === "NotAllowedError") { 49 setLastError(t("scanner.error.notAllowed")); 50 } else if ( 51 error.name === "InsecureContextError" || 52 (location.protocol !== "https:" && navigator.mediaDevices === undefined) 53 ) { 54 setLastError(t("scanner.error.insecureContext")); 55 } else if (error.name === "StreamApiNotSupportedError") { 56 setLastError(t("scanner.error.streamApiNotSupported")); 57 } else if (error.name === "NotReadableError") { 58 setLastError(t("scanner.error.notReadable")); 59 } else if (error.name === "NotFoundError") { 60 setLastError(t("scanner.error.notFound")); 61 } else { 62 setLastError(t("scanner.error.unknown", { error: error.name })); 63 } 64 }} 65 > 66 {lastError && ( 67 <div 68 style={{ 69 position: "absolute", 70 textAlign: "center", 71 width: "100%", 72 top: "50%", 73 }} 74 > 75 <p>{lastError}</p> 76 </div> 77 )} 78 </Scanner> 79 </Space> 80 </Modal> 81 </> 82 ); 83 }; 84 85 export default QRCodeScannerModal;