full project: admin panel, backend modules, docs

This commit is contained in:
Lizandro Guarnizo
2026-06-03 22:11:01 -05:00
parent 1635723035
commit afc096d552
94 changed files with 15994 additions and 240 deletions
+99
View File
@@ -0,0 +1,99 @@
'use client';
import { useEffect, useState, useCallback } from 'react';
import { api } from '@/lib/api';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { toast } from 'sonner';
import { Plus, Trash2 } from 'lucide-react';
interface Profession {
id: string;
name: string;
}
export default function ProfessionsPage() {
const [professions, setProfessions] = useState<Profession[]>([]);
const [newName, setNewName] = useState('');
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const load = useCallback(() => {
setLoading(true);
setError(null);
api.get<Profession[]>('/professions')
.then(setProfessions)
.catch(() => setError('Error al cargar las profesiones'))
.finally(() => setLoading(false));
}, []);
useEffect(() => { load(); }, [load]);
const add = async () => {
if (!newName.trim()) return;
await api.post('/professions', { name: newName.trim() });
toast.success('Profesión agregada');
setNewName('');
load();
};
const remove = async (id: string) => {
await api.delete(`/professions/${id}`);
toast.success('Profesión eliminada');
load();
};
return (
<div className="space-y-4">
<h1 className="text-2xl font-bold">Profesiones</h1>
<Card>
<CardHeader><CardTitle>Agregar profesión</CardTitle></CardHeader>
<CardContent className="flex gap-2">
<Input value={newName} onChange={(e) => setNewName(e.target.value)} placeholder="Nombre de la profesión" />
<Button onClick={add}><Plus className="mr-1 h-4 w-4" />Agregar</Button>
</CardContent>
</Card>
{error ? (
<div className="flex flex-col items-center justify-center py-8 text-destructive">
<p>{error}</p>
<Button variant="outline" size="sm" onClick={load} className="mt-2">
Reintentar
</Button>
</div>
) : (
<Card>
<CardContent className="pt-4">
<Table>
<TableHeader>
<TableRow>
<TableHead>Nombre</TableHead>
<TableHead className="w-20"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading ? (
<TableRow><TableCell colSpan={2} className="text-center">Cargando...</TableCell></TableRow>
) : professions.length === 0 ? (
<TableRow><TableCell colSpan={2} className="text-center">Sin resultados</TableCell></TableRow>
) : (
professions.map((p) => (
<TableRow key={p.id}>
<TableCell>{p.name}</TableCell>
<TableCell>
<Button variant="ghost" size="icon" onClick={() => remove(p.id)}>
<Trash2 className="h-4 w-4 text-destructive" />
</Button>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</CardContent>
</Card>
)}
</div>
);
}