wip
This commit is contained in:
@@ -1,32 +1,58 @@
|
||||
'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)
|
||||
*/
|
||||
type PenaltyTypeDTO =
|
||||
| 'time_penalty'
|
||||
| 'grid_penalty'
|
||||
| 'points_deduction'
|
||||
| 'disqualification'
|
||||
| 'warning'
|
||||
| 'license_points'
|
||||
| string;
|
||||
|
||||
interface ResultDTO {
|
||||
id: string;
|
||||
raceId: string;
|
||||
driverId: string;
|
||||
position: number;
|
||||
fastestLap: number;
|
||||
incidents: number;
|
||||
startPosition: number;
|
||||
getPositionChange(): number;
|
||||
}
|
||||
|
||||
interface DriverDTO {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface PenaltyData {
|
||||
driverId: string;
|
||||
type: PenaltyType;
|
||||
type: PenaltyTypeDTO;
|
||||
value?: number;
|
||||
}
|
||||
|
||||
interface ResultsTableProps {
|
||||
results: Result[];
|
||||
drivers: Driver[];
|
||||
results: ResultDTO[];
|
||||
drivers: DriverDTO[];
|
||||
pointsSystem: Record<number, number>;
|
||||
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);
|
||||
export default function ResultsTable({
|
||||
results,
|
||||
drivers,
|
||||
pointsSystem,
|
||||
fastestLapTime,
|
||||
penalties = [],
|
||||
currentDriverId,
|
||||
}: ResultsTableProps) {
|
||||
const getDriver = (driverId: string): DriverDTO | undefined => {
|
||||
return drivers.find((d) => d.id === driverId);
|
||||
};
|
||||
|
||||
const getDriverName = (driverId: string): string => {
|
||||
@@ -35,7 +61,7 @@ export default function ResultsTable({ results, drivers, pointsSystem, fastestLa
|
||||
};
|
||||
|
||||
const getDriverPenalties = (driverId: string): PenaltyData[] => {
|
||||
return penalties.filter(p => p.driverId === driverId);
|
||||
return penalties.filter((p) => p.driverId === driverId);
|
||||
};
|
||||
|
||||
const getPenaltyDescription = (penalty: PenaltyData): string => {
|
||||
@@ -97,30 +123,39 @@ export default function ResultsTable({ results, drivers, pointsSystem, fastestLa
|
||||
<tbody>
|
||||
{results.map((result) => {
|
||||
const positionChange = result.getPositionChange();
|
||||
const isFastestLap = fastestLapTime && result.fastestLap === fastestLapTime;
|
||||
const isFastestLap =
|
||||
typeof fastestLapTime === 'number' && result.fastestLap === fastestLapTime;
|
||||
const driverPenalties = getDriverPenalties(result.driverId);
|
||||
const driver = getDriver(result.driverId);
|
||||
const isCurrentUser = currentDriverId === result.driverId;
|
||||
const isPodium = result.position <= 3;
|
||||
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={result.id}
|
||||
className={`
|
||||
border-b border-charcoal-outline/50 transition-colors
|
||||
${isCurrentUser
|
||||
? 'bg-gradient-to-r from-primary-blue/20 via-primary-blue/10 to-transparent hover:from-primary-blue/30'
|
||||
: 'hover:bg-iron-gray/20'}
|
||||
${
|
||||
isCurrentUser
|
||||
? 'bg-gradient-to-r from-primary-blue/20 via-primary-blue/10 to-transparent hover:from-primary-blue/30'
|
||||
: 'hover:bg-iron-gray/20'
|
||||
}
|
||||
`}
|
||||
>
|
||||
<td className="py-3 px-4">
|
||||
<div className={`
|
||||
<div
|
||||
className={`
|
||||
inline-flex items-center justify-center w-8 h-8 rounded-lg font-bold text-sm
|
||||
${result.position === 1 ? 'bg-yellow-500/20 text-yellow-400' :
|
||||
result.position === 2 ? 'bg-gray-400/20 text-gray-300' :
|
||||
result.position === 3 ? 'bg-amber-600/20 text-amber-500' :
|
||||
'text-white'}
|
||||
`}>
|
||||
${
|
||||
result.position === 1
|
||||
? 'bg-yellow-500/20 text-yellow-400'
|
||||
: result.position === 2
|
||||
? 'bg-gray-400/20 text-gray-300'
|
||||
: result.position === 3
|
||||
? 'bg-amber-600/20 text-amber-500'
|
||||
: 'text-white'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{result.position}
|
||||
</div>
|
||||
</td>
|
||||
@@ -128,17 +163,27 @@ export default function ResultsTable({ results, drivers, pointsSystem, fastestLa
|
||||
<div className="flex items-center gap-3">
|
||||
{driver ? (
|
||||
<>
|
||||
<div className={`
|
||||
<div
|
||||
className={`
|
||||
w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold flex-shrink-0
|
||||
${isCurrentUser ? 'bg-primary-blue/30 text-primary-blue ring-2 ring-primary-blue/50' : 'bg-iron-gray text-gray-400'}
|
||||
`}>
|
||||
${
|
||||
isCurrentUser
|
||||
? 'bg-primary-blue/30 text-primary-blue ring-2 ring-primary-blue/50'
|
||||
: 'bg-iron-gray text-gray-400'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{driver.name.charAt(0)}
|
||||
</div>
|
||||
<Link
|
||||
href={`/drivers/${driver.id}`}
|
||||
className={`
|
||||
flex items-center gap-1.5 group
|
||||
${isCurrentUser ? 'text-primary-blue font-semibold' : 'text-white hover:text-primary-blue'}
|
||||
${
|
||||
isCurrentUser
|
||||
? 'text-primary-blue font-semibold'
|
||||
: 'text-white hover:text-primary-blue'
|
||||
}
|
||||
transition-colors
|
||||
`}
|
||||
>
|
||||
@@ -157,20 +202,30 @@ export default function ResultsTable({ results, drivers, pointsSystem, fastestLa
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={isFastestLap ? 'text-performance-green font-medium' : 'text-white'}>
|
||||
<span
|
||||
className={
|
||||
isFastestLap ? 'text-performance-green font-medium' : 'text-white'
|
||||
}
|
||||
>
|
||||
{formatLapTime(result.fastestLap)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={result.incidents > 0 ? 'text-warning-amber' : 'text-white'}>
|
||||
<span
|
||||
className={result.incidents > 0 ? 'text-warning-amber' : 'text-white'}
|
||||
>
|
||||
{result.incidents}×
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white font-medium">{getPoints(result.position)}</span>
|
||||
<span className="text-white font-medium">
|
||||
{getPoints(result.position)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={`font-medium ${getPositionChangeColor(positionChange)}`}>
|
||||
<span
|
||||
className={`font-medium ${getPositionChangeColor(positionChange)}`}
|
||||
>
|
||||
{getPositionChangeText(positionChange)}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user