'use client'; import React, { Component, ReactNode } from 'react'; import { Box, Button, Typography, Paper, Alert } from '@mui/material'; import { ErrorOutline, Refresh, Home } from '@mui/icons-material'; import errorLogger, { ErrorSeverity } from '@/lib/services/errorLogger'; interface Props { children: ReactNode; fallback?: ReactNode; onError?: (error: Error, errorInfo: React.ErrorInfo) => void; isolate?: boolean; // If true, only this section fails, not the whole app } interface State { hasError: boolean; error: Error | null; errorInfo: React.ErrorInfo | null; errorCount: number; } /** * Error Boundary component that catches JavaScript errors in child components * Displays fallback UI and logs errors for monitoring */ export class ErrorBoundary extends Component { constructor(props: Props) { super(props); this.state = { hasError: false, error: null, errorInfo: null, errorCount: 0, }; } static getDerivedStateFromError(error: Error): Partial { // Update state so the next render will show the fallback UI return { hasError: true, error, }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { // Log error to console in development if (process.env.NODE_ENV === 'development') { console.error('ErrorBoundary caught an error:', error, errorInfo); } // Update state with error details this.setState((prevState) => ({ errorInfo, errorCount: prevState.errorCount + 1, })); // Call custom error handler if provided if (this.props.onError) { this.props.onError(error, errorInfo); } // Log to error tracking service (e.g., Sentry) this.logErrorToService(error, errorInfo); } logErrorToService = (error: Error, errorInfo: React.ErrorInfo) => { // Log to error tracking service errorLogger.logError( error, { componentStack: errorInfo.componentStack, errorBoundary: this.props.isolate ? 'isolated' : 'global', }, ErrorSeverity.ERROR ); }; handleReset = () => { this.setState({ hasError: false, error: null, errorInfo: null, }); }; handleGoHome = () => { window.location.href = '/'; }; render() { if (this.state.hasError) { // Custom fallback UI if provided if (this.props.fallback) { return this.props.fallback; } // Default fallback UI return ( Oops! Something went wrong {this.props.isolate ? 'This section encountered an error. The rest of the app should still work.' : "We're sorry for the inconvenience. The error has been logged and we'll look into it."} {process.env.NODE_ENV === 'development' && this.state.error && ( {this.state.error.message} {this.state.error.stack} )} {!this.props.isolate && ( )} {this.state.errorCount > 1 && ( This error has occurred {this.state.errorCount} times. You may want to refresh the entire page or contact support. )} ); } return this.props.children; } } /** * Hook-based error boundary (for functional components) * Note: This is a workaround since React doesn't have hook-based error boundaries yet */ export function useErrorHandler(error?: Error) { const [, setError] = React.useState(); return React.useCallback( (error: Error) => { setError(() => { throw error; }); }, [setError] ); }