From ebfb7c1c8bc0a9ec50bde72eb9a0859c6e5dcee5 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Wed, 6 Aug 2025 21:52:21 +0200 Subject: Fix this fucking pile of steaming garbage --- src/frontend/app/routes/estimates-$id.css | 5 -- src/frontend/app/routes/estimates-$id.tsx | 59 ++++++---------- src/frontend/app/routes/map.css | 1 - src/frontend/app/routes/settings.css | 102 ++++++++++++++++++++++++++ src/frontend/app/routes/settings.tsx | 114 +++++++++++++++++++++++++++++- src/frontend/app/routes/stoplist.css | 5 -- src/frontend/app/routes/stoplist.tsx | 51 +++++-------- 7 files changed, 251 insertions(+), 86 deletions(-) (limited to 'src/frontend/app/routes') diff --git a/src/frontend/app/routes/estimates-$id.css b/src/frontend/app/routes/estimates-$id.css index 424c76f..8906147 100644 --- a/src/frontend/app/routes/estimates-$id.css +++ b/src/frontend/app/routes/estimates-$id.css @@ -29,11 +29,6 @@ } /* Estimates page specific styles */ -.estimates-page { - height: 100%; - overflow: hidden; -} - .estimates-header { display: flex; align-items: center; diff --git a/src/frontend/app/routes/estimates-$id.tsx b/src/frontend/app/routes/estimates-$id.tsx index d9b9b47..1582275 100644 --- a/src/frontend/app/routes/estimates-$id.tsx +++ b/src/frontend/app/routes/estimates-$id.tsx @@ -8,8 +8,6 @@ import { useApp } from "../AppContext"; import { GroupedTable } from "../components/GroupedTable"; import { useTranslation } from "react-i18next"; import { TimetableTable, type TimetableEntry } from "../components/TimetableTable"; -import { usePullToRefresh } from "../hooks/usePullToRefresh"; -import { PullToRefreshIndicator } from "../components/PullToRefresh"; import { useAutoRefresh } from "../hooks/useAutoRefresh"; export interface StopDetails { @@ -84,17 +82,6 @@ export default function Estimates() { ]); }, [loadEstimatesData, loadTimetableDataAsync]); - const { - containerRef, - isRefreshing, - pullDistance, - canRefresh, - } = usePullToRefresh({ - onRefresh: refreshData, - threshold: 80, - enabled: true, - }); - // Auto-refresh estimates data every 30 seconds useAutoRefresh({ onRefresh: loadEstimatesData, @@ -139,23 +126,18 @@ export default function Estimates() { return

{t("common.loading")}

; return ( -
- -
-

- - - {customName ?? data.stop.name}{" "} - ({data.stop.id}) -

-
+
+
+

+ + + {customName ?? data.stop.name}{" "} + ({data.stop.id}) +

+
{tableStyle === "grouped" ? ( @@ -175,15 +157,14 @@ export default function Estimates() {
- - {t("timetable.viewAll", "Ver todos los horarios")} - -
- )} -
- + className="view-all-link" + > + + {t("timetable.viewAll", "Ver todos los horarios")} + +
+ )} +
); } diff --git a/src/frontend/app/routes/map.css b/src/frontend/app/routes/map.css index 0b3ebe5..7d32de7 100644 --- a/src/frontend/app/routes/map.css +++ b/src/frontend/app/routes/map.css @@ -16,7 +16,6 @@ padding: 0; margin: 0; max-width: none; - overflow: hidden; } .fullscreen-map { diff --git a/src/frontend/app/routes/settings.css b/src/frontend/app/routes/settings.css index 8c612d3..47de391 100644 --- a/src/frontend/app/routes/settings.css +++ b/src/frontend/app/routes/settings.css @@ -92,3 +92,105 @@ .settings-section p { margin-top: 0.5em; } + +/* Update controls styles */ +.update-controls { + display: flex; + gap: 1rem; + margin-bottom: 1rem; + flex-wrap: wrap; +} + +.update-button, +.clear-cache-button { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem; + border: none; + border-radius: 8px; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; +} + +.update-button { + background-color: var(--button-background-color); + color: white; +} + +.update-button:hover:not(:disabled) { + background-color: var(--button-hover-background-color); +} + +.update-button:disabled { + background-color: var(--button-disabled-background-color); + cursor: not-allowed; +} + +.clear-cache-button { + background-color: #6c757d; + color: white; +} + +.clear-cache-button:hover { + background-color: #5a6268; +} + +.reset-pwa-button { + background-color: #dc3545; + color: white; + font-weight: bold; +} + +.reset-pwa-button:hover { + background-color: #c82333; +} + +.update-message { + padding: 0.75rem; + border-radius: 6px; + font-size: 0.9rem; + margin-bottom: 1rem; +} + +.update-message.success { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; +} + +.update-message.error { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} + +.update-help-text { + font-size: 0.85rem; + color: var(--subtitle-color); + line-height: 1.4; + margin: 0; +} + +.spinning { + animation: spin 1s linear infinite; +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +@media (max-width: 768px) { + .update-controls { + flex-direction: column; + } + + .update-button, + .clear-cache-button { + justify-content: center; + } +} diff --git a/src/frontend/app/routes/settings.tsx b/src/frontend/app/routes/settings.tsx index c08b2c9..b75434d 100644 --- a/src/frontend/app/routes/settings.tsx +++ b/src/frontend/app/routes/settings.tsx @@ -1,6 +1,9 @@ import { useApp } from "../AppContext"; import "./settings.css"; import { useTranslation } from "react-i18next"; +import { useState } from "react"; +import { swManager } from "../utils/serviceWorkerManager"; +import { RotateCcw, Download } from "lucide-react"; export default function Settings() { const { t, i18n } = useTranslation(); @@ -13,6 +16,66 @@ export default function Settings() { setMapPositionMode, } = useApp(); + const [isCheckingUpdates, setIsCheckingUpdates] = useState(false); + const [updateMessage, setUpdateMessage] = useState(null); + + const handleCheckForUpdates = async () => { + setIsCheckingUpdates(true); + setUpdateMessage(null); + + try { + // Check if service worker is supported + if (!("serviceWorker" in navigator)) { + setUpdateMessage(t("about.sw_not_supported", "Service Workers no son compatibles en este navegador")); + return; + } + + // Force check for updates + await swManager.checkForUpdates(); + + // Wait a moment for the update check to complete + setTimeout(() => { + if (swManager.isUpdateAvailable()) { + setUpdateMessage(t("about.update_available", "¡Nueva versión disponible! Aparecerá una notificación para actualizar.")); + } else { + setUpdateMessage(t("about.up_to_date", "Ya tienes la versión más reciente.")); + } + }, 2000); + + } catch (error) { + console.error("Error checking for updates:", error); + setUpdateMessage(t("about.update_error", "Error al comprobar actualizaciones. Intenta recargar la página.")); + } finally { + setIsCheckingUpdates(false); + } + }; + + const handleClearCache = async () => { + if (confirm(t("about.clear_cache_confirm", "¿Estás seguro de que quieres limpiar la caché? Esto eliminará todos los datos guardados localmente."))) { + try { + await swManager.clearCache(); + setUpdateMessage(t("about.cache_cleared", "Caché limpiada. La página se recargará para aplicar los cambios.")); + setTimeout(() => { + window.location.reload(); + }, 2000); + } catch (error) { + console.error("Error clearing cache:", error); + setUpdateMessage(t("about.cache_error", "Error al limpiar la caché.")); + } + } + }; + + const handleResetPWA = async () => { + if (confirm(t("about.reset_pwa_confirm", "¿Estás seguro? Esto eliminará TODOS los datos de la aplicación y la reiniciará completamente. Úsalo solo si hay problemas graves de caché."))) { + try { + await swManager.resetPWA(); + } catch (error) { + console.error("Error resetting PWA:", error); + setUpdateMessage(t("about.reset_pwa_error", "Error al reiniciar la PWA.")); + } + } + }; + return (

{t("about.title")}

@@ -67,7 +130,7 @@ export default function Settings() {
+

UrbanoVigo Web

+ +
+
+ +

{t("stoplist.all_stops", "Paradas")}

-
    - {data - ?.sort((a, b) => a.stopId - b.stopId) - .map((stop: Stop) => )} -
-
- +
    + {data + ?.sort((a, b) => a.stopId - b.stopId) + .map((stop: Stop) => )} +
+
); } -- cgit v1.3