mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 09:11:13 -05:00
feat: Implement network status banner
This commit is contained in:
83
src/components/ui/network-status-banner.tsx
Normal file
83
src/components/ui/network-status-banner.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { XCircle, Loader2 } from 'lucide-react';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { useCircuitBreakerStatus } from '@/hooks/useCircuitBreakerStatus';
|
||||
import { CircuitState } from '@/lib/circuitBreaker';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export function NetworkStatusBanner() {
|
||||
const { state, failureCount, isOpen, isHalfOpen } = useCircuitBreakerStatus();
|
||||
const [countdown, setCountdown] = useState(60);
|
||||
|
||||
// Countdown for next retry attempt (when OPEN)
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
|
||||
setCountdown(60); // Reset timeout from circuit breaker config
|
||||
const interval = setInterval(() => {
|
||||
setCountdown(prev => Math.max(0, prev - 1));
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [isOpen]);
|
||||
|
||||
// Don't show if circuit is closed
|
||||
if (state === CircuitState.CLOSED) return null;
|
||||
|
||||
// OPEN state - critical error
|
||||
if (isOpen) {
|
||||
return (
|
||||
<Alert
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
variant="destructive"
|
||||
className={cn(
|
||||
"rounded-none border-x-0 border-t-0",
|
||||
"animate-in slide-in-from-top-4 duration-300",
|
||||
"bg-destructive/90 backdrop-blur-sm"
|
||||
)}
|
||||
>
|
||||
<XCircle className="h-5 w-5 animate-pulse" />
|
||||
<AlertTitle className="font-semibold text-lg">
|
||||
Database Unavailable
|
||||
</AlertTitle>
|
||||
<AlertDescription className="text-sm mt-1">
|
||||
Our systems detected a service outage. <strong>Data and authentication are temporarily unavailable.</strong>
|
||||
{' '}Retrying automatically... (next attempt in {countdown}s)
|
||||
{failureCount > 0 && (
|
||||
<span className="block mt-1 text-xs opacity-80">
|
||||
{failureCount} failed connection attempts detected
|
||||
</span>
|
||||
)}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
// HALF_OPEN state - testing recovery
|
||||
if (isHalfOpen) {
|
||||
return (
|
||||
<Alert
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
className={cn(
|
||||
"rounded-none border-x-0 border-t-0",
|
||||
"animate-in slide-in-from-top-4 duration-300",
|
||||
"bg-amber-500/20 dark:bg-amber-500/30 border-amber-500"
|
||||
)}
|
||||
>
|
||||
<Loader2 className="h-5 w-5 animate-spin text-amber-600 dark:text-amber-400" />
|
||||
<AlertTitle className="font-semibold text-amber-900 dark:text-amber-100">
|
||||
Connection Unstable
|
||||
</AlertTitle>
|
||||
<AlertDescription className="text-sm text-amber-800 dark:text-amber-200 mt-1">
|
||||
Testing database connection... Some features may be slow or temporarily unavailable.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user