- Add TimeSlot component with available/booked visual states - Add BookingCalendar component with date navigation and court columns - Add BookingDialog for creating bookings and viewing/cancelling existing ones - Add bookings page with calendar integration - Fix sidebar navigation paths for route group structure Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
75 lines
1.9 KiB
TypeScript
75 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { cn, formatTime, formatCurrency } from "@/lib/utils";
|
|
|
|
interface TimeSlotProps {
|
|
time: string; // HH:MM format
|
|
available: boolean;
|
|
price: number;
|
|
clientName?: string;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
export function TimeSlot({
|
|
time,
|
|
available,
|
|
price,
|
|
clientName,
|
|
onClick,
|
|
}: TimeSlotProps) {
|
|
// Convert HH:MM string to a Date object for formatting
|
|
const [hours, minutes] = time.split(":").map(Number);
|
|
const timeDate = new Date();
|
|
timeDate.setHours(hours, minutes, 0, 0);
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
disabled={!available && !clientName}
|
|
className={cn(
|
|
"w-full rounded-md border p-3 text-left transition-all",
|
|
"focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2",
|
|
available && [
|
|
"border-accent bg-accent-50 hover:bg-accent-100",
|
|
"cursor-pointer",
|
|
],
|
|
!available && clientName && [
|
|
"border-primary-200 bg-primary-100",
|
|
"cursor-pointer hover:bg-primary-150",
|
|
],
|
|
!available && !clientName && [
|
|
"border-primary-200 bg-primary-100 opacity-50",
|
|
"cursor-not-allowed",
|
|
]
|
|
)}
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm font-medium text-primary-800">
|
|
{formatTime(timeDate)}
|
|
</span>
|
|
<span
|
|
className={cn(
|
|
"text-xs font-semibold",
|
|
available ? "text-accent-700" : "text-primary-500"
|
|
)}
|
|
>
|
|
{formatCurrency(price)}
|
|
</span>
|
|
</div>
|
|
{clientName && (
|
|
<div className="mt-1">
|
|
<span className="text-xs text-primary-600 truncate block">
|
|
{clientName}
|
|
</span>
|
|
</div>
|
|
)}
|
|
{available && (
|
|
<div className="mt-1">
|
|
<span className="text-xs text-accent-600">Disponible</span>
|
|
</div>
|
|
)}
|
|
</button>
|
|
);
|
|
}
|