"use client"; import { useMemo } from "react"; import { ChevronLeft, ChevronRight } from "lucide-react"; interface CalendarViewProps { entryDates: Set; // YYYY-MM-DD format selectedDate: string | null; onSelectDate: (date: string | null) => void; currentMonth: Date; onChangeMonth: (date: Date) => void; } export function CalendarView({ entryDates, selectedDate, onSelectDate, currentMonth, onChangeMonth, }: CalendarViewProps) { const { days, monthLabel } = useMemo(() => { const year = currentMonth.getFullYear(); const month = currentMonth.getMonth(); // First day of month const firstDay = new Date(year, month, 1); const startDayOfWeek = firstDay.getDay(); // Days in month const daysInMonth = new Date(year, month + 1, 0).getDate(); // Build calendar grid const days: { date: string; day: number; isCurrentMonth: boolean; hasEntry: boolean }[] = []; // Previous month padding const prevMonth = new Date(year, month, 0); const prevMonthDays = prevMonth.getDate(); for (let i = startDayOfWeek - 1; i >= 0; i--) { const day = prevMonthDays - i; const date = `${prevMonth.getFullYear()}-${String(prevMonth.getMonth() + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`; days.push({ date, day, isCurrentMonth: false, hasEntry: entryDates.has(date) }); } // Current month for (let day = 1; day <= daysInMonth; day++) { const date = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`; days.push({ date, day, isCurrentMonth: true, hasEntry: entryDates.has(date) }); } // Next month padding const remaining = 42 - days.length; // 6 rows * 7 days for (let day = 1; day <= remaining; day++) { const nextMonth = new Date(year, month + 2, 0); const date = `${nextMonth.getFullYear()}-${String(month + 2).padStart(2, "0")}-${String(day).padStart(2, "0")}`; days.push({ date, day, isCurrentMonth: false, hasEntry: entryDates.has(date) }); } const monthLabel = firstDay.toLocaleDateString("en-US", { month: "long", year: "numeric" }); return { days, monthLabel }; }, [currentMonth, entryDates]); const goToPrevMonth = () => { onChangeMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)); }; const goToNextMonth = () => { onChangeMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)); }; const goToToday = () => { onChangeMonth(new Date()); onSelectDate(null); }; return (
{/* Header */}
{monthLabel}
{/* Day headers */}
{["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => (
{day}
))}
{/* Calendar grid */}
{days.map(({ date, day, isCurrentMonth, hasEntry }) => { const isSelected = selectedDate === date; const isToday = date === new Date().toISOString().split("T")[0]; return ( ); })}
{/* Legend */}
Has entry
{selectedDate && ( )}
); }