import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import { ChevronLeft, ChevronRight, Dumbbell, Plus, Users } from 'lucide-react'; import { useBooking } from '../booking-provider'; import type { BookingCourtSchedule, BookingTimelineSegment } from '../booking.types'; import { timeToMinutes } from '../lib/booking-time'; import { BookingStatusLegend } from './booking-status-legend'; const courtInfoWidth = 220; const hourWidth = 104; export function BookingTimeline() { const { schedules, timelineHours, visibleTimeRange, currentTime, isLoading, isError, errorMessage, } = useBooking(); const rangeStart = timeToMinutes(visibleTimeRange.start); const rangeEnd = timeToMinutes(visibleTimeRange.end); const totalMinutes = rangeEnd - rangeStart; const gridWidth = Math.max((timelineHours.length - 1) * hourWidth, 760); const timelineMarks = timelineHours.map((hour) => ({ hour, left: ((timeToMinutes(hour) - rangeStart) / totalMinutes) * 100, })); return (
{isLoading && (
Cargando reservas...
)} {isError && !isLoading && (
{errorMessage}
)} {!isLoading && !isError && schedules.length === 0 && (
No hay canchas para los filtros seleccionados.
)} {!isLoading && !isError && schedules.length > 0 && (
{schedules.map((schedule) => ( ))}
{currentTime && ( )}
)}
); } interface TimelineHeaderProps { timelineMarks: Array<{ hour: string; left: number }>; courtInfoWidth: number; gridWidth: number; } function TimelineHeader({ timelineMarks, courtInfoWidth, gridWidth }: TimelineHeaderProps) { return (
{timelineMarks.map((mark) => (
{mark.hour}
))}
); } interface BookingCourtRowProps { schedule: BookingCourtSchedule; courtInfoWidth: number; gridWidth: number; rangeStart: number; totalMinutes: number; timelineMarks: Array<{ hour: string; left: number }>; } function BookingCourtRow({ schedule, courtInfoWidth, gridWidth, rangeStart, totalMinutes, timelineMarks, }: BookingCourtRowProps) { return (
{timelineMarks.map((mark) => ( ))}
{schedule.segments.map((segment) => ( ))}
); } function BookingCourtInfo({ schedule }: { schedule: BookingCourtSchedule }) { return (

{schedule.court.name}

{schedule.court.sport.name}

{schedule.metrics.free} {schedule.metrics.reserved} {schedule.metrics.maintenance}
); } interface BookingSlotBlockProps { segment: BookingTimelineSegment; schedule: BookingCourtSchedule; rangeStart: number; totalMinutes: number; } function BookingSlotBlock({ segment, schedule, rangeStart, totalMinutes }: BookingSlotBlockProps) { const { openCreateBooking, updateBookingStatus } = useBooking(); const left = ((segment.startMinutes - rangeStart) / totalMinutes) * 100; const width = ((segment.endMinutes - segment.startMinutes) / totalMinutes) * 100; const isFree = segment.status === 'free'; return ( ); } interface CurrentTimeIndicatorProps { time: string; courtInfoWidth: number; gridWidth: number; rangeStart: number; totalMinutes: number; } function CurrentTimeIndicator({ time, courtInfoWidth, gridWidth, rangeStart, totalMinutes, }: CurrentTimeIndicatorProps) { const left = courtInfoWidth + ((timeToMinutes(time) - rangeStart) / totalMinutes) * gridWidth; return (
{time}
); }