import { useState, useEffect } from "react"; import { Calendar } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Button } from "@/components/ui/button"; import { Calendar as CalendarIcon, Clock, X } from "lucide-react"; import { format } from "date-fns"; import { fr } from "date-fns/locale"; import { cn } from "@/lib/utils"; import { ScrollArea } from "@/components/ui/scroll-area"; interface DateTimePickerProps { value: Date | undefined; onChange: (date: Date | undefined) => void; occupiedDates?: Date[]; placeholder?: string; } const OPTIMAL_HOURS = [8, 12, 13, 18, 19, 20]; export function DateTimePicker({ value, onChange, occupiedDates = [], placeholder = "Sélectionner une date" }: DateTimePickerProps) { const [selectedDate, setSelectedDate] = useState(value); const [selectedHour, setSelectedHour] = useState(value?.getHours() || 8); const [selectedMinute, setSelectedMinute] = useState(value?.getMinutes() || 0); // Sync internal state with parent value prop useEffect(() => { if (value) { setSelectedDate(value); setSelectedHour(value.getHours()); setSelectedMinute(value.getMinutes()); } else { setSelectedDate(undefined); setSelectedHour(8); setSelectedMinute(0); } }, [value]); const hours = Array.from({ length: 24 }, (_, i) => i); const minutes = [0, 15, 30, 45]; const isOptimalHour = (hour: number) => OPTIMAL_HOURS.includes(hour); const handleDateSelect = (date: Date | undefined) => { setSelectedDate(date); if (date) { const newDate = new Date(date); newDate.setHours(selectedHour); newDate.setMinutes(selectedMinute); onChange(newDate); } else { onChange(undefined); } }; const handleTimeChange = (hour: number, minute: number) => { setSelectedHour(hour); setSelectedMinute(minute); if (selectedDate) { const newDate = new Date(selectedDate); newDate.setHours(hour); newDate.setMinutes(minute); onChange(newDate); } }; // Convert occupied dates to a Set of date strings for efficient lookup const occupiedDateStrings = new Set( occupiedDates.map(date => format(date, 'yyyy-MM-dd')) ); // Check if a date is occupied const isDateOccupied = (date: Date) => { return occupiedDateStrings.has(format(date, 'yyyy-MM-dd')); }; return (
isDateOccupied(date) }} modifiersClassNames={{ occupied: "bg-red-500/20 text-red-700 dark:text-red-300 font-bold hover:bg-red-500/30" }} disabled={(date) => date < new Date(new Date().setHours(0, 0, 0, 0))} data-testid="calendar-picker" /> {value && ( )}
{selectedDate && (
Heures
{hours.map((hour) => ( ))}
Minutes
{minutes.map((minute) => ( ))}
Heures optimales (8h, 12h-13h, 18h-20h)
)} {occupiedDates.length > 0 && (
Les dates en fond rouge ont déjà des publications programmées
)}
); }