From dc7fc11085773a030bc9109e8c435a62a3567051 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 09:48:33 +0000 Subject: Load route-details realtime only for selected stop Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com> --- src/frontend/app/routes/routes-$id.tsx | 92 +++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/frontend/app/routes/routes-$id.tsx b/src/frontend/app/routes/routes-$id.tsx index 32f1fb7..79997b5 100644 --- a/src/frontend/app/routes/routes-$id.tsx +++ b/src/frontend/app/routes/routes-$id.tsx @@ -18,6 +18,7 @@ import { } from "react-map-gl/maplibre"; import { Link, useParams } from "react-router"; import { fetchRouteDetails } from "~/api/transit"; +import { useStopArrivals } from "~/hooks/useArrivals"; import { AppMap } from "~/components/shared/AppMap"; import { useBackButton, @@ -55,12 +56,22 @@ export default function RouteDetailsPage() { () => formatDateKey(selectedWeekDate), [selectedWeekDate] ); + const isTodaySelectedDate = selectedDateKey === formatDateKey(new Date()); + const now = new Date(); + const nowSeconds = + now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds(); const { data: route, isLoading } = useQuery({ queryKey: ["route", id, selectedDateKey], queryFn: () => fetchRouteDetails(id!, selectedDateKey), enabled: !!id, }); + const { data: selectedStopRealtime, isLoading: isRealtimeLoading } = + useStopArrivals( + selectedStopId ?? "", + true, + Boolean(selectedStopId) && isTodaySelectedDate + ); usePageTitle( route?.shortName @@ -161,6 +172,35 @@ export default function RouteDetailsPage() { const selectedPatternLabel = selectedPattern ? selectedPattern.headsign || selectedPattern.name : t("routes.details", "Detalles de ruta"); + const sameDirectionPatterns = selectedPattern + ? patternsByDirection[selectedPattern.directionId] ?? [] + : []; + const departuresByStop = useMemo(() => { + const byStop = new Map< + string, + { departure: number; patternId: string; tripId?: string | null }[] + >(); + + for (const pattern of sameDirectionPatterns) { + for (const stop of pattern.stops) { + const current = byStop.get(stop.id) ?? []; + current.push( + ...stop.scheduledDepartures.map((departure) => ({ + departure, + patternId: pattern.id, + tripId: null, + })) + ); + byStop.set(stop.id, current); + } + } + + for (const stopDepartures of byStop.values()) { + stopDepartures.sort((a, b) => a.departure - b.departure); + } + + return byStop; + }, [sameDirectionPatterns]); const mapHeightClass = layoutMode === "map" @@ -551,24 +591,64 @@ export default function RouteDetailsPage() { )} {selectedStopId === stop.id && - stop.scheduledDepartures.length > 0 && ( + (departuresByStop.get(stop.id)?.length ?? 0) > 0 && (
- {stop.scheduledDepartures.map((dep, i) => ( + {(departuresByStop + .get(stop.id) + ?.filter((item) => + isTodaySelectedDate + ? item.departure >= nowSeconds - 3600 + : true + ) ?? [] + ).map((item, i) => ( - {Math.floor(dep / 3600) + {Math.floor(item.departure / 3600) .toString() .padStart(2, "0")} : - {Math.floor((dep % 3600) / 60) + {Math.floor((item.departure % 3600) / 60) .toString() .padStart(2, "0")} ))}
)} + + {selectedStopId === stop.id && isTodaySelectedDate && ( +
+
+ {t("routes.realtime", "Tiempo real")} +
+ {isRealtimeLoading ? ( +
+ {t("routes.loading_realtime", "Cargando...")} +
+ ) : ( +
+ {(selectedStopRealtime?.arrivals ?? []).map( + (arrival, i) => ( + + {arrival.estimate.minutes}′ + {arrival.delay?.minutes + ? ` (${arrival.delay.minutes > 0 ? "+" : ""}${arrival.delay.minutes})` + : ""} + + ) + )} +
+ )} +
+ )} ))} -- cgit v1.3