From 107295575e3a7c37911ae192baf426b0003975a4 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Mon, 8 Dec 2025 01:37:10 +0100 Subject: Refactor code structure for improved readability and maintainability; removed redundant code blocks and optimized functions. --- .../Stops/ConsolidatedCirculationCard.css | 1 - .../Stops/ConsolidatedCirculationCard.tsx | 96 +++++++++++++++++----- .../Stops/ConsolidatedCirculationList.tsx | 3 + 3 files changed, 77 insertions(+), 23 deletions(-) (limited to 'src/frontend/app/components/Stops') diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css index 57d30c8..9922b03 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css @@ -61,7 +61,6 @@ } .consolidated-circulation-card .route-info strong { - font-size: 1rem; color: var(--text-color); overflow: hidden; text-overflow: ellipsis; diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx index 635c0ce..70a9355 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import Marquee from 'react-fast-marquee'; import { useTranslation } from "react-i18next"; import LineIcon from "~components/LineIcon"; @@ -12,6 +12,7 @@ interface ConsolidatedCirculationCardProps { onMapClick?: () => void; readonly?: boolean; reduced?: boolean; + driver?: string; } // Utility function to parse service ID and get the turn number @@ -71,9 +72,52 @@ const parseServiceId = (serviceId: string): string => { return `${displayLine}-${turnNumber}`; }; +const AutoMarquee = ({ text }: { text: string }) => { + const containerRef = useRef(null); + const [shouldScroll, setShouldScroll] = useState(false); + + useEffect(() => { + const el = containerRef.current; + if (!el) return; + + const checkScroll = () => { + // 9px per char for text-sm font-mono is a safe upper bound estimate + // (14px * 0.6 = 8.4px) + const charWidth = 9; + const availableWidth = el.offsetWidth; + const textWidth = text.length * charWidth; + + setShouldScroll(textWidth > availableWidth); + }; + + checkScroll(); + + const observer = new ResizeObserver(checkScroll); + observer.observe(el); + + return () => observer.disconnect(); + }, [text]); + + if (shouldScroll) { + return ( +
+ +
{text}
+
+
+ ); + } + + return ( +
+ {text} +
+ ); +}; + export const ConsolidatedCirculationCard: React.FC< ConsolidatedCirculationCardProps -> = ({ estimate, onMapClick, readonly, reduced }) => { +> = ({ estimate, onMapClick, readonly, reduced, driver }) => { const { t } = useTranslation(); const formatDistance = (meters: number) => { @@ -157,7 +201,7 @@ export const ConsolidatedCirculationCard: React.FC< chips.push(delayChip); } - if (estimate.schedule) { + if (estimate.schedule && driver !== 'renfe') { chips.push({ label: `${parseServiceId(estimate.schedule.serviceId)} · ${getTripIdDisplay( estimate.schedule.tripId @@ -199,14 +243,17 @@ export const ConsolidatedCirculationCard: React.FC< // Check if bus has GPS position (live tracking) const hasGpsPosition = !!estimate.currentPosition; + const isRenfe = driver === 'renfe'; + const isClickable = hasGpsPosition; + const looksDisabled = !isClickable && !isRenfe; const Tag = readonly ? "div" : "button"; const interactiveProps = readonly ? {} : { - onClick: onMapClick, + onClick: isClickable ? onMapClick : undefined, type: "button" as const, - disabled: !hasGpsPosition, + disabled: !isClickable, }; if (reduced) { @@ -217,12 +264,14 @@ export const ConsolidatedCirculationCard: React.FC< bg-(--message-background-color) border border-(--border-color) rounded-xl px-3 py-2.5 transition-all ${readonly - ? !hasGpsPosition + ? looksDisabled ? "opacity-70 cursor-not-allowed" : "" - : hasGpsPosition + : isClickable ? "cursor-pointer hover:shadow-[0_4px_14px_rgba(0,0,0,0.08)] hover:border-(--button-background-color) hover:bg-[color-mix(in_oklab,var(--button-background-color)_5%,var(--message-background-color))] active:scale-[0.98]" - : "opacity-70 cursor-not-allowed" + : looksDisabled + ? "opacity-70 cursor-not-allowed" + : "" } `.trim()} {...interactiveProps} @@ -232,6 +281,9 @@ export const ConsolidatedCirculationCard: React.FC<
+ {driver === 'renfe' && estimate.schedule?.tripId && ( + {estimate.schedule.tripId} + )} {estimate.route} {metaChips.length > 0 && ( @@ -295,12 +347,14 @@ export const ConsolidatedCirculationCard: React.FC< return ( @@ -310,17 +364,15 @@ export const ConsolidatedCirculationCard: React.FC<
- {estimate.route} - {estimate.nextStreets && estimate.nextStreets.length > 0 && (() => { - const text = estimate.nextStreets.join(" — "); - return ( - 30}> -
- {text} -
-
- ); - })()} + + {driver === 'renfe' && estimate.schedule?.tripId && ( + {estimate.schedule.tripId} + )} + {estimate.route} + + {estimate.nextStreets && estimate.nextStreets.length > 0 && ( + + )}
diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx b/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx index 088f978..ec79f1c 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx @@ -9,12 +9,14 @@ interface ConsolidatedCirculationListProps { data: ConsolidatedCirculation[]; onCirculationClick?: (estimate: ConsolidatedCirculation, index: number) => void; reduced?: boolean; + driver?: string; } export const ConsolidatedCirculationList: React.FC = ({ data, onCirculationClick, reduced, + driver, }) => { const { t } = useTranslation(); @@ -43,6 +45,7 @@ export const ConsolidatedCirculationList: React.FC ( onCirculationClick?.(estimate, idx)} -- cgit v1.3