fix+upstream: hooks-order crash, ConfirmDialog/PageHeader/skeletons, styled error boundary
Hoists hooks above early return (render-time Navigate); ports finance's ConfirmDialog/PageHeader/loading/states + APC error-copy mapper; removes window.confirm, dead appbar search, and seeded fake notifications; wires toasts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
66
app/root.tsx
66
app/root.tsx
@@ -6,10 +6,14 @@ import {
|
||||
ScrollRestoration,
|
||||
isRouteErrorResponse,
|
||||
} from "react-router"
|
||||
import { AlertTriangle, Home, RotateCcw } from "lucide-react"
|
||||
|
||||
import type { Route } from "./+types/root"
|
||||
import "./app.css"
|
||||
|
||||
import { humanErrorMessage, humanErrorTitle } from "~/lib/errors"
|
||||
import { Button, buttonVariants } from "~/components/ui/button"
|
||||
|
||||
import { ToastProvider } from "@crema/notification-ui"
|
||||
import { CommandBusProvider } from "@crema/action-bus"
|
||||
// CREMA:PROVIDERS-IMPORTS
|
||||
@@ -50,30 +54,48 @@ export default function App() {
|
||||
}
|
||||
|
||||
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
||||
let message = "Oops!"
|
||||
let details = "An unexpected error occurred."
|
||||
let stack: string | undefined
|
||||
|
||||
if (isRouteErrorResponse(error)) {
|
||||
message = error.status === 404 ? "404" : "Error"
|
||||
details =
|
||||
error.status === 404
|
||||
? "The requested page could not be found."
|
||||
: error.statusText || details
|
||||
} else if (import.meta.env.DEV && error && error instanceof Error) {
|
||||
details = error.message
|
||||
stack = error.stack
|
||||
}
|
||||
const title = humanErrorTitle(error)
|
||||
const message = humanErrorMessage(error)
|
||||
const is404 = isRouteErrorResponse(error) && error.status === 404
|
||||
// Stack traces are a developer affordance — never leak them to users in
|
||||
// production, and even in dev keep them tucked below the human copy.
|
||||
const stack =
|
||||
import.meta.env.DEV && error instanceof Error ? error.stack : undefined
|
||||
|
||||
return (
|
||||
<main className="container mx-auto p-4 pt-16">
|
||||
<h1>{message}</h1>
|
||||
<p>{details}</p>
|
||||
{stack && (
|
||||
<pre className="w-full overflow-x-auto p-4">
|
||||
<code>{stack}</code>
|
||||
</pre>
|
||||
)}
|
||||
<main className="flex min-h-svh items-center justify-center bg-background p-6">
|
||||
<div className="w-full max-w-md rounded-2xl border bg-card p-8 text-center shadow-e1">
|
||||
<div className="mx-auto mb-5 flex size-12 items-center justify-center rounded-2xl bg-destructive/10 text-destructive">
|
||||
<AlertTriangle className="size-6" />
|
||||
</div>
|
||||
<h1 className="text-title font-semibold tracking-tight text-card-foreground">
|
||||
{is404 ? "Page not found" : title}
|
||||
</h1>
|
||||
<p className="mx-auto mt-2 max-w-sm text-[15px] leading-relaxed text-muted-foreground">
|
||||
{message}
|
||||
</p>
|
||||
<div className="mt-6 flex flex-wrap items-center justify-center gap-2">
|
||||
<a
|
||||
href="/"
|
||||
data-action="error-go-home"
|
||||
className={buttonVariants({ variant: "default" })}
|
||||
>
|
||||
<Home className="size-4" /> Go home
|
||||
</a>
|
||||
<Button
|
||||
data-action="error-retry"
|
||||
variant="outline"
|
||||
onClick={() => window.location.reload()}
|
||||
>
|
||||
<RotateCcw className="size-4" /> Try again
|
||||
</Button>
|
||||
</div>
|
||||
{stack ? (
|
||||
<pre className="mt-6 max-h-64 overflow-auto rounded-lg border bg-muted/40 p-4 text-left font-mono text-xs leading-relaxed text-muted-foreground">
|
||||
<code>{stack}</code>
|
||||
</pre>
|
||||
) : null}
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user