/* global React */ // Compromisos: listado + filtros avanzados + acciones (Admin / Súper Admin CGR) // HU.1.1, HU.1.2, HU.1.3, HU.1.4, HU.5.3 — mismo patrón de diseño que Instituciones. const { useState: useStateC, useMemo: useMemoC } = React; // ---------------- Helpers para alta de recomendación ---------------- const MESES_ABBR_C = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']; function fmtFechaISO_C(iso) { const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso || ''); if (!m) return iso || 'Sin plazo'; return parseInt(m[3], 10) + ' ' + MESES_ABBR_C[parseInt(m[2], 10) - 1] + ' ' + m[1]; } function diasHastaISO_C(iso) { const d = new Date((iso || '') + 'T00:00:00'); if (isNaN(d.getTime())) return 999; const hoy = new Date(); hoy.setHours(0, 0, 0, 0); return Math.round((d - hoy) / 86400000); } const ESTADO_LABEL_C = { ok: 'Cumplido', partial: 'Parcial', bad: 'No cumplido', pending: 'Pendiente', overdue: 'Vencido sin avance' }; // ---------------- KPI tira ---------------- function CompKpi({ icon, label, num, sub, tone }) { const I = window.Icons; return (
{React.createElement(I[icon], { size: 15 })}
{num}
{label}
{sub &&
{sub}
}
); } // ---------------- Fila de la tabla ---------------- function CompRow({ c, onOpen }) { const I = window.Icons; const dCls = c.d < 0 ? 'is-overdue' : c.d <= 3 ? 'is-soon' : c.d <= 7 ? 'is-warnish' : ''; return ( onOpen(c.id)}>
{c.id} {c.idIntl && {c.idIntl}}
{c.text}
{c.mecanismo}
{c.eje}
{c.tipo} · {c.prioridad}
{c.instituciones.slice(0, 2).map(i => {i})} {c.instituciones.length > 2 && +{c.instituciones.length - 2}}
{c.plazo}
{c.d < 0 ? `D+${Math.abs(c.d)} (vencido)` : c.d === 0 ? 'Vence hoy' : `D-${c.d}`}
); } // ---------------- Pantalla principal ---------------- function CompromisosScreen({ onOpenDetalle, onOpenNueva }) { const I = window.Icons; const [all, setAll] = window.usePersistentState('compromisos', () => window.COMPROMISOS_FULL.slice()); const handleSaveRec = (form) => { const cat = window.INSTITUCIONES_CATALOG || []; const siglaDe = (id) => { const f = cat.find(x => x.id === id); return f ? f.sigla : id; }; const insts = (form.instituciones || []).filter(r => r.institucionId).map(r => siglaDe(r.institucionId)); const plazos = (form.instituciones || []).map(r => r.plazo).filter(Boolean).sort(); const plazoISO = plazos[0] || ''; const prefijo = (form.mecanismo || 'REC').slice(0, 3).toUpperCase(); const rondaClean = (form.ronda || '').replace(/\s+/g, '') || 'S'; const nuevo = { id: prefijo + '-' + rondaClean + '-' + String(Date.now()).slice(-4), idIntl: form.idIntl || '', mecanismo: form.mecanismo, ronda: form.ronda, eje: form.eje, tipo: form.tipo, prioridad: form.prioridad, instituciones: insts.length ? insts : ['—'], plazo: plazoISO ? fmtFechaISO_C(plazoISO) : 'Sin plazo', d: plazoISO ? diasHastaISO_C(plazoISO) : 999, estado: 'pending', text: form.titulo, textoCompleto: form.texto, lastUpdate: 'recién', avances: 0, vinc: 0, }; setAll(list => [nuevo, ...list]); setView('list'); }; const [q, setQ] = useStateC(''); const [mech, setMech] = useStateC('Todos'); const [estado, setEstado] = useStateC('Todos'); const [tipo, setTipo] = useStateC('Todos'); const [inst, setInst] = useStateC('Todas'); const [eje, setEje] = useStateC('Todos los ejes'); const [advOpen, setAdvOpen] = useStateC(false); const [view, setView] = useStateC('list'); // 'list' | 'form' const MECH_OPTS = [{ v: 'Todos', l: 'Todos' }, { v: 'MESICIC', l: 'MESICIC' }, { v: 'UNCAC', l: 'UNCAC' }, { v: 'OCDE', l: 'OCDE' }]; const ESTADO_OPTS = [ { v: 'Todos', l: 'Todos' }, { v: 'Cumplidos', l: 'Cumplidos' }, { v: 'Parciales', l: 'Parciales' }, { v: 'No cumplidos', l: 'No cumplidos' }, { v: 'Vencidos sin avance', l: 'Vencidos sin avance' }, ]; const TIPO_OPTS = [{ v: 'Todos', l: 'Todos' }, { v: 'Normativa', l: 'Normativa' }, { v: 'Administrativa', l: 'Administrativa' }, { v: 'Operativa', l: 'Operativa' }]; const INST_OPTS = ['Todas', 'SENAC', 'Ministerio de Hacienda', 'Ministerio Público', 'Ministerio del Interior', 'Ministerio de Justicia', 'SEPRELAD', 'Poder Judicial', 'Contraloría General']; const EJE_OPTS = ['Todos los ejes', ...window.cgrData.ejes()]; const filtered = useMemoC(() => { return all.filter(c => { if (q && !(`${c.id} ${c.text} ${c.instituciones.join(' ')}`).toLowerCase().includes(q.toLowerCase())) return false; if (mech !== 'Todos' && c.mecanismo !== mech) return false; if (estado === 'Cumplidos' && c.estado !== 'ok') return false; if (estado === 'Parciales' && c.estado !== 'partial') return false; if (estado === 'No cumplidos' && c.estado !== 'bad') return false; if (estado === 'Vencidos sin avance' && c.d >= 0) return false; if (tipo !== 'Todos' && c.tipo !== tipo) return false; if (eje !== 'Todos los ejes' && c.eje !== eje) return false; if (inst !== 'Todas' && !c.instituciones.some(i => i.toLowerCase().includes(inst.toLowerCase()) || inst.toLowerCase().includes(i.toLowerCase()))) return false; return true; }); }, [all, q, mech, estado, tipo, inst, eje]); const advCount = [mech !== 'Todos', estado !== 'Todos', tipo !== 'Todos', inst !== 'Todas', eje !== 'Todos los ejes'].filter(Boolean).length; const resetAdv = () => { setMech('Todos'); setEstado('Todos'); setTipo('Todos'); setInst('Todas'); setEje('Todos los ejes'); }; const clearAll = () => { setQ(''); resetAdv(); }; const activeChips = []; if (mech !== 'Todos') activeChips.push({ key: 'mech', group: 'Mecanismo', label: mech, reset: () => setMech('Todos') }); if (estado !== 'Todos') activeChips.push({ key: 'estado', group: 'Estado', label: estado, reset: () => setEstado('Todos') }); if (tipo !== 'Todos') activeChips.push({ key: 'tipo', group: 'Tipo', label: tipo, reset: () => setTipo('Todos') }); if (inst !== 'Todas') activeChips.push({ key: 'inst', group: 'Institución',label: inst, reset: () => setInst('Todas') }); if (eje !== 'Todos los ejes') activeChips.push({ key: 'eje', group: 'Eje', label: eje, reset: () => setEje('Todos los ejes') }); // Vista de formulario (nueva recomendación) — ocupa la misma área que el listado if (view === 'form') { return ( setView('list')} onSave={handleSaveRec} /> ); } return (
Inventario de recomendaciones

Compromisos

Inventario único de las recomendaciones internacionales de Paraguay (MESICIC, UNCAC y OCDE). Registra, clasifica, asigna instituciones y da seguimiento al cumplimiento.

{/* Buscador + filtros avanzados */}
setQ(e.target.value)} />
{advOpen && (
Filtros avanzados Filtra el inventario por mecanismo, estado de cumplimiento, tipo de medida, institución responsable o eje temático. Los cambios se aplican al instante y se combinan con el buscador.
Mecanismo
{MECH_OPTS.map(o => ( ))}
Estado de cumplimiento
{ESTADO_OPTS.map(o => ( ))}
Tipo de medida
{TIPO_OPTS.map(o => ( ))}
Institución responsable
Eje temático
)} {!advOpen && advCount > 0 && (
{advCount} filtro{advCount === 1 ? '' : 's'} activo{advCount === 1 ? '' : 's'}: {activeChips.map(a => ( ))}
)} {filtered.length === 0 ? (

Sin resultados con los filtros aplicados

Intenta con otras palabras clave. {(q || advCount > 0) && ( <>{' '}. )}

) : ( <>
{filtered.map(c => )}
ID Recomendación Mecanismo Clasificación Instituciones Vence Estado
Mostrando {filtered.length} de {all.length} recomendaciones
)}
); } Object.assign(window, { CompromisosScreen });