feat: show expiry + qty pills on use-page product hero card; redesign card with accent border
This commit is contained in:
+75
-4
@@ -3027,10 +3027,72 @@ body.server-offline .bottom-nav {
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.product-preview-small {
|
||||
padding: 12px;
|
||||
/* Use-page hero card: larger, accent border, more breathing room */
|
||||
#page-use .product-preview-small {
|
||||
padding: 14px 16px;
|
||||
gap: 14px;
|
||||
border-left: 4px solid var(--primary);
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.use-hero-icon {
|
||||
font-size: 2.4rem;
|
||||
width: 52px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.use-hero-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.use-hero-name {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.use-hero-brand {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
.use-hero-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.use-meta-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
padding: 3px 8px;
|
||||
border-radius: 99px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Expiry pill colours */
|
||||
.use-pill-ok { background: #dcfce7; color: #166534; }
|
||||
.use-pill-warn { background: #fef9c3; color: #854d0e; }
|
||||
.use-pill-soon { background: #fed7aa; color: #7c2d12; }
|
||||
.use-pill-expired { background: #fee2e2; color: #991b1b; }
|
||||
/* Quantity pill */
|
||||
.use-pill-qty { background: #e0f2fe; color: #0c4a6e; }
|
||||
|
||||
.product-preview img, .product-preview-small img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
@@ -3040,8 +3102,11 @@ body.server-offline .bottom-nav {
|
||||
}
|
||||
|
||||
.product-preview-small img {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: var(--radius-sm);
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-preview-emoji {
|
||||
@@ -7510,6 +7575,12 @@ body.cooking-mode-active .app-header {
|
||||
/* ── Use inventory info ── */
|
||||
[data-theme="dark"] .use-inventory-info { background: #0c2a4e; color: #7dd3fc; }
|
||||
[data-theme="dark"] #use-expiry-hint { background: #2a1e00; border-color: #78350f; color: #fde68a; }
|
||||
[data-theme="dark"] #page-use .product-preview-small { border-left-color: var(--primary); }
|
||||
[data-theme="dark"] .use-pill-ok { background: #14532d; color: #86efac; }
|
||||
[data-theme="dark"] .use-pill-warn { background: #422006; color: #fde68a; }
|
||||
[data-theme="dark"] .use-pill-soon { background: #431407; color: #fdba74; }
|
||||
[data-theme="dark"] .use-pill-expired { background: #450a0a; color: #fca5a5; }
|
||||
[data-theme="dark"] .use-pill-qty { background: #0c2a4e; color: #7dd3fc; }
|
||||
|
||||
/* ── Recipe components ── */
|
||||
[data-theme="dark"] .recipe-expiry-note { background: #2a1e00; color: #fde68a; }
|
||||
|
||||
+53
-7
@@ -8408,18 +8408,61 @@ function showUseForm() {
|
||||
|
||||
function renderUsePreview() {
|
||||
const catIcon = CATEGORY_ICONS[mapToLocalCategory(currentProduct?.category, currentProduct?.name)] || '📦';
|
||||
const imgHtml = currentProduct?.image_url
|
||||
? `<img src="${escapeHtml(currentProduct.image_url)}" alt="">`
|
||||
: `<span class="use-hero-icon">${catIcon}</span>`;
|
||||
document.getElementById('use-product-preview').innerHTML = `
|
||||
${currentProduct?.image_url ?
|
||||
`<img src="${escapeHtml(currentProduct.image_url)}" alt="">` :
|
||||
`<span style="font-size:2rem">${catIcon}</span>`
|
||||
}
|
||||
<div class="product-preview-info">
|
||||
<h3>${escapeHtml(currentProduct?.name || '')}</h3>
|
||||
<p>${currentProduct?.brand ? escapeHtml(currentProduct.brand) : ''}</p>
|
||||
${imgHtml}
|
||||
<div class="use-hero-body">
|
||||
<div class="use-hero-name">${escapeHtml(currentProduct?.name || '')}</div>
|
||||
${currentProduct?.brand ? `<div class="use-hero-brand">${escapeHtml(currentProduct.brand)}</div>` : ''}
|
||||
<div class="use-hero-meta" id="use-hero-meta"></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the hero-card meta row with expiry badge + quantity pill.
|
||||
* Called from loadUseInventoryInfo() once inventory data is available.
|
||||
*/
|
||||
function _updateUseHeroMeta(items) {
|
||||
const metaEl = document.getElementById('use-hero-meta');
|
||||
if (!metaEl) return;
|
||||
const pills = [];
|
||||
|
||||
// ── Expiry badge ───────────────────────────────────────────────────
|
||||
const withExpiry = items.filter(i => i.expiry_date && parseFloat(i.quantity) > 0.01);
|
||||
if (withExpiry.length > 0) {
|
||||
withExpiry.sort((a, b) => new Date(a.expiry_date + 'T12:00:00') - new Date(b.expiry_date + 'T12:00:00'));
|
||||
const soonest = withExpiry[0];
|
||||
const expDate = new Date(soonest.expiry_date + 'T12:00:00');
|
||||
const today = new Date(); today.setHours(0,0,0,0);
|
||||
const days = Math.round((expDate - today) / 86400000);
|
||||
const locale = _currentLang === 'de' ? 'de-DE' : _currentLang === 'en' ? 'en-GB' : 'it-IT';
|
||||
const dateStr = expDate.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: '2-digit' });
|
||||
|
||||
let cls, label;
|
||||
if (days < 0) { cls = 'use-pill-expired'; label = `${t('expiry.badge_expired_ago').replace('{n}', Math.abs(days))} (${dateStr})`; }
|
||||
else if (days === 0){ cls = 'use-pill-soon'; label = t('expiry.badge_today'); }
|
||||
else if (days <= 3) { cls = 'use-pill-soon'; label = `${t('expiry.badge_expiring_short').replace('{n}', days)} (${dateStr})`; }
|
||||
else if (days <= 7) { cls = 'use-pill-warn'; label = `${t('expiry.badge_expiring_short').replace('{n}', days)} (${dateStr})`; }
|
||||
else { cls = 'use-pill-ok'; label = `📅 ${dateStr}`; }
|
||||
pills.push(`<span class="use-meta-pill ${cls}">${label}</span>`);
|
||||
}
|
||||
|
||||
// ── Quantity + location count pill ────────────────────────────────
|
||||
if (items.length > 0) {
|
||||
const totalQty = items.reduce((s, i) => s + parseFloat(i.quantity || 0), 0);
|
||||
const unit = items[0]?.unit;
|
||||
const qtyStr = stripHtml(formatQuantity(totalQty, unit, items[0]?.default_quantity, items[0]?.package_unit));
|
||||
const locCount = new Set(items.map(i => i.location)).size;
|
||||
const locSuffix = locCount > 1 ? ` · ${locCount} ${t('use.locations_short') || 'posti'}` : '';
|
||||
pills.push(`<span class="use-meta-pill use-pill-qty">📦 ${escapeHtml(qtyStr)}${locSuffix}</span>`);
|
||||
}
|
||||
|
||||
metaEl.innerHTML = pills.join('');
|
||||
}
|
||||
|
||||
// Conf-mode tracking for USE form
|
||||
let _useConfMode = null; // null = normal, { packageSize, packageUnit, totalSub, unit } = conf mode active
|
||||
let _useNormalUnit = 'pz'; // unit when not in conf mode
|
||||
@@ -8522,6 +8565,9 @@ async function loadUseInventoryInfo() {
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Hero card meta: expiry badge + qty pill ──────────────────
|
||||
_updateUseHeroMeta(items);
|
||||
|
||||
// ── Suggerisci quale confezione usare per prima ──────────────────
|
||||
_renderUseExpiryHint(items);
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user