'use client'; import { useState, useCallback } from 'react'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; import { PickersDay, PickersDayProps } from '@mui/x-date-pickers/PickersDay'; import dayjs, { Dayjs } from 'dayjs'; import isoWeek from 'dayjs/plugin/isoWeek'; import 'dayjs/locale/ru'; import Popover from '@mui/material/Popover'; dayjs.extend(isoWeek); dayjs.locale('ru'); export interface DateRangeValue { start_date: string; // YYYY-MM-DD end_date: string; } export interface DateRangePickerProps { value: DateRangeValue; onChange: (range: DateRangeValue) => void; disabled?: boolean; placeholder?: string; } const PRESETS = [ { label: 'Эта неделя', fn: () => ({ start_date: dayjs().startOf('isoWeek').format('YYYY-MM-DD'), end_date: dayjs().endOf('isoWeek').format('YYYY-MM-DD'), }), }, { label: 'Прошлая неделя', fn: () => { const w = dayjs().subtract(1, 'week'); return { start_date: w.startOf('isoWeek').format('YYYY-MM-DD'), end_date: w.endOf('isoWeek').format('YYYY-MM-DD') }; }, }, { label: 'Последние 7 дней', fn: () => ({ start_date: dayjs().subtract(6, 'day').format('YYYY-MM-DD'), end_date: dayjs().format('YYYY-MM-DD'), }), }, { label: 'Текущий месяц', fn: () => ({ start_date: dayjs().startOf('month').format('YYYY-MM-DD'), end_date: dayjs().endOf('month').format('YYYY-MM-DD'), }), }, { label: 'След. месяц', fn: () => { const m = dayjs().add(1, 'month'); return { start_date: m.startOf('month').format('YYYY-MM-DD'), end_date: m.endOf('month').format('YYYY-MM-DD') }; }, }, ]; export function DateRangePicker({ value, onChange, disabled = false, placeholder = 'Выберите период', }: DateRangePickerProps) { const [anchorEl, setAnchorEl] = useState(null); const [localStart, setLocalStart] = useState(() => (value.start_date ? dayjs(value.start_date) : null)); const [localEnd, setLocalEnd] = useState(() => (value.end_date ? dayjs(value.end_date) : null)); const [rangeMode, setRangeMode] = useState<'start' | 'end'>('start'); const syncFromValue = useCallback(() => { setLocalStart(value.start_date ? dayjs(value.start_date) : null); setLocalEnd(value.end_date ? dayjs(value.end_date) : null); }, [value.start_date, value.end_date]); const openPopover = (e: React.MouseEvent) => { if (disabled) return; syncFromValue(); setAnchorEl(e.currentTarget); }; const closePopover = () => setAnchorEl(null); const handleApply = () => { if (localStart && localEnd) { onChange({ start_date: localStart.format('YYYY-MM-DD'), end_date: localEnd.format('YYYY-MM-DD'), }); } closePopover(); }; const displayText = value.start_date && value.end_date ? `${dayjs(value.start_date).format('DD.MM.YYYY')} — ${dayjs(value.end_date).format('DD.MM.YYYY')}` : placeholder; return ( <>
Выберите период
{localStart && localEnd ? `${localStart.format('D MMM')} — ${localEnd.format('D MMM')}` : '—'}
{rangeMode === 'start' ? 'Клик: начало периода' : 'Клик: конец периода'}
{PRESETS.map(({ label, fn }) => ( ))}
{ const d = val ? dayjs(val as Date) : null; if (!d) return; if (rangeMode === 'start') { setLocalStart(d); setLocalEnd(null); setRangeMode('end'); } else { if (localStart && d.isBefore(localStart, 'day')) { setLocalStart(d); setLocalEnd(localStart); } else { setLocalEnd(d); } } }} slots={{ day: (props: PickersDayProps) => { const { day, selected, sx, ...rest } = props; const d = dayjs(day as Date); const start = localStart ? dayjs(localStart).startOf('day') : null; const end = localEnd ? dayjs(localEnd).startOf('day') : null; const isStart = start && d.isSame(start, 'day'); const isEnd = end && d.isSame(end, 'day'); const inBetween = start && end && !isStart && !isEnd && d.isAfter(start) && d.isBefore(end); const inRange = isStart || isEnd || inBetween; return ( ); }, }} sx={{ width: '100%', '& .MuiPickersCalendarHeader-root': { marginBottom: 0 } }} />
); }