diff --git a/client/package-lock.json b/client/package-lock.json index f12f1ff..83c8f79 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -17,6 +17,7 @@ "@refinedev/simple-rest": "^4.5.0", "@tanstack/react-query": "^4.29.19", "@types/loadable__component": "^5.13.4", + "@yudiel/react-qr-scanner": "^1.1.10", "antd": "^5.6.4", "flag-icons": "^6.7.0", "i18next": "^23.2.8", @@ -41,7 +42,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.1", "typescript": "^5.1.6", - "vite": "^4.4.1" + "vite": "^4.4.1", + "vite-plugin-mkcert": "^1.16.0" }, "engines": { "node": "16.x" @@ -1554,6 +1556,195 @@ "node": ">= 8" } }, + "node_modules/@octokit/auth-token": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", + "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", + "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", + "dev": true, + "dependencies": { + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/endpoint": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", + "dev": true, + "dependencies": { + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/endpoint/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", + "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", + "dev": true, + "dependencies": { + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", + "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", + "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", + "dev": true, + "dependencies": { + "@octokit/tsconfig": "^1.0.2", + "@octokit/types": "^9.2.3" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@octokit/core": ">=4" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "dev": true, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", + "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", + "dev": true, + "dependencies": { + "@octokit/types": "^10.0.0" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", + "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^18.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", + "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", + "dev": true, + "dependencies": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/request-error": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", + "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", + "dev": true, + "dependencies": { + "@octokit/types": "^9.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/request/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@octokit/rest": { + "version": "19.0.13", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz", + "integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==", + "dev": true, + "dependencies": { + "@octokit/core": "^4.2.1", + "@octokit/plugin-paginate-rest": "^6.1.2", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^7.1.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/tsconfig": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", + "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", + "dev": true + }, + "node_modules/@octokit/types": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", + "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^18.0.0" + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", @@ -2539,6 +2730,38 @@ "vite": "^4.2.0" } }, + "node_modules/@yudiel/react-qr-scanner": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-1.1.10.tgz", + "integrity": "sha512-+YIHbnocynkkGgyMK8MMkn1NBnJRwJntdm4shQ+linm4NdGdSAavLYxJYwnk2PixZyVu/GZ3Uc2aM0XWlBq+Zw==", + "dependencies": { + "@zxing/library": "^0.20.0" + }, + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@zxing/library": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.20.0.tgz", + "integrity": "sha512-6Ev6rcqVjMakZFIDvbUf0dtpPGeZMTfyxYg4HkVWioWeN7cRcnUWT3bU6sdohc82O1nPXcjq6WiGfXX2Pnit6A==", + "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==", + "optional": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -2831,6 +3054,12 @@ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -2946,6 +3175,12 @@ } ] }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -3523,6 +3758,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", @@ -3791,6 +4038,15 @@ "node": ">=0.10.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3800,6 +4056,12 @@ "node": ">= 0.8" } }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -4927,6 +5189,20 @@ "node": ">=0.10.0" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -7641,6 +7917,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -9791,6 +10073,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "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==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tslib": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", @@ -10004,6 +10294,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -10255,6 +10551,35 @@ } } }, + "node_modules/vite-plugin-mkcert": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-1.16.0.tgz", + "integrity": "sha512-5r+g8SB9wZzLNUFekGwZo3e0P6QlS6rbxK5p9z/itxNAimsYohgjK/YfVPVxM9EuglP9hjridq0lUejo9v1nVg==", + "dev": true, + "dependencies": { + "@octokit/rest": "^19.0.5", + "axios": "^1.2.2", + "debug": "^4.3.4", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=v16.7.0" + }, + "peerDependencies": { + "vite": ">=3" + } + }, + "node_modules/vite-plugin-mkcert/node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/vite-plugin-svgr": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-3.2.0.tgz", diff --git a/client/package.json b/client/package.json index a3e6c72..38995e1 100644 --- a/client/package.json +++ b/client/package.json @@ -16,12 +16,12 @@ "@refinedev/simple-rest": "^4.5.0", "@tanstack/react-query": "^4.29.19", "@types/loadable__component": "^5.13.4", + "@yudiel/react-qr-scanner": "^1.1.10", "antd": "^5.6.4", "flag-icons": "^6.7.0", "i18next": "^23.2.8", "i18next-browser-languagedetector": "^7.1.0", "i18next-xhr-backend": "^3.2.2", - "qr-scanner": "^1.4.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^13.0.1", @@ -41,7 +41,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.1", "typescript": "^5.1.6", - "vite": "^4.4.1" + "vite": "^4.4.1", + "vite-plugin-mkcert": "^1.16.0" }, "scripts": { "dev": "refine dev", diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index 1e475ba..8c86887 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -94,6 +94,15 @@ "selectedTotal_other": "{{count}} spools selected" } }, + "scanner": { + "error": { + "notAllowed": "You have not allowed access to the camera.", + "insecureContext": "The page is not served over HTTPS.", + "streamApiNotSupported": "The browser does not support the MediaStream API.", + "notReadable": "The camera is not readable.", + "unknown": "An unknown error occurred. ({{error}})" + } + }, "spool": { "spool": "Spools", "fields": { diff --git a/client/src/components/qrCodeScanner.tsx b/client/src/components/qrCodeScanner.tsx index 74f0265..32d8a3a 100644 --- a/client/src/components/qrCodeScanner.tsx +++ b/client/src/components/qrCodeScanner.tsx @@ -1,69 +1,30 @@ -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 React, { useEffect, useState } from "react"; +import { FloatButton, Modal, Space } from "antd"; +import { QrScanner } from "@yudiel/react-qr-scanner"; import { useNavigate } from "react-router-dom"; import { CameraOutlined } from "@ant-design/icons"; +import { useTranslate } from "@refinedev/core"; const QRCodeScannerModal: React.FC = () => { const [visible, setVisible] = useState(false); - const videoRef = useRef(null); - const scanner = useRef(null); + const [lastError, setLastError] = useState(null); + const t = useTranslate(); const navigate = useNavigate(); - const [hasCamera, setHasCamera] = useState(false); + + const onScan = (result: string) => { + // Check for the spoolman ID format + const match = result.match(/^web\+spoolman:s-(?[0-9]+)$/); + if (match && match.groups) { + setVisible(false); + navigate(`/spool/show/${match.groups.id}`); + } + }; useEffect(() => { - const onScan = (result: string) => { - // Check for the spoolman ID format - const match = result.match(/^web+spoolman:s-(?[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(); + setLastError(null); } - - return () => { - console.log("Destroying scanner"); - scanner.current?.destroy(); - scanner.current = null; - }; - }, [visible, navigate]); - - // Draw a centered div if no camera was found + }, [visible]); return ( <> @@ -81,30 +42,38 @@ const QRCodeScannerModal: React.FC = () => { >

Scan a Spoolman QR code to view details about the spool.

-
diff --git a/client/vite.config.ts b/client/vite.config.ts index 6335a4d..e315b23 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -1,8 +1,10 @@ import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; import svgr from "vite-plugin-svgr"; +import mkcert from 'vite-plugin-mkcert' export default defineConfig({ - plugins: [react(), svgr()], + server: { https: true }, + plugins: [react(), svgr(), mkcert()], });