feat: add error boundaries so a crash never blanks the whole app
No error.tsx existed anywhere in the app - an uncaught render error on any page (a beekeeper's most field-critical moment: mid-inspection, no signal, nowhere to go) showed nothing recoverable, not even a message, let alone a way back to a working page. Two boundaries, matching Next.js App Router's error-boundary scoping: - (app)/error.tsx covers every authenticated page. It only replaces the crashed page's content - the sidebar/header/bottom nav stay mounted and usable, so the user can navigate to a different page without a full reload. - app/error.tsx is the outer fallback (login, the public Herkunft page, or a crash in (app)/layout.tsx itself, which only a strictly higher boundary can catch). Its "Zum Dashboard" action is a plain <a> reload rather than client-side navigation, since a crash this high may have left client state corrupted. Both are in German, matching the app's existing card/honeycomb visual language, and explicitly reassure the user that already-saved data is unaffected. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
2e6846285d
commit
8bf9aa467d
2 files changed
+90
No files matched your search
@@ -0,0 +1,42 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
||||
export default function AppError({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
console.error(error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<main className="flex flex-col gap-4 p-4 sm:p-6">
|
||||
<Card className="max-w-lg">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span className="flex size-9 items-center justify-center rounded-xl bg-destructive/10 text-destructive">
|
||||
<AlertTriangle className="size-5" />
|
||||
</span>
|
||||
<CardTitle className="text-lg">Etwas ist schiefgelaufen</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Diese Seite konnte nicht angezeigt werden. Bereits gespeicherte Daten sind davon nicht
|
||||
betroffen. Über die Navigation kommst du zu jeder anderen Seite.
|
||||
</p>
|
||||
<Button onClick={() => reset()} className="w-fit">
|
||||
Erneut versuchen
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { HoneycombPattern } from "@/components/honeycomb-pattern";
|
||||
|
||||
export default function RootError({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
console.error(error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<main className="relative flex min-h-screen items-center justify-center overflow-hidden bg-background p-4">
|
||||
<HoneycombPattern />
|
||||
<Card className="relative w-full max-w-md shadow-[var(--shadow-elevated)]">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span className="flex size-9 items-center justify-center rounded-xl bg-destructive/10 text-destructive">
|
||||
<AlertTriangle className="size-5" />
|
||||
</span>
|
||||
<CardTitle className="text-lg">Etwas ist schiefgelaufen</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Es ist ein unerwarteter Fehler aufgetreten. Bereits gespeicherte Daten sind davon nicht
|
||||
betroffen.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button onClick={() => reset()}>Erneut versuchen</Button>
|
||||
{/* Plain reload, not client-side navigation - a crash here may
|
||||
have left the app's client state corrupted, so this must
|
||||
guarantee a fully clean slate rather than route through it. */}
|
||||
<Button variant="outline" render={<a href="/dashboard">Zum Dashboard</a>} />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user