'use client'; import { useState, useEffect } from 'react'; import { ApiConnectionMonitor, ConnectionStatus } from '@/lib/api/base/ApiConnectionMonitor'; import { CircuitBreakerRegistry } from '@/lib/api/base/RetryHandler'; import { Activity, Wifi, WifiOff, AlertTriangle, CheckCircle2, RefreshCw, Terminal, Shield, Clock, TrendingUp } from 'lucide-react'; interface ApiStatusToolbarProps { position?: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left'; autoHide?: boolean; } /** * Development toolbar showing real-time API connection status * Integrates with existing DevToolbar or works standalone */ export function ApiStatusToolbar({ position = 'bottom-right', autoHide = false }: ApiStatusToolbarProps) { const [status, setStatus] = useState('disconnected'); const [health, setHealth] = useState(ApiConnectionMonitor.getInstance().getHealth()); const [expanded, setExpanded] = useState(false); const [show, setShow] = useState(true); useEffect(() => { const monitor = ApiConnectionMonitor.getInstance(); const registry = CircuitBreakerRegistry.getInstance(); const updateState = () => { setStatus(monitor.getStatus()); setHealth(monitor.getHealth()); }; // Initial state updateState(); // Listen for events monitor.on('connected', updateState); monitor.on('disconnected', updateState); monitor.on('degraded', updateState); monitor.on('success', updateState); monitor.on('failure', updateState); // Auto-hide logic if (autoHide) { const hideTimer = setTimeout(() => setShow(false), 5000); const showOnInteraction = () => setShow(true); document.addEventListener('mousemove', showOnInteraction); document.addEventListener('click', showOnInteraction); return () => { clearTimeout(hideTimer); document.removeEventListener('mousemove', showOnInteraction); document.removeEventListener('click', showOnInteraction); monitor.off('connected', updateState); monitor.off('disconnected', updateState); monitor.off('degraded', updateState); monitor.off('success', updateState); monitor.off('failure', updateState); }; } return () => { monitor.off('connected', updateState); monitor.off('disconnected', updateState); monitor.off('degraded', updateState); monitor.off('success', updateState); monitor.off('failure', updateState); }; }, [autoHide]); const handleHealthCheck = async () => { const monitor = ApiConnectionMonitor.getInstance(); await monitor.performHealthCheck(); }; const handleReset = () => { ApiConnectionMonitor.getInstance().reset(); CircuitBreakerRegistry.getInstance().resetAll(); }; const getReliabilityColor = (reliability: number) => { if (reliability >= 95) return 'text-green-400'; if (reliability >= 80) return 'text-yellow-400'; return 'text-red-400'; }; const getStatusIcon = () => { switch (status) { case 'connected': return ; case 'degraded': return ; case 'disconnected': return ; case 'checking': return ; default: return ; } }; const getStatusColor = () => { switch (status) { case 'connected': return 'bg-green-500/20 border-green-500/40'; case 'degraded': return 'bg-yellow-500/20 border-yellow-500/40'; case 'disconnected': return 'bg-red-500/20 border-red-500/40'; default: return 'bg-gray-500/20 border-gray-500/40'; } }; const reliability = ((health.successfulRequests / Math.max(health.totalRequests, 1)) * 100).toFixed(1); if (!show) { return ( ); } return (
{/* Compact Status Indicator */} {!expanded ? ( ) : ( /* Expanded Panel */
{/* Header */}
API STATUS
{/* Body */}
{/* Status Row */}
Status {status}
{/* Reliability */}
Reliability {reliability}%
{/* Request Stats */}
Total
{health.totalRequests}
Success
{health.successfulRequests}
Failed
{health.failedRequests}
{/* Performance */}
Avg Response {health.averageResponseTime.toFixed(0)}ms
{/* Consecutive Failures */} {health.consecutiveFailures > 0 && (
Consecutive Failures {health.consecutiveFailures}
)} {/* Circuit Breakers */}
CIRCUIT BREAKERS
{/* Last Check */}
Last Check {health.lastCheck ? new Date(health.lastCheck).toLocaleTimeString() : 'Never'}
{/* Actions */}
)}
); } /** * Circuit Breaker Status Component */ function CircuitBreakerStatus() { const [status, setStatus] = useState(CircuitBreakerRegistry.getInstance().getStatus()); useEffect(() => { const registry = CircuitBreakerRegistry.getInstance(); // Poll for updates every 2 seconds const interval = setInterval(() => { setStatus(registry.getStatus()); }, 2000); return () => clearInterval(interval); }, []); const entries = Object.entries(status); if (entries.length === 0) { return (
No active circuit breakers
); } return (
{entries.map(([endpoint, breaker]) => (
{endpoint.split('/').pop() || endpoint} {breaker.state} {breaker.failures > 0 && ( ({breaker.failures}) )}
))}
); }