import type { Driver, Lap } from '../types'
import { formatGap, formatLapTime, teamColor } from '../utils'
interface Props {
laps: Lap[]
drivers?: Driver[]
}
interface DriverLapSummary {
driver_number: number
total: number
best: Lap | null
lastLap: number
pitOuts: number
}
export function LapsView({ laps, drivers = [] }: Props) {
if (laps.length === 0) {
return (
Laps not ingested. Run box-box --ingest-session <key> to
load this dataset.
)
}
const byDriver = new Map()
for (const lap of laps) {
const summary =
byDriver.get(lap.driver_number) ??
{
driver_number: lap.driver_number,
total: 0,
best: null,
lastLap: 0,
pitOuts: 0,
}
summary.total += 1
summary.lastLap = Math.max(summary.lastLap, lap.lap_number)
if (lap.is_pit_out_lap) summary.pitOuts += 1
if (
lap.lap_duration != null &&
lap.lap_duration > 0 &&
(!summary.best ||
summary.best.lap_duration == null ||
lap.lap_duration < summary.best.lap_duration)
) {
summary.best = lap
}
byDriver.set(lap.driver_number, summary)
}
const rows = [...byDriver.values()].sort((a, b) => {
const aBest = a.best?.lap_duration ?? Number.POSITIVE_INFINITY
const bBest = b.best?.lap_duration ?? Number.POSITIVE_INFINITY
if (aBest !== bBest) return aBest - bBest
return a.driver_number - b.driver_number
})
const driversByNumber = new Map(drivers.map((driver) => [driver.driver_number, driver]))
const fastest = rows.find((row) => row.best?.lap_duration != null)?.best
const fastestTime = fastest?.lap_duration ?? null
return (
| Driver |
Best Lap |
Best Time |
Gap |
Laps |
Pit Outs |
{rows.map((row) => {
const driver = driversByNumber.get(row.driver_number)
const driverName =
driver?.full_name || driver?.broadcast_name || driver?.name_acronym || `#${row.driver_number}`
const colour = teamColor(driver?.team_colour)
const isFastest =
fastest &&
row.best?.driver_number === fastest.driver_number &&
row.best?.lap_number === fastest.lap_number
const gap =
row.best?.lap_duration != null && fastestTime != null
? row.best.lap_duration - fastestTime
: null
return (
|
{driverName}
{row.driver_number}
|
{row.best ? row.best.lap_number : '—'}
|
{formatLapTime(row.best?.lap_duration)} |
{isFastest ? '—' : formatGap(gap)} |
{row.lastLap || row.total} |
{row.pitOuts || '—'}
|
)
})}
)
}