73 lines
1.7 KiB
TypeScript
73 lines
1.7 KiB
TypeScript
import type { FC, PropsWithChildren } from "react";
|
|
|
|
import { Button, Stack, Text, Title } from "@mantine/core";
|
|
import { Component } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Link, useLocation } from "react-router";
|
|
|
|
import { useAuth } from "@/features/auth";
|
|
import { useAppDocumentTitle } from "@/shared/ui";
|
|
|
|
type BoundaryProps = PropsWithChildren<{
|
|
authenticated: boolean;
|
|
}>;
|
|
|
|
type RouteErrorFallbackProps = {
|
|
authenticated: boolean;
|
|
};
|
|
|
|
type State = { hasError: boolean };
|
|
|
|
class Boundary extends Component<BoundaryProps, State> {
|
|
static getDerivedStateFromError(): State {
|
|
return { hasError: true };
|
|
}
|
|
|
|
override state: State = { hasError: false };
|
|
|
|
override render() {
|
|
return this.state.hasError
|
|
? <RouteErrorFallback authenticated={this.props.authenticated} />
|
|
: (
|
|
this.props.children
|
|
);
|
|
}
|
|
}
|
|
|
|
const RouteErrorFallback: FC<RouteErrorFallbackProps> = (props) => {
|
|
const { authenticated } = props;
|
|
const { t } = useTranslation();
|
|
useAppDocumentTitle(t("routeError.title"));
|
|
const to = authenticated ? "/accounts" : "/login";
|
|
|
|
return (
|
|
<Stack>
|
|
<Title order={1}>{t("routeError.title")}</Title>
|
|
|
|
<Text>{t("routeError.text")}</Text>
|
|
|
|
<Button component={Link} to={to}>
|
|
{t("routeError.action")}
|
|
</Button>
|
|
|
|
<Button component="a" href={to} variant="default">
|
|
{t("routeError.reload")}
|
|
</Button>
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
const RouteErrorBoundary: FC<PropsWithChildren> = (props) => {
|
|
const { children } = props;
|
|
const { key, pathname, search } = useLocation();
|
|
const { user } = useAuth();
|
|
|
|
return (
|
|
<Boundary authenticated={Boolean(user)} key={`${pathname}${search}:${key}`}>
|
|
{children}
|
|
</Boundary>
|
|
);
|
|
};
|
|
|
|
export { RouteErrorBoundary };
|