first commit

This commit is contained in:
unknown
2026-06-03 16:59:27 -04:00
commit b35cc2f54b
36 changed files with 5634 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
import { useState, useEffect } from 'react';
import { usersApi } 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 load = async () => {
try {
setUsers(await usersApi.list());
} catch (e) {
setError(e.message);
} finally {
setLoading(false);
}
};
useEffect(() => {
load();
}, []);
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);
}
};
if (loading) return <p className="loading">Cargando usuarios</p>;
return (
<div>
<h1 className="page-title">Administración de usuarios</h1>
<p style={{ color: 'var(--muted)' }}>
El superusuario <strong>JEFE</strong> puede crear usuarios, asignar contraseñas y habilitar acceso por planilla.
</p>
{error && <div className="alert alert-error">{error}</div>}
<div className="card admin-grid" style={{ marginBottom: '1.5rem' }}>
<h2 style={{ marginTop: 0 }}>Nuevo usuario</h2>
<form onSubmit={handleCreate}>
<div className="form-group">
<label>Usuario</label>
<input
value={newUser.username}
onChange={(e) => setNewUser((p) => ({ ...p, username: e.target.value }))}
required
/>
</div>
<div className="form-group">
<label>Contraseña</label>
<input
type="password"
value={newUser.password}
onChange={(e) => setNewUser((p) => ({ ...p, password: e.target.value }))}
required
/>
</div>
<p style={{ fontSize: '0.85rem' }}>Permisos por planilla:</p>
<div className="perm-grid">
{SHEET_KEYS.filter((k) => k !== 'reportes').map((key) => (
<div key={key} className="perm-item">
<strong>{SHEET_LABELS[key]}</strong>
<label className="checkbox-row">
<input
type="checkbox"
checked={newUser.permissions[key]?.view}
onChange={(e) =>
setNewUser((p) => ({
...p,
permissions: {
...p.permissions,
[key]: { ...p.permissions[key], view: e.target.checked },
},
}))
}
/>
Ver
</label>
<label className="checkbox-row">
<input
type="checkbox"
checked={newUser.permissions[key]?.edit}
onChange={(e) =>
setNewUser((p) => ({
...p,
permissions: {
...p.permissions,
[key]: { ...p.permissions[key], edit: e.target.checked },
},
}))
}
/>
Editar
</label>
</div>
))}
</div>
<button type="submit" className="btn btn-primary" style={{ marginTop: '1rem' }}>
Crear usuario
</button>
</form>
</div>
<div className="card">
<h2 style={{ marginTop: 0 }}>Usuarios del sistema</h2>
{users.map((u) => (
<div key={u.id} style={{ borderBottom: '1px solid var(--border)', padding: '1rem 0' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }}>
<strong>{u.username}</strong>
{u.isAdmin && <span style={{ color: 'var(--accent)' }}>Administrador</span>}
{!u.isAdmin && (
<button type="button" className="btn btn-secondary" onClick={() => toggleActive(u)}>
{u.active ? 'Deshabilitar' : 'Habilitar'}
</button>
)}
</div>
{!u.isAdmin && (
<div className="perm-grid" style={{ marginTop: '0.75rem' }}>
{SHEET_KEYS.map((key) => (
<div key={key} className="perm-item">
<span>{SHEET_LABELS[key]}</span>
<label className="checkbox-row">
<input
type="checkbox"
checked={u.permissions?.[key]?.view}
onChange={(e) => updateUserPerms(u, key, 'view', e.target.checked)}
/>
Ver
</label>
<label className="checkbox-row">
<input
type="checkbox"
checked={u.permissions?.[key]?.edit}
onChange={(e) => updateUserPerms(u, key, 'edit', e.target.checked)}
/>
Editar
</label>
</div>
))}
</div>
)}
</div>
))}
</div>
</div>
);
}