/* global React */ // Alertas y Plazos — HU.3.2 // Lista de notificaciones del semáforo D-7 / D-3 / D-1 / D / D+1 // + panel de configuración de hitos y canales const { useState: useStateAl, useMemo: useMemoAl } = React; function AlertasScreen({ roleId, user, onOpenDetalle }) { const I = window.Icons; const alertas = window.getAlertas(roleId); const [filter, setFilter] = useStateAl('todas'); const [scope, setScope] = useStateAl('todas'); // todas, vencimientos, devoluciones, sin_avance, sistema // Cuenta de hitos const counts = useMemoAl(() => { const c = { todas: alertas.length, unread: 0, d7: 0, d3: 0, d1: 0, d0: 0, dplus: 0, sin: 0 }; alertas.forEach(a => { if (!a.read) c.unread++; if (a.code === 'D-7') c.d7++; else if (a.code === 'D-3') c.d3++; else if (a.code === 'D-1') c.d1++; else if (a.code === 'D') c.d0++; else if (a.code.startsWith('D+')) c.dplus++; else if (a.code === 'sin' || a.code === 'devol') c.sin++; }); return c; }, [alertas]); const filtered = useMemoAl(() => { return alertas.filter(a => { if (filter === 'unread' && a.read) return false; if (filter === 'D-7' && a.code !== 'D-7') return false; if (filter === 'D-3' && a.code !== 'D-3') return false; if (filter === 'D-1' && a.code !== 'D-1') return false; if (filter === 'D' && a.code !== 'D') return false; if (filter === 'overdue' && !a.code.startsWith('D+')) return false; if (filter === 'sin_plazo' && a.code !== 'sin') return false; if (scope === 'vencimientos' && a.tipo !== 'vencimiento') return false; if (scope === 'devoluciones' && a.tipo !== 'devolucion') return false; if (scope === 'sin_avance' && a.tipo !== 'sin_avance') return false; if (scope === 'sistema' && a.tipo !== 'sistema') return false; return true; }); }, [alertas, filter, scope]); return (
{/* Header */}
{user.org}

Alertas y Plazos

Notificaciones automáticas del semáforo D-7 / D-3 / D-1 / D / D+1. {roleId === 'institucion' ? ' Cubre tus compromisos asignados.' : ' Sobre el universo de las 527 recomendaciones del país.'}

{roleId !== 'institucion' && ( )}
{/* KPI strip */}
{counts.todas}
Alertas activas
{counts.unread} sin leer
{counts.d1 + counts.d0}
D-1 / Hoy
Acción urgente
{counts.d3}
D-3
Próximos 3 días
{counts.d7}
D-7
Primer aviso
{counts.dplus}
Vencidos · D+
Sin avance registrado
{/* MAIN */}
{/* Tabs por hito */}
{/* Scope chips */}
{[ { v: 'todas', l: 'Todos los tipos' }, { v: 'vencimientos', l: '⏱ Vencimientos' }, { v: 'sin_avance', l: '⚠ Sin avance' }, { v: 'devoluciones', l: '↩ Devoluciones' }, { v: 'sistema', l: '⚙ Sistema' }, ].map(it => ( ))}
{/* Lista de alertas */}
    {filtered.map(a => ( ))}
{filtered.length === 0 && (

No hay alertas con esta combinación

Ajusta los filtros o vuelve a "Todas" para ver el conjunto completo.

)}
{/* RAIL */}
); } // ---------------- Alert item ---------------- function AlertItem({ a, onOpen, roleId }) { const I = window.Icons; const tipoMeta = { vencimiento: { icon: 'Clock', label: 'Vencimiento' }, sin_avance: { icon: 'AlertTriangle', label: 'Sin avance' }, devolucion: { icon: 'AlertCircle', label: 'Devolución' }, sistema: { icon: 'Settings', label: 'Sistema' }, }[a.tipo] || { icon: 'Bell', label: 'Notificación' }; const ICON = I[tipoMeta.icon]; return (
  • {a.code === 'sin' ? '—' : a.code === 'devol' ? '↩' : a.code}
    {tipoMeta.label} {a.mecanismo} {a.compromisoId} {a.institucion} {!a.read && }
    {a.msg}
    Plazo: {a.plazo} · Enviada {a.sentAt}
    {roleId !== 'institucion' && a.tipo === 'vencimiento' && ( )}
  • ); } Object.assign(window, { AlertasScreen });