Files
taller_automotriz/src/app/admin/servicios/page.tsx
T
Beldor f79e5ce75c
Deploy / deploy (push) Successful in 4m2s
Lighten admin page titles and loading text over background image
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:24:10 -03:00

136 lines
5.0 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Card from "@/components/ui/Card";
import Button from "@/components/ui/Button";
import Input from "@/components/ui/Input";
interface Servicio { id: string; nombre: string; duracionHoras: number; activo: boolean; }
export default function ServiciosPage() {
const [servicios, setServicios] = useState<Servicio[]>([]);
const [loading, setLoading] = useState(true);
const [mostrarForm, setMostrarForm] = useState(false);
const [form, setForm] = useState({ nombre: "", duracionHoras: "" });
const [guardando, setGuardando] = useState(false);
const [editando, setEditando] = useState<Servicio | null>(null);
const [errorForm, setErrorForm] = useState("");
useEffect(() => { cargar(); }, []);
async function cargar() {
setLoading(true);
const res = await fetch("/api/admin/servicios");
setServicios(await res.json());
setLoading(false);
}
function set(f: string) {
return (e: React.ChangeEvent<HTMLInputElement>) => setForm((v) => ({ ...v, [f]: e.target.value }));
}
async function guardar(e: React.FormEvent) {
e.preventDefault();
setGuardando(true);
setErrorForm("");
if (editando) {
const res = await fetch(`/api/admin/servicios/${editando.id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ nombre: form.nombre, duracionHoras: Number(form.duracionHoras) }),
});
if (!res.ok) { setErrorForm("Error al guardar"); setGuardando(false); return; }
} else {
const res = await fetch("/api/admin/servicios", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ nombre: form.nombre, duracionHoras: Number(form.duracionHoras) }),
});
if (!res.ok) { setErrorForm("Error al guardar"); setGuardando(false); return; }
}
setGuardando(false);
setMostrarForm(false);
setEditando(null);
setForm({ nombre: "", duracionHoras: "" });
cargar();
}
async function toggleActivo(s: Servicio) {
await fetch(`/api/admin/servicios/${s.id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ activo: !s.activo }),
});
cargar();
}
function iniciarEdicion(s: Servicio) {
setEditando(s);
setForm({ nombre: s.nombre, duracionHoras: String(s.duracionHoras) });
setMostrarForm(true);
}
return (
<div className="flex flex-col gap-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-white">Tipos de servicio</h1>
<Button
onClick={() => { setMostrarForm(true); setEditando(null); setForm({ nombre: "", duracionHoras: "" }); }}
className="text-sm"
>
+ Nuevo servicio
</Button>
</div>
{mostrarForm && (
<Card title={editando ? "Editar servicio" : "Nuevo servicio"}>
<form onSubmit={guardar} className="flex flex-col gap-4">
<Input id="nombre" label="Nombre del servicio" placeholder="Cambio de aceite" value={form.nombre} onChange={set("nombre")} required />
<Input id="duracion" type="number" label="Duración (horas)" placeholder="1.5" step="0.5" min="0.5" max="10" value={form.duracionHoras} onChange={set("duracionHoras")} required />
{errorForm && <p className="text-sm text-red-500">{errorForm}</p>}
<div className="flex gap-2 justify-end">
<Button variant="secondary" type="button" onClick={() => { setMostrarForm(false); setEditando(null); }}>Cancelar</Button>
<Button type="submit" loading={guardando}>Guardar</Button>
</div>
</form>
</Card>
)}
{loading ? (
<div className="text-center py-10 text-gray-200">Cargando...</div>
) : (
<div className="flex flex-col gap-3">
{servicios.map((s) => (
<div
key={s.id}
className={`flex items-center justify-between gap-3 bg-white border rounded-xl px-4 py-3 ${!s.activo ? "opacity-50" : ""}`}
>
<div>
<p className={`font-medium ${s.activo ? "text-gray-800" : "text-gray-400 line-through"}`}>
{s.nombre}
</p>
<p className="text-sm text-gray-500">
{s.duracionHoras === 1 ? "1 hora" : `${s.duracionHoras} horas`}
</p>
</div>
<div className="flex gap-2">
<Button variant="ghost" onClick={() => iniciarEdicion(s)} className="text-sm px-2 py-1">
✏️
</Button>
<Button
variant={s.activo ? "secondary" : "ghost"}
onClick={() => toggleActivo(s)}
className="text-sm px-3 py-1"
>
{s.activo ? "Desactivar" : "Activar"}
</Button>
</div>
</div>
))}
</div>
)}
</div>
);
}