diff options
| author | Ariel Costas Guerrero <ariel@costas.dev> | 2025-12-23 21:33:17 +0100 |
|---|---|---|
| committer | Ariel Costas Guerrero <ariel@costas.dev> | 2025-12-23 21:33:17 +0100 |
| commit | 4a866f5352a51916ddb9849b2d68213856196c9c (patch) | |
| tree | 3ba01ba01d5f6931adaf708b76ffccdd798fc78b /src/frontend/app/routes | |
| parent | 87417c313b455ba0dee19708528cc8d0b830a276 (diff) | |
Full real-time page, coruña real time
Diffstat (limited to 'src/frontend/app/routes')
| -rw-r--r-- | src/frontend/app/routes/stops-$id.tsx | 174 |
1 files changed, 56 insertions, 118 deletions
diff --git a/src/frontend/app/routes/stops-$id.tsx b/src/frontend/app/routes/stops-$id.tsx index 46358dc..7adcef2 100644 --- a/src/frontend/app/routes/stops-$id.tsx +++ b/src/frontend/app/routes/stops-$id.tsx @@ -2,50 +2,22 @@ import { CircleHelp, Eye, EyeClosed, Star } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useParams } from "react-router"; +import { fetchArrivals } from "~/api/arrivals"; +import { type Arrival, type Position, type RouteInfo } from "~/api/schema"; +import { ArrivalList } from "~/components/arrivals/ArrivalList"; import { ErrorDisplay } from "~/components/ErrorDisplay"; import LineIcon from "~/components/LineIcon"; import { PullToRefresh } from "~/components/PullToRefresh"; -import { StopAlert } from "~/components/StopAlert"; import { StopHelpModal } from "~/components/StopHelpModal"; import { StopMapModal } from "~/components/StopMapModal"; -import { ConsolidatedCirculationList } from "~/components/Stops/ConsolidatedCirculationList"; import { ConsolidatedCirculationListSkeleton } from "~/components/Stops/ConsolidatedCirculationListSkeleton"; -import { APP_CONSTANTS } from "~/config/constants"; import { usePageTitle } from "~/contexts/PageTitleContext"; import { useAutoRefresh } from "~/hooks/useAutoRefresh"; -import StopDataProvider, { type Stop } from "../data/StopDataProvider"; +import StopDataProvider from "../data/StopDataProvider"; import "./stops-$id.css"; -export interface ConsolidatedCirculation { - line: string; - route: string; - schedule?: { - running: boolean; - minutes: number; - serviceId: string; - tripId: string; - shapeId?: string; - }; - realTime?: { - minutes: number; - distance: number; - }; - currentPosition?: { - latitude: number; - longitude: number; - orientationDegrees: number; - shapeIndex?: number; - }; - isPreviousTrip?: boolean; - previousTripShapeId?: string; - nextStreets?: string[]; -} - -export const getCirculationId = (c: ConsolidatedCirculation): string => { - if (c.schedule?.tripId) { - return `trip:${c.schedule.tripId}`; - } - return `rt:${c.line}:${c.route}:${c.realTime?.minutes ?? "?"}`; +export const getArrivalId = (a: Arrival): string => { + return a.tripId; }; interface ErrorInfo { @@ -54,59 +26,18 @@ interface ErrorInfo { message?: string; } -const loadConsolidatedData = async ( - stopId: string -): Promise<ConsolidatedCirculation[]> => { - const resp = await fetch( - `${APP_CONSTANTS.consolidatedCirculationsEndpoint}?stopId=${stopId}`, - { - headers: { - Accept: "application/json", - }, - } - ); - - if (!resp.ok) { - throw new Error(`HTTP ${resp.status}: ${resp.statusText}`); - } - - return await resp.json(); -}; - -export interface ConsolidatedCirculation { - line: string; - route: string; - schedule?: { - running: boolean; - minutes: number; - serviceId: string; - tripId: string; - shapeId?: string; - }; - realTime?: { - minutes: number; - distance: number; - }; - currentPosition?: { - latitude: number; - longitude: number; - orientationDegrees: number; - shapeIndex?: number; - }; - isPreviousTrip?: boolean; - previousTripShapeId?: string; - nextStreets?: string[]; -} - export default function Estimates() { const { t } = useTranslation(); const params = useParams(); const stopId = params.id ?? ""; - const [customName, setCustomName] = useState<string | undefined>(undefined); - const [stopData, setStopData] = useState<Stop | undefined>(undefined); + const [stopName, setStopName] = useState<string | undefined>(undefined); + const [apiRoutes, setApiRoutes] = useState<RouteInfo[]>([]); + const [apiLocation, setApiLocation] = useState<Position | undefined>( + undefined + ); // Data state - const [data, setData] = useState<ConsolidatedCirculation[] | null>(null); + const [data, setData] = useState<Arrival[] | null>(null); const [dataDate, setDataDate] = useState<Date | null>(null); const [dataLoading, setDataLoading] = useState(true); const [dataError, setDataError] = useState<ErrorInfo | null>(null); @@ -116,16 +47,15 @@ export default function Estimates() { const [isMapModalOpen, setIsMapModalOpen] = useState(false); const [isHelpModalOpen, setIsHelpModalOpen] = useState(false); const [isReducedView, setIsReducedView] = useState(false); - const [selectedCirculationId, setSelectedCirculationId] = useState< + const [selectedArrivalId, setSelectedArrivalId] = useState< string | undefined >(undefined); // Helper function to get the display name for the stop const getStopDisplayName = useCallback(() => { - if (customName) return customName; - if (stopData?.name) return stopData.name; + if (stopName) return stopName; return `Parada ${stopId}`; - }, [customName, stopData, stopId]); + }, [stopId, stopName]); usePageTitle(getStopDisplayName()); @@ -154,16 +84,16 @@ export default function Estimates() { try { setDataError(null); - const body = await loadConsolidatedData(stopId); - setData(body); + const response = await fetchArrivals(stopId, false); + setData(response.arrivals); + setStopName(response.stopName); + setApiRoutes(response.routes); + if (response.stopLocation) { + setApiLocation(response.stopLocation); + } setDataDate(new Date()); - - // Load stop data from StopDataProvider - const stop = await StopDataProvider.getStopById(stopId); - setStopData(stop); - setCustomName(StopDataProvider.getCustomName(stopId)); } catch (error) { - console.error("Error loading consolidated data:", error); + console.error("Error loading arrivals data:", error); setDataError(parseError(error)); setData(null); setDataDate(null); @@ -214,17 +144,22 @@ export default function Estimates() { return ( <PullToRefresh onRefresh={handleManualRefresh}> <div className="page-container stops-page"> - {stopData && stopData.lines && stopData.lines.length > 0 && ( + {apiRoutes.length > 0 && ( <div className={`estimates-lines-container scrollable`}> - {stopData.lines.map((line) => ( - <div key={line} className="estimates-line-icon"> - <LineIcon line={line} mode="rounded" /> + {apiRoutes.map((line) => ( + <div key={line.shortName} className="estimates-line-icon"> + <LineIcon + line={line.shortName} + colour={line.colour} + textColour={line.textColour} + mode="pill" + /> </div> ))} </div> )} - {stopData && <StopAlert stop={stopData} />} + {/*{stopData && <StopAlert stop={stopData} />}*/} <div className="estimates-list-container"> {dataLoading ? ( @@ -281,12 +216,11 @@ export default function Estimates() { )} </div> </div> - <ConsolidatedCirculationList - data={data} + <ArrivalList + arrivals={data} reduced={isReducedView} - driver={stopData?.stopId.split(":")[0]} - onCirculationClick={(estimate, idx) => { - setSelectedCirculationId(getCirculationId(estimate)); + onArrivalClick={(arrival) => { + setSelectedArrivalId(getArrivalId(arrival)); setIsMapModalOpen(true); }} /> @@ -294,25 +228,29 @@ export default function Estimates() { ) : null} </div> - {stopData && ( + {apiLocation && ( <StopMapModal - stop={stopData} - circulations={(data ?? []).map((c) => ({ - id: getCirculationId(c), - line: c.line, - route: c.route, - currentPosition: c.currentPosition, - isPreviousTrip: c.isPreviousTrip, - previousTripShapeId: c.previousTripShapeId, - schedule: c.schedule - ? { - shapeId: c.schedule.shapeId, - } - : undefined, + stop={{ + stopId: stopId, + name: stopName ?? "", + latitude: apiLocation?.latitude, + longitude: apiLocation?.longitude, + lines: [], + }} + circulations={(data ?? []).map((a) => ({ + id: getArrivalId(a), + line: a.route.shortName, + route: a.headsign.destination, + currentPosition: a.currentPosition ?? undefined, + stopShapeIndex: a.stopShapeIndex ?? undefined, + schedule: { + shapeId: undefined, + }, + shape: a.shape, }))} isOpen={isMapModalOpen} onClose={() => setIsMapModalOpen(false)} - selectedCirculationId={selectedCirculationId} + selectedCirculationId={selectedArrivalId} /> )} |
