'use client'; import Link from 'next/link'; import { Result } from '@gridpilot/racing/domain/entities/Result'; import { Driver } from '@gridpilot/racing/domain/entities/Driver'; import type { PenaltyType } from '@gridpilot/racing/domain/entities/Penalty'; import { AlertTriangle, ExternalLink } from 'lucide-react'; /** * Penalty data for display (can be domain Penalty or RacePenaltyDTO) */ interface PenaltyData { driverId: string; type: PenaltyType; value?: number; } interface ResultsTableProps { results: Result[]; drivers: Driver[]; pointsSystem: Record; fastestLapTime?: number; penalties?: PenaltyData[]; currentDriverId?: string; } export default function ResultsTable({ results, drivers, pointsSystem, fastestLapTime, penalties = [], currentDriverId }: ResultsTableProps) { const getDriver = (driverId: string): Driver | undefined => { return drivers.find(d => d.id === driverId); }; const getDriverName = (driverId: string): string => { const driver = getDriver(driverId); return driver?.name || 'Unknown Driver'; }; const getDriverPenalties = (driverId: string): PenaltyData[] => { return penalties.filter(p => p.driverId === driverId); }; const getPenaltyDescription = (penalty: PenaltyData): string => { const descriptions: Record = { time_penalty: `+${penalty.value}s time penalty`, grid_penalty: `${penalty.value} place grid penalty`, points_deduction: `-${penalty.value} points`, disqualification: 'Disqualified', warning: 'Warning', license_points: `${penalty.value} license points`, }; return descriptions[penalty.type] || penalty.type; }; const formatLapTime = (seconds: number): string => { const minutes = Math.floor(seconds / 60); const secs = (seconds % 60).toFixed(3); return `${minutes}:${secs.padStart(6, '0')}`; }; const getPoints = (position: number): number => { return pointsSystem[position] || 0; }; const getPositionChangeColor = (change: number): string => { if (change > 0) return 'text-performance-green'; if (change < 0) return 'text-warning-amber'; return 'text-gray-500'; }; const getPositionChangeText = (change: number): string => { if (change > 0) return `+${change}`; if (change < 0) return `${change}`; return '0'; }; if (results.length === 0) { return (
No results available
); } return (
{results.map((result) => { const positionChange = result.getPositionChange(); const isFastestLap = fastestLapTime && result.fastestLap === fastestLapTime; const driverPenalties = getDriverPenalties(result.driverId); const driver = getDriver(result.driverId); const isCurrentUser = currentDriverId === result.driverId; const isPodium = result.position <= 3; return ( ); })}
Pos Driver Fastest Lap Incidents Points +/- Penalties
{result.position}
{driver ? ( <>
{driver.name.charAt(0)}
{driver.name} {isCurrentUser && ( You )} ) : ( {getDriverName(result.driverId)} )}
{formatLapTime(result.fastestLap)} 0 ? 'text-warning-amber' : 'text-white'}> {result.incidents}× {getPoints(result.position)} {getPositionChangeText(positionChange)} {driverPenalties.length > 0 ? (
{driverPenalties.map((penalty, idx) => (
{getPenaltyDescription(penalty)}
))}
) : ( )}
); }