diff options
Diffstat (limited to 'src/frontend/app/components/StopSummarySheet.tsx')
| -rw-r--r-- | src/frontend/app/components/StopSummarySheet.tsx | 209 |
1 files changed, 0 insertions, 209 deletions
diff --git a/src/frontend/app/components/StopSummarySheet.tsx b/src/frontend/app/components/StopSummarySheet.tsx deleted file mode 100644 index c2d6ffe..0000000 --- a/src/frontend/app/components/StopSummarySheet.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import { RefreshCw } from "lucide-react"; -import React, { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Sheet } from "react-modal-sheet"; -import { Link } from "react-router"; -import { ConsolidatedCirculationList } from "~/components/Stops/ConsolidatedCirculationList"; -import { REGION_DATA } from "~/config/RegionConfig"; -import type { Stop } from "~/data/StopDataProvider"; -import { type ConsolidatedCirculation } from "../routes/stops-$id"; -import { ErrorDisplay } from "./ErrorDisplay"; -import LineIcon from "./LineIcon"; -import { StopAlert } from "./StopAlert"; -import "./StopSummarySheet.css"; -import { StopSummarySheetSkeleton } from "./StopSummarySheetSkeleton"; - -interface StopSheetProps { - isOpen: boolean; - onClose: () => void; - stop: Stop; -} - -interface ErrorInfo { - type: "network" | "server" | "unknown"; - status?: number; - message?: string; -} - -const loadConsolidatedData = async ( - stopId: string -): Promise<ConsolidatedCirculation[]> => { - const resp = await fetch( - `${REGION_DATA.consolidatedCirculationsEndpoint}?stopId=${stopId}`, - { - headers: { - Accept: "application/json", - }, - } - ); - - if (!resp.ok) { - throw new Error(`HTTP ${resp.status}: ${resp.statusText}`); - } - - return await resp.json(); -}; - -export const StopSheet: React.FC<StopSheetProps> = ({ - isOpen, - onClose, - stop, -}) => { - const { t } = useTranslation(); - const [data, setData] = useState<ConsolidatedCirculation[] | null>(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState<ErrorInfo | null>(null); - const [lastUpdated, setLastUpdated] = useState<Date | null>(null); - - const parseError = (error: any): ErrorInfo => { - if (!navigator.onLine) { - return { type: "network", message: "No internet connection" }; - } - - if ( - error.message?.includes("Failed to fetch") || - error.message?.includes("NetworkError") - ) { - return { type: "network" }; - } - - if (error.message?.includes("HTTP")) { - const statusMatch = error.message.match(/HTTP (\d+):/); - const status = statusMatch ? parseInt(statusMatch[1]) : undefined; - return { type: "server", status }; - } - - return { type: "unknown", message: error.message }; - }; - - const loadData = async () => { - try { - setLoading(true); - setError(null); - setData(null); - - const stopData = await loadConsolidatedData(stop.stopId); - setData(stopData); - setLastUpdated(new Date()); - } catch (err) { - console.error("Failed to load stop data:", err); - setError(parseError(err)); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - if (isOpen && stop.stopId) { - loadData(); - } - }, [isOpen, stop.stopId]); - - // Show only the next 4 arrivals - const sortedData = data - ? [...data].sort( - (a, b) => - (a.realTime?.minutes ?? a.schedule?.minutes ?? 999) - - (b.realTime?.minutes ?? b.schedule?.minutes ?? 999) - ) - : []; - const limitedEstimates = sortedData.slice(0, 4); - - return ( - <Sheet isOpen={isOpen} onClose={onClose} detent="content"> - <Sheet.Container> - <Sheet.Header /> - <Sheet.Content drag="y"> - <div className="stop-sheet-content"> - <div className="stop-sheet-header"> - <h2 className="stop-sheet-title">{stop.name.original}</h2> - <span className="stop-sheet-id">({stop.stopId})</span> - </div> - - <div - className={`stop-sheet-lines-container ${stop.lines.length >= 10 ? "scrollable" : ""}`} - > - {stop.lines.map((line) => ( - <div key={line} className="stop-sheet-line-icon"> - <LineIcon line={line} mode="rounded" /> - </div> - ))} - </div> - - <StopAlert stop={stop} compact /> - - {loading ? ( - <StopSummarySheetSkeleton /> - ) : error ? ( - <ErrorDisplay - error={error} - onRetry={loadData} - title={t( - "errors.estimates_title", - "Error al cargar estimaciones" - )} - className="compact" - /> - ) : data ? ( - <> - <div className="stop-sheet-estimates"> - <h3 className="stop-sheet-subtitle"> - {t("estimates.next_arrivals", "Next arrivals")} - </h3> - - {limitedEstimates.length === 0 ? ( - <div className="stop-sheet-no-estimates"> - {t("estimates.none", "No hay estimaciones disponibles")} - </div> - ) : ( - <ConsolidatedCirculationList - data={data.slice(0, 4)} - driver={stop.stopId.split(":")[0]} - reduced - /> - )} - </div> - </> - ) : null} - </div> - </Sheet.Content> - - <div className="stop-sheet-footer"> - {lastUpdated && ( - <div className="stop-sheet-timestamp"> - {t("estimates.last_updated", "Actualizado a las")}{" "} - {lastUpdated.toLocaleTimeString(undefined, { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - })} - </div> - )} - - <div className="stop-sheet-actions"> - <button - className="stop-sheet-reload" - onClick={loadData} - disabled={loading} - title={t("estimates.reload", "Recargar estimaciones")} - > - <RefreshCw - className={`reload-icon ${loading ? "spinning" : ""}`} - /> - {t("estimates.reload", "Recargar")} - </button> - - <Link - to={`/stops/${stop.stopId}`} - className="stop-sheet-view-all" - onClick={onClose} - > - {t("map.view_all_estimates", "Ver todas las estimaciones")} - </Link> - </div> - </div> - </Sheet.Container> - <Sheet.Backdrop onTap={onClose} /> - </Sheet> - ); -}; |
