fix: opened-but-not-edible items missing from banner + remove confusing strikethrough

- Banner (loadBannerAlerts): add step 1b — any item from statsData.opened
  with is_edible=false is queued as expired even when client-side
  getExpiredSafety would consider it 'ok' (e.g. conserve <30d past expiry).
  Applies to all product types, not just conserve.
  Requires fetching stats in the same Promise.all (no extra round-trip since
  loadDashboard already calls stats separately).
- CSS: remove text-decoration:line-through from .alert-item-spoiled .alert-item-name.
  The badge (/⚠️) already communicates the state; strikethrough added no
  information and confused users into thinking the item had been deleted.
This commit is contained in:
dadaloop82
2026-05-16 20:32:51 +00:00
parent 0f567c4ba0
commit aaf9323ba5
2 changed files with 14 additions and 2 deletions
-1
View File
@@ -5751,7 +5751,6 @@ body.cooking-mode-active .app-header {
opacity: 0.75;
}
.alert-item-spoiled .alert-item-name {
text-decoration: line-through;
color: var(--text-light);
}
+14 -1
View File
@@ -3926,11 +3926,12 @@ async function loadBannerAlerts() {
if (!banner) { _bannerLoading = false; console.warn('[Banner] #alert-banner not found'); return; }
try {
const [invData, predData, anomalyData, finishedData] = await Promise.all([
const [invData, predData, anomalyData, finishedData, statsData] = await Promise.all([
api('inventory_list'),
api('consumption_predictions').catch(err => { console.warn('[Banner] predictions fetch failed:', err); return { predictions: [] }; }),
api('inventory_anomalies').catch(err => { console.warn('[Banner] anomalies fetch failed:', err); return { anomalies: [] }; }),
api('inventory_finished_items').catch(err => { console.warn('[Banner] finished_items fetch failed:', err); return { finished: [] }; }),
api('stats').catch(() => ({ opened: [] })),
]);
const items = invData.inventory || [];
const confirmed = getReviewConfirmed();
@@ -3971,6 +3972,18 @@ async function loadBannerAlerts() {
_queuedItemIds.add(item.id);
});
// 1b. Opened items the SERVER considers not edible (is_edible=false from stats).
// The client-side getExpiredSafety check above uses conservative thresholds (e.g.
// conserve are 'ok' for 30 days past), but the server uses product-specific AI shelf
// life. Trust the server: any opened item with is_edible=false that isn't already
// queued goes into the banner as expired.
const openedNotEdible = (statsData.opened || []).filter(oi => !oi.is_edible && !_queuedItemIds.has(oi.id) && !confirmed['exp_' + oi.id]);
openedNotEdible.forEach(oi => {
const daysOI = Math.abs(oi.days_to_expiry ?? 0);
_bannerQueue.push({ type: 'expired', data: { ...oi, days_expired: daysOI } });
_queuedItemIds.add(oi.id);
});
// 2. Suspicious quantities ("expiring soon" shown only in dashboard sections, not in banner)
// Group items by product identity to detect sibling entries in other locations.
// A "low quantity" alert is suppressed when other stock of the same product exists