Client: Added simple qr code scanner

This commit is contained in:
Donkie
2023-08-03 21:51:49 +02:00
parent d7ccd24257
commit 3eda3580f6
3 changed files with 117 additions and 0 deletions

View File

@@ -21,6 +21,7 @@
"i18next": "^23.2.8", "i18next": "^23.2.8",
"i18next-browser-languagedetector": "^7.1.0", "i18next-browser-languagedetector": "^7.1.0",
"i18next-xhr-backend": "^3.2.2", "i18next-xhr-backend": "^3.2.2",
"qr-scanner": "^1.4.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^13.0.1", "react-i18next": "^13.0.1",

View File

@@ -15,6 +15,7 @@ import { ColorModeContext } from "../../contexts/color-mode";
import "/node_modules/flag-icons/css/flag-icons.min.css"; import "/node_modules/flag-icons/css/flag-icons.min.css";
import { languages } from "../../i18n"; import { languages } from "../../i18n";
import QRCodeScannerModal from "../qrCodeScanner";
const { useToken } = theme; const { useToken } = theme;
@@ -84,6 +85,7 @@ export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
onChange={() => setMode(mode === "light" ? "dark" : "light")} onChange={() => setMode(mode === "light" ? "dark" : "light")}
defaultChecked={mode === "dark"} defaultChecked={mode === "dark"}
/> />
<QRCodeScannerModal />
</Space> </Space>
</AntdLayout.Header> </AntdLayout.Header>
); );

View File

@@ -0,0 +1,114 @@
import React, { useEffect, useRef, useState } from "react";
import { Button, FloatButton, Modal, Space } from "antd";
import QrScanner from "qr-scanner"; // Make sure to import from the correct path
import { useNavigate } from "react-router-dom";
import { CameraOutlined } from "@ant-design/icons";
const QRCodeScannerModal: React.FC = () => {
const [visible, setVisible] = useState(false);
const videoRef = useRef<HTMLVideoElement | null>(null);
const scanner = useRef<QrScanner | null>(null);
const navigate = useNavigate();
const [hasCamera, setHasCamera] = useState(false);
useEffect(() => {
const onScan = (result: string) => {
// Check for the spoolman ID format
const match = result.match(/^web+spoolman:s-(?<id>[0-9]+)$/);
if (match && match.groups) {
navigate(`/spool/show/${match.groups.id}`);
}
};
const startCamera = async () => {
console.log("Starting camera");
if (!(await QrScanner.hasCamera())) {
console.log("No camera found on this device");
setHasCamera(false);
return;
} else {
console.log("Camera found on this device");
setHasCamera(true);
if (videoRef.current) {
scanner.current = new QrScanner(
videoRef.current,
(result) => {
console.log("QR Code detected:", result);
onScan(result.data);
},
{
preferredCamera: "environment",
}
);
console.log("Starting scanner");
try {
await scanner.current.start();
} catch (e) {
setHasCamera(false);
console.log(e);
}
} else {
console.log("No video ref");
}
}
};
if (visible) {
startCamera();
}
return () => {
console.log("Destroying scanner");
scanner.current?.destroy();
scanner.current = null;
};
}, [visible, navigate]);
// Draw a centered div if no camera was found
return (
<>
<FloatButton
type="primary"
onClick={() => setVisible(true)}
icon={<CameraOutlined />}
shape="circle"
/>
<Modal
open={visible}
onCancel={() => setVisible(false)}
footer={null}
title="QR Code Scanner"
>
<Space direction="vertical" style={{ width: "100%" }}>
<p>Scan a Spoolman QR code to view details about the spool.</p>
<video
style={{
width: "100%",
display: hasCamera ? "block" : "none",
}}
ref={videoRef}
/>
{!hasCamera && (
<div
style={{
width: "100%",
position: "relative",
backgroundColor: "black",
display: hasCamera ? "none" : "block",
padding: "4rem 0rem",
textAlign: "center",
}}
>
No camera detected.
<br />
<br />
Ensure you have given the browser permission to use the camera.
</div>
)}
</Space>
</Modal>
</>
);
};
export default QRCodeScannerModal;