Datepicker (React Datepicker)
More information: react-datepicker
// This component requires the following additional imports: // import ReactDatePicker from 'react-datepicker' // import 'react-datepicker/dist/react-datepicker.css' // import { mdiCalendar, mdiChevronLeft, mdiChevronRight, mdiClose } from '@mdi/js' // import { Global } from '@emotion/react' // import { datePickerStyles } from 'src/theme/components/datepicker' // Add this DatePickerStyles component for consistent styling const DatePickerStyles = () => <Global styles={datePickerStyles} /> /** * Format date to display as "Month Day, Year" (e.g., "Jun 26, 2023") */ const formatDate = (date: Date): string => { const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}` } /** * Format date range for display */ const formatDateRange = (startDate: Date | null, endDate: Date | null): string => { if (startDate && endDate) { return `Date: ${formatDate(startDate)} - ${formatDate(endDate)}` } else if (startDate) { return `Date: ${formatDate(startDate)}` } return "Date" } /** * Custom hook for date range selection with double-click support */ const useDateRangeSelection = () => { const [dateRange, setDateRange] = useState<[Date | null, Date | null]>([null, null]) const [lastClickedEndDate, setLastClickedEndDate] = useState<Date | null>(null) const [lastClickTime, setLastClickTime] = useState<number>(0) const handleDateChange = (dates: [Date | null, Date | null]) => { const [start, end] = dates // Check if this is a double-click on the end date const isDoubleClick = end && lastClickedEndDate && end.getTime() === lastClickedEndDate.getTime() && Date.now() - lastClickTime < 300 if (isDoubleClick) { // Double click detected - make end date the new start date setDateRange([end, null]) setLastClickedEndDate(null) setLastClickTime(0) } else { setDateRange(dates) // If an end date was selected, remember it for potential double-click if (end) { setLastClickedEndDate(end) setLastClickTime(Date.now()) } else { setLastClickedEndDate(null) } } } return { dateRange, handleDateChange } } // Example usage const DatePickerExample = () => { const { dateRange, handleDateChange } = useDateRangeSelection() return ( <Stack gap="10"> {/* Include the DatePickerStyles component */} <DatePickerStyles /> <FormControl> <FormLabel>Date range selection</FormLabel> <Menu> <MenuButton as={Button} variant="filter" leftIcon={<Icon><path d={mdiCalendar} /></Icon>} rightIcon={ dateRange[0] || dateRange[1] ? ( <Icon onClick={(e) => { e.stopPropagation(); handleDateChange([null, null]); }}> <path d={mdiClose} /> </Icon> ) : null } > {formatDateRange(dateRange[0], dateRange[1])} </MenuButton> <MenuList p="0"> <ReactDatePicker selected={dateRange[0]} onChange={handleDateChange} startDate={dateRange[0]} endDate={dateRange[1]} selectsRange inline showPopperArrow={false} placeholderText="No date selected" isClearable={true} renderCustomHeader={({ decreaseMonth, increaseMonth, date, }) => ( <Flex height="9" paddingY="1" justifyContent="space-between" alignItems="center" alignSelf="stretch" px="2" > <IconButton variant="ghost" size="sm" icon={<Icon><path d={mdiChevronLeft} /></Icon>} onClick={decreaseMonth} aria-label="Previous month" /> <Heading size="sm"> {date.toLocaleString('default', { month: 'long', year: 'numeric' })} </Heading> <IconButton variant="ghost" size="sm" icon={<Icon><path d={mdiChevronRight} /></Icon>} onClick={increaseMonth} aria-label="Next month" /> </Flex> )} /> </MenuList> </Menu> </FormControl> </Stack> ) }