diff --git a/package.json b/package.json index 3954513..1f571cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lonc-web", - "version": "0.2.0", + "version": "0.2.1", "private": true, "type": "module", "scripts": { diff --git a/src/app/config.js b/src/app/config.js index b113193..7b3e317 100644 --- a/src/app/config.js +++ b/src/app/config.js @@ -1,5 +1,5 @@ export const APP_NAME = 'Lonc'; -export const APP_VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '0.2.0'; +export const APP_VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '0.2.1'; export const TRYTON_APPLICATION = 'kitchen'; export const CONNECTION_STATES = { @@ -14,6 +14,7 @@ export const STORAGE_KEYS = { session: 'lonc.auth.session', activeKitchen: 'lonc.kitchen.active', labelDraft: 'lonc.labels.draft', + stockListContext: 'lonc.stock.list.context', }; export const DEFAULT_CONFIG = { diff --git a/src/features/stock/stock-list-page.js b/src/features/stock/stock-list-page.js index 028f0e7..6b9693e 100644 --- a/src/features/stock/stock-list-page.js +++ b/src/features/stock/stock-list-page.js @@ -1,4 +1,5 @@ import { + getStockEntry, listGroupedStockEntries, listKitchenChanges, listStockEntries, @@ -6,6 +7,8 @@ import { useStockItem, } from '../../api/stock.js'; import { fetchLocations } from '../../api/locations.js'; +import { STORAGE_KEYS } from '../../app/config.js'; +import { clearStoredValue, loadStoredValue, saveStoredValue } from '../shared/storage.js'; import { createAsyncState } from '../shared/ui-state.js'; import { formatDate } from '../shared/date-utils.js'; @@ -38,6 +41,24 @@ const EXPIRATION_LEGEND = [ const EXPIRATION_KEYS = EXPIRATION_LEGEND.map((state) => state.key); const GROUPED_PAGE_SIZE = 24; const CHANGE_POLL_INTERVAL_MS = 60 * 1000; +const STOCK_LIST_CONTEXT_TTL_MS = 10 * 60 * 1000; +let stockListRuntimeCache = null; + +function cloneRuntimeSnapshot(value) { + if (typeof structuredClone === 'function') { + try { + return structuredClone(value); + } catch { + // Alpine/reactive proxies can throw DataCloneError in some browsers. + } + } + + try { + return JSON.parse(JSON.stringify(value)); + } catch { + return null; + } +} function todayAtMidnight() { const now = new Date(); @@ -57,6 +78,16 @@ function parseDateValue(value) { return new Date(year, month - 1, day); } +function daysUntilDate(value) { + const parsed = parseDateValue(value); + if (!parsed) { + return null; + } + + const today = todayAtMidnight(); + return Math.round((parsed - today) / (24 * 60 * 60 * 1000)); +} + function expirationInfo(entry) { const expireDateValue = Array.isArray(entry.items) && (entry.first_expire_date || entry.first_expire_in !== undefined) @@ -497,7 +528,19 @@ export function renderStockListPage() {
- View item + + View item + +