- Reemplaza lista de slots por calendario cuadrado mensual - Sábados y domingos grisados, días sin slots deshabilitados - Click en día hábil abre modal con horarios disponibles - Slot dot indicator en días con turnos disponibles - Amplía búsqueda a 60 días / 500 slots para cubrir todo el mes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,6 @@ export async function GET(req: NextRequest) {
|
||||
if (!servicio || !servicio.activo)
|
||||
return NextResponse.json({ error: "Servicio no encontrado" }, { status: 404 });
|
||||
|
||||
const slots = await obtenerSlotsDisponibles(servicio.duracionHoras);
|
||||
const slots = await obtenerSlotsDisponibles(servicio.duracionHoras, 60, 500);
|
||||
return NextResponse.json(slots);
|
||||
}
|
||||
|
||||
+232
-100
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { Suspense, useEffect, useState } from "react";
|
||||
import { Suspense, useEffect, useMemo, useState } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import Card from "@/components/ui/Card";
|
||||
@@ -9,23 +9,53 @@ import Badge from "@/components/ui/Badge";
|
||||
interface TipoServicio { id: string; nombre: string; duracionHoras: number; }
|
||||
interface Slot { fechaInicio: string; fechaFin: string; }
|
||||
interface Turno {
|
||||
id: string;
|
||||
fechaInicio: string;
|
||||
fechaFin: string;
|
||||
id: string; fechaInicio: string; fechaFin: string;
|
||||
estado: "PENDIENTE" | "CONFIRMADO" | "CANCELADO" | "COMPLETADO";
|
||||
tipoServicio: { nombre: string };
|
||||
auto: { marca: string; modelo: string; patente: string };
|
||||
tipoServicio: { nombre: string }; auto: { marca: string; modelo: string; patente: string };
|
||||
}
|
||||
|
||||
type Step = "servicio" | "slot" | "confirmado";
|
||||
const MESES = ["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"];
|
||||
const DIAS_HEADER = ["Lun","Mar","Mié","Jue","Vie","Sáb","Dom"];
|
||||
|
||||
function formatDuracion(horas: number): string {
|
||||
if (horas < 1) return `${Math.round(horas * 60)} min`;
|
||||
if (horas === 1) return "1 hora";
|
||||
if (Number.isInteger(horas)) return `${horas} horas`;
|
||||
const h = Math.floor(horas);
|
||||
const m = Math.round((horas % 1) * 60);
|
||||
return `${h} h ${m} min`;
|
||||
type Step = "servicio" | "calendario" | "confirmado";
|
||||
|
||||
function formatDuracion(h: number) {
|
||||
if (h < 1) return `${Math.round(h * 60)} min`;
|
||||
if (h === 1) return "1 hora";
|
||||
if (Number.isInteger(h)) return `${h} horas`;
|
||||
return `${Math.floor(h)} h ${Math.round((h % 1) * 60)} min`;
|
||||
}
|
||||
|
||||
// Convierte ISO UTC a fecha Argentina "YYYY-MM-DD"
|
||||
function fechaArg(iso: string) {
|
||||
return new Date(iso).toLocaleDateString("sv-SE", { timeZone: "America/Argentina/Buenos_Aires" });
|
||||
}
|
||||
|
||||
// Convierte ISO UTC a hora Argentina "HH:MM"
|
||||
function horaArg(iso: string) {
|
||||
return new Date(iso).toLocaleTimeString("es-AR", {
|
||||
timeZone: "America/Argentina/Buenos_Aires", hour: "2-digit", minute: "2-digit",
|
||||
});
|
||||
}
|
||||
|
||||
// Hoy en Argentina "YYYY-MM-DD"
|
||||
function hoyArg() {
|
||||
return new Date().toLocaleDateString("sv-SE", { timeZone: "America/Argentina/Buenos_Aires" });
|
||||
}
|
||||
|
||||
// Celdas del mes (null = celda vacía antes del día 1)
|
||||
function celdasMes(year: number, month: number): (number | null)[] {
|
||||
const primer = new Date(year, month, 1);
|
||||
const total = new Date(year, month + 1, 0).getDate();
|
||||
const offset = (primer.getDay() + 6) % 7; // Lunes = 0
|
||||
const result: (number | null)[] = Array(offset).fill(null);
|
||||
for (let d = 1; d <= total; d++) result.push(d);
|
||||
return result;
|
||||
}
|
||||
|
||||
function esFinDeSemana(year: number, month: number, day: number) {
|
||||
const dow = new Date(year, month, day).getDay();
|
||||
return dow === 0 || dow === 6;
|
||||
}
|
||||
|
||||
function TurnosContent() {
|
||||
@@ -37,34 +67,60 @@ function TurnosContent() {
|
||||
const [servicios, setServicios] = useState<TipoServicio[]>([]);
|
||||
const [servicioSel, setServicioSel] = useState<TipoServicio | null>(null);
|
||||
const [slots, setSlots] = useState<Slot[]>([]);
|
||||
const [slotSel, setSlotSel] = useState<Slot | null>(null);
|
||||
const [loadingSlots, setLoadingSlots] = useState(false);
|
||||
const [kilometros, setKilometros] = useState("");
|
||||
const [reservando, setReservando] = useState(false);
|
||||
const [turnoCreado, setTurnoCreado] = useState<Turno | null>(null);
|
||||
const [misTurnos, setMisTurnos] = useState<Turno[]>([]);
|
||||
const [loadingTurnos, setLoadingTurnos] = useState(true);
|
||||
|
||||
// Calendario
|
||||
const hoy = new Date();
|
||||
const [mesVista, setMesVista] = useState({ year: hoy.getFullYear(), month: hoy.getMonth() });
|
||||
const [diaSeleccionado, setDiaSeleccionado] = useState<string | null>(null);
|
||||
const [slotSel, setSlotSel] = useState<Slot | null>(null);
|
||||
const [kilometros, setKilometros] = useState("");
|
||||
const [reservando, setReservando] = useState(false);
|
||||
const [turnoCreado, setTurnoCreado] = useState<Turno | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!autoId) { router.push("/cliente/dashboard"); return; }
|
||||
fetch("/api/cliente/servicios")
|
||||
.then((r) => r.json())
|
||||
.then((data) => setServicios(data));
|
||||
fetch("/api/cliente/servicios").then(r => r.json()).then(setServicios);
|
||||
fetch("/api/cliente/turnos")
|
||||
.then((r) => r.json())
|
||||
.then((data) => { setMisTurnos(data.filter((t: Turno & { autoId: string }) => t.autoId === autoId)); setLoadingTurnos(false); });
|
||||
.then(r => r.json())
|
||||
.then((data) => {
|
||||
setMisTurnos(data.filter((t: Turno & { autoId: string }) => t.autoId === autoId));
|
||||
setLoadingTurnos(false);
|
||||
});
|
||||
}, [autoId, router]);
|
||||
|
||||
// Agrupar slots por fecha Argentina
|
||||
const slotsPorDia = useMemo(() => {
|
||||
const m: Record<string, Slot[]> = {};
|
||||
for (const s of slots) {
|
||||
const d = fechaArg(s.fechaInicio);
|
||||
if (!m[d]) m[d] = [];
|
||||
m[d].push(s);
|
||||
}
|
||||
return m;
|
||||
}, [slots]);
|
||||
|
||||
async function seleccionarServicio(s: TipoServicio) {
|
||||
setServicioSel(s);
|
||||
setLoadingSlots(true);
|
||||
setStep("slot");
|
||||
setSlots([]);
|
||||
setDiaSeleccionado(null);
|
||||
setSlotSel(null);
|
||||
setStep("calendario");
|
||||
const res = await fetch(`/api/cliente/slots?tipoServicioId=${s.id}`);
|
||||
const data = await res.json();
|
||||
setSlots(data);
|
||||
setLoadingSlots(false);
|
||||
}
|
||||
|
||||
function seleccionarDia(dateStr: string) {
|
||||
setDiaSeleccionado(dateStr);
|
||||
setSlotSel(null);
|
||||
setKilometros("");
|
||||
}
|
||||
|
||||
async function reservar() {
|
||||
if (!slotSel || !servicioSel || !autoId || !kilometros) return;
|
||||
setReservando(true);
|
||||
@@ -75,23 +131,33 @@ function TurnosContent() {
|
||||
});
|
||||
const data = await res.json();
|
||||
setReservando(false);
|
||||
if (res.ok) {
|
||||
setTurnoCreado(data);
|
||||
setStep("confirmado");
|
||||
}
|
||||
if (res.ok) { setTurnoCreado(data); setDiaSeleccionado(null); setStep("confirmado"); }
|
||||
}
|
||||
|
||||
function formatSlot(slot: Slot) {
|
||||
const inicio = new Date(slot.fechaInicio);
|
||||
const fin = new Date(slot.fechaFin);
|
||||
const dia = inicio.toLocaleDateString("es-AR", { weekday: "long", day: "numeric", month: "long" });
|
||||
const h1 = inicio.toLocaleTimeString("es-AR", { hour: "2-digit", minute: "2-digit" });
|
||||
const h2 = fin.toLocaleTimeString("es-AR", { hour: "2-digit", minute: "2-digit" });
|
||||
return { dia: dia.charAt(0).toUpperCase() + dia.slice(1), horas: `${h1} - ${h2}` };
|
||||
// Navegación de mes
|
||||
const hoyStr = hoyArg();
|
||||
const mesActual = { year: hoy.getFullYear(), month: hoy.getMonth() };
|
||||
const puedeRetroceder = mesVista.year > mesActual.year || (mesVista.year === mesActual.year && mesVista.month > mesActual.month);
|
||||
|
||||
function prevMes() {
|
||||
if (!puedeRetroceder) return;
|
||||
setMesVista(m => {
|
||||
if (m.month === 0) return { year: m.year - 1, month: 11 };
|
||||
return { year: m.year, month: m.month - 1 };
|
||||
});
|
||||
}
|
||||
|
||||
function nextMes() {
|
||||
setMesVista(m => {
|
||||
if (m.month === 11) return { year: m.year + 1, month: 0 };
|
||||
return { year: m.year, month: m.month + 1 };
|
||||
});
|
||||
}
|
||||
|
||||
const celdas = celdasMes(mesVista.year, mesVista.month);
|
||||
const slotsDelDia = diaSeleccionado ? (slotsPorDia[diaSeleccionado] ?? []) : [];
|
||||
|
||||
if (step === "confirmado" && turnoCreado) {
|
||||
const { dia, horas } = formatSlot({ fechaInicio: turnoCreado.fechaInicio, fechaFin: turnoCreado.fechaFin });
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-[50vh] text-center gap-4">
|
||||
<div className="text-5xl">✅</div>
|
||||
@@ -100,12 +166,12 @@ function TurnosContent() {
|
||||
<p className="text-sm text-gray-500 mb-1">Servicio</p>
|
||||
<p className="font-semibold mb-3">{turnoCreado.tipoServicio.nombre}</p>
|
||||
<p className="text-sm text-gray-500 mb-1">Fecha</p>
|
||||
<p className="font-semibold mb-1">{dia}</p>
|
||||
<p className="text-gray-600">{horas}</p>
|
||||
<p className="font-semibold">{new Date(turnoCreado.fechaInicio).toLocaleDateString("es-AR", {
|
||||
timeZone: "America/Argentina/Buenos_Aires", weekday: "long", day: "numeric", month: "long"
|
||||
})}</p>
|
||||
<p className="text-gray-600">{horaArg(turnoCreado.fechaInicio)} – {horaArg(turnoCreado.fechaFin)}</p>
|
||||
</Card>
|
||||
<Link href="/cliente/dashboard">
|
||||
<Button variant="secondary">← Volver a mis autos</Button>
|
||||
</Link>
|
||||
<Link href="/cliente/dashboard"><Button variant="secondary">← Volver a mis autos</Button></Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -113,30 +179,26 @@ function TurnosContent() {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex items-center gap-3">
|
||||
{step === "slot" ? (
|
||||
{step === "calendario" ? (
|
||||
<Button variant="ghost" className="px-2" onClick={() => setStep("servicio")}>←</Button>
|
||||
) : (
|
||||
<Link href="/cliente/dashboard"><Button variant="ghost" className="px-2">←</Button></Link>
|
||||
)}
|
||||
<h1 className="text-2xl font-bold text-gray-800">
|
||||
{step === "servicio" ? "Elegí el servicio" : "Elegí el horario"}
|
||||
<h1 className="text-xl sm:text-2xl font-bold text-gray-800">
|
||||
{step === "servicio" ? "Elegí el servicio" : `${servicioSel?.nombre}`}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* STEP: servicio */}
|
||||
{step === "servicio" && (
|
||||
<>
|
||||
<div className="grid gap-3">
|
||||
{servicios.map((s) => (
|
||||
<button
|
||||
key={s.id}
|
||||
onClick={() => seleccionarServicio(s)}
|
||||
className="text-left bg-white border border-gray-200 rounded-xl p-4 hover:border-blue-500 hover:shadow-sm transition flex items-center justify-between"
|
||||
>
|
||||
{servicios.map(s => (
|
||||
<button key={s.id} onClick={() => seleccionarServicio(s)}
|
||||
className="text-left bg-white border border-gray-200 rounded-xl p-4 hover:border-blue-500 hover:shadow-sm transition flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium text-gray-800">{s.nombre}</p>
|
||||
<p className="text-sm text-gray-500 mt-0.5">
|
||||
Duración: {formatDuracion(s.duracionHoras)}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mt-0.5">Duración: {formatDuracion(s.duracionHoras)}</p>
|
||||
</div>
|
||||
<span className="text-gray-400 text-lg">→</span>
|
||||
</button>
|
||||
@@ -146,84 +208,154 @@ function TurnosContent() {
|
||||
{!loadingTurnos && misTurnos.length > 0 && (
|
||||
<Card title="Mis turnos para este auto">
|
||||
<div className="flex flex-col gap-3">
|
||||
{misTurnos.map((t) => {
|
||||
const { dia, horas } = formatSlot({ fechaInicio: t.fechaInicio, fechaFin: t.fechaFin });
|
||||
return (
|
||||
{misTurnos.map(t => (
|
||||
<div key={t.id} className="flex items-center justify-between flex-wrap gap-2">
|
||||
<div>
|
||||
<p className="text-sm font-medium">{t.tipoServicio.nombre}</p>
|
||||
<p className="text-xs text-gray-500">{dia} · {horas}</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
{new Date(t.fechaInicio).toLocaleDateString("es-AR", {
|
||||
timeZone: "America/Argentina/Buenos_Aires",
|
||||
weekday: "short", day: "numeric", month: "short"
|
||||
})} · {horaArg(t.fechaInicio)} – {horaArg(t.fechaFin)}
|
||||
</p>
|
||||
</div>
|
||||
<Badge estado={t.estado} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{step === "slot" && (
|
||||
{/* STEP: calendario */}
|
||||
{step === "calendario" && (
|
||||
<div className="flex flex-col gap-4">
|
||||
{loadingSlots ? (
|
||||
<div className="text-center py-10 text-gray-400">Buscando horarios disponibles...</div>
|
||||
) : slots.length === 0 ? (
|
||||
<Card>
|
||||
<p className="text-center text-gray-400 py-4">
|
||||
No hay horarios disponibles en los próximos 14 días. Consultá al taller.
|
||||
</p>
|
||||
</Card>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-sm text-gray-500">
|
||||
Servicio: <strong>{servicioSel?.nombre}</strong>
|
||||
</p>
|
||||
<div className="grid gap-2">
|
||||
{slots.map((slot, i) => {
|
||||
const { dia, horas } = formatSlot(slot);
|
||||
const sel = slotSel?.fechaInicio === slot.fechaInicio;
|
||||
{loadingSlots && (
|
||||
<p className="text-center text-sm text-gray-400">Cargando disponibilidad...</p>
|
||||
)}
|
||||
|
||||
{/* Cabecera del mes */}
|
||||
<div className="flex items-center justify-between">
|
||||
<button onClick={prevMes} disabled={!puedeRetroceder}
|
||||
className={`p-2 rounded-lg transition ${puedeRetroceder ? "hover:bg-gray-100 text-gray-700" : "text-gray-300 cursor-default"}`}>
|
||||
‹
|
||||
</button>
|
||||
<span className="font-semibold text-gray-800">
|
||||
{MESES[mesVista.month]} {mesVista.year}
|
||||
</span>
|
||||
<button onClick={nextMes} className="p-2 rounded-lg hover:bg-gray-100 text-gray-700 transition">
|
||||
›
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Grid del calendario */}
|
||||
<div className="bg-white border border-gray-200 rounded-2xl overflow-hidden shadow-sm">
|
||||
{/* Headers días */}
|
||||
<div className="grid grid-cols-7 border-b border-gray-100">
|
||||
{DIAS_HEADER.map(d => (
|
||||
<div key={d} className={`text-center text-xs font-medium py-2 ${d === "Sáb" || d === "Dom" ? "text-gray-300" : "text-gray-500"}`}>
|
||||
{d}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Celdas */}
|
||||
<div className="grid grid-cols-7">
|
||||
{celdas.map((dia, i) => {
|
||||
if (dia === null) return <div key={`e-${i}`} className="aspect-square" />;
|
||||
|
||||
const dateStr = `${mesVista.year}-${String(mesVista.month + 1).padStart(2, "0")}-${String(dia).padStart(2, "0")}`;
|
||||
const finde = esFinDeSemana(mesVista.year, mesVista.month, dia);
|
||||
const pasado = dateStr < hoyStr;
|
||||
const tieneSlots = !!slotsPorDia[dateStr];
|
||||
const seleccionado = diaSeleccionado === dateStr;
|
||||
const esHoy = dateStr === hoyStr;
|
||||
const deshabilitado = finde || pasado || (!tieneSlots && !loadingSlots);
|
||||
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => setSlotSel(slot)}
|
||||
className={`text-left rounded-xl p-4 border transition ${
|
||||
sel
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 bg-white hover:border-blue-300"
|
||||
}`}
|
||||
key={dateStr}
|
||||
disabled={deshabilitado}
|
||||
onClick={() => seleccionarDia(dateStr)}
|
||||
className={`aspect-square flex items-center justify-center text-sm relative transition
|
||||
${deshabilitado ? "cursor-default" : "hover:bg-blue-50 cursor-pointer"}
|
||||
${seleccionado ? "bg-blue-600 text-white rounded-full font-semibold" : ""}
|
||||
${!seleccionado && esHoy ? "font-bold text-blue-600" : ""}
|
||||
${!seleccionado && finde ? "text-gray-300" : ""}
|
||||
${!seleccionado && pasado && !finde ? "text-gray-300" : ""}
|
||||
${!seleccionado && !deshabilitado ? "text-gray-800" : ""}
|
||||
`}
|
||||
>
|
||||
<p className="font-medium text-gray-800">{dia}</p>
|
||||
<p className="text-sm text-gray-500">{horas}</p>
|
||||
{dia}
|
||||
{tieneSlots && !seleccionado && !deshabilitado && (
|
||||
<span className="absolute bottom-1 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-blue-500" />
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<label htmlFor="kilometros" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
</div>
|
||||
|
||||
{!loadingSlots && slots.length === 0 && (
|
||||
<p className="text-center text-sm text-gray-400">No hay turnos disponibles en los próximos 60 días.</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* MODAL de horarios */}
|
||||
{diaSeleccionado && (
|
||||
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center">
|
||||
<div className="absolute inset-0 bg-black/40" onClick={() => setDiaSeleccionado(null)} />
|
||||
<div className="relative bg-white w-full sm:w-96 rounded-t-2xl sm:rounded-2xl shadow-xl p-5 flex flex-col gap-4 max-h-[80vh] overflow-y-auto">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="font-semibold text-gray-800">
|
||||
{new Date(`${diaSeleccionado}T12:00:00`).toLocaleDateString("es-AR", {
|
||||
weekday: "long", day: "numeric", month: "long"
|
||||
})}
|
||||
</h2>
|
||||
<button onClick={() => setDiaSeleccionado(null)} className="text-gray-400 hover:text-gray-600 text-xl leading-none">×</button>
|
||||
</div>
|
||||
|
||||
{slotsDelDia.length === 0 ? (
|
||||
<p className="text-sm text-gray-400 text-center py-4">No hay horarios disponibles este día.</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{slotsDelDia.map((s, i) => {
|
||||
const sel = slotSel?.fechaInicio === s.fechaInicio;
|
||||
return (
|
||||
<button key={i} onClick={() => setSlotSel(s)}
|
||||
className={`rounded-xl py-2 text-sm font-medium border transition
|
||||
${sel ? "bg-blue-600 text-white border-blue-600" : "border-gray-200 text-gray-700 hover:border-blue-400"}`}>
|
||||
{horaArg(s.fechaInicio)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{slotSel && (
|
||||
<div className="flex flex-col gap-3 border-t border-gray-100 pt-3">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Kilometraje actual <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="kilometros"
|
||||
type="number"
|
||||
min={0}
|
||||
placeholder="Ej: 85000"
|
||||
type="number" min={0} placeholder="Ej: 85000"
|
||||
value={kilometros}
|
||||
onChange={(e) => setKilometros(e.target.value)}
|
||||
onChange={e => setKilometros(e.target.value)}
|
||||
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={reservar}
|
||||
disabled={!slotSel || !kilometros}
|
||||
loading={reservando}
|
||||
className="w-full mt-2"
|
||||
>
|
||||
Confirmar turno
|
||||
<Button onClick={reservar} disabled={!kilometros} loading={reservando} className="w-full">
|
||||
Confirmar turno · {horaArg(slotSel.fechaInicio)} – {horaArg(slotSel.fechaFin)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -68,7 +68,8 @@ export interface SlotDisponible {
|
||||
|
||||
export async function obtenerSlotsDisponibles(
|
||||
duracionHoras: number,
|
||||
diasAdelante = 14
|
||||
diasAdelante = 14,
|
||||
limite = 300
|
||||
): Promise<SlotDisponible[]> {
|
||||
const slots: SlotDisponible[] = [];
|
||||
const ahora = new Date();
|
||||
@@ -83,7 +84,7 @@ export async function obtenerSlotsDisponibles(
|
||||
cursor = new Date(cursor.getTime() + avanzarMin * 60 * 1000);
|
||||
cursor.setUTCSeconds(0, 0);
|
||||
|
||||
while (cursor < fechaLimite && slots.length < 20) {
|
||||
while (cursor < fechaLimite && slots.length < limite) {
|
||||
if (!esDiaHabil(cursor)) {
|
||||
cursor = inicioJornada(new Date(cursor.getTime() + 24 * 60 * 60 * 1000));
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user