import React, { useState, useEffect } from 'react'; import { Box, Container, Paper, Typography, Button, Stack, CircularProgress, Alert, LinearProgress, Fade, Chip, Card, CardContent, List, ListItem, ListItemIcon, ListItemText } from '@mui/material'; import { WifiOff as ConnectionIcon, Refresh as RefreshIcon, Home as HomeIcon, Settings as SettingsIcon, CheckCircle as CheckCircleIcon, Error as ErrorIcon, Schedule as ScheduleIcon, CloudQueue as CloudIcon } from '@mui/icons-material'; interface BackendConnectionErrorProps { error?: string; onRetry?: () => void; onGoHome?: () => void; } interface ConnectionAttempt { timestamp: number; success: boolean; responseTime?: number; } /** * Enhanced Backend Connection Error Component * * Shows a loading state for 2 minutes while attempting to reconnect, * then gracefully shows error if backend remains unresponsive. */ const BackendConnectionError: React.FC = ({ error = 'Backend service is not available. Please check if the server is running.', onRetry, onGoHome }) => { const [isRetrying, setIsRetrying] = useState(true); const [timeElapsed, setTimeElapsed] = useState(0); const [connectionAttempts, setConnectionAttempts] = useState([]); const [showError, setShowError] = useState(false); const MAX_RETRY_TIME = 120; // 2 minutes in seconds const RETRY_INTERVAL = 5000; // 5 seconds // Timer for elapsed time useEffect(() => { const timer = setInterval(() => { setTimeElapsed(prev => { const newTime = prev + 1; if (newTime >= MAX_RETRY_TIME) { setIsRetrying(false); setShowError(true); return MAX_RETRY_TIME; } return newTime; }); }, 1000); return () => clearInterval(timer); }, []); // Retry attempts useEffect(() => { if (!isRetrying) return; const retryTimer = setInterval(async () => { const startTime = Date.now(); try { // Try to connect to a simple health check endpoint with short timeout const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 2000); // 2 second timeout const response = await fetch('/health', { method: 'GET', signal: controller.signal }); clearTimeout(timeoutId); const responseTime = Date.now() - startTime; setConnectionAttempts(prev => [...prev, { timestamp: Date.now(), success: response.ok, responseTime }]); if (response.ok) { // Backend is back online, trigger retry callback setIsRetrying(false); setShowError(false); if (onRetry) { onRetry(); } return; } } catch (error: any) { setConnectionAttempts(prev => [...prev, { timestamp: Date.now(), success: false, responseTime: Date.now() - startTime }]); } }, RETRY_INTERVAL); return () => clearInterval(retryTimer); }, [isRetrying, onRetry]); const progress = (timeElapsed / MAX_RETRY_TIME) * 100; const minutes = Math.floor(timeElapsed / 60); const seconds = timeElapsed % 60; const timeString = `${minutes}:${seconds.toString().padStart(2, '0')}`; const handleManualRetry = () => { setIsRetrying(true); setShowError(false); setTimeElapsed(0); setConnectionAttempts([]); }; const handleGoHome = () => { if (onGoHome) { onGoHome(); } else { window.location.href = '/'; } }; if (showError) { // Show final error state after 2 minutes return ( {/* Error Icon */} {/* Error Title */} Connection Error {/* Error Message */} {error} {/* Troubleshooting Tips */} Troubleshooting Steps {/* Action Buttons */} {/* Connection Attempts Summary */} {connectionAttempts.length > 0 && ( Connection attempts: {connectionAttempts.length} Last attempt: {connectionAttempts[connectionAttempts.length - 1]?.success ? 'Successful' : 'Failed'} )} ); } // Show loading state for first 2 minutes return ( {/* Loading Animation */} {/* Loading Title */} Connecting to Backend {/* Progress Bar */} {/* Time and Progress Info */} Attempting to reconnect... {timeString} {/* Motivational Messages */} } sx={{ maxWidth: 500, textAlign: 'center', '& .MuiAlert-message': { width: '100%', }, }} > {timeElapsed < 60 ? "We're working to restore your connection..." : "Still trying to connect. This may take a moment..." } {/* Connection Attempts */} {connectionAttempts.length > 0 && ( Connection attempts: {connectionAttempts.length} {connectionAttempts.filter(attempt => attempt.success).length} successful,{' '} {connectionAttempts.filter(attempt => !attempt.success).length} failed )} {/* Action Buttons */} {/* Help Text */} If this issue persists, please check your internet connection and ensure the backend server is running. ); }; export default BackendConnectionError;