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 (
);
}