Files
edr-platform/apps/edr-freight-web/backoffice/src/components/ErrorBoundary.tsx
2026-07-16 08:52:29 +00:00

103 lines
2.8 KiB
TypeScript

import { Component, type ErrorInfo, type ReactNode } from "react";
import { captureException } from "@/lib/posthog";
interface ErrorBoundaryProps {
children: ReactNode;
}
interface ErrorBoundaryState {
error: Error | null;
}
/**
* App-wide error boundary. Without this, any render-time exception unmounts the
* React tree and the user sees a blank white screen. This surfaces the actual
* error message + stack so failures are diagnosable in place.
*/
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
state: ErrorBoundaryState = { error: null };
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
captureException(error, { componentStack: info.componentStack });
// eslint-disable-next-line no-console
console.error("[ErrorBoundary] Uncaught render error:", error, info.componentStack);
}
handleReset = () => this.setState({ error: null });
render() {
const { error } = this.state;
if (!error) return this.props.children;
return (
<div
style={{
minHeight: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: 24,
background: "#f8fafc",
fontFamily: "system-ui, sans-serif",
}}
>
<div
style={{
maxWidth: 720,
width: "100%",
background: "#fff",
border: "1px solid #fecaca",
borderRadius: 12,
padding: 24,
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
}}
>
<h2 style={{ margin: 0, color: "#b91c1c", fontSize: 18 }}>Something went wrong</h2>
<p style={{ color: "#64748b", fontSize: 14 }}>
A render error was caught. Details below share this with the developer.
</p>
<pre
style={{
whiteSpace: "pre-wrap",
wordBreak: "break-word",
background: "#0f172a",
color: "#fca5a5",
padding: 16,
borderRadius: 8,
fontSize: 12,
maxHeight: 320,
overflow: "auto",
}}
>
{error.message}
{"\n\n"}
{error.stack}
</pre>
<button
type="button"
onClick={this.handleReset}
style={{
marginTop: 12,
padding: "8px 16px",
border: "none",
borderRadius: 8,
background: "#0f766e",
color: "#fff",
cursor: "pointer",
fontSize: 14,
}}
>
Dismiss
</button>
</div>
</div>
);
}
}