import { format } from 'date-fns' import { Calendar as CalendarIcon } from 'lucide-react' import { HTMLAttributes, useEffect, useState } from 'react' import type { DateRange } from 'react-day-picker' import { Button, Calendar, cn, Input, Label_Shadcn_ as Label, Popover_Shadcn_ as Popover, PopoverContent_Shadcn_ as PopoverContent, PopoverSeparator_Shadcn_ as PopoverSeparator, PopoverTrigger_Shadcn_ as PopoverTrigger, Select_Shadcn_ as Select, SelectContent_Shadcn_ as SelectContent, SelectGroup_Shadcn_ as SelectGroup, SelectItem_Shadcn_ as SelectItem, SelectLabel_Shadcn_ as SelectLabel, SelectTrigger_Shadcn_ as SelectTrigger, SelectValue_Shadcn_ as SelectValue, } from 'ui' import { presets as defaultPresets } from './DataTable.constants' import type { DatePreset, DateRangeDisabled } from './DataTable.types' import { useDebounce } from './hooks/useDebounce' import { kdbClassName } from './primitives/Kbd' interface DatePickerWithRangeProps extends HTMLAttributes { date: DateRange | undefined setDate: (date: DateRange | undefined) => void presets?: DatePreset[] dateRangeDisabled?: DateRangeDisabled } // [Joshen] This might be better placed in ui instead of DataTable since it could be reusable export function DatePickerWithRange({ className, date, setDate, presets = defaultPresets, dateRangeDisabled, }: DatePickerWithRangeProps) { const [open, setOpen] = useState(false) useEffect(() => { const down = (e: KeyboardEvent) => { if (!open) return presets.map((preset) => { if (preset.shortcut === e.key) { setDate({ from: preset.from, to: preset.to }) } }) } document.addEventListener('keydown', down) return () => document.removeEventListener('keydown', down) }, [setDate, presets, open]) return (
) } function DatePresets({ selected, onSelect, presets, }: { selected: DateRange | undefined onSelect: (date: DateRange | undefined) => void presets: DatePreset[] }) { return (

Date Range

{presets.map(({ label, shortcut, from, to }) => { const isActive = selected?.from === from && selected?.to === to return ( ) })}
) } function DatePresetsSelect({ selected, onSelect, presets, }: { selected: DateRange | undefined onSelect: (date: DateRange | undefined) => void presets: DatePreset[] }) { function findPreset(from?: Date, to?: Date) { return presets.find((p) => p.from === from && p.to === to)?.shortcut } const [value, setValue] = useState(findPreset(selected?.from, selected?.to)) useEffect(() => { const preset = findPreset(selected?.from, selected?.to) if (preset === value) return setValue(preset) }, [selected, presets]) return ( ) } // REMINDER: We can add min max date range validation https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local#setting_maximum_and_minimum_dates_and_times function CustomDateRange({ selected, onSelect, }: { selected: DateRange | undefined onSelect: (date: DateRange | undefined) => void }) { const [dateFrom, setDateFrom] = useState(selected?.from) const [dateTo, setDateTo] = useState(selected?.to) const debounceDateFrom = useDebounce(dateFrom, 1000) const debounceDateTo = useDebounce(dateTo, 1000) const formatDateForInput = (date: Date | undefined): string => { if (!date) return '' const utcDate = new Date(date.getTime() - date.getTimezoneOffset() * 60000) return utcDate.toISOString().slice(0, 16) } useEffect(() => { onSelect({ from: debounceDateFrom, to: debounceDateTo }) // eslint-disable-next-line react-hooks/exhaustive-deps }, [debounceDateFrom, debounceDateTo]) return (

Custom Range

{ const newDate = new Date(e.target.value) if (!Number.isNaN(newDate.getTime())) { setDateFrom(newDate) } }} disabled={!selected?.from} />
{ const newDate = new Date(e.target.value) if (!Number.isNaN(newDate.getTime())) { setDateTo(newDate) } }} disabled={!selected?.to} />
) }