From 30c5bf6048102fcf466d9341a35c140749629c57 Mon Sep 17 00:00:00 2001 From: Anton15K Date: Thu, 30 Apr 2026 16:43:52 +0300 Subject: [PATCH 1/3] feat: add dedicated tire outings dashboard page - implement `OutingTable` component for session-wide tire history - create dedicated `/dashboard/tires` page - enhance `DriverHistoryTires` with stint progression and used set markers - integrate "Tires" link into sidebar navigation - update help documentation with tire history details --- dashboard/src/app/(nav)/help/page.tsx | 9 ++ dashboard/src/app/dashboard/tires/page.tsx | 18 ++++ dashboard/src/components/Sidebar.tsx | 4 + .../src/components/dashboard/OutingTable.tsx | 90 +++++++++++++++++++ .../components/driver/DriverHistoryTires.tsx | 6 +- dashboard/tsconfig.json | 2 +- 6 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 dashboard/src/app/dashboard/tires/page.tsx create mode 100644 dashboard/src/components/dashboard/OutingTable.tsx diff --git a/dashboard/src/app/(nav)/help/page.tsx b/dashboard/src/app/(nav)/help/page.tsx index 268208fa..646afb9a 100644 --- a/dashboard/src/app/(nav)/help/page.tsx +++ b/dashboard/src/app/(nav)/help/page.tsx @@ -1,4 +1,5 @@ import Image from "next/image"; +import Link from "next/link"; import Note from "@/components/Note"; import DriverDRS from "@/components/driver/DriverDRS"; @@ -151,6 +152,14 @@ export default function HelpPage() { In this example, the driver has a soft tire which is 12 laps old and he pitted one time.

+ + For a complete history of all tire stints and outings during the session, you can visit the dedicated{" "} + + Tires + {" "} + page in the dashboard. + +
+
+

Tire Outings

+

Real-time history of tire compounds and outing progression.

+
+ +
+ +
+
+ ); +} diff --git a/dashboard/src/components/Sidebar.tsx b/dashboard/src/components/Sidebar.tsx index c1dba34b..1f352528 100644 --- a/dashboard/src/components/Sidebar.tsx +++ b/dashboard/src/components/Sidebar.tsx @@ -23,6 +23,10 @@ const liveTimingItems = [ href: "/dashboard/track-map", name: "Track Map", }, + { + href: "/dashboard/tires", + name: "Tires", + }, { href: "/dashboard/standings", name: "Standings", diff --git a/dashboard/src/components/dashboard/OutingTable.tsx b/dashboard/src/components/dashboard/OutingTable.tsx new file mode 100644 index 00000000..7d7ae387 --- /dev/null +++ b/dashboard/src/components/dashboard/OutingTable.tsx @@ -0,0 +1,90 @@ +"use client"; + +import { AnimatePresence, LayoutGroup, motion } from "motion/react"; +import clsx from "clsx"; + +import { useDataStore } from "@/stores/useDataStore"; +import { useSettingsStore } from "@/stores/useSettingsStore"; +import { sortPos } from "@/lib/sorting"; + +import DriverTag from "@/components/driver/DriverTag"; +import DriverHistoryTires from "@/components/driver/DriverHistoryTires"; + +export default function OutingTable() { + const drivers = useDataStore(({ state }) => state?.DriverList); + const driversTiming = useDataStore(({ state }) => state?.TimingData); + const appDriversTiming = useDataStore(({ state }) => state?.TimingAppData); + + const oledMode = useSettingsStore((state) => state.oledMode); + + return ( +
+
+

Driver

+

Tire History / Outings

+
+ + {(!drivers || !driversTiming) && + new Array(20).fill("").map((_, index) => )} + + +
+ {drivers && driversTiming && ( + + {Object.values(driversTiming.Lines) + .sort(sortPos) + .map((timingDriver, index) => { + const driver = drivers[timingDriver.RacingNumber]; + const appTiming = appDriversTiming?.Lines[timingDriver.RacingNumber]; + + return ( + + +
+ +
+
+ ); + })} +
+ )} +
+
+
+ ); +} + +function SkeletonRow() { + return ( +
+
+
+ {[1, 2, 3].map((i) => ( +
+
+
+
+ ))} +
+
+ ); +} diff --git a/dashboard/src/components/driver/DriverHistoryTires.tsx b/dashboard/src/components/driver/DriverHistoryTires.tsx index 8f4ab3ba..ddf09627 100644 --- a/dashboard/src/components/driver/DriverHistoryTires.tsx +++ b/dashboard/src/components/driver/DriverHistoryTires.tsx @@ -14,7 +14,7 @@ export default function DriverHistoryTires({ stints }: Props) {
{stints && stints.map((stint, i) => ( -
+
{unknownCompound(stint) && unknown} {!unknownCompound(stint) && stint.Compound && ( )} -

{stint.TotalLaps}L

+

+ {stint.TotalLaps}L{stint.New === "FALSE" ? "*" : ""} +

))} diff --git a/dashboard/tsconfig.json b/dashboard/tsconfig.json index 354b9b90..4224aa4d 100644 --- a/dashboard/tsconfig.json +++ b/dashboard/tsconfig.json @@ -13,7 +13,7 @@ "noEmit": true, "esModuleInterop": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "verbatimModuleSyntax": true, From 5073d66730af28dfcdf63d43fc68ae428db11308 Mon Sep 17 00:00:00 2001 From: Ak-15 <54205422+Anton15K@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:52:32 +0300 Subject: [PATCH 2/3] Update dashboard/src/app/dashboard/tires/page.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- dashboard/src/app/dashboard/tires/page.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/dashboard/src/app/dashboard/tires/page.tsx b/dashboard/src/app/dashboard/tires/page.tsx index c855f440..ebe9f405 100644 --- a/dashboard/src/app/dashboard/tires/page.tsx +++ b/dashboard/src/app/dashboard/tires/page.tsx @@ -1,5 +1,3 @@ -"use client"; - import OutingTable from "@/components/dashboard/OutingTable"; export default function TiresPage() { From 378d2ed12b3d27f0b81648299ad2c9912453c96a Mon Sep 17 00:00:00 2001 From: Anton15K Date: Sat, 16 May 2026 15:35:11 +0300 Subject: [PATCH 3/3] fix: correct used tire detection logic and typing - update `Stint` type to explicitly use `"TRUE" | "FALSE"` for the `New` field - fix used tire marker (`*`) display logic in `DriverHistoryTires` and `DriverTire` components to consistently check for `"TRUE"` value --- dashboard/src/components/driver/DriverHistoryTires.tsx | 2 +- dashboard/src/components/driver/DriverTire.tsx | 2 +- dashboard/src/types/state.type.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dashboard/src/components/driver/DriverHistoryTires.tsx b/dashboard/src/components/driver/DriverHistoryTires.tsx index ddf09627..ee52e95d 100644 --- a/dashboard/src/components/driver/DriverHistoryTires.tsx +++ b/dashboard/src/components/driver/DriverHistoryTires.tsx @@ -26,7 +26,7 @@ export default function DriverHistoryTires({ stints }: Props) { )}

- {stint.TotalLaps}L{stint.New === "FALSE" ? "*" : ""} + {stint.TotalLaps}L{stint.New !== "TRUE" ? "*" : ""}

))} diff --git a/dashboard/src/components/driver/DriverTire.tsx b/dashboard/src/components/driver/DriverTire.tsx index 90b5e754..836ba121 100644 --- a/dashboard/src/components/driver/DriverTire.tsx +++ b/dashboard/src/components/driver/DriverTire.tsx @@ -35,7 +35,7 @@ export default function DriverTire({ stints }: Props) {

L {currentStint?.TotalLaps ?? 0} - {currentStint?.New ? "" : "*"} + {currentStint?.New === "TRUE" ? "" : "*"}

PIT {stops}

diff --git a/dashboard/src/types/state.type.ts b/dashboard/src/types/state.type.ts index 568e19fd..6e2104d7 100644 --- a/dashboard/src/types/state.type.ts +++ b/dashboard/src/types/state.type.ts @@ -57,7 +57,7 @@ export type TimingAppDataDriver = { export type Stint = { TotalLaps?: number; Compound?: "SOFT" | "MEDIUM" | "HARD" | "INTERMEDIATE" | "WET"; - New?: string; // TRUE | FALSE + New?: "TRUE" | "FALSE"; }; export type WeatherData = {