fix: keep session when refresh fails on network error or 5xx (WealthLedger/frontend#97)
This commit was merged in pull request #100.
This commit is contained in:
@@ -190,6 +190,30 @@ describe("AppRoutes", () => {
|
||||
expect(document.title).toBe("Карты — WealthLedger");
|
||||
});
|
||||
|
||||
it("offers a retry instead of the login form while the server is unreachable, then restores the route", async () => {
|
||||
let isOutage = true;
|
||||
server.use(
|
||||
http.post("*/api/v1/auth/refresh", () =>
|
||||
isOutage
|
||||
? new HttpResponse(null, { status: 502 })
|
||||
: HttpResponse.json({
|
||||
accessToken: "test-token",
|
||||
user: { email: "user@example.com", id: "user-1" },
|
||||
}),
|
||||
),
|
||||
);
|
||||
renderRoutes("/accounts");
|
||||
|
||||
expect(await screen.findByRole("alert")).toHaveTextContent("Не удалось подключиться");
|
||||
expect(screen.queryByRole("heading", { name: "Вход" })).not.toBeInTheDocument();
|
||||
isOutage = false;
|
||||
fireEvent.click(screen.getByRole("button", { name: "Повторить" }));
|
||||
|
||||
expect(
|
||||
await screen.findByRole("heading", { level: 2, name: "Нет инвестиционных счетов" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it("lazy-loads the protected shell for an authenticated accounts route", async () => {
|
||||
server.use(
|
||||
http.post("*/api/v1/auth/refresh", () =>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Button, Container } from "@mantine/core";
|
||||
import { StateView } from "@wealthledger/ui";
|
||||
import { type FC, type PropsWithChildren, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Navigate, useLocation } from "react-router";
|
||||
|
||||
import { useAuth } from "@/features/auth";
|
||||
@@ -7,12 +10,26 @@ import { RouteSkeleton } from "./RouteFallback";
|
||||
|
||||
const Protected: FC<PropsWithChildren> = (props) => {
|
||||
const { children } = props;
|
||||
const { ready, signedOut, user } = useAuth();
|
||||
const { ready, retry, signedOut, unavailable, user } = useAuth();
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const [wasAuthenticated, setWasAuthenticated] = useState(false);
|
||||
if (user && !wasAuthenticated) setWasAuthenticated(true);
|
||||
if (!ready) return <RouteSkeleton variant="shell" />;
|
||||
|
||||
// The server was unreachable (e.g. mid-deploy), so the session is unproven, not gone.
|
||||
if (!user && unavailable)
|
||||
return (
|
||||
<Container py="xl" size={560}>
|
||||
<StateView
|
||||
action={<Button onClick={retry}>{t("auth.retry")}</Button>}
|
||||
error
|
||||
text={t("auth.unavailableText")}
|
||||
title={t("auth.unavailableTitle")}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
|
||||
const loginState = signedOut && wasAuthenticated
|
||||
? undefined
|
||||
: { returnTo: `${location.pathname}${location.search}` };
|
||||
|
||||
Reference in New Issue
Block a user