import { Component, type ErrorInfo, type ReactNode } from "react"; import { logClient } from "./logger.js"; // Top-level React error boundary: catches a render/lifecycle crash anywhere in the // tree, reports it to the backend log store (app_logs), and shows a minimal recovery // screen instead of a white page. A booth must never be left staring at a blank // screen with no trace of why. See wiki/concepts/app-logs.md. interface State { hasError: boolean; message?: string; } export class ErrorBoundary extends Component<{ children: ReactNode }, State> { override state: State = { hasError: false }; static getDerivedStateFromError(err: Error): State { return { hasError: true, message: err.message }; } override componentDidCatch(err: Error, info: ErrorInfo): void { logClient({ level: "fatal", message: err.message || "React render error", stack: err.stack, path: typeof location !== "undefined" ? location.pathname : undefined, context: { kind: "react_error_boundary", componentStack: info.componentStack }, }); } override render(): ReactNode { if (!this.state.hasError) return this.props.children; // Intentionally un-i18n'd + dependency-free: the app tree just crashed, so we can't // assume providers (i18n/router/query) are healthy. return (

Something went wrong

The screen crashed and has been reported. Try reloading.

{this.state.message &&
{this.state.message}
}
); } }