diff --git a/assets/js/app.js b/assets/js/app.js index f6b344a..4f8f36b 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -8901,7 +8901,7 @@ async function fetchAllPrices(forceRefresh = false) { if (forceRefresh) { _cachedPrices = {}; - try { sessionStorage.removeItem('_pricecache'); sessionStorage.removeItem('_pricetotal'); } catch { /* ignore */ } + try { sessionStorage.removeItem('_pricecache'); sessionStorage.removeItem('_pricetotal'); sessionStorage.removeItem('_pricecachets'); } catch { /* ignore */ } shoppingItems.forEach((_, idx) => { const badge = document.getElementById(`price-badge-${idx}`); if (badge) badge.innerHTML = ``; @@ -8962,7 +8962,10 @@ async function fetchAllPrices(forceRefresh = false) { if (cc > 0 && totalEl) totalEl.textContent = `ca. ${sym}${ct.toFixed(2)}`; } finally { _pricesFetching = false; - try { sessionStorage.setItem('_pricecache', JSON.stringify(_cachedPrices)); } catch { /* quota */ } + try { + sessionStorage.setItem('_pricecache', JSON.stringify(_cachedPrices)); + sessionStorage.setItem('_pricecachets', String(Date.now())); + } catch { /* quota */ } if (loadingBar) { if (loadingInner) loadingInner.style.width = '100%'; setTimeout(() => { loadingBar.style.display = 'none'; }, 300); } if (fetchBtn) fetchBtn.disabled = false; if (refreshBtn) { refreshBtn.disabled = false; refreshBtn.textContent = '🔄'; } @@ -9946,13 +9949,17 @@ 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; - // Check if ALL items are already cached (server already returned prices for them) - const _allCached = shoppingItems.length > 0 && shoppingItems.every(item => { + // 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) { - // Prices are fully fresh — apply instantly, no loading state + // 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'); diff --git a/index.html b/index.html index d38037e..b7dfab9 100644 --- a/index.html +++ b/index.html @@ -1461,6 +1461,6 @@ - +