siftlode/frontend/src/components/ErrorBoundary.tsx

49 lines
1.3 KiB
TypeScript
Raw Normal View History

import { Component, type ReactNode } from "react";
import { notify } from "../lib/notifications";
interface Props {
children: ReactNode;
}
interface State {
crashed: boolean;
}
// Catches render-time crashes anywhere in the tree, logs a fatal notification (kept
// in the center across the reload) and offers a recovery action.
export default class ErrorBoundary extends Component<Props, State> {
state: State = { crashed: false };
static getDerivedStateFromError(): State {
return { crashed: true };
}
componentDidCatch(error: Error) {
notify({
level: "fatal",
title: "Something broke",
message: error.message || "Unexpected error",
requiresInteraction: true,
});
}
render() {
if (this.state.crashed) {
return (
<div className="min-h-screen grid place-items-center text-muted p-6 text-center">
<div>
<div className="text-lg font-semibold text-fg mb-1">Something went wrong.</div>
<div className="text-sm mb-3">The app hit an unexpected error.</div>
<button
onClick={() => location.reload()}
className="text-accent hover:underline text-sm font-semibold"
>
Reload
</button>
</div>
</div>
);
}
return this.props.children;
}
}