// SATMELI — Feed de notificaciones (el corazón de la app). function deltaInfo(price, target) { if (!target) return null; const pct = Math.round(((target - price) / target) * 100); if (pct >= 0) return { pct, under: true, label: `${pct}% bajo tu tope` }; return { pct: -pct, under: false, label: `${-pct}% sobre tu tope` }; } // ── Item de notificación ─────────────────────────────────────────────────── function NotifItem({ n, search, mode, onOpenSearch, onMarkRead, onGoMeli, i }) { const cat = search ? search.cat : 'tech'; const c = SAT_CATS[cat]; const delta = deltaInfo(n.price, n.target); const unread = !n.read; const desktop = mode === 'desktop'; return (
{/* barra de no-leído */} {unread &&
}
{/* thumb */}
{unread && }
{/* contenido */}
{/* origen + tiempo */}
{unread && NUEVO} {ago(n.foundAt)}
{/* título */}
{n.title}
{/* precio + meta */}
{fmtARS(n.price)} {delta && ( {delta.label} )}
{condLabel(n.condition)} {n.location} {desktop && {n.sellerRep}}
{/* acciones — mobile */} {!desktop && (
{ e.stopPropagation(); onGoMeli(n); }} style={{ flex: 1 }}>Ver en MELI {unread && { e.stopPropagation(); onMarkRead(n.id); }}>Leída}
)}
{/* acciones — desktop (columna derecha) */} {desktop && (
{ e.stopPropagation(); onGoMeli(n); }}>Ver en MELI
)}
); } // ── Feed ─────────────────────────────────────────────────────────────────── function Feed({ notifs, searches, mode, onOpenSearch, onMarkRead, onMarkAll, onGoMeli }) { const [filter, setFilter] = React.useState('all'); const desktop = mode === 'desktop'; const byId = Object.fromEntries(searches.map((s) => [s.id, s])); const sorted = [...notifs].sort((a, b) => a.foundAt - b.foundAt); const shown = filter === 'all' ? sorted : sorted.filter((n) => n.searchId === filter); const unread = notifs.filter((n) => !n.read).length; // agrupar por día const groups = []; shown.forEach((n) => { const lbl = dayLabel(n.foundAt); let g = groups.find((x) => x.lbl === lbl); if (!g) { g = { lbl, items: [] }; groups.push(g); } g.items.push(n); }); return (
{/* header */}
Tiempo real

Alertas {unread > 0 && {unread} sin leer}

{unread > 0 && Marcar todas leídas}
{/* filtros por búsqueda */}
setFilter('all')}>Todas {searches.map((s) => ( setFilter(s.id)} dot={SAT_CATS[s.cat].tint}> {s.term} ))}
{/* grupos */} {groups.map((g) => (
{g.lbl} {g.items.length}
{g.items.map((n, idx) => ( ))}
))} {groups.length === 0 && (
Sin alertas para este filtro todavía.
)}
); } function FilterChip({ children, active, onClick, dot }) { return ( ); } Object.assign(window, { Feed, deltaInfo });