From cda756557d4d65bf642a0cecd8efcecd3ddf8b01 Mon Sep 17 00:00:00 2001 From: Donkie Date: Tue, 6 Jan 2026 13:05:54 +0100 Subject: [PATCH] Updated react qr scanner --- client/package-lock.json | 120 ++++++++++++++++-------- client/package.json | 2 +- client/src/components/qrCodeScanner.tsx | 50 +++++----- 3 files changed, 110 insertions(+), 62 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 6badd03..aba7078 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -20,7 +20,7 @@ "@types/loadable__component": "^5.13.10", "@types/lodash": "^4.17.21", "@types/uuid": "^10.0.0", - "@yudiel/react-qr-scanner": "^1.2.10", + "@yudiel/react-qr-scanner": "^2.5.0", "axios": "^1.13.2", "html-to-image": "^1.11.13", "i18next": "^25.7.3", @@ -4511,6 +4511,12 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/emscripten": { + "version": "1.41.5", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", + "integrity": "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -4905,40 +4911,19 @@ } }, "node_modules/@yudiel/react-qr-scanner": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-1.2.10.tgz", - "integrity": "sha512-I94AyrEu/2oZxXT6TEOK9+K2IfjqfPmic/GUah7alMIxfgXP9rs9+IZE56JhQr4pZ7Iz2RUC4JFfeaysFYNEIA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-2.5.0.tgz", + "integrity": "sha512-wVWvm0z5kGGc3tiMcxyr2aji3C6aU5K3Q7R08MOdyFDFkvMbFMF1Hz5P5WFYW+zuuqxDPBcRZPCvmVs6jBheTQ==", "license": "MIT", "dependencies": { - "@zxing/library": "^0.20.0" + "barcode-detector": "3.0.8", + "webrtc-adapter": "9.0.3" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" } }, - "node_modules/@zxing/library": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.20.0.tgz", - "integrity": "sha512-6Ev6rcqVjMakZFIDvbUf0dtpPGeZMTfyxYg4HkVWioWeN7cRcnUWT3bU6sdohc82O1nPXcjq6WiGfXX2Pnit6A==", - "license": "MIT", - "dependencies": { - "ts-custom-error": "^3.2.1" - }, - "engines": { - "node": ">= 10.4.0" - }, - "optionalDependencies": { - "@zxing/text-encoding": "~0.9.0" - } - }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "license": "(Unlicense OR Apache-2.0)", - "optional": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5377,6 +5362,15 @@ "dev": true, "license": "MIT" }, + "node_modules/barcode-detector": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.0.8.tgz", + "integrity": "sha512-Z9jzzE8ngEDyN9EU7lWdGgV07mcnEQnrX8W9WecXDqD2v+5CcVjt9+a134a5zb+kICvpsrDx6NYA6ay4LGFs8A==", + "license": "MIT", + "dependencies": { + "zxing-wasm": "2.2.4" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -12555,6 +12549,12 @@ "compute-scroll-into-view": "^3.0.2" } }, + "node_modules/sdp": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.1.tgz", + "integrity": "sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==", + "license": "MIT" + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -13399,6 +13399,18 @@ "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/temp": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", @@ -13601,15 +13613,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-custom-error": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz", - "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -14317,6 +14320,19 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "license": "BSD-2-Clause" }, + "node_modules/webrtc-adapter": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-9.0.3.tgz", + "integrity": "sha512-5fALBcroIl31OeXAdd1YUntxiZl1eHlZZWzNg3U4Fn+J9/cGL3eT80YlrsWGvj2ojuz1rZr2OXkgCzIxAZ7vRQ==", + "license": "BSD-3-Clause", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -15036,6 +15052,34 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } + }, + "node_modules/zxing-wasm": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-2.2.4.tgz", + "integrity": "sha512-1gq5zs4wuNTs5umWLypzNNeuJoluFvwmvjiiT3L9z/TMlVveeJRWy7h90xyUqCe+Qq0zL0w7o5zkdDMWDr9aZA==", + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.41.5", + "type-fest": "^5.2.0" + }, + "peerDependencies": { + "@types/emscripten": ">=1.39.6" + } + }, + "node_modules/zxing-wasm/node_modules/type-fest": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.3.1.tgz", + "integrity": "sha512-VCn+LMHbd4t6sF3wfU/+HKT63C9OoyrSIf4b+vtWHpt2U7/4InZG467YDNMFMR70DdHjAdpPWmw2lzRdg0Xqqg==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/client/package.json b/client/package.json index a389c1b..0811377 100644 --- a/client/package.json +++ b/client/package.json @@ -19,7 +19,7 @@ "@types/loadable__component": "^5.13.10", "@types/lodash": "^4.17.21", "@types/uuid": "^10.0.0", - "@yudiel/react-qr-scanner": "^1.2.10", + "@yudiel/react-qr-scanner": "^2.5.0", "axios": "^1.13.2", "html-to-image": "^1.11.13", "i18next": "^25.7.3", diff --git a/client/src/components/qrCodeScanner.tsx b/client/src/components/qrCodeScanner.tsx index 83573b5..d43b35a 100644 --- a/client/src/components/qrCodeScanner.tsx +++ b/client/src/components/qrCodeScanner.tsx @@ -1,6 +1,6 @@ import { CameraOutlined } from "@ant-design/icons"; import { useTranslate } from "@refinedev/core"; -import { QrScanner } from "@yudiel/react-qr-scanner"; +import { IDetectedBarcode, Scanner } from "@yudiel/react-qr-scanner"; import { FloatButton, Modal, Space } from "antd"; import React, { useState } from "react"; import { useNavigate } from "react-router"; @@ -11,7 +11,12 @@ const QRCodeScannerModal: React.FC = () => { const t = useTranslate(); const navigate = useNavigate(); - const onScan = (result: string) => { + const onScan = (detectedCodes: IDetectedBarcode[]) => { + if (detectedCodes.length === 0) { + return; + } + const result = detectedCodes[0].rawValue; + // Check for the spoolman ID format const match = result.match(/^web\+spoolman:s-(?[0-9]+)$/); if (match && match.groups) { @@ -28,31 +33,17 @@ const QRCodeScannerModal: React.FC = () => { return ( <> setVisible(true)} icon={} shape="circle" /> - setVisible(false)} footer={null} title={t("scanner.title")}> + setVisible(false)} footer={null} title={t("scanner.title")}>

{t("scanner.description")}

- ( -
-

{lastError}

-
- ) - : undefined - } - onDecode={onScan} - onError={(error: Error) => { + onScan={onScan} + formats={["qr_code"]} + onError={(err: unknown) => { + const error = err as Error; console.error(error); if (error.name === "NotAllowedError") { setLastError(t("scanner.error.notAllowed")); @@ -71,7 +62,20 @@ const QRCodeScannerModal: React.FC = () => { setLastError(t("scanner.error.unknown", { error: error.name })); } }} - /> + > + {lastError && ( +
+

{lastError}

+
+ )} +