Create error boundary for unauthenticated zone

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-03-14 12:14:34 +04:00
parent ac7fa6edb3
commit b3751636b2
2 changed files with 282 additions and 229 deletions

View File

@@ -11,6 +11,7 @@ import ErrorBoundary from "./components/ErrorBoundary";
import ConsoleLayout from "./layouts/ConsoleLayout"; import ConsoleLayout from "./layouts/ConsoleLayout";
import AuthLayout from "./layouts/AuthLayout"; import AuthLayout from "./layouts/AuthLayout";
import { RelayEnvironment } from "./RelayEnvironment"; import { RelayEnvironment } from "./RelayEnvironment";
import VisitorErrorBoundary from "./components/VisitorErrorBoundary";
posthog.init(process.env.POSTHOG_KEY!, { posthog.init(process.env.POSTHOG_KEY!, {
api_host: process.env.POSTHOG_HOST, api_host: process.env.POSTHOG_HOST,
@@ -57,7 +58,6 @@ const UpdatePolicyPage = lazy(() => import("./pages/UpdatePolicyPage"));
function App() { function App() {
return ( return (
<StrictMode> <StrictMode>
<ErrorBoundary key={location.pathname}>
<PostHogProvider client={posthog}> <PostHogProvider client={posthog}>
<RelayEnvironmentProvider environment={RelayEnvironment}> <RelayEnvironmentProvider environment={RelayEnvironment}>
<HelmetProvider> <HelmetProvider>
@@ -75,8 +75,7 @@ function App() {
} }
/> />
<Route path="*" element={<ConsoleLayout />}> <Route path="organizations" element={<ConsoleLayout />}>
<Route path="organizations">
<Route <Route
path="create" path="create"
element={ element={
@@ -271,23 +270,16 @@ function App() {
/> />
</Route> </Route>
</Route> </Route>
</Route>
{/* Authentication Routes - Accessible without login */} {/* Authentication Routes - Accessible without login */}
<Route <Route element={<AuthLayout />}>
element={
<ErrorBoundaryWithLocation>
<AuthLayout />
</ErrorBoundaryWithLocation>
}
>
<Route <Route
path="login" path="login"
element={ element={
<Suspense> <Suspense>
<ErrorBoundaryWithLocation> <VisitorErrorBoundaryWithLocation>
<LoginPage /> <LoginPage />
</ErrorBoundaryWithLocation> </VisitorErrorBoundaryWithLocation>
</Suspense> </Suspense>
} }
/> />
@@ -295,9 +287,9 @@ function App() {
path="register" path="register"
element={ element={
<Suspense> <Suspense>
<ErrorBoundaryWithLocation> <VisitorErrorBoundaryWithLocation>
<RegisterPage /> <RegisterPage />
</ErrorBoundaryWithLocation> </VisitorErrorBoundaryWithLocation>
</Suspense> </Suspense>
} }
/> />
@@ -305,15 +297,16 @@ function App() {
path="confirm-email" path="confirm-email"
element={ element={
<Suspense> <Suspense>
<ErrorBoundaryWithLocation> <VisitorErrorBoundaryWithLocation>
<ConfirmEmailPage /> <ConfirmEmailPage />
</ErrorBoundaryWithLocation> </VisitorErrorBoundaryWithLocation>
</Suspense> </Suspense>
} }
/> />
</Route> </Route>
<Route <Route
path="*"
element={ element={
<Suspense> <Suspense>
<NotFoundPage /> <NotFoundPage />
@@ -326,7 +319,6 @@ function App() {
</HelmetProvider> </HelmetProvider>
</RelayEnvironmentProvider> </RelayEnvironmentProvider>
</PostHogProvider> </PostHogProvider>
</ErrorBoundary>
</StrictMode> </StrictMode>
); );
} }
@@ -340,6 +332,19 @@ function ErrorBoundaryWithLocation({
return <ErrorBoundary key={location.pathname}>{children}</ErrorBoundary>; return <ErrorBoundary key={location.pathname}>{children}</ErrorBoundary>;
} }
function VisitorErrorBoundaryWithLocation({
children,
}: {
children: React.ReactNode;
}) {
const location = useLocation();
return (
<VisitorErrorBoundary key={location.pathname}>
{children}
</VisitorErrorBoundary>
);
}
const container = document.getElementById("root"); const container = document.getElementById("root");
const root = createRoot(container!); const root = createRoot(container!);
root.render(<App />); root.render(<App />);

View File

@@ -0,0 +1,48 @@
import { Component, ErrorInfo, ReactNode } from "react";
import { ErrorPage } from "@/pages/ErrorPage";
import { UnAuthenticatedError } from "@/RelayEnvironment";
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
}
class VisitorErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
if (error instanceof UnAuthenticatedError) {
return { hasError: false, error: undefined };
}
return { hasError: true, error };
}
componentDidCatch(error: Error, info: ErrorInfo): void {
console.error("ErrorBoundary caught an error:", error);
console.error("Error info:", info.componentStack);
}
render(): ReactNode {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return <ErrorPage error={this.state.error} />;
}
return this.props.children;
}
}
export default VisitorErrorBoundary;