diff --git a/packages/dashboard/index.html b/packages/dashboard/index.html index 643bdd0..6b6146a 100644 --- a/packages/dashboard/index.html +++ b/packages/dashboard/index.html @@ -1866,20 +1866,24 @@ async function openTxDetail(id) { if (iVer) verItems.push('✓ Image'); if (dVer) verItems.push('✓ Details'); if (fVer) { - h += '
' - + '★ 100% VERIFIED' - + '' - + verItems.join('·') - + (t.fully_verified_at ? 'seit ' + fmtDate(t.fully_verified_at) + '' : '') + // Inside the green bar: all text must be white/light — not #2d6a4f (same as bg) + var fvItems = []; + if (pVer) fvItems.push('✓ Price'); + if (iVer) fvItems.push('✓ Image'); + if (dVer) fvItems.push('✓ Details'); + h += '
' + + '★ 100% VERIFIED' + + '' + + fvItems.join('·') + + (t.fully_verified_at ? 'seit ' + fmtDate(t.fully_verified_at) + '' : '') + '
'; } else if (verItems.length > 0) { + // Partial verification on white background: dark green is fine here h += '
' + verItems.join('·') + '
'; - } else { - // No verification data yet — show neutral indicator - h += '
Data not yet verified from official sources
'; } + // No verification → no badge. Never show unverified data as verified. // Helper: render a spec section as a clean table (like Flexoptix spec tables) function renderSpecTable(title, rows) { @@ -1948,30 +1952,27 @@ async function openTxDetail(id) { ['Year Mainstream', t.year_mainstream], ]); - // SPECIFICATION — Pricing (verified prices from DB) - var prices = t.competitor_prices || []; + // SPECIFICATION — Pricing + // Rule: Only show prices that were scraped from a real URL within the last 30 days. + // Unverified / estimated prices are NOT shown — silence is better than wrong data. + var prices = (t.competitor_prices || []).filter(function(p) { return p.url && p.price > 0; }); if (prices.length > 0) { h += '
Current Prices
'; h += '
'; prices.forEach(function(p) { - var verBadge = p.is_verified - ? '✓ Verified' - : 'unverified'; - var priceStr = p.currency + ' ' + parseFloat(p.price).toLocaleString('de-DE', {minimumFractionDigits:2,maximumFractionDigits:2}); - var dateStr = '' + fmtDate(p.observed_at) + ''; - var urlLink = p.url ? ' ' : ''; + // Verified badge only if observed within 7 days AND has a real URL + var verBadge = p.is_verified === true + ? '✓ Verified Price' + : ''; // No badge for older observations — not wrong, just not shown as verified + var priceStr = '' + p.currency + '\u00a0' + parseFloat(p.price).toLocaleString('de-DE', {minimumFractionDigits:2,maximumFractionDigits:2}) + ''; + var dateStr = 'Stand: ' + fmtDate(p.observed_at) + ''; + var urlLink = '↗ Quelle'; h += '
' + esc(p.vendor_name) + '' - + '' + priceStr + verBadge + dateStr + urlLink + '
'; + + '' + priceStr + verBadge + dateStr + urlLink + '
'; }); h += '
'; - } else { - // Fallback: show MSRP/street from transceivers table if no price_observations - h += renderSpecTable('Pricing', [ - ['MSRP', t.msrp_usd ? '$' + parseFloat(t.msrp_usd).toLocaleString() : null], - ['Street Price', t.street_price_usd ? '$' + parseFloat(t.street_price_usd).toLocaleString() : null], - ['Price Tier', t.price_tier], - ]); } + // No price_observations → show nothing. Never display estimated or unverifiable prices. // Notes (scraped extra specs) if (t.notes) {