/* global React */ // Usuarios (HU.4.1) — Gestión de cuentas y roles // Mismo patrón de diseño que Instituciones. const { useState: useStateUs, useMemo: useMemoUs } = React; // ---------------- Filtros avanzados ---------------- const ADV_DEFAULT_US = { rol: 'todos', // todos | superadmin | admin | institucion | cancilleria | lector institucion: [], // array de instituciones seleccionadas (multi-select) estado: 'todos', // todos | activo | pendiente | desactivado orden: 'az', // az | za }; const ADV_GROUPS_US = [ { key: 'rol', label: 'Rol', icon: 'Users', options: [ { v: 'todos', l: 'Todos' }, { v: 'superadmin', l: 'Súper Admin' }, { v: 'admin', l: 'Admin' }, { v: 'institucion', l: 'Enlace Institucional' }, { v: 'cancilleria', l: 'Cancillería' }, ], }, { key: 'institucion', label: 'Institución', icon: 'Building2', type: 'select', options: [], }, { key: 'estado', label: 'Estado', icon: 'CheckCircle2', options: [ { v: 'todos', l: 'Todos' }, { v: 'activo', l: 'Activos' }, { v: 'pendiente', l: 'Pendientes' }, { v: 'desactivado', l: 'Desactivados' }, ], }, { key: 'orden', label: 'Ordenar por nombre', icon: 'ListChecks', options: [ { v: 'az', l: 'A → Z' }, { v: 'za', l: 'Z → A' }, ], }, ]; // Ícono encendido/apagado (toggle) function PowerGlyphUs({ size = 13 }) { return ( ); } function UsuariosScreen({ roleId, user, onOpenNuevo }) { const I = window.Icons; const [items, setItems] = window.usePersistentState('usuarios', () => window.USUARIOS.slice()); const [q, setQ] = useStateUs(''); const [adv, setAdv] = useStateUs(ADV_DEFAULT_US); const [advOpen, setAdvOpen] = useStateUs(false); const [toggling, setToggling] = useStateUs(null); const [deleting, setDeleting] = useStateUs(null); // Vista de formulario (crear / editar) const [view, setView] = useStateUs('list'); // 'list' | 'form' const [editing, setEditing] = useStateUs(null); const openCreate = () => { setEditing(null); setView('form'); }; const openEdit = (u) => { setEditing(u); setView('form'); }; const backToList = () => { setView('list'); setEditing(null); }; const handleSaveUser = (data) => { const wantsContacto = !!data.esContacto; const clean = { ...data }; delete clean.esContacto; // el contacto principal vive en institucion.contacto let savedUser; if (editing) { savedUser = { ...editing, ...clean }; delete savedUser.esContacto; setItems(list => list.map(it => it.id === editing.id ? savedUser : it)); } else { const id = `u-${Date.now().toString(36)}`; savedUser = { id, ultimo: 'Nunca', estado: 'pendiente', ...clean }; setItems(list => [savedUser, ...list]); } // Sincroniza el contacto principal de la institución (solo enlaces institucionales) if (window.cgrData && window.cgrData.ajustarContacto && savedUser.rol === 'institucion') { window.cgrData.ajustarContacto(savedUser.institucion, savedUser.nombre, savedUser.email, wantsContacto); if (editing && editing.institucion && editing.institucion !== savedUser.institucion) { window.cgrData.ajustarContacto(editing.institucion, savedUser.nombre, savedUser.email, false); } } backToList(); }; const advCount = (adv.institucion.length ? 1 : 0) + (adv.rol !== 'todos' ? 1 : 0) + (adv.estado !== 'todos' ? 1 : 0) + (adv.orden !== 'az' ? 1 : 0); // Lista de instituciones (para el dropdown del filtro) const instituciones = useMemoUs(() => { const set = new Set(items.map(u => u.institucion).filter(Boolean)); return Array.from(set).sort((a, b) => a.localeCompare(b, 'es', { sensitivity: 'base' })); }, [items]); const filtered = useMemoUs(() => { const list = items.filter(u => { if (q && !`${u.nombre} ${u.email} ${u.institucion}`.toLowerCase().includes(q.toLowerCase())) return false; if (adv.rol !== 'todos' && u.rol !== adv.rol) return false; if (adv.institucion.length && adv.institucion.indexOf(u.institucion) === -1) return false; if (adv.estado !== 'todos' && window.cgrData.estadoUsuario(u) !== 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 setAdvKey = (k, v) => setAdv(prev => ({ ...prev, [k]: v })); const setAdvInst = (arr) => setAdv(prev => ({ ...prev, institucion: arr })); const freshAdvUs = () => ({ rol: 'todos', institucion: [], estado: 'todos', orden: 'az' }); const resetAdv = () => setAdv(freshAdvUs()); const clearAll = () => { setQ(''); setAdv(freshAdvUs()); }; 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; setItems(list => list.filter(it => it.id !== deleting.id)); setDeleting(null); }; const activeAdv = []; if (adv.institucion.length) activeAdv.push({ key: 'institucion', group: 'Institución', label: adv.institucion.length === 1 ? adv.institucion[0] : `${adv.institucion.length} instituciones`, reset: () => setAdvInst([]) }); ['rol', 'estado', 'orden'].forEach(k => { if (adv[k] !== ADV_DEFAULT_US[k]) { const group = ADV_GROUPS_US.find(g => g.key === k); const opt = group.options.find(o => o.v === adv[k]); activeAdv.push({ key: k, group: group.label, label: opt ? opt.l : adv[k], reset: () => setAdvKey(k, ADV_DEFAULT_US[k]) }); } }); // Vista de formulario (crear / editar) — ocupa la misma área que el listado if (view === 'form') { return ( ); } return (
Gestión de accesos

Usuarios

Administra las cuentas y roles de los funcionarios de la CGR y de las instituciones reportantes. Crea, edita o desactiva accesos; el historial de cada cuenta se conserva.

{/* Buscador + filtros avanzados */}
setQ(e.target.value)} />
{advOpen && (
Filtros avanzados Encuentra una cuenta más rápido: filtra por rol, institución o estado y ordena la lista alfabéticamente. Los cambios se aplican al instante y se combinan con el buscador.
{ADV_GROUPS_US.map(g => { const Icon = I[g.icon] || I.Filter; return (
{g.label}
{g.type === 'select' ? ( ) : (
{g.options.map(o => ( ))}
)}
); })}
)} {!advOpen && advCount > 0 && (
{advCount} filtro{advCount === 1 ? '' : 's'} activo{advCount === 1 ? '' : 's'}: {activeAdv.map(a => ( ))}
)} {filtered.length === 0 ? (

Sin resultados

No hay usuarios que coincidan con la combinación actual de filtros. {(q || advCount > 0) && ( <>{' '}. )}

) : ( <>
{filtered.map(u => { const estadoEf = window.cgrData.estadoUsuario(u); const instApagada = !window.cgrData.instActiva(u.institucion); const esContacto = window.cgrData.esContactoPrincipal(u); const isActive = estadoEf !== 'desactivado'; return ( ); })}
Usuario Rol Institución Estado Acciones
{u.initials}
{u.nombre} {u.email}
{u.institucion} {estadoEf === 'activo' ? 'Activo' : estadoEf === 'pendiente' ? 'Pendiente' : 'Desactivado'} {instApagada && u.estado !== 'desactivado' && ( institución desactivada )}
{esContacto ? ( ) : ( <> {!instApagada && ( )} )}
Mostrando {filtered.length} de {items.length} usuarios
)} {toggling && ( setToggling(null)} onConfirm={handleToggleConfirm} /> )} {deleting && ( setDeleting(null)} onConfirm={handleDeleteConfirm} /> )}
); } function RolePillTag({ rol, label }) { const cls = rol === 'superadmin' ? 'role-super' : rol === 'admin' ? 'role-admin' : rol === 'institucion'? 'role-inst' : rol === 'cancilleria'? 'role-canc' : rol === 'lector' ? 'role-lect' : 'role-default'; return {label}; } // ---------------- Activar / Desactivar usuario ---------------- function ToggleUsuarioDialog({ usuario, onCancel, onConfirm }) { const I = window.Icons; const isActive = usuario.estado !== 'desactivado'; return (
e.stopPropagation()}>
{isActive ? : }

{isActive ? `¿Desactivar a “${usuario.nombre}”?` : `¿Activar a “${usuario.nombre}”?`}

{isActive ? ( <>{usuario.nombre} perderá el acceso a la plataforma de inmediato, pero se conserva todo el historial de sus acciones. Podrás reactivarlo cuando lo necesites. ) : ( <>{usuario.nombre} recuperará el acceso a la plataforma con su rol actual. )}

); } // ---------------- Eliminar usuario ---------------- function DeleteUsuarioDialog({ usuario, onCancel, onConfirm }) { const I = window.Icons; return (
e.stopPropagation()}>

¿Eliminar a “{usuario.nombre}”?

Se eliminará la cuenta de {usuario.nombre} de forma permanente. Esta acción no se puede deshacer. Si solo quieres suspender el acceso temporalmente, usa Desactivar en su lugar.

); } Object.assign(window, { UsuariosScreen });