import React, { useEffect, useState } from 'react' import { ChevronLeft, ChevronRight, Loader2 } from 'lucide-react' import './JumpToDatePopover.scss' interface JumpToDatePopoverProps { isOpen: boolean onClose: () => void onSelect: (date: Date) => void className?: string style?: React.CSSProperties currentDate?: Date messageDates?: Set hasLoadedMessageDates?: boolean messageDateCounts?: Record loadingDates?: boolean loadingDateCounts?: boolean } const JumpToDatePopover: React.FC = ({ isOpen, onClose, onSelect, className, style, currentDate = new Date(), messageDates, hasLoadedMessageDates = false, messageDateCounts, loadingDates = false, loadingDateCounts = false }) => { const [calendarDate, setCalendarDate] = useState(new Date(currentDate)) const [selectedDate, setSelectedDate] = useState(new Date(currentDate)) useEffect(() => { if (!isOpen) return const normalized = new Date(currentDate) setCalendarDate(normalized) setSelectedDate(normalized) }, [isOpen, currentDate]) if (!isOpen) return null const getDaysInMonth = (date: Date): number => { const year = date.getFullYear() const month = date.getMonth() return new Date(year, month + 1, 0).getDate() } const getFirstDayOfMonth = (date: Date): number => { const year = date.getFullYear() const month = date.getMonth() return new Date(year, month, 1).getDay() } const toDateKey = (day: number): string => { const year = calendarDate.getFullYear() const month = calendarDate.getMonth() + 1 return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}` } const hasMessage = (day: number): boolean => { if (!hasLoadedMessageDates) return true if (!messageDates || messageDates.size === 0) return false return messageDates.has(toDateKey(day)) } const isToday = (day: number): boolean => { const today = new Date() return day === today.getDate() && calendarDate.getMonth() === today.getMonth() && calendarDate.getFullYear() === today.getFullYear() } const isSelected = (day: number): boolean => { return day === selectedDate.getDate() && calendarDate.getMonth() === selectedDate.getMonth() && calendarDate.getFullYear() === selectedDate.getFullYear() } const generateCalendar = (): Array => { const daysInMonth = getDaysInMonth(calendarDate) const firstDay = getFirstDayOfMonth(calendarDate) const days: Array = [] for (let i = 0; i < firstDay; i++) { days.push(null) } for (let i = 1; i <= daysInMonth; i++) { days.push(i) } return days } const handleDateClick = (day: number) => { if (hasLoadedMessageDates && !hasMessage(day)) return const targetDate = new Date(calendarDate.getFullYear(), calendarDate.getMonth(), day) setSelectedDate(targetDate) onSelect(targetDate) onClose() } const getDayClassName = (day: number | null): string => { if (day === null) return 'day-cell empty' const classes = ['day-cell'] if (isToday(day)) classes.push('today') if (isSelected(day)) classes.push('selected') if (hasLoadedMessageDates && !hasMessage(day)) classes.push('no-message') return classes.join(' ') } const weekdays = ['日', '一', '二', '三', '四', '五', '六'] const days = generateCalendar() const mergedClassName = ['jump-date-popover', className || ''].join(' ').trim() return (
{calendarDate.getFullYear()}年{calendarDate.getMonth() + 1}月
{loadingDates && ( 日期加载中 )} {!loadingDates && loadingDateCounts && ( 条数加载中 )}
{weekdays.map(day => (
{day}
))}
{days.map((day, index) => { if (day === null) return
const dateKey = toDateKey(day) const hasMessageOnDay = hasMessage(day) const count = Number(messageDateCounts?.[dateKey] || 0) const showCount = count > 0 const showCountLoading = hasMessageOnDay && loadingDateCounts && !showCount return ( ) })}
) } export default JumpToDatePopover