'use client'; import { useState, useEffect, useRef } from 'react'; import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, Globe, X } from 'lucide-react'; import { gregorianToEthiopian, ethiopianToGregorian, formatEthiopianDate, getDaysInEthiopianMonth, ETHIOPIAN_MONTHS, type EthiopianDate, } from '@/lib/ethiopian-calendar'; import { format } from 'date-fns'; interface ModernDatePickerProps { value?: Date; onChange: (date: Date) => void; minDate?: Date; maxDate?: Date; placeholder?: string; } export default function ModernDatePicker({ value, onChange, minDate, maxDate, placeholder = 'Select date', }: ModernDatePickerProps) { const [isOpen, setIsOpen] = useState(false); const [isMobileView, setIsMobileView] = useState(false); const [calendarType, setCalendarType] = useState<'gregorian' | 'ethiopian'>('gregorian'); const [viewMonth, setViewMonth] = useState(value?.getMonth() ?? new Date().getMonth()); const [viewYear, setViewYear] = useState(value?.getFullYear() ?? new Date().getFullYear()); const initialEthDate = gregorianToEthiopian(value || new Date()); const [ethViewMonth, setEthViewMonth] = useState(initialEthDate.month); const [ethViewYear, setEthViewYear] = useState(initialEthDate.year); const containerRef = useRef(null); useEffect(() => { const check = () => setIsMobileView(window.innerWidth < 768); check(); window.addEventListener('resize', check); return () => window.removeEventListener('resize', check); }, []); useEffect(() => { if (value) { setViewMonth(value.getMonth()); setViewYear(value.getFullYear()); const ethDate = gregorianToEthiopian(value); setEthViewMonth(ethDate.month); setEthViewYear(ethDate.year); } }, [value]); // Lock body scroll when modal is open (both mobile and desktop modal) useEffect(() => { if (isOpen) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } return () => { document.body.style.overflow = ''; }; }, [isOpen]); const toggleCalendarType = () => { const newType = calendarType === 'gregorian' ? 'ethiopian' : 'gregorian'; const ref = value || new Date(); if (newType === 'ethiopian') { const ethDate = gregorianToEthiopian(ref); setEthViewMonth(ethDate.month); setEthViewYear(ethDate.year); } else { setViewMonth(ref.getMonth()); setViewYear(ref.getFullYear()); } setCalendarType(newType); }; const handleDateSelect = (date: Date) => { onChange(date); setIsOpen(false); }; const handleEthiopianDateSelect = (ethDate: EthiopianDate) => { handleDateSelect(ethiopianToGregorian(ethDate)); }; const renderGregorianCalendar = () => { const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate(); const firstDay = new Date(viewYear, viewMonth, 1).getDay(); const days: (number | null)[] = Array(firstDay).fill(null); for (let d = 1; d <= daysInMonth; d++) days.push(d); const monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December']; return (
{monthNames[viewMonth]} {viewYear}
{['Su','Mo','Tu','We','Th','Fr','Sa'].map(d => (
{d}
))}
{days.map((day, i) => { if (day === null) return
; const date = new Date(viewYear, viewMonth, day); const isSelected = value && date.getDate() === value.getDate() && date.getMonth() === value.getMonth() && date.getFullYear() === value.getFullYear(); const isToday = date.toDateString() === new Date().toDateString(); const isDisabled = (minDate && date < new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate())) || (maxDate && date > new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate())); return ( ); })}
); }; const renderEthiopianCalendar = () => { const daysInMonth = getDaysInEthiopianMonth(ethViewYear, ethViewMonth); const firstDate = ethiopianToGregorian({ year: ethViewYear, month: ethViewMonth, day: 1 }); const firstDayOfWeek = firstDate.getDay(); const daysWithOffset: (number | null)[] = Array(firstDayOfWeek).fill(null); for (let d = 1; d <= daysInMonth; d++) daysWithOffset.push(d); const monthName = ETHIOPIAN_MONTHS[ethViewMonth - 1] || `Month ${ethViewMonth}`; return (
{monthName} {ethViewYear}
{['Su','Mo','Tu','We','Th','Fr','Sa'].map(d => (
{d}
))}
{daysWithOffset.map((day, i) => { if (day === null) return
; const ethDate: EthiopianDate = { year: ethViewYear, month: ethViewMonth, day }; const gregDate = ethiopianToGregorian(ethDate); const isSelected = value && gregDate.getDate() === value.getDate() && gregDate.getMonth() === value.getMonth() && gregDate.getFullYear() === value.getFullYear(); const todayEth = gregorianToEthiopian(new Date()); const isToday = ethDate.day === todayEth.day && ethDate.month === todayEth.month && ethDate.year === todayEth.year; let isDisabled = false; if (minDate) { const [mY, mM, mD] = [minDate.getFullYear(), minDate.getMonth(), minDate.getDate()]; const [gY, gM, gD] = [gregDate.getFullYear(), gregDate.getMonth(), gregDate.getDate()]; if (gY < mY || (gY === mY && gM < mM) || (gY === mY && gM === mM && gD < mD)) isDisabled = true; } if (maxDate && !isDisabled) { const [mY, mM, mD] = [maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()]; const [gY, gM, gD] = [gregDate.getFullYear(), gregDate.getMonth(), gregDate.getDate()]; if (gY > mY || (gY === mY && gM > mM) || (gY === mY && gM === mM && gD > mD)) isDisabled = true; } return ( ); })}
); }; const calendarFooter = value && (
Gregorian: {format(value, 'MMMM d, yyyy')}
Ethiopian: {formatEthiopianDate(gregorianToEthiopian(value))}
); // Shared modal content (used by both mobile and desktop) const modalContent = (
{/* Header row: title + close */}

Select Date

{/* Toggle row: always full-width, clearly visible */}
{/* Calendar body */}
{calendarType === 'gregorian' ? renderGregorianCalendar() : renderEthiopianCalendar()} {calendarFooter}
); return (
{/* Trigger button */} {isOpen && ( <> {/* Mobile: full-screen takeover */} {isMobileView ? (
{modalContent}
) : ( /* Desktop: centred modal with backdrop */ <>
setIsOpen(false)} />
{modalContent}
)} )}
); }