forked from admin/runners-calendar
67 lines
2.7 KiB
TypeScript
67 lines
2.7 KiB
TypeScript
import { useEffect, useState } from "react";
|
||
import { useParams } from "react-router-dom";
|
||
import { ApiError, getPublicRaces } from "../api";
|
||
import type { PublicRace } from "../api";
|
||
import { formatDistance, formatRaceDate, getRaceStatusClassName, getRaceStatusLabel } from "../lib";
|
||
|
||
export function PublicProfilePage(): JSX.Element {
|
||
const { userId } = useParams<{ userId: string }>();
|
||
const [races, setRaces] = useState<PublicRace[]>([]);
|
||
const [error, setError] = useState("");
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
const ac = new AbortController();
|
||
if (!userId) {
|
||
setError("Страница пользователя не найдена.");
|
||
setLoading(false);
|
||
return () => ac.abort();
|
||
}
|
||
void getPublicRaces(userId, { signal: ac.signal })
|
||
.then((items) => {
|
||
if (!ac.signal.aborted) {
|
||
setRaces(items);
|
||
}
|
||
})
|
||
.catch((cause) => {
|
||
if (!ac.signal.aborted) {
|
||
setError(cause instanceof ApiError ? cause.message : "Не удалось загрузить страницу пользователя.");
|
||
}
|
||
})
|
||
.finally(() => {
|
||
if (!ac.signal.aborted) {
|
||
setLoading(false);
|
||
}
|
||
});
|
||
return () => ac.abort();
|
||
}, [userId]);
|
||
|
||
return (
|
||
<section className="page page--race-day">
|
||
<section className="race-day-hero">
|
||
<p className="race-day-hero__eyebrow">Публичная страница</p>
|
||
<h1 className="page__title">Календарь стартов</h1>
|
||
<p className="page__subtitle">Опубликованные старты пользователя.</p>
|
||
</section>
|
||
{loading ? <p className="page__subtitle" aria-busy="true">Загружаем…</p> : null}
|
||
{error ? <p className="page__subtitle page__subtitle--error" role="alert">{error}</p> : null}
|
||
{!loading && !error && races.length === 0 ? <p className="page__subtitle">Пока нет опубликованных стартов.</p> : null}
|
||
{!loading && !error && races.length > 0 ? (
|
||
<ul className="race-day__list">
|
||
{races.map((race, index) => (
|
||
<li className="race-day__item" key={`${race.date}-${race.title}-${index}`}>
|
||
<div className="race-day__body">
|
||
<span className="race-day__title">{race.title}</span>
|
||
<span className="race-day__meta">
|
||
{formatRaceDate(race.date)} · {formatDistance(race.distanceKm)} ·{" "}
|
||
<span className={getRaceStatusClassName(race.status, race.date)}>{getRaceStatusLabel(race.status, race.date)}</span>
|
||
</span>
|
||
</div>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
) : null}
|
||
</section>
|
||
);
|
||
}
|