feat: русский UI, версии в футере, даты и устойчивость загрузки API
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
- API: дата старта всегда YYYY-MM-DD; фронт: parseRaceDate без двойного T00:00:00 - GET /health с version из package.json; Vite define __FRONTEND_VERSION__ - Футер с версиями клиента/сервера (BEM), сетка app-shell на три ряда - AbortController для карточки старта; ретраи GET при 502–504 и понятные ошибки шлюза - Русские подписи навигации/страниц, lang=ru, без английских фраз в интерфейсе
This commit is contained in:
@@ -57,6 +57,7 @@ export function RaceDetailsPage(): JSX.Element {
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const ac = new AbortController();
|
||||
let isMounted = true;
|
||||
|
||||
async function loadRace(): Promise<void> {
|
||||
@@ -67,19 +68,19 @@ export function RaceDetailsPage(): JSX.Element {
|
||||
}
|
||||
|
||||
try {
|
||||
const item = await getRaceById(raceId);
|
||||
if (!isMounted) {
|
||||
const item = await getRaceById(raceId, { signal: ac.signal });
|
||||
if (!isMounted || ac.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
setRace(item);
|
||||
setErrorMessage(null);
|
||||
} catch (error) {
|
||||
if (!isMounted) {
|
||||
if (ac.signal.aborted || !isMounted) {
|
||||
return;
|
||||
}
|
||||
setErrorMessage(getErrorMessage(error));
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
if (isMounted && !ac.signal.aborted) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
@@ -88,6 +89,7 @@ export function RaceDetailsPage(): JSX.Element {
|
||||
void loadRace();
|
||||
return () => {
|
||||
isMounted = false;
|
||||
ac.abort();
|
||||
};
|
||||
}, [raceId]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user