/* global React */ // Mis Compromisos Asignados — vista de la Institución Reportante // HU.2.1 (cargar avance), HU.2.2 (historial), HU.2.3 (devolución para ajuste) const { useState: useStateM, useMemo: useMemoM } = React; function MisCompromisosScreen({ user, onOpenDetalle, onCargar }) { const I = window.Icons; const all = window.MIS_COMPROMISOS; const [filter, setFilter] = useStateM('todos'); const [view, setView] = useStateM('cards'); // cards | tabla // Conteos por estado de ciclo const counts = useMemoM(() => { const c = { todos: all.length, pending: 0, draft: 0, in_review: 0, returned: 0, approved: 0, overdue: 0 }; all.forEach(x => { c[x.estadoCiclo] = (c[x.estadoCiclo] || 0) + 1; }); return c; }, [all]); const filtered = useMemoM(() => { if (filter === 'todos') return all; return all.filter(c => c.estadoCiclo === filter); }, [all, filter]); // KPIs derivados const total = all.length; const cumplidos = all.filter(c => c.estado === 'ok').length; const parciales = all.filter(c => c.estado === 'partial').length; const noCump = all.filter(c => c.estado === 'bad').length; const proximos = all.filter(c => c.d >= 0 && c.d <= 7).length; // Hay devoluciones? const devoluciones = all.filter(c => c.estadoCiclo === 'returned'); return (
{/* Header */}
{user.org}

Mis Compromisos Asignados

{total} recomendaciones internacionales bajo responsabilidad de tu institución, ordenadas por plazo interno de carga de avances. Para cada una verás el estado de cumplimiento vigente, el último reporte enviado, las observaciones de la CGR pendientes de atender y el indicador D-7 / D-3 / D-1 cuando el plazo se acerca. Carga tu avance con descripción y evidencias (PDF, JPG, PNG, XLSX, DOCX o URLs), consulta el historial completo de versiones y atiende las devoluciones recibidas.

{/* Banner: devolución pendiente (HU.2.3) */} {devoluciones.length > 0 && (
{devoluciones.length} reporte devuelto para ajuste

{devoluciones[0].id} — {devoluciones[0].text}. Observación de {devoluciones[0].observador} · {devoluciones[0].obsFecha}.

)} {/* KPI strip */}
{total}
Compromisos asignados
{cumplidos} cumpl. · {parciales} parc. · {noCump} no cumpl.
{proximos}
Plazos próximos (D-7)
Requieren acción esta semana
{counts.returned || 0}
Devueltos para ajuste
Editar lo observado
{counts.in_review || 0}
En revisión por CGR
Esperando validación
{counts.approved || 0}
Aprobados
Ciclo cerrado por CGR
{/* Tabs por estado de ciclo */}
Todos Pendientes de cargar Devueltos para ajuste Borradores En revisión Aprobados Vencidos
{/* Cards / lista */} {view === 'cards' ? (
{filtered.map(c => ( ))}
) : (
{filtered.map(c => { const meta = window.cicloMeta(c.estadoCiclo); const dCls = c.d < 0 ? 'is-overdue' : c.d <= 3 ? 'is-soon' : ''; return ( onOpenDetalle(c.id)}> ); })}
ID Recomendación Estado del ciclo Vence Estado cumplim. Último avance
{c.id} {c.text}
{c.mecanismo} · {c.ronda} · Rol: {c.rol}
{c.plazo}
{c.d < 0 ? `D+${Math.abs(c.d)}` : c.d === 0 ? 'Hoy' : `D-${c.d}`}
{c.ultimoAvance} e.stopPropagation()}>
)}
); } // ---------------- Card individual ---------------- function MisCompromisoCard({ c, onOpen, onCargar }) { const I = window.Icons; const meta = window.cicloMeta(c.estadoCiclo); const ICON = I[meta.icon]; const isUrgent = c.d < 0 || c.estadoCiclo === 'returned' || c.estadoCiclo === 'overdue'; const isSoon = c.d >= 0 && c.d <= 7; const dueText = c.d < 0 ? `Vencido hace ${Math.abs(c.d)} día${Math.abs(c.d) !== 1 ? 's' : ''}` : c.d === 0 ? 'Vence hoy' : c.d <= 7 ? `Vence en ${c.d} día${c.d !== 1 ? 's' : ''}` : `Vence el ${c.plazo}`; const ctaLabel = c.estadoCiclo === 'pending' || c.estadoCiclo === 'overdue' ? 'Cargar avance' : c.estadoCiclo === 'returned' ? 'Atender observación' : c.estadoCiclo === 'draft' ? 'Continuar borrador' : c.estadoCiclo === 'in_review' ? 'Ver avance enviado' : 'Ver detalle'; return (
{c.mecanismo} {c.id} · {c.ronda}
{meta.label} Rol: {c.rol} {c.lider !== '—' && c.rol !== 'Líder' && · Líder: {c.lider}}
{/* Observación destacada si está devuelto */} {c.estadoCiclo === 'returned' && c.observacion && (
Observación de la CGR · {c.obsFecha}

{c.observacion}

{c.observador}
)}
{dueText}
{c.avances} {c.evidencias} · {c.ultimoAvance}
); } // ---------------- Tab pill (filter) ---------------- function CicloTab({ id, count, tone, active, onSet, children }) { return ( ); } // ---------------- Pill compacta ciclo ---------------- function CicloPill({ ciclo }) { const I = window.Icons; const meta = window.cicloMeta(ciclo); const ICON = I[meta.icon]; return ( {meta.label} ); } Object.assign(window, { MisCompromisosScreen, CicloPill });