wip
This commit is contained in:
@@ -1,19 +1,18 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Standing } from '@gridpilot/racing/domain/entities/Standing';
|
||||
import { Driver } from '@gridpilot/racing/domain/entities/Driver';
|
||||
import DriverIdentity from '@/components/drivers/DriverIdentity';
|
||||
import type { DriverDTO } from '@gridpilot/racing/application/dto/DriverDTO';
|
||||
import type { LeagueDriverSeasonStatsDTO } from '@gridpilot/racing/application/dto/LeagueDriverSeasonStatsDTO';
|
||||
|
||||
interface StandingsTableProps {
|
||||
standings: Standing[];
|
||||
drivers: Driver[];
|
||||
standings: LeagueDriverSeasonStatsDTO[];
|
||||
drivers: DriverDTO[];
|
||||
leagueId: string;
|
||||
}
|
||||
|
||||
export default function StandingsTable({ standings, drivers, leagueId }: StandingsTableProps) {
|
||||
const getDriverName = (driverId: string): string => {
|
||||
const driver = drivers.find((d) => d.id === driverId);
|
||||
return driver?.name || 'Unknown Driver';
|
||||
const getDriver = (driverId: string): DriverDTO | undefined => {
|
||||
return drivers.find((d) => d.id === driverId);
|
||||
};
|
||||
|
||||
if (standings.length === 0) {
|
||||
@@ -26,50 +25,121 @@ export default function StandingsTable({ standings, drivers, leagueId }: Standin
|
||||
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-charcoal-outline">
|
||||
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-400">Pos</th>
|
||||
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-400">Driver</th>
|
||||
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-400">Points</th>
|
||||
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-400">Wins</th>
|
||||
<th className="text-left py-3 px-4 text-sm font-semibold text-gray-400">Races</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Pos</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Driver</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Team</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Total Pts</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Pts / Race</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Started</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Finished</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">DNF</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">No‑Shows</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Penalty</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Bonus</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Avg Finish</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-400">Rating Δ</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{standings.map((standing) => {
|
||||
const isLeader = standing.position === 1;
|
||||
{standings.map((row) => {
|
||||
const isLeader = row.position === 1;
|
||||
const driver = getDriver(row.driverId);
|
||||
|
||||
const totalPointsLine =
|
||||
row.penaltyPoints > 0
|
||||
? `Total Points: ${row.totalPoints} (-${row.penaltyPoints} penalty)`
|
||||
: `Total Points: ${row.totalPoints}`;
|
||||
|
||||
const ratingDelta =
|
||||
row.ratingChange === null || row.ratingChange === 0
|
||||
? '—'
|
||||
: row.ratingChange > 0
|
||||
? `+${row.ratingChange}`
|
||||
: `${row.ratingChange}`;
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={`${standing.leagueId}-${standing.driverId}`}
|
||||
key={`${row.leagueId}-${row.driverId}`}
|
||||
className="border-b border-charcoal-outline/50 hover:bg-iron-gray/20 transition-colors"
|
||||
>
|
||||
<td className="py-3 px-4">
|
||||
<span className={`font-semibold ${isLeader ? 'text-yellow-500' : 'text-white'}`}>
|
||||
{standing.position}
|
||||
{row.position}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<Link
|
||||
href={`/drivers/${standing.driverId}?from=league&leagueId=${leagueId}`}
|
||||
className={
|
||||
isLeader
|
||||
? 'text-white font-semibold hover:text-primary-blue transition-colors'
|
||||
: 'text-white hover:text-primary-blue transition-colors'
|
||||
}
|
||||
>
|
||||
{getDriverName(standing.driverId)}
|
||||
</Link>
|
||||
{driver ? (
|
||||
<DriverIdentity
|
||||
driver={driver}
|
||||
href={`/drivers/${row.driverId}?from=league-standings&leagueId=${leagueId}`}
|
||||
contextLabel={`P${row.position}`}
|
||||
size="sm"
|
||||
meta={totalPointsLine}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-white">Unknown Driver</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white font-medium">{standing.points}</span>
|
||||
<span className="text-gray-300">
|
||||
{row.teamName ?? '—'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">{standing.wins}</span>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-white font-medium">{row.totalPoints}</span>
|
||||
{row.penaltyPoints > 0 || row.bonusPoints !== 0 ? (
|
||||
<span className="text-xs text-gray-400">
|
||||
base {row.basePoints}
|
||||
{row.penaltyPoints > 0 && (
|
||||
<span className="text-red-400"> −{row.penaltyPoints}</span>
|
||||
)}
|
||||
{row.bonusPoints !== 0 && (
|
||||
<span className="text-green-400"> +{row.bonusPoints}</span>
|
||||
)}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">{standing.racesCompleted}</span>
|
||||
<span className="text-white">
|
||||
{row.pointsPerRace.toFixed(2)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">{row.racesStarted}</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">{row.racesFinished}</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">{row.dnfs}</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">{row.noShows}</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={row.penaltyPoints > 0 ? 'text-red-400' : 'text-gray-300'}>
|
||||
{row.penaltyPoints > 0 ? `-${row.penaltyPoints}` : '—'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={row.bonusPoints !== 0 ? 'text-green-400' : 'text-gray-300'}>
|
||||
{row.bonusPoints !== 0 ? `+${row.bonusPoints}` : '—'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-white">
|
||||
{row.avgFinish !== null ? row.avgFinish.toFixed(2) : '—'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={row.ratingChange && row.ratingChange > 0 ? 'text-green-400' : row.ratingChange && row.ratingChange < 0 ? 'text-red-400' : 'text-gray-300'}>
|
||||
{ratingDelta}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user