import React, { useRef, useState, useEffect, useContext } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { setFromDate, setToDate, setMobileFilterType, setMobileDatePickerMode, setMinDate, setMaxDate, setDateFlexibility } from '../../store/qsm-slice'; import { QSMRootState } from '../../store/qsm-store'; import { addYears, format, startOfDay } from 'date-fns'; import DateRangePicker from '../date-range-picker'; import useMediaQuery from '../../../shared/utils/use-media-query-util'; import QSMConfigurationContext from '../../qsm-configuration-context'; const DatePicker: React.FC = () => { const dispatch = useDispatch(); const isSmallScreen = useMediaQuery('(max-width: 768px)'); /* 🔑 STATE FIRST (no TDZ issues) */ const [isOpen, setIsOpen] = useState(false); // range pop-over const [isSingleOpen, setIsSingleOpen] = useState(false); // single pop-over const { datesIcon, showReturnDate = true, minDate, maxDate, dateFlexibility = [] } = useContext(QSMConfigurationContext); const isSingleDate = !showReturnDate; const dateInputWrapperRef = useRef(null); const dateInputRef = useRef(null); const today = startOfDay(new Date()); const effectiveMinDate = minDate ?? today; const effectiveMaxDate = maxDate ?? addYears(today, 1); const { fromDate, toDate } = useSelector((state: QSMRootState) => ({ fromDate: state.qsm.fromDate, toDate: state.qsm.toDate })); /* ----------------------- outside click close ----------------------- */ useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( dateInputWrapperRef.current && !dateInputWrapperRef.current.contains(event.target as Node) && dateInputRef.current && !dateInputRef.current.contains(event.target as Node) ) { setIsOpen(false); setIsSingleOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); /* ----------------------- min/max & flexibility sync ---------------- */ useEffect(() => { dispatch(setMinDate(effectiveMinDate.toISOString())); dispatch(setMaxDate(effectiveMaxDate.toISOString())); }, [dispatch, effectiveMinDate, effectiveMaxDate]); useEffect(() => { if (dateFlexibility.length) { dispatch(setDateFlexibility(dateFlexibility)); } }, [dispatch, JSON.stringify(dateFlexibility)]); /* =================== SINGLE DATE (only departure) ================= */ if (isSingleDate) { return (
{ if (isSmallScreen) { dispatch(setMobileDatePickerMode('single')); dispatch(setMobileFilterType('date')); } else { setIsSingleOpen(true); } }}> {datesIcon && {datesIcon}}
{!isSmallScreen && isSingleOpen && (
{ dispatch(setFromDate(from ? from.toISOString() : undefined)); dispatch(setToDate(undefined)); }} onRequestClose={() => setIsSingleOpen(false)} isSingleDate />
)}
); } /* ======================== RANGE PICKER ============================= */ const handleFromDateClick = () => { if (isSmallScreen) { dispatch(setMobileDatePickerMode('range')); dispatch(setMobileFilterType('date')); } else { setIsOpen(true); } }; return (
{/* Departure */}