recipe-manager/frontend/src/components/ErrorBoundary.tsx

96 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Error Boundary component to catch React errors
*/
import { Component, type ReactNode } from 'react';
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: (error: Error, resetError: () => void) => ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
/**
* Error boundary that catches React errors and displays a fallback UI
*/
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = {
hasError: false,
error: null,
};
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return {
hasError: true,
error,
};
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
console.error('Error boundary caught error:', error, errorInfo);
}
resetError = (): void => {
this.setState({
hasError: false,
error: null,
});
};
render(): ReactNode {
if (this.state.hasError && this.state.error) {
if (this.props.fallback) {
return this.props.fallback(this.state.error, this.resetError);
}
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4">
<div className="max-w-md w-full bg-white rounded-lg shadow-lg p-6">
<div className="text-center mb-4">
<div className="text-6xl mb-4"></div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">Something went wrong</h2>
<p className="text-gray-600 mb-4">
An unexpected error occurred. Please try refreshing the page.
</p>
</div>
<details className="mb-4">
<summary className="cursor-pointer text-sm text-gray-600 hover:text-gray-800 font-medium">
Error details
</summary>
<pre className="mt-2 p-3 bg-gray-50 rounded text-xs text-red-600 overflow-auto">
{this.state.error.toString()}
{this.state.error.stack && `\n\n${this.state.error.stack}`}
</pre>
</details>
<div className="flex gap-3">
<button
onClick={() => window.location.reload()}
className="flex-1 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 font-medium"
>
Refresh Page
</button>
<button
onClick={this.resetError}
className="flex-1 bg-gray-200 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-300 font-medium"
>
Try Again
</button>
</div>
</div>
</div>
);
}
return this.props.children;
}
}