feat: bootstrap taller-turnos project
Estructura inicial con Next.js 14, PostgreSQL/Prisma 7, autenticación por magic link (clientes) y JWT (admins), lógica de scheduling con 4 slots paralelos y API routes completas para cliente y panel admin. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { verificarSesion } from "@/lib/auth-admin";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { searchParams } = new URL(req.url);
|
||||
const q = searchParams.get("q");
|
||||
|
||||
const clientes = await prisma.cliente.findMany({
|
||||
where: q
|
||||
? {
|
||||
OR: [
|
||||
{ nombre: { contains: q, mode: "insensitive" } },
|
||||
{ apellido: { contains: q, mode: "insensitive" } },
|
||||
{ email: { contains: q, mode: "insensitive" } },
|
||||
],
|
||||
}
|
||||
: undefined,
|
||||
include: { autos: true },
|
||||
orderBy: { apellido: "asc" },
|
||||
take: 50,
|
||||
});
|
||||
|
||||
return NextResponse.json(clientes);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { verificarSesion } from "@/lib/auth-admin";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { searchParams } = new URL(req.url);
|
||||
const autoId = searchParams.get("autoId");
|
||||
if (!autoId) return NextResponse.json({ error: "autoId requerido" }, { status: 400 });
|
||||
|
||||
const historial = await prisma.historialServicio.findMany({
|
||||
where: { autoId },
|
||||
include: { admin: { select: { nombre: true } }, tipoServicio: { select: { nombre: true } } },
|
||||
orderBy: { fechaRealizado: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(historial);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { autoId, tipoServicioId, descripcion, observaciones, fechaRealizado } = await req.json();
|
||||
if (!autoId || !descripcion || !fechaRealizado)
|
||||
return NextResponse.json({ error: "Datos incompletos" }, { status: 400 });
|
||||
|
||||
const registro = await prisma.historialServicio.create({
|
||||
data: {
|
||||
autoId,
|
||||
adminId: sesion.sub,
|
||||
tipoServicioId: tipoServicioId || null,
|
||||
descripcion,
|
||||
observaciones: observaciones || null,
|
||||
fechaRealizado: new Date(fechaRealizado),
|
||||
},
|
||||
include: { admin: { select: { nombre: true } }, tipoServicio: { select: { nombre: true } } },
|
||||
});
|
||||
|
||||
return NextResponse.json(registro, { status: 201 });
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { verificarSesion } from "@/lib/auth-admin";
|
||||
|
||||
export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { id } = await params;
|
||||
const data = await req.json();
|
||||
|
||||
const servicio = await prisma.tipoServicio.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...(data.nombre !== undefined && { nombre: data.nombre }),
|
||||
...(data.duracionHoras !== undefined && { duracionHoras: Number(data.duracionHoras) }),
|
||||
...(data.activo !== undefined && { activo: data.activo }),
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(servicio);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { verificarSesion } from "@/lib/auth-admin";
|
||||
|
||||
export async function GET() {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const servicios = await prisma.tipoServicio.findMany({ orderBy: { nombre: "asc" } });
|
||||
return NextResponse.json(servicios);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { nombre, duracionHoras } = await req.json();
|
||||
if (!nombre || !duracionHoras)
|
||||
return NextResponse.json({ error: "nombre y duracionHoras requeridos" }, { status: 400 });
|
||||
|
||||
const servicio = await prisma.tipoServicio.create({
|
||||
data: { nombre, duracionHoras: Number(duracionHoras) },
|
||||
});
|
||||
|
||||
return NextResponse.json(servicio, { status: 201 });
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { verificarSesion } from "@/lib/auth-admin";
|
||||
|
||||
export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { id } = await params;
|
||||
const { estado } = await req.json();
|
||||
|
||||
const turno = await prisma.turno.update({
|
||||
where: { id },
|
||||
data: { estado },
|
||||
include: { auto: true, tipoServicio: true, cliente: true },
|
||||
});
|
||||
|
||||
return NextResponse.json(turno);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { verificarSesion } from "@/lib/auth-admin";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const sesion = await verificarSesion("admin_session");
|
||||
if (!sesion) return NextResponse.json({ error: "No autorizado" }, { status: 401 });
|
||||
|
||||
const { searchParams } = new URL(req.url);
|
||||
const fecha = searchParams.get("fecha"); // YYYY-MM-DD
|
||||
|
||||
const where = fecha
|
||||
? {
|
||||
fechaInicio: {
|
||||
gte: new Date(`${fecha}T00:00:00`),
|
||||
lte: new Date(`${fecha}T23:59:59`),
|
||||
},
|
||||
}
|
||||
: {};
|
||||
|
||||
const turnos = await prisma.turno.findMany({
|
||||
where,
|
||||
include: {
|
||||
cliente: { select: { nombre: true, apellido: true, telefono: true } },
|
||||
auto: true,
|
||||
tipoServicio: true,
|
||||
},
|
||||
orderBy: { fechaInicio: "asc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(turnos);
|
||||
}
|
||||
Reference in New Issue
Block a user