Add preset expiration day picker to label form

This commit is contained in:
2026-04-06 17:47:02 +02:00
parent 218647b2cb
commit d4205f93b8
2 changed files with 125 additions and 9 deletions
+84 -9
View File
@@ -22,6 +22,7 @@ const STOCK_LEVEL_OPTIONS = [
];
const QUANTITY_UNIT_OPTIONS = ['g', 'ml', 'pc'];
const EXPIRATION_DAY_OPTIONS = ['3', '5', '8', '10', '15', '20', '25', '30', '45', '60', '90', '120', '150', '180'];
export function renderLabelCreatePage() {
return `
@@ -300,15 +301,47 @@ export function renderLabelCreatePage() {
</div>
<div class="row g-2">
<div class="col-5">
<input
class="form-control"
type="number"
min="0"
step="1"
x-model="form.expireDays"
@input="syncExpireDateFromDays()"
placeholder="30"
/>
<div
class="position-relative"
x-ref="expireDaysPicker"
@focusin="expireDaysPickerOpen = true"
@focusout="handleExpireDaysFocusOut($event)"
>
<input
class="form-control"
type="text"
inputmode="numeric"
x-model="form.expireDays"
@input="onExpireDaysInput()"
@click="openExpireDaysPicker()"
@keydown.escape="expireDaysPickerOpen = false"
placeholder="30"
autocomplete="off"
/>
<template x-if="expireDaysPickerOpen">
<div class="shadow-sm position-absolute start-0 end-0 z-3 mt-1 quantity-unit-picker expiration-days-picker">
<template x-if="filteredExpireDayOptions.length">
<div class="expiration-days-grid">
<template x-for="days in filteredExpireDayOptions" :key="days">
<button
class="btn btn-outline-secondary btn-sm expiration-days-option"
type="button"
@click="pickExpireDays(days)"
:class="{ 'active': form.expireDays === days }"
>
<span class="fw-semibold" x-text="days"></span>
</button>
</template>
</div>
</template>
<template x-if="!filteredExpireDayOptions.length">
<div class="text-body-secondary small p-3">
No matching day values found.
</div>
</template>
</div>
</template>
</div>
</div>
<div class="col-7">
<input
@@ -466,11 +499,13 @@ export function labelCreatePageData(store) {
stockTypeOptions: STOCK_TYPE_OPTIONS,
stockLevelOptions: STOCK_LEVEL_OPTIONS,
quantityUnitOptions: QUANTITY_UNIT_OPTIONS,
expirationDayOptions: EXPIRATION_DAY_OPTIONS,
suggestions: [],
locations: [],
locationSearch: '',
locationPickerOpen: false,
quantityUnitPickerOpen: false,
expireDaysPickerOpen: false,
previewUrl: '',
successMessage: '',
submitError: '',
@@ -580,6 +615,26 @@ export function labelCreatePageData(store) {
return this.quantityUnitOptions;
},
get filteredExpireDayOptions() {
const query = this.form.expireDays.trim();
if (!query) {
return this.expirationDayOptions;
}
if (this.expirationDayOptions.includes(query)) {
return this.expirationDayOptions;
}
const matches = this.expirationDayOptions.filter((days) =>
days.includes(query),
);
if (matches.length) {
return matches;
}
return this.expirationDayOptions;
},
get selectedLocation() {
return this.locations.find(
(location) => String(location.id) === String(this.form.locationId),
@@ -606,6 +661,9 @@ export function labelCreatePageData(store) {
openQuantityUnitPicker() {
this.quantityUnitPickerOpen = true;
},
openExpireDaysPicker() {
this.expireDaysPickerOpen = true;
},
onLocationInput() {
this.locationPickerOpen = true;
if (this.selectedLocation && this.locationSearch !== this.selectedLocation.name) {
@@ -631,10 +689,27 @@ export function labelCreatePageData(store) {
this.quantityUnitPickerOpen = false;
},
onExpireDaysInput() {
this.expireDaysPickerOpen = true;
this.syncExpireDateFromDays();
},
handleExpireDaysFocusOut(event) {
const nextTarget = event.relatedTarget;
if (nextTarget && this.$refs.expireDaysPicker?.contains(nextTarget)) {
return;
}
this.expireDaysPickerOpen = false;
},
pickQuantityUnit(unit) {
this.form.uom = unit;
this.quantityUnitPickerOpen = false;
},
pickExpireDays(days) {
this.form.expireDays = days;
this.expireDaysPickerOpen = false;
this.syncExpireDateFromDays();
},
syncLocationSelection() {
if (!this.form.locationId) {
this.locationSearch = '';