diff --git a/frontend/components/App/ScannerModal.vue b/frontend/components/App/ScannerModal.vue
index 9aff71f5..0ee299bd 100644
--- a/frontend/components/App/ScannerModal.vue
+++ b/frontend/components/App/ScannerModal.vue
@@ -57,6 +57,17 @@
errorMessage.value = t("scanner.error");
};
+ const checkPermissionsError = async () => {
+ if (navigator.permissions) {
+ const permissionStatus = await navigator.permissions.query({ name: "camera" as PermissionName });
+ if (permissionStatus.state === "denied") {
+ errorMessage.value = t("scanner.permission_denied");
+ console.error("Camera permission denied");
+ return true;
+ }
+ }
+ };
+
const startScanner = async () => {
errorMessage.value = null;
if (!(navigator && navigator.mediaDevices && "enumerateDevices" in navigator.mediaDevices)) {
@@ -64,6 +75,10 @@
return;
}
+ if (await checkPermissionsError()) {
+ return;
+ }
+
try {
const devices = await codeReader.listVideoInputDevices();
sources.value = devices;
diff --git a/frontend/layouts/default.vue b/frontend/layouts/default.vue
index 68e0300e..c7d5768b 100644
--- a/frontend/layouts/default.vue
+++ b/frontend/layouts/default.vue
@@ -137,7 +137,7 @@
-
@@ -207,6 +207,7 @@
import { useDialog } from "~/components/ui/dialog-provider";
import { Input } from "~/components/ui/input";
import { Button } from "~/components/ui/button";
+ import { toast } from "@/components/ui/sonner";
const { t, locale } = useI18n();
const username = computed(() => authCtx.user?.name || "User");
@@ -241,6 +242,23 @@
}
};
+ const openScanner = () => {
+ // request permission
+ if (navigator.mediaDevices) {
+ navigator.mediaDevices
+ .getUserMedia({ video: true })
+ .then(() => {
+ openDialog("scanner");
+ })
+ .catch(err => {
+ console.error(err);
+ toast.error(t("scanner.permission_denied"));
+ });
+ } else {
+ toast.error(t("scanner.unsupported"));
+ }
+ };
+
// Preload currency format
useFormatCurrency();
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index 1c124e37..6dd7a352 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -378,7 +378,8 @@
"no_sources": "No video sources available",
"select_video_source": "Pick a video source",
"title": "Scanner",
- "unsupported": "Media Stream API is not supported without HTTPS"
+ "unsupported": "Media Stream API is not supported without HTTPS",
+ "permission_denied": "Camera permission denied, please allow access to the camera in your browser settings"
},
"tools": {
"actions": "Inventory Actions",