/* global React */
const { useState: useStateT } = React;
// ---------------- KPI Card ----------------
function KpiCard({ icon, label, num, sub, tone, gauge }) {
const I = window.Icons;
return (
{React.createElement(I[icon], { size: 16 })}
{label}
{num}
{gauge != null &&
}
{sub &&
{sub}
}
);
}
// Small SVG arc for % gauges
function KpiArc({ value, tone }) {
const r = 22, c = 2 * Math.PI * r;
const offset = c * (1 - value / 100);
const color =
tone === 'ok' ? 'var(--sem-success)' :
tone === 'warn' ? 'var(--sem-warning-bg)' :
tone === 'danger' ? 'var(--sem-danger)' :
'var(--cgr-primary)';
return (
);
}
// ---------------- Mecanismo Stacked Bar ----------------
function MecanismoStacked({ items }) {
return (
{items.map(m => {
const okPct = (m.ok / m.total) * 100;
const prPct = (m.partial / m.total) * 100;
const bdPct = (m.bad / m.total) * 100;
return (
{m.label}
{m.total}
{m.ok}
{m.partial}
{m.bad}
);
})}
);
}
// ---------------- Horizontal Inst Bar Chart ----------------
function InstBars({ items, max }) {
return (
{items.slice(0, 6).map(it => {
const w = (it.total / max) * 100;
const tone = it.cumpl >= 75 ? 'is-ok' : it.cumpl >= 55 ? 'is-warn' : 'is-danger';
return (
{it.inst}
{it.total}
{it.cumpl}%
);
})}
);
}
// ---------------- Sparkline (evolution) ----------------
function Sparkline({ data, w = 320, h = 100 }) {
if (!data.length) return null;
const pad = 4;
const min = Math.min(...data.map(d => d.v)) - 4;
const max = Math.max(...data.map(d => d.v)) + 4;
const step = (w - pad * 2) / (data.length - 1);
const pts = data.map((d, i) => {
const x = pad + i * step;
const y = h - pad - ((d.v - min) / (max - min)) * (h - pad * 2);
return [x, y];
});
const pathD = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
const areaD = pathD + ` L${pts[pts.length - 1][0]} ${h - pad} L${pts[0][0]} ${h - pad} Z`;
const last = pts[pts.length - 1];
return (
);
}
// ---------------- Filter chip / select ----------------
function FilterSelect({ icon, label, value }) {
const I = window.Icons;
return (
);
}
// ---------------- Status pill mapping ----------------
function StatusPill({ estado }) {
const I = window.Icons;
const map = {
ok: { cls: 'is-ok', icon: 'CheckCircle2', label: 'Cumplido' },
partial: { cls: 'is-warn', icon: 'AlertCircle', label: 'Parcial' },
bad: { cls: 'is-danger', icon: 'XCircle', label: 'No cumplido' },
overdue: { cls: 'is-dark', icon: 'AlertTriangle',label: 'Vencido s/avance' },
};
const s = map[estado] || map.partial;
return (
{React.createElement(I[s.icon], { size: 11 })}
{s.label}
);
}
// ---------------- TABLERO SCREEN ----------------
function TableroScreen({ onOpenDetalle }) {
const I = window.Icons;
const [filter, setFilter] = useStateT('todos');
const compromisos = window.COMPROMISOS;
const maxInst = Math.max(...window.INST_RANKING.map(i => i.total));
return (
{/* Page header */}
CGR · Dirección de Análisis de Datos
Tablero de Control
Estado consolidado del cumplimiento país en los tres mecanismos —
MESICIC, UNCAC y OCDE — actualizado al 21 de mayo de 2026.
{/* Filters */}
{/* KPI bento */}
{/* Charts row */}
Distribución por mecanismo
3 mecanismos activos
Top 6 instituciones con más compromisos
Evolución del cumplimiento
17 meses
62%
↑ 21 pts vs. ene 2025
{/* Tabla principal */}
Compromisos · vista detallada
Mostrando {compromisos.length} de 527 · ordenados por proximidad de vencimiento
| ID |
Recomendación |
Mecanismo |
Institución responsable |
Vence |
Estado |
|
{compromisos.map(c => (
onOpenDetalle && onOpenDetalle(c.id)}>
| {c.id} |
{c.text} |
{c.mecanismo}
{c.ronda}
|
{c.inst} |
{c.vence}
{c.d < 0 ? `D+${Math.abs(c.d)} (vencido)` : c.d === 0 ? 'Hoy' : `D-${c.d}`}
|
|
|
))}
Página 1 de 44 · 12 por página
…
);
}
Object.assign(window, { TableroScreen, StatusPill });