import { useEffect, useMemo, useState } from "react"; import { Link } from "react-router-dom"; import type { Race, RacesQuery } from "../api"; import { ApiError, getRaces } from "../api"; import { formatDistance, formatRaceDate, getRaceStatusClassName, getRaceStatusLabel, splitRacesByDate, } from "../lib"; const MONTH_OPTIONS: { value: string; label: string }[] = [ { value: "", label: "Все месяцы" }, { value: "1", label: "Январь" }, { value: "2", label: "Февраль" }, { value: "3", label: "Март" }, { value: "4", label: "Апрель" }, { value: "5", label: "Май" }, { value: "6", label: "Июнь" }, { value: "7", label: "Июль" }, { value: "8", label: "Август" }, { value: "9", label: "Сентябрь" }, { value: "10", label: "Октябрь" }, { value: "11", label: "Ноябрь" }, { value: "12", label: "Декабрь" }, ]; function yearSelectOptions(): number[] { const current = new Date().getFullYear(); const start = current - 2; const end = current + 4; const years: number[] = []; for (let y = start; y <= end; y += 1) { years.push(y); } return years; } function getErrorMessage(error: unknown): string { if (error instanceof ApiError) { return error.message; } return "Не удалось загрузить календарь стартов."; } function RaceList(props: { title: string; races: Race[] }): JSX.Element { const { title, races } = props; return (

{title}

{races.length > 0 ? ( ) : (

Пока нет данных в этом разделе.

)}
); } export function RacesPage(): JSX.Element { const [races, setRaces] = useState([]); const [isLoading, setIsLoading] = useState(true); const [errorMessage, setErrorMessage] = useState(null); const [yearFilter, setYearFilter] = useState(""); const [monthFilter, setMonthFilter] = useState(""); const listQuery = useMemo((): RacesQuery | undefined => { const q: RacesQuery = {}; if (yearFilter !== "") { const y = parseInt(yearFilter, 10); if (!Number.isNaN(y)) { q.year = y; } } if (monthFilter !== "") { const m = parseInt(monthFilter, 10); if (!Number.isNaN(m)) { q.month = m; } } return Object.keys(q).length > 0 ? q : undefined; }, [yearFilter, monthFilter]); useEffect(() => { let isMounted = true; async function loadRaces(): Promise { setIsLoading(true); try { const items = await getRaces(listQuery); if (!isMounted) { return; } setRaces(items); setErrorMessage(null); } catch (error) { if (!isMounted) { return; } setErrorMessage(getErrorMessage(error)); } finally { if (isMounted) { setIsLoading(false); } } } void loadRaces(); return () => { isMounted = false; }; }, [listQuery]); const { upcoming, past } = useMemo(() => splitRacesByDate(races), [races]); if (errorMessage && races.length === 0 && !isLoading) { return (

Календарь стартов

{errorMessage}

); } return (

Календарь стартов

Будущие и прошедшие старты в одном месте.

{errorMessage && !isLoading ? (

{errorMessage}

) : null}
{isLoading ? (

Загружаем данные...

) : null}
); }