'use client' import * as React from 'react' import type { DateRange } from 'react-day-picker' import { Button } from '@admin/components/ui/button' import { Calendar } from '@admin/components/ui/calendar' import { Input } from '@admin/components/ui/input' import { Popover, PopoverContent, PopoverTrigger } from '@admin/components/ui/popover' import { buildDateRange } from '@admin/utils/date/build-date-range' import { DATE_RANGE_END_TIME } from '@admin/utils/date/date-range-end-time' import { DATE_RANGE_START_TIME } from '@admin/utils/date/date-range-start-time' import { formatDateRangeInputDate } from '@admin/utils/date/format-date-range-input-date' import { formatDateRangeParamDate } from '@admin/utils/date/format-date-range-param-date' import { getDateRangeTriggerLabel } from '@admin/utils/date/get-date-range-trigger-label' import { getOrderedDateRange } from '@admin/utils/date/get-ordered-date-range' import { normalizeDateRangeTime } from '@admin/utils/date/normalize-date-range-time' import { parseDateInputValue } from '@admin/utils/date/parse-date-input-value' import { parseEditableDateRangeDate } from '@admin/utils/date/parse-editable-date-range-date' import { cn } from '@admin/utils/shared/cn' import { CalendarIcon, ChevronDown, CornerDownLeft } from 'lucide-react' interface DateRangePickerProps { from?: string to?: string onChange?: (range: { from?: string; to?: string; fromTime?: string; toTime?: string }) => void disabled?: boolean placeholder?: string className?: string } export function DateRangePicker({ from, to, onChange, disabled, placeholder = 'Pick a date range', className }: DateRangePickerProps) { const [open, setOpen] = React.useState(false) const [draftRange, setDraftRange] = React.useState(() => buildDateRange(from, to) ) const [fromInput, setFromInput] = React.useState(() => formatDateRangeInputDate(parseDateInputValue(from)) ) const [toInput, setToInput] = React.useState(() => formatDateRangeInputDate(parseDateInputValue(to)) ) const [fromTime, setFromTime] = React.useState(DATE_RANGE_START_TIME) const [toTime, setToTime] = React.useState(DATE_RANGE_END_TIME) const [calendarMonth, setCalendarMonth] = React.useState( () => parseDateInputValue(from) ?? parseDateInputValue(to) ) const committedFrom = parseDateInputValue(from) const committedTo = parseDateInputValue(to) const triggerLabel = getDateRangeTriggerLabel(committedFrom, committedTo, placeholder) const syncDraftFromProps = () => { const nextRange = buildDateRange(from, to) setDraftRange(nextRange) setFromInput(formatDateRangeInputDate(nextRange?.from)) setToInput(formatDateRangeInputDate(nextRange?.to)) setFromTime(DATE_RANGE_START_TIME) setToTime(DATE_RANGE_END_TIME) setCalendarMonth(nextRange?.from ?? nextRange?.to) } const handleApply = () => { const orderedRange = getOrderedDateRange({ from: parseEditableDateRangeDate(fromInput) ?? draftRange?.from, to: parseEditableDateRangeDate(toInput) ?? draftRange?.to }) onChange?.({ from: orderedRange?.from ? formatDateRangeParamDate(orderedRange.from) : undefined, to: orderedRange?.to ? formatDateRangeParamDate(orderedRange.to) : undefined, fromTime: normalizeDateRangeTime(fromTime, DATE_RANGE_START_TIME), toTime: normalizeDateRangeTime(toTime, DATE_RANGE_END_TIME) }) setOpen(false) } const handleRangeSelect = (nextRange: DateRange | undefined, selectedDay?: Date) => { const nextDraftRange = draftRange?.from && draftRange.to && selectedDay ? { from: selectedDay, to: undefined } : nextRange const orderedRange = getOrderedDateRange(nextDraftRange) setDraftRange(orderedRange) setFromInput(formatDateRangeInputDate(orderedRange?.from)) setToInput(formatDateRangeInputDate(orderedRange?.to)) setCalendarMonth(orderedRange?.from ?? orderedRange?.to) } const handleDateInputChange = (field: 'from' | 'to', value: string) => { const parsedDate = parseEditableDateRangeDate(value) if (field === 'from') { setFromInput(value) if (parsedDate) setCalendarMonth(parsedDate) setDraftRange((currentRange) => getOrderedDateRange({ from: parsedDate, to: currentRange?.to }) ) return } setToInput(value) if (parsedDate) setCalendarMonth(parsedDate) setDraftRange((currentRange) => getOrderedDateRange({ from: currentRange?.from, to: parsedDate }) ) } const canApply = Boolean(parseEditableDateRangeDate(fromInput) ?? draftRange?.from) return ( { setOpen(nextOpen) if (nextOpen) { syncDraftFromProps() } }} > } > {triggerLabel}
handleDateInputChange('from', event.target.value)} placeholder="Apr 10, 2026" className="h-8 rounded-md px-3 text-sm" /> setFromTime(event.target.value)} aria-label="Start time" className="h-8 rounded-md px-3 text-sm tabular-nums" />
handleDateInputChange('to', event.target.value)} placeholder="Apr 30, 2026" className="h-8 rounded-md px-3 text-sm" /> setToTime(event.target.value)} aria-label="End time" className="h-8 rounded-md px-3 text-sm tabular-nums" />
) }