import { cn } from "@/utils/class-merge"; import { BackwardIcon } from "@heroicons/react/24/solid"; import { FunctionComponent, h } from "preact"; import { useState } from "preact/hooks"; interface BackButtonProps { selectedDate: Date; onClick: () => void; } const BackButton: FunctionComponent = ({ selectedDate, onClick }: BackButtonProps) => { const currentDate = new Date(); return currentDate.getMonth() !== selectedDate.getMonth() ? ( ) : null; }; type MarkedDateType = "event" | "holiday" | "important" | string; type MarkedDates = Record; interface BigCalendarProps { onDateSelect?: (date: Date) => void; markedDates?: MarkedDates; className?: string; } const BigCalendar: FunctionComponent = ({ onDateSelect = () => {}, markedDates = {}, className = "", }: BigCalendarProps) => { const [currentDate, setCurrentDate] = useState(new Date()); const [selectedDate, setSelectedDate] = useState(null); const monthNames: string[] = [ "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь", ]; const dayNames: string[] = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]; const getDaysInMonth = (year: number, month: number): number => { return new Date(year, month + 1, 0).getDate(); }; const getFirstDayOfMonth = (year: number, month: number): number => { const day = new Date(year, month, 1).getDay(); return day === 0 ? 6 : day; }; const handlePrevMonth = (): void => { setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1)); }; const handleNextMonth = (): void => { setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1)); }; const handleDateClick = (date: Date, isCurrentMonth: boolean): void => { if (!isCurrentMonth) { setCurrentDate(new Date(date.getFullYear(), date.getMonth(), 1)); } setSelectedDate(date); onDateSelect(date); }; const isDateMarked = (date: Date): MarkedDateType | undefined => { const dateStr = date.toISOString().split("T")[0]; return markedDates[dateStr]; }; const getLastDayOfMonth = (year: number, month: number): number => { const day = new Date(year, month + 1, 0).getDay(); return day === 0 ? 6 : day; }; const renderDays = (): h.JSX.Element[] => { const year: number = currentDate.getFullYear(); const month: number = currentDate.getMonth(); const daysInMonth: number = getDaysInMonth(year, month); const firstDayOfMonth: number = getFirstDayOfMonth(year, month); const lastDayOfMonth: number = getLastDayOfMonth(year, month); const days: h.JSX.Element[] = []; // Дни предыдущего месяца const prevMonthDays = getDaysInMonth(year, month - 1); const daysFromPrevMonth = firstDayOfMonth === 0 ? 6 : firstDayOfMonth; for (let i = daysFromPrevMonth - 1; i >= 0; i--) { const day = prevMonthDays - i; const date = new Date(year, month - 1, day); const dateStr = date.toISOString().split("T")[0]; const isSelected = selectedDate?.toISOString().split("T")[0] === dateStr; const markType = isDateMarked(date); days.push(
handleDateClick(date, false)} >
{day}
{markType && (
{markType}
)}
); } // Дни текущего месяца for (let day = 1; day <= daysInMonth; day++) { const date = new Date(year, month, day); const dateStr = date.toISOString().split("T")[0]; const isSelected = selectedDate?.toISOString().split("T")[0] === dateStr; const markType = isDateMarked(date); const isToday = new Date().toISOString().split("T")[0] === dateStr; days.push(
(selectedDate ? setSelectedDate(null) : handleDateClick(date, true))} >
{day}
{markType && (
{markType}
)}
); } // Дни следующего месяца const daysToAdd = 6 - (lastDayOfMonth === 6 ? 3 : lastDayOfMonth); for (let day = 1; day <= daysToAdd; day++) { const date = new Date(year, month + 1, day); const dateStr = date.toISOString().split("T")[0]; const isSelected = selectedDate?.toISOString().split("T")[0] === dateStr; const markType = isDateMarked(date); days.push(
handleDateClick(date, false)} >
{day}
{markType && (
{markType}
)}
); } return days; }; return (
Закрыто

{monthNames[currentDate.getMonth()]} {currentDate.getFullYear()}

{dayNames.map((day) => (
{day}
))}
{renderDays()}
setCurrentDate(new Date())} />
); }; export default BigCalendar;