45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import { Component } from 'react';
|
|
import type { ErrorInfo, ReactNode } from 'react';
|
|
import * as Sentry from '@sentry/react';
|
|
|
|
interface ErrorBoundaryProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
interface ErrorBoundaryState {
|
|
hasError: boolean;
|
|
}
|
|
|
|
/**
|
|
* Top-level, on-brand error boundary (NFR Design resilience pattern; SECURITY-09/SECURITY-15).
|
|
* Shows a generic, themed fallback message — never technical details like stack traces.
|
|
*/
|
|
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
state: ErrorBoundaryState = { hasError: false };
|
|
|
|
static getDerivedStateFromError(): ErrorBoundaryState {
|
|
return { hasError: true };
|
|
}
|
|
|
|
componentDidCatch(error: Error, info: ErrorInfo): void {
|
|
console.error('Unexpected application error', error, info);
|
|
Sentry.captureException(error, { extra: { componentStack: info.componentStack } });
|
|
}
|
|
|
|
render(): ReactNode {
|
|
if (this.state.hasError) {
|
|
return (
|
|
<div
|
|
className="theme-red flex min-h-screen items-center justify-center bg-bg px-6 text-center text-text"
|
|
role="alert"
|
|
data-testid="error-boundary-fallback"
|
|
>
|
|
<p className="font-display text-lg">Er ging iets mis. Probeer de pagina te vernieuwen.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return this.props.children;
|
|
}
|
|
}
|