import React, { Component, ErrorInfo, ReactNode } from 'react';
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error?: Error;
errorInfo?: ErrorInfo;
}
class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.setState({
error,
errorInfo
});
// Log error to monitoring service
console.error('Error caught by boundary:', error, errorInfo);
// In production, you would send this to your error tracking service
// Example: Sentry.captureException(error, { extra: errorInfo });
}
handleRetry = () => {
this.setState({ hasError: false, error: undefined, errorInfo: undefined });
};
handleGoHome = () => {
window.location.href = '/';
};
render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div className="min-h-screen bg-gradient-to-br from-primary-50 via-white to-secondary-50 flex items-center justify-center p-4">
<div className="max-w-md w-full bg-white rounded-xl shadow-lg border border-gray-200 p-8 text-center">
<div className="mb-6">
<div className="bg-red-100 p-4 rounded-full w-20 h-20 flex items-center justify-center mx-auto mb-4">
<AlertTriangle className="h-10 w-10 text-red-500" />
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Oops! Something went wrong
</h2>
<p className="text-gray-600">
We're sorry, but something unexpected happened. Our team has been notified.
</p>
</div>
{process.env.NODE_ENV === 'development' && this.state.error && (
<div className="mb-6 p-4 bg-gray-100 rounded-lg text-left">
<h3 className="font-semibold text-gray-900 mb-2">Error Details:</h3>
<pre className="text-xs text-gray-700 overflow-auto max-h-32">
{this.state.error.toString()}
{this.state.errorInfo?.componentStack}
</pre>
</div>
)}
<div className="flex flex-col sm:flex-row gap-3">
<button
onClick={this.handleRetry}
className="flex-1 bg-gradient-to-r from-primary-500 to-secondary-500 text-white px-6 py-3 rounded-lg hover:from-primary-600 hover:to-secondary-600 transition-all duration-200 font-medium flex items-center justify-center space-x-2"
>
<RefreshCw className="h-4 w-4" />
<span>Try Again</span>
</button>
<button
onClick={this.handleGoHome}
className="flex-1 border border-gray-300 text-gray-700 px-6 py-3 rounded-lg hover:bg-gray-50 transition-all duration-200 font-medium flex items-center justify-center space-x-2"
>
<Home className="h-4 w-4" />
<span>Go Home</span>
</button>
</div>
<div className="mt-6 text-sm text-gray-500">
<p>Error ID: {Date.now().toString(36)}</p>
<p>If this problem persists, please contact support.</p>
</div>
</div>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;