From 3227c7bc6bd233c92b1cf54bec689f0582dca547 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Mon, 1 Dec 2025 22:25:56 +0100 Subject: refactor: replace StopSheet with StopSummarySheet and update related components - Deleted StopSheet and StopSheetSkeleton components. - Introduced StopSummarySheet and StopSummarySheetSkeleton components. - Updated ConsolidatedCirculationCard to support a reduced view. - Modified ConsolidatedCirculationList to accept a reduced prop. - Adjusted map route to use StopSummarySheet. - Cleaned up CSS styles related to the stop sheet components. - Enhanced error handling and loading states in the new summary sheet. - Updated stop report logic to filter out empty next streets. --- .../Stops/ConsolidatedCirculationCard.tsx | 168 +++++++++++++++------ .../Stops/ConsolidatedCirculationList.tsx | 30 ++-- 2 files changed, 141 insertions(+), 57 deletions(-) (limited to 'src/frontend/app/components/Stops') diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx index 7198c7b..8f43939 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx @@ -10,6 +10,7 @@ interface ConsolidatedCirculationCardProps { estimate: ConsolidatedCirculation; onMapClick?: () => void; readonly?: boolean; + reduced?: boolean; } // Utility function to parse service ID and get the turn number @@ -71,7 +72,7 @@ const parseServiceId = (serviceId: string): string => { export const ConsolidatedCirculationCard: React.FC< ConsolidatedCirculationCardProps -> = ({ estimate, onMapClick, readonly }) => { +> = ({ estimate, onMapClick, readonly, reduced }) => { const { t } = useTranslation(); const formatDistance = (meters: number) => { @@ -118,7 +119,7 @@ export const ConsolidatedCirculationCard: React.FC< // On time if (delta === 0) { return { - label: t("estimates.delay_on_time", "En hora (0 min)"), + label: reduced ? "OK" : t("estimates.delay_on_time", "En hora (0 min)"), tone: "delay-ok", } as const; } @@ -128,7 +129,7 @@ export const ConsolidatedCirculationCard: React.FC< const tone = delta <= 2 ? "delay-ok" : delta <= 10 ? "delay-warn" : "delay-critical"; return { - label: t("estimates.delay_positive", "Retraso de {{minutes}} min", { + label: reduced ? `R${delta}` : t("estimates.delay_positive", "Retraso de {{minutes}} min", { minutes: delta, }), tone, @@ -138,12 +139,12 @@ export const ConsolidatedCirculationCard: React.FC< // Early const tone = absDelta <= 2 ? "delay-ok" : "delay-early"; return { - label: t("estimates.delay_negative", "Adelanto de {{minutes}} min", { + label: reduced ? `A${absDelta}` : t("estimates.delay_negative", "Adelanto de {{minutes}} min", { minutes: absDelta, }), tone, } as const; - }, [estimate.schedule, estimate.realTime, t]); + }, [estimate.schedule, estimate.realTime, t, reduced]); const metaChips = useMemo(() => { const chips: Array<{ label: string; tone?: string }> = []; @@ -175,6 +176,84 @@ export const ConsolidatedCirculationCard: React.FC< disabled: !hasGpsPosition, }; + if (reduced) { + return ( + +
+ +
+
+ + {estimate.route} + + {metaChips.length > 0 && ( +
+ {metaChips.map((chip, idx) => { + let chipColourClasses = ""; + switch (chip.tone) { + case "delay-ok": + chipColourClasses = "bg-green-600/20 dark:bg-green-600/30 text-green-700 dark:text-green-300"; + break; + case "delay-warn": + chipColourClasses = "bg-amber-600/20 dark:bg-yellow-600/30 text-amber-700 dark:text-yellow-300"; + break; + case "delay-critical": + chipColourClasses = "bg-red-400/20 dark:bg-red-600/30 text-red-600 dark:text-red-300"; + break; + case "delay-early": + chipColourClasses = "bg-blue-400/20 dark:bg-blue-600/30 text-blue-700 dark:text-blue-300"; + break; + default: + chipColourClasses = "bg-black/[0.06] dark:bg-white/[0.12] text-[var(--text-color)]"; + } + + return ( + + {chip.label} + + ); + })} +
+ )} +
+
+
+ {etaValue} + {etaUnit} +
+
+
+ ); + } + return ( -
-
- -
-
- {estimate.route} -
- {hasGpsPosition && ( -
- + <> +
+
+
- )} -
-
- {etaValue} - {etaUnit} +
+ {estimate.route} + {estimate.nextStreets && estimate.nextStreets.length > 0 && ( + +
+ {estimate.nextStreets.join(" — ")} +
+
+ )}
-
-
- {metaChips.length > 0 && ( -
- {metaChips.map((chip, idx) => ( - - {chip.label} - - ))} - - {estimate.nextStreets && estimate.nextStreets.length > 0 && ( - -
- {estimate.nextStreets.join(" — ")} -
+ {hasGpsPosition && ( +
+ +
)} +
+
+ {etaValue} + {etaUnit} +
+
- )} + + {metaChips.length > 0 && ( +
+ {metaChips.map((chip, idx) => ( + + {chip.label} + + ))} +
+ )} + ); }; diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx b/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx index 547fdf7..088f978 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationList.tsx @@ -2,18 +2,19 @@ import { useTranslation } from "react-i18next"; import { type ConsolidatedCirculation } from "~routes/stops-$id"; import { ConsolidatedCirculationCard } from "./ConsolidatedCirculationCard"; +import { useCallback } from "react"; import "./ConsolidatedCirculationList.css"; -interface RegularTableProps { +interface ConsolidatedCirculationListProps { data: ConsolidatedCirculation[]; - dataDate: Date | null; onCirculationClick?: (estimate: ConsolidatedCirculation, index: number) => void; + reduced?: boolean; } -export const ConsolidatedCirculationList: React.FC = ({ +export const ConsolidatedCirculationList: React.FC = ({ data, - dataDate, onCirculationClick, + reduced, }) => { const { t } = useTranslation(); @@ -23,28 +24,31 @@ export const ConsolidatedCirculationList: React.FC = ({ (b.realTime?.minutes ?? b.schedule?.minutes ?? 999) ); + const generateKey = useCallback((estimate: ConsolidatedCirculation) => { + if (estimate.realTime && estimate.schedule) { + return `rt-${estimate.schedule.tripId}`; + } + + return `sch-${estimate.schedule ? estimate.schedule.tripId : estimate.line + "-" + estimate.route}`; + }, []); + return ( <> -
- {t("estimates.caption", "Estimaciones de llegadas a las {{time}}", { - time: dataDate?.toLocaleTimeString(), - })} -
- {sortedData.length === 0 ? (
{t("estimates.none", "No hay estimaciones disponibles")}
) : ( - <> +
{sortedData.map((estimate, idx) => ( onCirculationClick?.(estimate, idx)} /> ))} - +
)} ); -- cgit v1.3