mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-21 13:23:14 +01:00
ProductBarcode: apply linting and fixes on frontend
This commit is contained in:
@@ -15,13 +15,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="detectedBarcode"
|
v-if="detectedBarcode"
|
||||||
class="border-accent-foreground bg-accent text-accent-foreground mb-5 flex flex-col items-center gap-2 rounded-md border p-4"
|
class="mb-5 flex flex-col items-center gap-2 rounded-md border border-accent-foreground bg-accent p-4 text-accent-foreground"
|
||||||
role="alert"
|
role="alert"
|
||||||
>
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<MdiBarcode class="text-default mr-2" />
|
<MdiBarcode class="mr-2" />
|
||||||
<span class="flex-1 text-center text-sm font-medium">
|
<span class="flex-1 text-center text-sm font-medium">
|
||||||
{{ detectedBarcodeType }} {{ $t("scanner.barcode_detected_message") }}: <strong>{{ detectedBarcode }}</strong>
|
{{ detectedBarcodeType }} {{ $t("scanner.barcode_detected_message") }}:
|
||||||
|
<strong>{{ detectedBarcode }}</strong>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -74,7 +75,6 @@
|
|||||||
const errorMessage = ref<string | null>(null);
|
const errorMessage = ref<string | null>(null);
|
||||||
const detectedBarcode = ref<string>("");
|
const detectedBarcode = ref<string>("");
|
||||||
const detectedBarcodeType = ref<string>("");
|
const detectedBarcodeType = ref<string>("");
|
||||||
const api = useUserApi();
|
|
||||||
|
|
||||||
const handleError = (error: unknown) => {
|
const handleError = (error: unknown) => {
|
||||||
console.error("Scanner error:", error);
|
console.error("Scanner error:", error);
|
||||||
@@ -170,9 +170,9 @@
|
|||||||
case BarcodeFormat.UPC_EAN_EXTENSION:
|
case BarcodeFormat.UPC_EAN_EXTENSION:
|
||||||
console.info("Barcode detected");
|
console.info("Barcode detected");
|
||||||
detectedBarcode.value = result.getText();
|
detectedBarcode.value = result.getText();
|
||||||
detectedBarcodeType.value = BarcodeFormat[bcfmt].replaceAll("_","-");
|
detectedBarcodeType.value = BarcodeFormat[bcfmt].replaceAll("_", "-");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
handleError(err);
|
handleError(err);
|
||||||
}
|
}
|
||||||
@@ -194,4 +194,3 @@
|
|||||||
stopScanner();
|
stopScanner();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog dialog-id="product-import">
|
<Dialog dialog-id="product-import">
|
||||||
<DialogContent :class="'w-full md:max-w-xl lg:max-w-4xl'" >
|
<DialogContent :class="'w-full md:max-w-xl lg:max-w-4xl'">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{{ $t("components.item.product_import.title") }}</DialogTitle>
|
<DialogTitle>{{ $t("components.item.product_import.title") }}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<FormTextField :disabled=searching class="w-[30%]" :modelValue="barcode" :label="$t('components.item.product_import.barcode')" />
|
<FormTextField
|
||||||
<Button :variant="searching ? 'destructive' : 'default'" @click="retrieveProductInfo(barcode)" style="margin-top: auto">
|
:disabled="searching"
|
||||||
|
class="w-[30%]"
|
||||||
|
:model-value="barcode"
|
||||||
|
:label="$t('components.item.product_import.barcode')"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
:variant="searching ? 'destructive' : 'default'"
|
||||||
|
style="margin-top: auto"
|
||||||
|
@click="retrieveProductInfo(barcode)"
|
||||||
|
>
|
||||||
<div class="relative mx-2">
|
<div class="relative mx-2">
|
||||||
<div class="absolute inset-0 flex items-center justify-center">
|
<div class="absolute inset-0 flex items-center justify-center">
|
||||||
<MdiBarcode class="size-5 group-hover:hidden" />
|
<MdiBarcode class="size-5 group-hover:hidden" />
|
||||||
@@ -16,7 +25,7 @@
|
|||||||
{{ searching ? "Cancel" : "Search product" }}
|
{{ searching ? "Cancel" : "Search product" }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="divide-y border-t" />
|
<div class="divide-y border-t" />
|
||||||
|
|
||||||
<BaseCard>
|
<BaseCard>
|
||||||
@@ -43,31 +52,34 @@
|
|||||||
</TableHeader>
|
</TableHeader>
|
||||||
|
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow
|
<TableRow
|
||||||
v-for="(p, index) in products"
|
v-for="(p, index) in products"
|
||||||
:key="index"
|
:key="index"
|
||||||
class='cursor-pointer'
|
class="cursor-pointer"
|
||||||
:class="{ selected: selectedRow === index }"
|
:class="{ selected: selectedRow === index }"
|
||||||
@click="selectProduct(index)">
|
@click="selectProduct(index)"
|
||||||
<TableCell v-for="h in headers"
|
>
|
||||||
:class="{
|
<TableCell
|
||||||
|
v-for="h in headers"
|
||||||
|
:key="h.value"
|
||||||
|
:class="{
|
||||||
'text-center': h.align === 'center',
|
'text-center': h.align === 'center',
|
||||||
'text-left': h.align === 'left',
|
'text-left': h.align === 'left',
|
||||||
}">
|
}"
|
||||||
|
>
|
||||||
|
<template v-if="h.type === 'name'">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<img :src="p.imageBase64" class="w-16 rounded object-fill shadow-sm" alt="Product's photo" />
|
||||||
|
<span class="text-sm font-medium">
|
||||||
|
{{ p.item.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-if="h.type === 'name'">
|
<slot v-else :name="cell(h)">
|
||||||
<div class="flex items-center space-x-4">
|
{{ extractValue(p, h.value) }}
|
||||||
<img :src="p.imageBase64" class="w-16 rounded object-fill shadow-sm" alt="Product's photo" />
|
</slot>
|
||||||
<span class="text-sm font-medium">
|
</TableCell>
|
||||||
{{ p.item.name }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<slot v-else :name="cell(h)">
|
|
||||||
{{ extractValue(p, h.value) }}
|
|
||||||
</slot>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
@@ -81,20 +93,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Button, ButtonGroup } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import type { BarcodeProduct } from "~~/lib/api/types/data-contracts";
|
import type { BarcodeProduct } from "~~/lib/api/types/data-contracts";
|
||||||
import { useDialog } from "~/components/ui/dialog-provider";
|
import { useDialog } from "~/components/ui/dialog-provider";
|
||||||
import MdiBarcode from "~icons/mdi/barcode";
|
import MdiBarcode from "~icons/mdi/barcode";
|
||||||
import type { TableData } from "~/components/Item/View/Table.types";
|
import type { TableData } from "~/components/Item/View/Table.types";
|
||||||
const { openDialog, activeDialog, closeDialog } = useDialog();
|
|
||||||
|
const { openDialog, activeDialog } = useDialog();
|
||||||
|
|
||||||
const searching = ref(false);
|
const searching = ref(false);
|
||||||
const barcode = ref<string>("");
|
const barcode = ref<string>("");
|
||||||
const products = ref<BarcodeProduct[] | null>(null);
|
const products = ref<BarcodeProduct[] | null>(null);
|
||||||
const selectedRow = ref(-1);
|
const selectedRow = ref(-1);
|
||||||
|
|
||||||
import type { ItemSummary } from "~~/lib/api/types/data-contracts";
|
|
||||||
|
|
||||||
type BarcodeTableHeader = {
|
type BarcodeTableHeader = {
|
||||||
text: string;
|
text: string;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -109,9 +120,9 @@
|
|||||||
align: "left",
|
align: "left",
|
||||||
type: "name",
|
type: "name",
|
||||||
},
|
},
|
||||||
{ text: "items.manufacturer", value: "manufacturer", align: "center"},
|
{ text: "items.manufacturer", value: "manufacturer", align: "center" },
|
||||||
{ text: "items.model_number", value: "modelNumber", align: "center"},
|
{ text: "items.model_number", value: "modelNumber", align: "center" },
|
||||||
{ text: "DB source", value: "search_engine_name", align: "center"},
|
{ text: "DB source", value: "search_engine_name", align: "center" },
|
||||||
] satisfies BarcodeTableHeader[];
|
] satisfies BarcodeTableHeader[];
|
||||||
|
|
||||||
// Need for later filtering
|
// Need for later filtering
|
||||||
@@ -123,21 +134,16 @@
|
|||||||
if (active && active.id === "product-import") {
|
if (active && active.id === "product-import") {
|
||||||
selectedRow.value = -1;
|
selectedRow.value = -1;
|
||||||
|
|
||||||
if(active.params)
|
if (active.params) {
|
||||||
{
|
|
||||||
// Reset if the barcode is different
|
// Reset if the barcode is different
|
||||||
if(active.params != barcode.value)
|
if (active.params !== barcode.value) {
|
||||||
{
|
|
||||||
barcode.value = active.params;
|
barcode.value = active.params;
|
||||||
|
|
||||||
retrieveProductInfo(barcode.value).then(() =>
|
retrieveProductInfo(barcode.value).then(() => {
|
||||||
{
|
|
||||||
console.log("Processing finished");
|
console.log("Processing finished");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
barcode.value = "";
|
barcode.value = "";
|
||||||
products.value = null;
|
products.value = null;
|
||||||
}
|
}
|
||||||
@@ -147,11 +153,10 @@
|
|||||||
|
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
|
|
||||||
async function createItem(close = true) {
|
function createItem() {
|
||||||
if (products !== null)
|
if (products !== null) {
|
||||||
{
|
const p = products.value![selectedRow.value];
|
||||||
var p = products.value![selectedRow.value];
|
openDialog("create-item", p);
|
||||||
openDialog("create-item", p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,23 +165,19 @@
|
|||||||
searching.value = true;
|
searching.value = true;
|
||||||
|
|
||||||
if (!barcode || barcode.trim().length === 0) {
|
if (!barcode || barcode.trim().length === 0) {
|
||||||
console.error('Invalid barcode provided');
|
console.error("Invalid barcode provided");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await api.products.searchFromBarcode(barcode.trim());
|
const result = await api.products.searchFromBarcode(barcode.trim());
|
||||||
if(result.error)
|
if (result.error) {
|
||||||
{
|
console.error("API Error:", result.error);
|
||||||
console.error('API Error:', result.error);
|
} else {
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
products.value = result.data;
|
products.value = result.data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to retrieve product info:', error);
|
console.error("Failed to retrieve product info:", error);
|
||||||
} finally {
|
} finally {
|
||||||
searching.value = false;
|
searching.value = false;
|
||||||
}
|
}
|
||||||
@@ -197,26 +198,22 @@
|
|||||||
|
|
||||||
function selectProduct(index: number) {
|
function selectProduct(index: number) {
|
||||||
// Unselect if already selected
|
// Unselect if already selected
|
||||||
if(selectedRow.value == index)
|
if (selectedRow.value === index) {
|
||||||
{
|
|
||||||
selectedRow.value = -1;
|
selectedRow.value = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedRow.value = index;
|
selectedRow.value = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
tr.selected {
|
||||||
tr.selected {
|
|
||||||
background-color: hsl(var(--primary));
|
|
||||||
color: hsl(var(--background));
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover.selected {
|
|
||||||
background-color: hsl(var(--primary));
|
background-color: hsl(var(--primary));
|
||||||
}
|
color: hsl(var(--background));
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
tr:hover.selected {
|
||||||
|
background-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -10,28 +10,28 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>{{ $t('components.item.create_modal.product_tooltip_input_barcode') }}</p>
|
<p>{{ $t("components.item.create_modal.product_tooltip_input_barcode") }}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Button variant="outline" :disabled="loading" data-pos="end" @click="openQrScannerPage()">
|
<Button variant="outline" :disabled="loading" data-pos="end" @click="openQrScannerPage()">
|
||||||
<MdiBarcodeScan class="size-5" />
|
<MdiBarcodeScan class="size-5" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>{{ $t('components.item.create_modal.product_tooltip_scan_barcode') }}</p>
|
<p>{{ $t("components.item.create_modal.product_tooltip_scan_barcode") }}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</TooltipProvider >
|
</TooltipProvider>
|
||||||
<div class= "items-center justify-center flex mx-2">
|
<div class="mx-2 flex items-center justify-center">
|
||||||
{{ $t('components.item.create_modal.product_autofill') }}
|
{{ $t("components.item.create_modal.product_autofill") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=" border-t" />
|
<div class="border-t" />
|
||||||
|
|
||||||
<form class="flex flex-col gap-2" @submit.prevent="create()">
|
<form class="flex flex-col gap-2" @submit.prevent="create()">
|
||||||
<LocationSelector v-model="form.location" />
|
<LocationSelector v-model="form.location" />
|
||||||
<ItemSelector
|
<ItemSelector
|
||||||
@@ -345,19 +345,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(active.params)
|
if (active.params) {
|
||||||
{
|
|
||||||
form.name = active.params.item.name;
|
form.name = active.params.item.name;
|
||||||
form.description = active.params.item.description;
|
form.description = active.params.item.description;
|
||||||
|
|
||||||
if(active.params.imageURL)
|
if (active.params.imageURL) {
|
||||||
{
|
|
||||||
form.photos.push({
|
form.photos.push({
|
||||||
photoName: "product_view.jpg",
|
photoName: "product_view.jpg",
|
||||||
fileBase64: active.params.imageBase64,
|
fileBase64: active.params.imageBase64,
|
||||||
primary: form.photos.length === 0,
|
primary: form.photos.length === 0,
|
||||||
file: dataURLtoFile(active.params.imageBase64 ,"product_view.jpg")
|
file: dataURLtoFile(active.params.imageBase64, "product_view.jpg"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,13 +515,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openQrScannerPage() {
|
function openQrScannerPage() {
|
||||||
closeDialog("create-item");
|
closeDialog("create-item");
|
||||||
openDialog("scanner")
|
openDialog("scanner");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openBarcodeDialog() {
|
function openBarcodeDialog() {
|
||||||
closeDialog("create-item");
|
closeDialog("create-item");
|
||||||
openDialog("product-import")
|
openDialog("product-import");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { BaseAPI, route } from "../base";
|
import { BaseAPI, route } from "../base";
|
||||||
import type { ActionAmountResult, ItemCreate } from "../types/data-contracts";
|
import type { ActionAmountResult } from "../types/data-contracts";
|
||||||
|
|
||||||
export class ActionsAPI extends BaseAPI {
|
export class ActionsAPI extends BaseAPI {
|
||||||
ensureAssetIDs() {
|
ensureAssetIDs() {
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ export class ProductAPI extends BaseAPI {
|
|||||||
searchFromBarcode(productEAN: string) {
|
searchFromBarcode(productEAN: string) {
|
||||||
return this.http.get<BarcodeProduct[]>({ url: route(`/products/search-from-barcode`, { productEAN }) });
|
return this.http.get<BarcodeProduct[]>({ url: route(`/products/search-from-barcode`, { productEAN }) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user