diff --git a/apps/web/public/launchcontrol-badge.png b/apps/web/public/launchcontrol-badge.png new file mode 100644 index 0000000..c5e3f63 Binary files /dev/null and b/apps/web/public/launchcontrol-badge.png differ diff --git a/apps/web/src/app/events/[slug]/leaderboard-table.tsx b/apps/web/src/app/events/[slug]/leaderboard-table.tsx index ba91a25..3278a59 100644 --- a/apps/web/src/app/events/[slug]/leaderboard-table.tsx +++ b/apps/web/src/app/events/[slug]/leaderboard-table.tsx @@ -1,6 +1,6 @@ "use client"; -import { useMemo, useRef, useState } from "react"; +import { useMemo, useState } from "react"; import { type ColumnDef, type SortingState, @@ -135,7 +135,7 @@ function DriverCard({ delta, }: { row: LeaderboardRow; - rank: number; + rank: number | undefined; delta: { fromPrior: number | null; fromP1: number | null } | undefined; }) { return ( @@ -190,8 +190,6 @@ export function LeaderboardTable({ { id: "bestRawMs", desc: false }, ]); const [classFilter, setClassFilter] = useState(ALL_CLASSES); - const rankByIdRef = useRef>(new Map()); - const filteredRows = useMemo( () => classFilter === ALL_CLASSES @@ -200,23 +198,25 @@ export function LeaderboardTable({ [rows, classFilter], ); - const deltaByRow = useMemo(() => { - const map = new Map(); + const { deltaByRow, rankByRow } = useMemo(() => { + const delta = new Map(); + const rank = new Map(); const ranked = filteredRows .filter((r) => r.bestRawMs != null) .sort((a, b) => a.bestRawMs! - b.bestRawMs!); const leader = ranked[0]?.bestRawMs ?? null; ranked.forEach((r, i) => { + rank.set(r, i + 1); if (i === 0) { - map.set(r, { fromPrior: null, fromP1: null }); + delta.set(r, { fromPrior: null, fromP1: null }); } else { - map.set(r, { + delta.set(r, { fromPrior: r.bestRawMs! - ranked[i - 1]!.bestRawMs!, fromP1: leader == null ? null : r.bestRawMs! - leader, }); } }); - return map; + return { deltaByRow: delta, rankByRow: rank }; }, [filteredRows]); const columns = useMemo[]>( @@ -226,7 +226,7 @@ export function LeaderboardTable({ header: () => #, enableSorting: false, cell: ({ row }) => ( - + ), }, { @@ -325,7 +325,7 @@ export function LeaderboardTable({ cell: ({ row }) => , }, ], - [deltaByRow], + [deltaByRow, rankByRow], ); // React Compiler can't safely memoize TanStack Table's returned functions; @@ -344,10 +344,6 @@ export function LeaderboardTable({ const sortedRows = table.getRowModel().rows; - const newRankMap = new Map(); - sortedRows.forEach((r, i) => newRankMap.set(r.id, i + 1)); - rankByIdRef.current = newRankMap; - return (
{/* Filter header strip */} @@ -392,8 +388,8 @@ export function LeaderboardTable({ No entries match the current filter. ) : ( - sortedRows.map((row, i) => ( - + sortedRows.map((row) => ( + )) )} @@ -431,13 +427,13 @@ export function LeaderboardTable({ ) : ( - sortedRows.map((row, i) => { - const rank = i + 1; + sortedRows.map((row) => { + const rank = rankByRow.get(row.original); return (
+
+ Launch Control — PCA Rocky Mountain Region autocross +
diff --git a/apps/web/src/components/podium.tsx b/apps/web/src/components/podium.tsx index 683bacb..18af4a0 100644 --- a/apps/web/src/components/podium.tsx +++ b/apps/web/src/components/podium.tsx @@ -26,7 +26,8 @@ export function podiumClasses(rank: number): string { } } -export function RankPill({ rank }: { rank: number }) { +export function RankPill({ rank }: { rank: number | undefined }) { + if (rank == null) return null; return (