import { useState, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { usersApi, settingsApi } from '../api/client'; const SHEET_LABELS = { ventas: 'Ventas', servicios: 'Servicios', alquileres: 'Alquileres', gastos_diarios: 'Gastos diarios', gastos_fijos: 'Gastos fijos', personal: 'Personal', reportes: 'Reportes', }; const SHEET_KEYS = Object.keys(SHEET_LABELS); function emptyPerms() { return Object.fromEntries(SHEET_KEYS.map((k) => [k, { view: false, edit: false }])); } export default function AdminPage() { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [newUser, setNewUser] = useState({ username: '', password: '', permissions: emptyPerms() }); const [gestion, setGestion] = useState(null); const [fechaCierre, setFechaCierre] = useState(''); const [gestionMsg, setGestionMsg] = useState(''); const [gestionError, setGestionError] = useState(''); const location = useLocation(); const load = async () => { setError(''); setGestionError(''); try { setUsers(await usersApi.list()); } catch (e) { setError(e.message); } try { const gestionData = await settingsApi.getGestion(); setGestion(gestionData); setFechaCierre(gestionData.sugerirCierre || gestionData.fechaCierreGestion || ''); } catch (e) { setGestionError( e.message.includes('404') || e.message.includes('Error en la solicitud') ? 'No se pudo cargar el cierre de gestión. Reconstruya Docker: docker compose build --no-cache && docker compose up -d' : e.message ); } finally { setLoading(false); } }; useEffect(() => { load(); }, []); useEffect(() => { if (location.hash === '#cierre-gestion') { document.getElementById('cierre-gestion')?.scrollIntoView({ behavior: 'smooth' }); } }, [location.hash, loading]); const handleCreate = async (e) => { e.preventDefault(); setError(''); try { await usersApi.create(newUser); setNewUser({ username: '', password: '', permissions: emptyPerms() }); await load(); } catch (err) { setError(err.message); } }; const updateUserPerms = async (user, sheet, field, value) => { const permissions = { ...user.permissions, [sheet]: { ...user.permissions[sheet], [field]: value } }; try { await usersApi.update(user.id, { permissions }); await load(); } catch (err) { setError(err.message); } }; const toggleActive = async (user) => { if (user.isAdmin) return; try { await usersApi.update(user.id, { active: !user.active }); await load(); } catch (err) { setError(err.message); } }; const cerrarGestion = async (e) => { e.preventDefault(); if (!fechaCierre) { setError('Indique el último día de la gestión a cerrar.'); return; } const etiqueta = gestion?.gestionActual?.fechaInicio ? `del ${gestion.gestionActual.fechaInicio} al ${fechaCierre}` : `hasta el ${fechaCierre}`; if ( !window.confirm( `¿Cerrar la gestión ${etiqueta}?\n\nSe bloqueará el período para todos (excepto JEFE) y comenzará una gestión nueva. El historial quedará en la barra lateral de cada planilla.` ) ) { return; } setGestionMsg(''); setError(''); try { const data = await settingsApi.cerrarGestion(fechaCierre); setGestion(data); setFechaCierre(data.sugerirCierre || ''); const nombre = data.cierre?.cerrada?.etiqueta || 'gestión cerrada'; setGestionMsg(`"${nombre}" cerrada. Nueva gestión desde ${data.cierre?.nueva?.fechaInicio || 'mañana'}.`); } catch (err) { setError(err.message); } }; if (loading) return

Cargando administración…

; return (

Administración

Solo visible para el administrador JEFE. Gestione el cierre del período y los usuarios.

{error &&
{error}
} {gestionMsg &&
{gestionMsg}
}

Cierre de gestión

{gestionError &&
{gestionError}
}
¿Cómo funciona?
  • Al cerrar la gestión (típicamente fin de mes), el período queda bloqueado de inmediato.
  • Cada planilla muestra solo la gestión actual; el historial está en la barra lateral (solo lectura).
  • La nueva gestión comienza el día siguiente al cierre. Use el botón + para cargar datos nuevos.
  • Filas con fecha del período cerrado no se pueden editar (excepto JEFE).
{gestion?.gestionActual && (

Gestión actual: desde {gestion.gestionActual.fechaInicio} — Hoy:{' '} {gestion.hoy}

)} {gestion?.historial?.length > 0 && (

Gestiones cerradas:

    {gestion.historial.map((g) => (
  • {g.etiqueta} ({g.fechaInicio} → {g.fechaFin})
  • ))}
)}
setFechaCierre(e.target.value)} required /> {gestion?.sugerirCierre && (

Sugerido (fin de mes): {gestion.sugerirCierre}

)}

Usuarios — Nuevo usuario

setNewUser((p) => ({ ...p, username: e.target.value }))} required />
setNewUser((p) => ({ ...p, password: e.target.value }))} required />

Permisos por planilla:

{SHEET_KEYS.filter((k) => k !== 'reportes').map((key) => (
{SHEET_LABELS[key]}
))}

Usuarios del sistema

{users.map((u) => (
{u.username} {u.isAdmin && Administrador} {!u.isAdmin && ( )}
{!u.isAdmin && (
{SHEET_KEYS.map((key) => (
{SHEET_LABELS[key]}
))}
)}
))}
); }