import { Bedtime, CalendarMonth, Close, EventNote, LightMode, NextWeek, NightsStay, Today, WbSunny, WbTwilight, Weekend, } from '@mui/icons-material' import { Box, Button, Checkbox, IconButton, Input, List, ListItem, Typography, } from '@mui/joy' import moment from 'moment' import { useEffect, useMemo, useState } from 'react' import Calendar from 'react-calendar' import { useLocalization } from '../../contexts/LocalizationContext' import { useResponsiveModal } from '../../hooks/useResponsiveModal' const DueDatePickerField = ({ dueDateOnly, dueTime, useCustomTime, onDueDateChange, onDueTimeChange, onUseCustomTimeChange, onClear, emptyDisplay = 'icon-text', size = 'sm', }) => { const [isOpen, setIsOpen] = useState(false) const { ResponsiveModal } = useResponsiveModal() const { firstDayOfWeek } = useLocalization() // Local buffered state — only committed on Apply const [localDueDateOnly, setLocalDueDateOnly] = useState(dueDateOnly) const [localDueTime, setLocalDueTime] = useState(dueTime) const [localUseCustomTime, setLocalUseCustomTime] = useState(useCustomTime) // Sync local state from props whenever the modal opens useEffect(() => { if (isOpen) { setLocalDueDateOnly(dueDateOnly) setLocalDueTime(dueTime) setLocalUseCustomTime(useCustomTime) } }, [isOpen, dueDateOnly, dueTime, useCustomTime]) const calendarType = firstDayOfWeek === 1 ? 'iso8601' : firstDayOfWeek === 6 ? 'islamic' : 'gregory' const pillListSx = { '--List-gap': '8px', '--ListItem-radius': '20px', } const getQuickScheduleDate = option => { const now = new Date() const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()) switch (option) { case 'today': return today case 'tomorrow': { const tomorrow = new Date(today) tomorrow.setDate(today.getDate() + 1) return tomorrow } case 'weekend': { const weekend = new Date(today) const daysUntilSaturday = (6 - today.getDay() + 7) % 7 || 7 weekend.setDate(today.getDate() + daysUntilSaturday) return weekend } case 'next-week': { const nextWeek = new Date(today) const daysUntilMonday = (1 - today.getDay() + 7) % 7 || 7 nextWeek.setDate(today.getDate() + daysUntilMonday) return nextWeek } case 'next-month': { const nextMonth = new Date(today) nextMonth.setMonth(today.getMonth() + 1) return nextMonth } default: return today } } const handleQuickSchedule = option => { const date = getQuickScheduleDate(option) setLocalDueDateOnly(date.toISOString().split('T')[0]) } const handleQuickTime = timeStr => { // Tap the active chip again to deselect it if (localUseCustomTime && localDueTime === timeStr) { setLocalUseCustomTime(false) setLocalDueTime(null) return } if (!localDueDateOnly) { setLocalDueDateOnly(new Date().toISOString().split('T')[0]) } setLocalUseCustomTime(true) setLocalDueTime(timeStr) } const handleCalendarChange = selected => { if (!selected || Array.isArray(selected)) return setLocalDueDateOnly(moment(selected).format('YYYY-MM-DD')) } const handleLocalTimeInputChange = e => { setLocalUseCustomTime(true) setLocalDueTime(e.target.value) } const handleSave = () => { onDueDateChange?.({ target: { value: localDueDateOnly || '' } }) onUseCustomTimeChange?.(localUseCustomTime) if (localUseCustomTime && localDueTime) { onDueTimeChange?.({ target: { value: localDueTime } }) } else { onDueTimeChange?.({ target: { value: '' } }) } setIsOpen(false) } const hasDueDate = Boolean(dueDateOnly) const shouldShowLabel = hasDueDate || emptyDisplay === 'icon-text' const dueDateLabel = useMemo(() => { if (!dueDateOnly) { return 'Due' } const formattedDate = moment(dueDateOnly).format('MMM D') if (useCustomTime && dueTime) { return `${formattedDate}, ${dueTime}` } return formattedDate }, [dueDateOnly, dueTime, useCustomTime]) return ( <> {hasDueDate && onClear && ( { e.stopPropagation() onClear?.() }} sx={{ position: 'absolute', top: -12, right: -16, zIndex: 10, maxHeight: 18, maxWidth: 18, borderRadius: '50%', '&:hover': { bgcolor: 'danger.softBg', }, }} > )} setIsOpen(false)} title='Due Date' footer={ {hasDueDate && ( )} } > {/* Date shortcuts */} Quick date {[ { key: 'today', label: 'Today', icon: , }, { key: 'tomorrow', label: 'Tomorrow', icon: , }, { key: 'weekend', label: 'Weekend', icon: , }, { key: 'next-week', label: 'Next week', icon: , }, { key: 'next-month', label: 'Next month', icon: , }, ].map(opt => { const dateStr = getQuickScheduleDate(opt.key) .toISOString() .split('T')[0] return ( handleQuickSchedule(opt.key)} overlay disableIcon variant='soft' label={ {opt.icon} {opt.label} } /> ) })} {/* Time shortcuts */} Quick time {[ { time: '09:00', label: 'Morning', icon: , }, { time: '12:00', label: 'Noon', icon: , }, { time: '15:00', label: 'Afternoon', icon: , }, { time: '18:00', label: 'Evening', icon: , }, { time: '22:00', label: 'Night', icon: , }, ].map(opt => ( handleQuickTime(opt.time)} overlay disableIcon variant='soft' label={ {opt.icon} {opt.label} } /> ))} ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'][date.getDay()] } formatMonth={(locale, date) => [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ][date.getMonth()] } /> Custom time ) } export default DueDatePickerField