import { Button } from '@/components/ui/button'; import { ResponsiveDialog, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogFooter, ResponsiveDialogHeader, ResponsiveDialogTitle, } from '@/components/ui/responsive-dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import type { AdminBooking } from '@repo/api-contract'; import { CalendarSync } from 'lucide-react'; import { useMemo, useState } from 'react'; import { useBooking } from '../booking-provider'; import { getDayOfWeek, getNowTime, isTodayIso, minutesToTime, timeToMinutes, } from '../lib/booking-time'; interface BookingRescheduleDialogProps { booking: AdminBooking; open: boolean; onOpenChange: (open: boolean) => void; } export function BookingRescheduleDialog({ booking, open, onOpenChange, }: BookingRescheduleDialogProps) { const { courts, bookings, rescheduleBooking } = useBooking(); const [courtId, setCourtId] = useState(booking.courtId); const [startTime, setStartTime] = useState(booking.startTime); const sportId = booking.sport.id; const filteredCourts = useMemo( () => courts.filter((c) => c.sportId === sportId), [courts, sportId] ); const selectedCourt = filteredCourts.find((c) => c.id === courtId); const dayOfWeek = getDayOfWeek(booking.date); const availableStartTimes = useMemo(() => { if (!selectedCourt) return []; const times: string[] = []; const dayAvailability = selectedCourt.availability .filter((range) => range.dayOfWeek === dayOfWeek) .sort((a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime)); const courtBookings = bookings.filter( (b) => b.date === booking.date && b.courtId === selectedCourt.id && b.id !== booking.id && b.status !== 'CANCELLED' ); for (const range of dayAvailability) { const start = timeToMinutes(range.startTime); const end = timeToMinutes(range.endTime); for ( let minute = start; minute + selectedCourt.slotDurationMinutes <= end; minute += selectedCourt.slotDurationMinutes ) { const slotEnd = minute + selectedCourt.slotDurationMinutes; if (isTodayIso(booking.date) && minute <= timeToMinutes(getNowTime())) continue; const isBooked = courtBookings.some((b) => { const bookingStart = timeToMinutes(b.startTime); const bookingEnd = timeToMinutes(b.endTime); return minute < bookingEnd && slotEnd > bookingStart; }); if (!isBooked) { times.push(minutesToTime(minute)); } } } return times; }, [bookings, booking.date, booking.id, dayOfWeek, selectedCourt]); const hasChanges = courtId !== booking.courtId || startTime !== booking.startTime; const handleConfirm = () => { if (!hasChanges) return; const payload: Record = {}; if (courtId !== booking.courtId) payload.courtId = courtId; if (startTime !== booking.startTime) payload.startTime = startTime; rescheduleBooking(booking.id, payload); onOpenChange(false); }; const handleOpenChange = (newOpen: boolean) => { if (newOpen) { setCourtId(booking.courtId); setStartTime(booking.startTime); } onOpenChange(newOpen); }; return ( Reprogramar reserva Cambiá la cancha y/o el horario de la reserva para el mismo día.
Reserva {booking.bookingCode} — {booking.customerName}

Cancha

Horario

); }