// components/live/LiveTiming.tsx 'use client'; import { BoltIcon, TrophyIcon } from '@/components/ui/icons'; interface TimingEntry { position: number; carID: number; driver_name: string; car_model: string; current_lap: number; last_lap_time: number | null; best_lap_time: number | null; gap_to_leader: string; avg_lap_time: number | null; user_rank?: number | null; // Driver's position in rankings (1st, 2nd, etc.) user_rating?: number | null; // Driver's rating score (ELO-style) } interface LiveTimingProps { entries: TimingEntry[]; } export default function LiveTiming({ entries }: LiveTimingProps) { // Format lap time from milliseconds const formatLapTime = (ms: number | null) => { if (!ms || ms === 0) return '--:--.---'; const minutes = Math.floor(ms / 60000); const seconds = Math.floor((ms % 60000) / 1000); const milliseconds = ms % 1000; return `${minutes}:${String(seconds).padStart(2, '0')}.${String(milliseconds).padStart(3, '0')}`; }; // Format position with fallback const formatPosition = (position: number | null | undefined) => { if (!position || position === 0) return '--'; return String(position).padStart(2, '0'); }; // Format lap count with fallback const formatLapCount = (laps: number | null | undefined) => { if (!laps || laps === 0) return '--'; return laps; }; // Get position color const getPositionColor = (position: number) => { if (!position || position === 0) return 'text-white/40 border-white/10'; if (position === 1) return 'text-white border-white'; if (position === 2) return 'text-white/90 border-white/70'; if (position === 3) return 'text-white/80 border-white/50'; return 'text-white/60 border-white/20'; }; // Get rank badge color const getRankColor = (rank: number | null | undefined) => { if (!rank) return 'bg-white/10 text-white/40'; if (rank <= 10) return 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'; if (rank <= 50) return 'bg-blue-500/20 text-blue-400 border-blue-500/30'; if (rank <= 100) return 'bg-green-500/20 text-green-400 border-green-500/30'; return 'bg-white/10 text-white/60 border-white/20'; }; return (
{/* Header */}
POS
DRIVER
LAP
LAST LAP
BEST
{/* Timing Entries */}
{entries.map((entry) => { const isLeader = entry.position === 1; const isFastestLap = entries.length > 0 && entry.best_lap_time && entry.best_lap_time > 0 && entry.best_lap_time === Math.min(...entries.filter(e => e.best_lap_time && e.best_lap_time > 0).map(e => e.best_lap_time!)); return (
{/* Position */}
{formatPosition(entry.position)}
{/* Driver Info */}
{entry.driver_name} {entry.user_rank && (
#{entry.user_rank} {entry.user_rating && ( {entry.user_rating} )}
)}
{entry.car_model}
{/* Current Lap */}
{formatLapCount(entry.current_lap)}
{/* Last Lap Time */}
{formatLapTime(entry.last_lap_time)}
{entry.avg_lap_time && entry.avg_lap_time > 0 && (
Avg: {formatLapTime(entry.avg_lap_time)}
)}
{/* Best Lap Time */}
{formatLapTime(entry.best_lap_time)} {isFastestLap && ( )}
); })}
{/* Legend */}
Fastest lap overall
#1-10 Top 10 ranked driver
Times updated in real-time from server telemetry
-- indicates driver has not started or is in pits
); }