From 3227c7bc6bd233c92b1cf54bec689f0582dca547 Mon Sep 17 00:00:00 2001
From: Ariel Costas Guerrero <ariel@costas.dev>
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.
---
 src/frontend/app/components/StopSheet.tsx | 213 ------------------------------
 1 file changed, 213 deletions(-)
 delete mode 100644 src/frontend/app/components/StopSheet.tsx

(limited to 'src/frontend/app/components/StopSheet.tsx')

diff --git a/src/frontend/app/components/StopSheet.tsx b/src/frontend/app/components/StopSheet.tsx
deleted file mode 100644
index 77bb5f1..0000000
--- a/src/frontend/app/components/StopSheet.tsx
+++ /dev/null
@@ -1,213 +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 { 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 { ConsolidatedCirculationCard } from "./Stops/ConsolidatedCirculationCard";
-import "./StopSheet.css";
-import { StopSheetSkeleton } from "./StopSheetSkeleton";
-
-interface StopSheetProps {
-  isOpen: boolean;
-  onClose: () => void;
-  stop: Stop;
-}
-
-interface ErrorInfo {
-  type: "network" | "server" | "unknown";
-  status?: number;
-  message?: string;
-}
-
-const loadConsolidatedData = async (
-  stopId: number
-): 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 ? (
-              <StopSheetSkeleton />
-            ) : 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>
-                  ) : (
-                    <div className="stop-sheet-estimates-list">
-                      {limitedEstimates.map((estimate, idx) => (
-                        <ConsolidatedCirculationCard
-                          key={idx}
-                          estimate={estimate}
-                          readonly
-                        />
-                      ))}
-                    </div>
-                  )}
-                </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>
-  );
-};
-- 
cgit v1.3

