// components/dashboard/DashboardClient.tsx 'use client'; import { useEffect, useState } from 'react'; import { UsersIcon, ServerIcon, ActivityIcon, MapPinIcon, FlagIcon, LiveDotIcon, ClockIcon } from '@/components/ui/icons'; import { cleanTrackName, cleanTrackConfig } from '@/lib/trackUtils'; interface Driver { driver_guid: string; driver_name: string; driver_team: string; car_model: string; car_skin: string; laps_completed: number; user_rank: number; server: { server_id: number; server_name: string; server_track: string; server_config: string; session_type: number; session_flag: string; session_time: number; session_laps: number; session_elapsed_time: number; session_ambient_temp: number; session_road_temp: number; connected_players: number; }; } function getSessionTypeName(type: number): string { switch (type) { case 0: return 'PRACTICE'; case 1: return 'RACE'; case 2: return 'QUALIFYING'; default: return 'UNKNOWN'; } } function getSessionTypeColor(type: number): string { switch (type) { case 0: return 'border-blue-500/30 bg-blue-500/10 text-blue-400'; case 1: return 'border-red-500/30 bg-red-500/10 text-red-400'; case 2: return 'border-yellow-500/30 bg-yellow-500/10 text-yellow-400'; default: return 'border-white/20 bg-white/5 text-white/60'; } } function formatElapsedTime(ms: number): string { const totalSeconds = Math.floor(ms / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; if (hours > 0) { return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; } return `${minutes}:${String(seconds).padStart(2, '0')}`; } export default function DashboardClient({ initialDrivers }: { initialDrivers: Driver[] }) { const [drivers, setDrivers] = useState(initialDrivers); const [isLoading, setIsLoading] = useState(false); // Auto-refresh every 3 seconds useEffect(() => { const fetchData = async () => { try { setIsLoading(true); const response = await fetch('/api/dashboard'); const data = await response.json(); setDrivers(data.drivers); } catch (error) { console.error('[Dashboard] Failed to fetch data:', error); } finally { setIsLoading(false); } }; const interval = setInterval(fetchData, 3000); return () => clearInterval(interval); }, []); // Group drivers by server const serverGroups = drivers.reduce((acc, driver) => { const serverId = driver.server?.server_id ?? 0; if (!acc[serverId]) { acc[serverId] = []; } acc[serverId].push(driver); return acc; }, {} as Record); return ( <> {/* Stats Grid */}
} pulse={isLoading} /> } pulse={isLoading} /> sum + d.laps_completed, 0)} icon={} pulse={isLoading} />
{/* Server Listings */}
{Object.keys(serverGroups).length === 0 ? (

NO ACTIVE SESSIONS

System idle — waiting for connections

) : ( Object.entries(serverGroups).map(([serverId, serverDrivers]) => { const server = serverDrivers[0].server; return (
{/* Server Header */}
LIVE
ID: {server?.server_id}

{server?.server_name}

{cleanTrackName(server?.server_track || '')} {server?.server_config && ` - ${cleanTrackConfig(server.server_config)}`}
{server?.session_flag}
{server?.connected_players} CONNECTED
{/* Session Info Badge */}
{getSessionTypeName(server?.session_type || 0)}
{formatElapsedTime(server?.session_elapsed_time || 0)}
{/* Driver Table */}
{serverDrivers.map((driver, index) => ( ))}
POS DRIVER TEAM CAR RANK LAPS
{String(index + 1).padStart(2, '0')} {driver.driver_name} {driver.driver_team || '—'} {driver.car_model} {driver.user_rank} {driver.laps_completed}
); }) )}
); } function StatCard({ title, value, icon, pulse }: { title: string; value: number; icon: React.ReactNode; pulse?: boolean; }) { return (
{title}
{icon}
{value.toLocaleString()}
); }