From 5614fbc76c59a8c0bfe5cafc9af4805e43351c1c Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Wed, 31 Dec 2025 14:38:29 +0100 Subject: feat: Add vehicle information to arrival details and update related components --- .../app/components/arrivals/ArrivalCard.tsx | 42 +++++++++++++++++----- .../app/components/arrivals/ReducedArrivalCard.tsx | 39 +++++++++++++++++--- 2 files changed, 68 insertions(+), 13 deletions(-) (limited to 'src/frontend/app/components') diff --git a/src/frontend/app/components/arrivals/ArrivalCard.tsx b/src/frontend/app/components/arrivals/ArrivalCard.tsx index 6952f8f..f1fc1a5 100644 --- a/src/frontend/app/components/arrivals/ArrivalCard.tsx +++ b/src/frontend/app/components/arrivals/ArrivalCard.tsx @@ -1,4 +1,4 @@ -import { AlertTriangle, LocateIcon } from "lucide-react"; +import { AlertTriangle, BusFront, LocateIcon } from "lucide-react"; import React, { useEffect, useMemo, useRef, useState } from "react"; import Marquee from "react-fast-marquee"; import { useTranslation } from "react-i18next"; @@ -59,7 +59,8 @@ export const ArrivalCard: React.FC = ({ onClick, }) => { const { t } = useTranslation(); - const { route, headsign, estimate, delay, shift } = arrival; + const { route, headsign, estimate, delay, shift, vehicleInformation } = + arrival; const etaValue = estimate.minutes.toString(); const etaUnit = t("estimates.minutes", "min"); @@ -81,7 +82,7 @@ export const ArrivalCard: React.FC = ({ const chips: Array<{ label: string; tone?: string; - kind?: "regular" | "gps" | "delay" | "warning"; + kind?: "regular" | "gps" | "delay" | "warning" | "vehicle"; }> = []; // Badge/Shift info as a chip @@ -140,7 +141,10 @@ export const ArrivalCard: React.FC = ({ tone: "warning", kind: "warning", }); - } else if (estimate.precision === "confident") { + } else if ( + estimate.precision === "confident" && + arrival.currentPosition !== null + ) { chips.push({ label: t("estimates.bus_gps_position"), kind: "gps", @@ -155,8 +159,27 @@ export const ArrivalCard: React.FC = ({ }); } + // Vehicle information if available + if (vehicleInformation) { + let label = vehicleInformation.identifier; + if (vehicleInformation.make) { + label += ` (${vehicleInformation.make}`; + if (vehicleInformation.model) { + label += ` ${vehicleInformation.model}`; + } + if (vehicleInformation.year) { + label += ` - ${vehicleInformation.year}`; + } + label += `)`; + } + chips.push({ + label, + kind: "vehicle", + }); + } + return chips; - }, [delay, shift, estimate.precision, t, headsign.badge]); + }, [delay, shift, estimate.precision, t, headsign.badge, vehicleInformation]); const isClickable = !!onClick && estimate.precision !== "past"; const Tag = isClickable ? "button" : "div"; @@ -208,7 +231,7 @@ export const ArrivalCard: React.FC = ({ -
+
{metaChips.map((chip, idx) => { let chipColourClasses = ""; switch (chip.tone) { @@ -243,10 +266,13 @@ export const ArrivalCard: React.FC = ({ className={`text-xs px-2.5 py-0.5 rounded-full flex items-center justify-center gap-1 shrink-0 font-medium tracking-wide ${chipColourClasses}`} > {chip.kind === "gps" && ( - + )} {chip.kind === "warning" && ( - + + )} + {chip.kind === "vehicle" && ( + )} {chip.label} diff --git a/src/frontend/app/components/arrivals/ReducedArrivalCard.tsx b/src/frontend/app/components/arrivals/ReducedArrivalCard.tsx index 2c1ea20..44c8eda 100644 --- a/src/frontend/app/components/arrivals/ReducedArrivalCard.tsx +++ b/src/frontend/app/components/arrivals/ReducedArrivalCard.tsx @@ -1,4 +1,4 @@ -import { AlertTriangle, LocateIcon } from "lucide-react"; +import { AlertTriangle, BusFront, LocateIcon } from "lucide-react"; import React, { useMemo } from "react"; import { useTranslation } from "react-i18next"; import LineIcon from "~/components/LineIcon"; @@ -15,7 +15,8 @@ export const ReducedArrivalCard: React.FC = ({ onClick, }) => { const { t } = useTranslation(); - const { route, headsign, estimate, delay, shift } = arrival; + const { route, headsign, estimate, delay, shift, vehicleInformation } = + arrival; const etaValue = estimate.minutes.toString(); const etaUnit = t("estimates.minutes", "min"); @@ -37,7 +38,7 @@ export const ReducedArrivalCard: React.FC = ({ const chips: Array<{ label: string; tone?: string; - kind?: "regular" | "gps" | "delay" | "warning"; + kind?: "regular" | "gps" | "delay" | "warning" | "vehicle"; }> = []; // Badge/Shift info as a chip @@ -96,15 +97,40 @@ export const ReducedArrivalCard: React.FC = ({ tone: "warning", kind: "warning", }); - } else if (estimate.precision === "confident") { + } else if ( + estimate.precision === "confident" && + arrival.currentPosition !== null + ) { chips.push({ label: "", // Just the icon for reduced kind: "gps", }); } + // Vehicle information if available + if (vehicleInformation) { + let label = vehicleInformation.identifier; + if (vehicleInformation.make) { + label += ` (${vehicleInformation.make}`; + if (vehicleInformation.kind) { + const kindLabel = + vehicleInformation.kind.charAt(0).toUpperCase() + + vehicleInformation.kind.slice(1).toLowerCase(); + label += ` ${kindLabel}.`; + } + if (vehicleInformation.year) { + label += ` ${vehicleInformation.year}`; + } + label += `)`; + } + chips.push({ + label, + kind: "vehicle", + }); + } + return chips; - }, [delay, shift, estimate.precision, headsign.badge]); + }, [delay, shift, estimate.precision, headsign.badge, vehicleInformation]); const isClickable = !!onClick && estimate.precision !== "past"; const Tag = isClickable ? "button" : "div"; @@ -173,6 +199,9 @@ export const ReducedArrivalCard: React.FC = ({ {chip.kind === "warning" && ( )} + {chip.kind === "vehicle" && ( + + )} {chip.label} ); -- cgit v1.3