veza/apps/web/src/components/ErrorBoundary.tsx
2025-12-12 21:34:34 -05:00

104 lines
3.2 KiB
TypeScript

import { Component, type ErrorInfo, type ReactNode } from 'react';
import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { AlertTriangle, RefreshCw } from 'lucide-react';
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error?: Error;
errorInfo?: ErrorInfo;
}
export 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 l'erreur pour le monitoring
console.error('ErrorBoundary caught an error:', error, errorInfo);
}
handleReset = () => {
this.setState({ hasError: false, error: undefined, errorInfo: undefined });
};
render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 p-4">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-red-100 dark:bg-red-900">
<AlertTriangle className="h-6 w-6 text-red-600 dark:text-red-400" />
</div>
<CardTitle className="text-xl">
Oups ! Une erreur est survenue
</CardTitle>
<CardDescription>
Une erreur inattendue s'est produite. Veuillez réessayer.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{process.env.NODE_ENV === 'development' && this.state.error && (
<div className="rounded-md bg-red-50 dark:bg-red-900 p-3">
<h4 className="text-sm font-medium text-red-800 dark:text-red-200 mb-2">
Détails de l'erreur :
</h4>
<pre className="text-xs text-red-700 dark:text-red-300 whitespace-pre-wrap">
{this.state.error.toString()}
</pre>
{this.state.errorInfo && (
<pre className="text-xs text-red-700 dark:text-red-300 whitespace-pre-wrap mt-2">
{this.state.errorInfo.componentStack}
</pre>
)}
</div>
)}
<div className="flex space-x-2">
<Button onClick={this.handleReset} className="flex-1">
<RefreshCw className="mr-2 h-4 w-4" />
Réessayer
</Button>
<Button
variant="outline"
onClick={() => (window.location.href = '/')}
className="flex-1"
>
Retour à l'accueil
</Button>
</div>
</CardContent>
</Card>
</div>
);
}
return this.props.children;
}
}