/* global React */
// Instituciones (HU.4.3) — Catálogo en formato lista, editar y eliminar
const { useState: useStateIn, useMemo: useMemoIn } = React;
const PAGE_SIZE = 8;
// ---------------- Advanced filters config ----------------
const ADV_DEFAULT = {
tipo: [], // array de tipos seleccionados (multi-select)
estado: 'todos', // todos | activo | desactivado
orden: 'az', // az | za
};
// Grupos de chips (estado + orden). El "tipo de institución" se filtra con un
// multi-select aparte (permite elegir varios a la vez) y sus opciones vienen del catálogo.
const ADV_GROUPS = [
{
key: 'estado',
label: 'Estado',
icon: 'CheckCircle2',
options: [
{ v: 'todos', l: 'Todos' },
{ v: 'activo', l: 'Activas' },
{ v: 'desactivado', l: 'Desactivadas' },
],
},
{
key: 'orden',
label: 'Ordenar por nombre',
icon: 'ListChecks',
options: [
{ v: 'az', l: 'A → Z' },
{ v: 'za', l: 'Z → A' },
],
},
];
// Convierte "Hoy" / "Ayer" / "12 abr" / "Nunca" a una fecha con año (para el Excel).
const MESES_AB = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'];
function fmtUltimoAcceso(v) {
if (!v || String(v).toLowerCase() === 'nunca') return v || '';
const hoy = new Date();
const fmt = (d) => `${d.getDate()} ${MESES_AB[d.getMonth()]} ${d.getFullYear()}`;
const s = String(v).toLowerCase().trim();
if (s === 'hoy') return fmt(hoy);
if (s === 'ayer') { const d = new Date(hoy); d.setDate(d.getDate() - 1); return fmt(d); }
const m = /^(\d{1,2})\s+([a-záéíóú]{3,})/.exec(s);
if (m) { const mi = MESES_AB.indexOf(m[2].slice(0, 3)); return `${parseInt(m[1], 10)} ${MESES_AB[mi >= 0 ? mi : 0]} ${hoy.getFullYear()}`; }
return v;
}
function InstitucionesScreen({ user, onOpenNueva }) {
const I = window.Icons;
const [items, setItems] = window.usePersistentState('instituciones', () => window.INSTITUCIONES_CATALOG.slice());
const [q, setQ] = useStateIn('');
const [page, setPage] = useStateIn(1);
// Advanced filters
const [adv, setAdv] = useStateIn(ADV_DEFAULT);
const [advOpen, setAdvOpen] = useStateIn(false);
// Form view (crear / editar) + activar/desactivar confirmation state
const [view, setView] = useStateIn('list'); // 'list' | 'form'
const [editing, setEditing] = useStateIn(null); // null = creando
const [toggling, setToggling] = useStateIn(null);
const [deleting, setDeleting] = useStateIn(null);
const tipoOptions = (window.cgrData ? window.cgrData.tiposInstitucion() : []);
const openCreate = () => { setEditing(null); setView('form'); };
const openEdit = (inst) => { setEditing(inst); setView('form'); };
const backToList = () => { setView('list'); setEditing(null); };
const advCount = (adv.tipo.length ? 1 : 0) + (adv.estado !== 'todos' ? 1 : 0) + (adv.orden !== 'az' ? 1 : 0);
const filtered = useMemoIn(() => {
const list = items.filter(i => {
if (q && !`${i.nombre} ${i.sigla} ${i.contacto}`.toLowerCase().includes(q.toLowerCase())) return false;
if (adv.tipo.length && adv.tipo.indexOf(i.tipo) === -1) return false;
if (adv.estado !== 'todos' && i.estado !== adv.estado) return false;
return true;
});
list.sort((a, b) => a.nombre.localeCompare(b.nombre, 'es', { sensitivity: 'base' }));
if (adv.orden === 'za') list.reverse();
return list;
}, [items, q, adv]);
const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
const safePage = Math.min(page, totalPages);
const pageStart = (safePage - 1) * PAGE_SIZE;
const pageItems = filtered.slice(pageStart, pageStart + PAGE_SIZE);
const onSearch = (v) => { setQ(v); setPage(1); };
const setAdvKey = (k, v) => { setAdv(prev => ({ ...prev, [k]: v })); setPage(1); };
const setAdvTipo = (arr) => { setAdv(prev => ({ ...prev, tipo: arr })); setPage(1); };
const freshAdv = () => ({ tipo: [], estado: 'todos', orden: 'az' });
const resetAdv = () => { setAdv(freshAdv()); setPage(1); };
const clearAll = () => { setQ(''); setAdv(freshAdv()); setPage(1); };
const handleSave = (data) => {
if (editing) {
// Edición de una institución existente
setItems(list => list.map(it => it.id === editing.id ? { ...it, ...data } : it));
} else {
// Alta de una nueva institución
const id = (data.sigla || '').toUpperCase().replace(/[^A-Z0-9]+/g, '-').replace(/^-|-$/g, '');
setItems(list => [
{ id: id || `INST-${list.length + 1}`, usuarios: 0, compromisos: 0, ultimo: 'Nunca', ...data },
...list,
]);
setPage(1);
}
backToList();
};
const handleToggleConfirm = () => {
if (!toggling) return;
const next = toggling.estado === 'desactivado' ? 'activo' : 'desactivado';
setItems(list => list.map(it => it.id === toggling.id ? { ...it, estado: next } : it));
setToggling(null);
};
const handleDeleteConfirm = () => {
if (!deleting) return;
const inst = deleting;
setItems(list => list.filter(it => it.id !== inst.id));
// Cascada: eliminar también los usuarios vinculados a esta institución.
try {
const sig = (inst.sigla || '').toLowerCase();
const nom = (inst.nombre || '').toLowerCase();
const usuarios = window.cgrStore.load('usuarios', window.USUARIOS || []);
const restante = usuarios.filter(u => {
const seg = (u.institucion || '').toLowerCase().split('·')[0].trim();
return !(seg === sig || seg === nom || (nom && nom.indexOf(seg) === 0) || (nom && seg.indexOf(nom) === 0));
});
window.cgrStore.save('usuarios', restante);
} catch (e) {}
setDeleting(null);
};
// Active advanced-filter chips for the bar above the list
const activeAdv = [];
if (adv.tipo.length) activeAdv.push({ key: 'tipo', group: 'Tipo', label: adv.tipo.length === 1 ? adv.tipo[0] : `${adv.tipo.length} tipos`, reset: () => setAdvTipo([]) });
['estado', 'orden'].forEach(k => {
if (adv[k] !== ADV_DEFAULT[k]) {
const group = ADV_GROUPS.find(g => g.key === k);
const opt = group.options.find(o => o.v === adv[k]);
activeAdv.push({ key: k, group: group.label, label: opt.l, reset: () => setAdvKey(k, ADV_DEFAULT[k]) });
}
});
// Vista de formulario (crear / editar) — ocupa la misma área que la lista
if (view === 'form') {
return (
Consulta, edita y administra las instituciones del Estado habilitadas como reportantes.
Búscalas por nombre o sigla y gestiona cada ficha desde la lista.
No hay instituciones que coincidan con la combinación actual de filtros. {(q || advCount > 0) && ( <> {' '} . > )}
Esta acción no se puede deshacer. Se eliminará {inst.nombre} y todo lo relacionado: sus usuarios, las asignaciones de compromisos, y los avances y evidencias vinculados a esta institución.
{isActive ? ( <>{inst.nombre} perderá el acceso a la plataforma, pero conserva todo su historial de avances y evidencias. Podrás reactivarla cuando lo necesites.> ) : ( <>{inst.nombre} recuperará el acceso a la plataforma y volverá a recibir asignaciones y alertas de plazos.> )}