diff --git a/assets/js/app.js b/assets/js/app.js index 04afa63..6829fbe 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -8742,11 +8742,10 @@ async function forceSyncBring() { // ───────────────────────────────────────────────────────────────── let _pricesFetching = false; /** In-memory price cache: survives list re-renders in the same session */ -// Price cache persisted in sessionStorage — survives SPA navigation, cleared on tab close. -// Each entry includes _qty/_unit metadata so stale estimated_totals auto-invalidate when qty changes. -let _cachedPrices = (() => { - try { return JSON.parse(sessionStorage.getItem('_pricecache') || '{}'); } catch { return {}; } -})(); +// Price cache — populated by fetchAllPrices() from the server response. +// Intentionally NOT pre-loaded from sessionStorage: the server is the single +// source of truth so every client (phone, tablet, browser) sees the same prices. +let _cachedPrices = {}; /** * Build the items payload for the price API from the current shoppingItems array. @@ -9203,7 +9202,8 @@ function _updateDashboardPriceTotal() { const s = getSettings(); if (!s.price_enabled) { el.style.display = 'none'; return; } - // Compute total from cached prices (server is source of truth — entries set by batch call) + // Compute total only from prices just received from the server (in _cachedPrices). + // No sessionStorage fallback — the server is the single source of truth. const sym = _currencySymbol(s.price_currency || 'EUR'); let total = 0, count = 0; for (const item of shoppingItems) { @@ -9214,14 +9214,11 @@ function _updateDashboardPriceTotal() { const text = `ca. ${sym}${total.toFixed(2)}`; el.textContent = text; el.style.display = ''; + // Persist only so the screensaver can show it (ephemeral — never used as cache) try { sessionStorage.setItem('_pricetotal', text); } catch { /* quota */ } - return; + } else { + el.style.display = 'none'; } - - // Fallback: restore last known total from sessionStorage - const saved = sessionStorage.getItem('_pricetotal'); - if (saved) { el.textContent = saved; el.style.display = ''; } - else el.style.display = 'none'; } /** @@ -9949,33 +9946,14 @@ async function renderShoppingItems() { document.getElementById('btn-fetch-prices').style.display = 'inline-flex'; // Allow a new fetch (re-render may have happened while old fetch was running) _pricesFetching = false; - // Trust client cache only if a batch call was made recently (< 5 min). - // This aligns with the server-side 5-minute total cache and prevents stale - // per-item data (from the old approach) from being shown as authoritative. - const _cacheTs = parseInt(sessionStorage.getItem('_pricecachets') || '0'); - const _cacheAge = Date.now() - _cacheTs; - const _allCached = _cacheAge < 5 * 60 * 1000 && shoppingItems.length > 0 && shoppingItems.every(item => { - const e = _cachedPrices[item.name]; - return e && e.estimated_total != null; - }); - if (_allCached) { - // Server batch was called recently — apply instantly, no new network call - const { total: ct, count: cc } = _applyPriceBadgesFromCache(); - const sym = _currencySymbol(s2.price_currency || 'EUR'); - const totalEl = document.getElementById('price-total-value'); - if (totalEl && cc > 0) totalEl.textContent = `ca. ${sym}${ct.toFixed(2)}`; - const fetchBtn2 = document.getElementById('btn-fetch-prices'); - const refreshBtn2 = document.getElementById('btn-price-refresh'); - if (fetchBtn2) fetchBtn2.disabled = false; - if (refreshBtn2) { refreshBtn2.disabled = false; refreshBtn2.textContent = '🔄'; } - _updateDashboardPriceTotal(); - } else if (smartShoppingItems.length === 0 && _smartShoppingLastFetch === 0) { - // Smart data hasn't loaded yet — don't trigger fetch now. - // The second renderShoppingItems() call (inside loadSmartShopping().then()) will handle prices - // once we have real qty/unit data. Just apply whatever is cached silently. + if (smartShoppingItems.length === 0 && _smartShoppingLastFetch === 0) { + // Smart data hasn't loaded yet — show cached badges silently. + // loadSmartShopping().then() will call renderShoppingItems() again with real data. _applyPriceBadgesFromCache(); } else { - // Apply any cached prices instantly while batch fetch runs + // Always ask the server — it has a 5-min total cache and responds instantly + // if data is fresh. This guarantees every client sees the same prices. + // Show cached badges instantly while the server call is in flight. _applyPriceBadgesFromCache(); fetchAllPrices(false); } diff --git a/index.html b/index.html index 9886dcc..1196177 100644 --- a/index.html +++ b/index.html @@ -1462,6 +1462,6 @@ - +