import { memo, useCallback, useEffect, useRef, useState } from 'react'; import { useToggle } from 'react-use'; import clsx from 'clsx'; import dayjs from 'dayjs'; import isEqual from 'lodash/isEqual'; import DatePickerReact from 'react-datepicker'; import Button from '@mui/material/Button'; import Menu from '@mui/material/Menu'; import IconButton from '@mui/material/IconButton'; import Divider from '@mui/material/Divider'; import Grid from '@mui/material/Grid'; import InputLabel from '@mui/material/InputLabel'; import Fade from '@mui/material/Fade'; import { ASSETS_URL } from '../../../consts/common'; import { CustomIcon } from '../../custom-icon'; import { DateRange, HeaderDatePicker, SelectMMYY } from './parts'; import createClasses from './styles'; const anchorElTopAddition = -42; export type DateValues = Date | string | null; export interface DatesValues { startDate: DateValues; endDate: DateValues; } export interface DatePickerProps { input: { value: DatesValues; onChange: (values: DatesValues) => void; }; label?: string; rangeSection?: boolean; calendarSection?: boolean; triggerResetDatePicker?: boolean; minDate?: Date; maxDate?: Date; placeholder?: string; /** * If `true`, the popup will be opened initially. * @default false */ openOnce?: boolean; /** * Custom class name in case you need to add custom styles to the component. */ className?: string; /** * Default classes overrides. */ classes?: Partial>; } export const defaultDateObj: DatesValues = { startDate: null, endDate: null }; const DatePicker = (props: DatePickerProps) => { const { label = '', rangeSection, calendarSection = true, input, triggerResetDatePicker, minDate, maxDate, placeholder, openOnce = false, className, classes } = props; const styles = createClasses(); const [startDate, setStartDate] = useState( input.value.startDate === null ? null : new Date(input.value.startDate) ); const [endDate, setEndDate] = useState( input.value.endDate === null ? null : new Date(input.value.endDate) ); const [isOpen, setIsOpen] = useState(false); const [selectDate, setSelectDate] = useState(); const [isOpenMMYY, setIsOpenMMYY] = useState(false); const toggleMMYY = useCallback(() => setIsOpenMMYY(!isOpenMMYY), [isOpenMMYY]); const buttonList = useRef(null); const [fieldFocus, toggleFieldFocus] = useToggle(false); useEffect(() => { if (input.value.startDate === null && input.value.endDate === null) { setStartDate(null); setEndDate(null); } else if (input.value.startDate && input.value.endDate) { setStartDate(new Date(input.value.startDate)); setEndDate(new Date(input.value.endDate)); } // eslint-disable-next-line }, [triggerResetDatePicker]); useEffect(() => { const formattedStartDate = dayjs(startDate).format('MM/DD/YYYY'); const formattedEndDate = dayjs(endDate).format('MM/DD/YYYY'); if ( startDate !== null && endDate !== null && !isEqual({ startDate: formattedStartDate, endDate: formattedEndDate }, input.value) ) { input.onChange({ startDate: formattedStartDate, endDate: formattedEndDate }); } else if ( startDate === null && endDate === null && input.value.startDate !== null && input.value.endDate !== null ) { input.onChange(defaultDateObj); } // eslint-disable-next-line }, [endDate]); useEffect(() => { setSelectDate(startDate || new Date()); // eslint-disable-next-line }, []); const handleOpen = useCallback( (newState?: boolean | Event) => { if (newState && typeof newState !== 'boolean') { setAnchorEl((newState?.currentTarget as HTMLElement)?.parentElement); } toggleFieldFocus(true); setIsOpen(typeof newState === 'boolean' ? newState : !isOpen); }, [isOpen, toggleFieldFocus] ); const handleClear = useCallback(() => { input.onChange(defaultDateObj); setStartDate(null); setEndDate(null); }, [input]); const onChange = useCallback((dates: [start: Date, end: Date]) => { const [start, end] = dates; setSelectDate(start); setStartDate(start); setEndDate(end); }, []); const handleMenuClose = useCallback(() => { setIsOpen(false); setAnchorEl(null); setIsOpenMMYY(false); }, []); const [anchorEl, setAnchorEl] = useState(null); const menuRef = useRef(null); const [menuSizes, setMenuSizes] = useState({ width: 0, height: 0 }); useEffect(() => { setMenuSizes({ width: menuRef.current?.clientWidth || 0, height: menuRef.current?.clientHeight || 0 }); }, [anchorEl]); useEffect(() => { if (openOnce) { setAnchorEl(buttonList?.current as HTMLElement); setIsOpen(true); } }, [openOnce]); return ( <> {label} {!isOpenMMYY ? ( {rangeSection && ( <> )} {calendarSection && ( { const { date, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled } = headerProps; return ( ); }} /> )} ) : ( )} ); }; DatePicker.defaultProps = { label: '', placeholder: '', minDate: '', maxDate: '', rangeSection: true, calendarSection: true, triggerResetDatePicker: false }; const m = memo(DatePicker); export { m as DatePicker };