import React from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { AlertTriangle, RefreshCw, Home, Bug, Wifi, WifiOff, Copy, ExternalLink } from 'lucide-react' interface GlobalErrorBoundaryState { hasError: boolean error?: Error errorInfo?: React.ErrorInfo errorId?: string retryCount: number } interface GlobalErrorBoundaryProps { children: React.ReactNode fallback?: React.ReactNode onError?: (error: Error, errorInfo: React.ErrorInfo) => void } export class GlobalErrorBoundary extends React.Component { private retryTimeout?: NodeJS.Timeout constructor(props: GlobalErrorBoundaryProps) { super(props) this.state = { hasError: false, retryCount: 0 } } static getDerivedStateFromError(error: Error): Partial { const errorId = `error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` return { hasError: true, error, errorId } } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { console.error('🚨 Global Error Boundary caught an error:', error, errorInfo) // Generate detailed error report const errorReport = { timestamp: new Date().toISOString(), errorId: this.state.errorId, message: error.message, stack: error.stack, componentStack: errorInfo.componentStack, userAgent: navigator.userAgent, url: window.location.href, retryCount: this.state.retryCount, memoryUsage: (performance as any).memory ? { usedJSHeapSize: (performance as any).memory.usedJSHeapSize, totalJSHeapSize: (performance as any).memory.totalJSHeapSize, jsHeapSizeLimit: (performance as any).memory.jsHeapSizeLimit } : 'unavailable' } console.error('📊 Error Report:', errorReport) // Store error report in localStorage for debugging try { const existingReports = JSON.parse(localStorage.getItem('error-reports') || '[]') existingReports.unshift(errorReport) // Keep only last 10 error reports localStorage.setItem('error-reports', JSON.stringify(existingReports.slice(0, 10))) } catch (e) { console.warn('Could not save error report to localStorage:', e) } this.setState({ error, errorInfo }) // Call onError callback if provided this.props.onError?.(error, errorInfo) } handleRetry = () => { const newRetryCount = this.state.retryCount + 1 if (newRetryCount > 3) { console.warn('⚠️ Maximum retry attempts reached') return } console.log(`🔄 Retrying error recovery (attempt ${newRetryCount})`) this.setState({ hasError: false, error: undefined, errorInfo: undefined, retryCount: newRetryCount }) // Auto-retry with exponential backoff for certain errors if (this.shouldAutoRetry()) { this.retryTimeout = setTimeout(() => { this.handleRetry() }, Math.pow(2, newRetryCount) * 1000) } } shouldAutoRetry = (): boolean => { if (!this.state.error) return false const retryableErrors = [ 'Network Error', 'ChunkLoadError', 'Loading chunk', 'Failed to fetch' ] return retryableErrors.some(pattern => this.state.error!.message.includes(pattern) ) } handleGoHome = () => { window.location.href = '/' } handleRefreshPage = () => { window.location.reload() } handleCopyError = async () => { const errorText = `Error ID: ${this.state.errorId} Timestamp: ${new Date().toISOString()} Message: ${this.state.error?.message} Stack: ${this.state.error?.stack} Component Stack: ${this.state.errorInfo?.componentStack}` try { await navigator.clipboard.writeText(errorText) console.log('✅ Error details copied to clipboard') } catch (e) { console.warn('Could not copy to clipboard:', e) } } handleReportBug = () => { const title = encodeURIComponent(`Error: ${this.state.error?.message || 'Unknown Error'}`) const body = encodeURIComponent(`**Error ID:** ${this.state.errorId} **Timestamp:** ${new Date().toISOString()} **Message:** ${this.state.error?.message} **URL:** ${window.location.href} **User Agent:** ${navigator.userAgent} **Stack Trace:** \`\`\` ${this.state.error?.stack} \`\`\` **Component Stack:** \`\`\` ${this.state.errorInfo?.componentStack} \`\`\``) const url = `https://github.com/endlessblink/Like-I-Said-memory-mcp-server/issues/new?title=${title}&body=${body}&labels=bug,error-boundary` window.open(url, '_blank') } componentWillUnmount() { if (this.retryTimeout) { clearTimeout(this.retryTimeout) } } render() { if (this.state.hasError) { if (this.props.fallback) { return this.props.fallback } const isNetworkError = this.state.error?.message.includes('Network') || this.state.error?.message.includes('fetch') return (
Application Error
Error ID: {this.state.errorId} {isNetworkError && ( Network Issue )}

Something went wrong and the application couldn't recover automatically.

{isNetworkError ? "This appears to be a network connectivity issue. Please check your internet connection." : "This might be due to a temporary issue or a bug in the application." }

{this.state.error && (
Error Details:
{this.state.error.message}
)}

If this error persists, please report it to help us improve the application.

Retry Count: {this.state.retryCount} | Time: {new Date().toLocaleTimeString()}
Like-I-Said Memory MCP Server | Error Boundary v1.0
) } return this.props.children } }