A backend outage during deploy cleared the session and sent the user to login although the refresh cookie was still valid. Only a definitive 401 ends the session now; network errors and 5xx keep it and show a retry screen.
72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
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";
|
|
|
|
import { RouteSkeleton } from "./RouteFallback";
|
|
|
|
const Protected: FC<PropsWithChildren> = (props) => {
|
|
const { children } = props;
|
|
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}` };
|
|
|
|
return user
|
|
? <>{children}</>
|
|
: (
|
|
<Navigate
|
|
replace
|
|
state={loginState}
|
|
to="/login"
|
|
/>
|
|
);
|
|
};
|
|
|
|
const Public: FC<PropsWithChildren> = (props) => {
|
|
const { children } = props;
|
|
const { ready, user } = useAuth();
|
|
const location = useLocation();
|
|
|
|
if (!ready) return <RouteSkeleton variant="shell" />;
|
|
|
|
const state: unknown = location.state;
|
|
|
|
const requested = state && typeof state === "object" && "returnTo" in state
|
|
? state.returnTo
|
|
: undefined;
|
|
|
|
const returnTo
|
|
= typeof requested === "string"
|
|
&& requested.startsWith("/")
|
|
&& !requested.startsWith("//")
|
|
? requested
|
|
: "/accounts";
|
|
|
|
return user ? <Navigate replace to={returnTo} /> : <>{children}</>;
|
|
};
|
|
|
|
export { Protected, Public };
|