'use client'; import { useState, useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import { DayPicker } from 'react-day-picker'; import { ChevronLeft, ChevronRight, Calendar, X } from 'lucide-react'; import { format, parse, isValid } from 'date-fns'; import { cn } from '@/lib/utils'; interface DatePickerProps { value: string; // YYYY-MM-DD onChange: (value: string) => void; placeholder?: string; disabled?: boolean; minDate?: Date; className?: string; } export default function DatePicker({ value, onChange, placeholder = 'Pick a date', disabled = false, minDate, className, }: DatePickerProps) { const [open, setOpen] = useState(false); const [mounted, setMounted] = useState(false); const triggerRef = useRef(null); const [popoverPos, setPopoverPos] = useState({ top: 0, left: 0 }); useEffect(() => { setMounted(true); }, []); useEffect(() => { if (!open) return; const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') setOpen(false); }; document.addEventListener('keydown', handler); return () => document.removeEventListener('keydown', handler); }, [open]); const selected = value ? parse(value, 'yyyy-MM-dd', new Date()) : undefined; const validSelected = selected && isValid(selected) ? selected : undefined; // Clear the value if it's now before the minDate useEffect(() => { if (minDate && validSelected && validSelected < minDate) { onChange(''); } }, [minDate, validSelected, onChange]); function handleOpen() { if (disabled) return; if (triggerRef.current) { const rect = triggerRef.current.getBoundingClientRect(); setPopoverPos({ top: rect.bottom + window.scrollY + 6, left: rect.left + window.scrollX, }); } setOpen(true); } function handleSelect(date: Date | undefined) { if (date && isValid(date)) { onChange(format(date, 'yyyy-MM-dd')); } setOpen(false); } function handleClear(e: React.MouseEvent) { e.stopPropagation(); onChange(''); } const displayText = validSelected ? format(validSelected, 'MMM d, yyyy') : null; const popover = open && mounted ? createPortal( <>
setOpen(false)} />
e.stopPropagation()} > orientation === 'left' ? : , DayButton: ({ day, modifiers, className: cls, ...props }) => (
, document.body, ) : null; return (
{popover}
); }