import EventIcon from "@mui/icons-material/Event"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { Accordion, AccordionDetails, AccordionSummary, Chip, List, ListItem, ListItemButton, ListItemText, Paper, Typography } from "@mui/material"; import { useQuery } from "@tanstack/react-query"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { fetchUpcomingDeadlines } from "../api/contracts"; import PageHeader from "../components/PageHeader"; import { UpcomingDeadline } from "../types"; import { formatDate } from "../utils/date"; const UNKNOWN_MONTH_KEY = "__unknown__"; function groupByMonth(deadlines: UpcomingDeadline[], unknownKey: string) { const groups = new Map(); deadlines.forEach((deadline) => { const month = deadline.terminationDeadline?.slice(0, 7) ?? unknownKey; if (!groups.has(month)) { groups.set(month, []); } groups.get(month)!.push(deadline); }); return Array.from(groups.entries()) .sort(([a], [b]) => a.localeCompare(b)) .map(([month, items]) => ({ month, items: items.sort((a, b) => (a.terminationDeadline ?? "").localeCompare(b.terminationDeadline ?? "")) })); } export default function CalendarView() { const { data, isLoading } = useQuery({ queryKey: ["deadlines", "calendar"], queryFn: () => fetchUpcomingDeadlines(365) }); const groups = useMemo(() => { if (!data || !Array.isArray(data)) return [] as ReturnType; return groupByMonth(data, UNKNOWN_MONTH_KEY); }, [data]); const navigate = useNavigate(); const { t, i18n } = useTranslation(); return ( <> {isLoading ? ( {t("calendar.loading")} ) : groups.length === 0 ? ( {t("calendar.none")} ) : ( groups.map(({ month, items }) => ( }> {formatMonth(month, i18n.language, t("calendar.unknownMonth"))} {items.map((deadline) => ( ) : undefined } > navigate(`/contracts/${deadline.id}`)}> {t("deadlineList.terminateBy", { date: formatDate(deadline.terminationDeadline) })} {deadline.contractEndDate ? ` • ${t("deadlineList.contractEnds", { date: formatDate(deadline.contractEndDate) })}` : ""} } primaryTypographyProps={{ fontWeight: 600 }} /> ))} )) )} ); } function formatMonth(month: string, locale: string, unknownLabel: string): string { if (month === UNKNOWN_MONTH_KEY) return unknownLabel; const [year, monthNumber] = month.split("-"); const date = new Date(Number(year), Number(monthNumber) - 1); return new Intl.DateTimeFormat(locale.startsWith("de") ? "de-DE" : "en-US", { month: "long", year: "numeric" }).format(date); }