aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/app/routes
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-09-07 17:29:53 +0200
committerAriel Costas Guerrero <ariel@costas.dev>2025-09-07 17:29:53 +0200
commit8182a08f60e88595984ba80b472f29ccf53c19bd (patch)
treec377ad8a7d43b8794b5df0f7283f71ac24408210 /src/frontend/app/routes
parent577a6f00a0f006ca51276ae606835c2d892da872 (diff)
feat: Enhance development scripts and add Angular support
- Added new scripts for Angular development and formatting in package.json. - Updated workspaces to include Angular frontend. - Modified backend project file to exclude specific views from content inclusion. - Updated logging settings in appsettings.json to include HttpClient warnings. - Refactored TimetableTable component for cleaner rendering. - Removed UpdateNotification component and related service worker management code. - Simplified service worker registration in root component. - Cleaned up settings page by removing update management functionality. - Improved stoplist component structure for better readability. - Updated PWA worker to streamline caching and response handling.
Diffstat (limited to 'src/frontend/app/routes')
-rw-r--r--src/frontend/app/routes/estimates-$id.tsx35
-rw-r--r--src/frontend/app/routes/settings.tsx108
-rw-r--r--src/frontend/app/routes/stoplist.tsx91
3 files changed, 64 insertions, 170 deletions
diff --git a/src/frontend/app/routes/estimates-$id.tsx b/src/frontend/app/routes/estimates-$id.tsx
index 1582275..ab10c53 100644
--- a/src/frontend/app/routes/estimates-$id.tsx
+++ b/src/frontend/app/routes/estimates-$id.tsx
@@ -122,8 +122,9 @@ export default function Estimates() {
}
};
- if (data === null)
+ if (data === null) {
return <h1 className="page-title">{t("common.loading")}</h1>;
+ }
return (
<div className="page-container estimates-page">
@@ -139,24 +140,24 @@ export default function Estimates() {
</h1>
</div>
- <div className="table-responsive">
- {tableStyle === "grouped" ? (
- <GroupedTable data={data} dataDate={dataDate} />
- ) : (
- <RegularTable data={data} dataDate={dataDate} />
- )}
- </div>
+ <div className="table-responsive">
+ {tableStyle === "grouped" ? (
+ <GroupedTable data={data} dataDate={dataDate} />
+ ) : (
+ <RegularTable data={data} dataDate={dataDate} />
+ )}
+ </div>
- <div className="timetable-section">
- <TimetableTable
- data={timetableData}
- currentTime={new Date().toTimeString().slice(0, 8)} // HH:MM:SS
- />
+ <div className="timetable-section">
+ <TimetableTable
+ data={timetableData}
+ currentTime={new Date().toTimeString().slice(0, 8)} // HH:MM:SS
+ />
- {timetableData.length > 0 && (
- <div className="timetable-actions">
- <Link
- to={`/timetable/${params.id}`}
+ {timetableData.length > 0 && (
+ <div className="timetable-actions">
+ <Link
+ to={`/timetable/${params.id}`}
className="view-all-link"
>
<ExternalLink className="external-icon" />
diff --git a/src/frontend/app/routes/settings.tsx b/src/frontend/app/routes/settings.tsx
index b75434d..3bc3492 100644
--- a/src/frontend/app/routes/settings.tsx
+++ b/src/frontend/app/routes/settings.tsx
@@ -2,8 +2,6 @@ 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();
@@ -19,63 +17,6 @@ export default function Settings() {
const [isCheckingUpdates, setIsCheckingUpdates] = useState(false);
const [updateMessage, setUpdateMessage] = useState<string | null>(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 (
<div className="page-container">
<h1 className="page-title">{t("about.title")}</h1>
@@ -153,55 +94,6 @@ export default function Settings() {
<dd>{t("about.details_grouped")}</dd>
</dl>
</details>
-
- <div className="settings-section">
- <h3>{t("about.app_updates", "Actualizaciones de la aplicación")}</h3>
- <div className="update-controls">
- <button
- className="update-button"
- onClick={handleCheckForUpdates}
- disabled={isCheckingUpdates}
- >
- {isCheckingUpdates ? (
- <>
- <RotateCcw className="spinning" size={18} />
- {t("about.checking_updates", "Comprobando...")}
- </>
- ) : (
- <>
- <Download size={18} />
- {t("about.check_updates", "Comprobar actualizaciones")}
- </>
- )}
- </button>
-
- <button
- className="clear-cache-button"
- onClick={handleClearCache}
- >
- <RotateCcw size={18} />
- {t("about.clear_cache", "Limpiar caché")}
- </button>
-
- <button
- className="reset-pwa-button"
- onClick={handleResetPWA}
- >
- <RotateCcw size={18} />
- {t("about.reset_pwa", "Reiniciar PWA (Nuclear)")}
- </button>
- </div>
-
- {updateMessage && (
- <div className={`update-message ${updateMessage.includes("Error") || updateMessage.includes("error") ? 'error' : 'success'}`}>
- {updateMessage}
- </div>
- )}
-
- <p className="update-help-text">
- {t("about.update_help", "Si tienes problemas con la aplicación o no ves las últimas funciones, usa estos botones para forzar una actualización o limpiar los datos guardados.")}
- </p>
- </div>
</section>
<h2>{t("about.credits")}</h2>
<p>
diff --git a/src/frontend/app/routes/stoplist.tsx b/src/frontend/app/routes/stoplist.tsx
index 1e55dc9..885a0da 100644
--- a/src/frontend/app/routes/stoplist.tsx
+++ b/src/frontend/app/routes/stoplist.tsx
@@ -69,8 +69,9 @@ export default function StopList() {
return stopsList.reverse();
}, [data]);
- if (data === null)
+ if (data === null) {
return <h1 className="page-title">{t("common.loading")}</h1>;
+ }
return (
<div className="page-container stoplist-page">
@@ -83,60 +84,60 @@ export default function StopList() {
</label>
<input
className="form-input"
- type="text"
- placeholder={randomPlaceholder}
- id="stopName"
- onChange={handleStopSearch}
- />
- </div>
- </form>
-
- {searchResults && searchResults.length > 0 && (
- <div className="list-container">
- <h2 className="page-subtitle">
- {t("stoplist.search_results", "Resultados de la búsqueda")}
- </h2>
- <ul className="list">
- {searchResults.map((stop: Stop) => (
- <StopItem key={stop.stopId} stop={stop} />
- ))}
- </ul>
- </div>
- )}
+ type="text"
+ placeholder={randomPlaceholder}
+ id="stopName"
+ onChange={handleStopSearch}
+ />
+ </div>
+ </form>
+ {searchResults && searchResults.length > 0 && (
<div className="list-container">
- <h2 className="page-subtitle">{t("stoplist.favourites")}</h2>
-
- {favouritedStops?.length === 0 && (
- <p className="message">
- {t(
- "stoplist.no_favourites",
- "Accede a una parada y márcala como favorita para verla aquí.",
- )}
- </p>
- )}
-
+ <h2 className="page-subtitle">
+ {t("stoplist.search_results", "Resultados de la búsqueda")}
+ </h2>
<ul className="list">
- {favouritedStops
- ?.sort((a, b) => a.stopId - b.stopId)
- .map((stop: Stop) => <StopItem key={stop.stopId} stop={stop} />)}
+ {searchResults.map((stop: Stop) => (
+ <StopItem key={stop.stopId} stop={stop} />
+ ))}
</ul>
</div>
+ )}
- {recentStops && recentStops.length > 0 && (
- <div className="list-container">
- <h2 className="page-subtitle">{t("stoplist.recents")}</h2>
+ <div className="list-container">
+ <h2 className="page-subtitle">{t("stoplist.favourites")}</h2>
- <ul className="list">
- {recentStops.map((stop: Stop) => (
- <StopItem key={stop.stopId} stop={stop} />
- ))}
- </ul>
- </div>
+ {favouritedStops?.length === 0 && (
+ <p className="message">
+ {t(
+ "stoplist.no_favourites",
+ "Accede a una parada y márcala como favorita para verla aquí.",
+ )}
+ </p>
)}
+ <ul className="list">
+ {favouritedStops
+ ?.sort((a, b) => a.stopId - b.stopId)
+ .map((stop: Stop) => <StopItem key={stop.stopId} stop={stop} />)}
+ </ul>
+ </div>
+
+ {recentStops && recentStops.length > 0 && (
<div className="list-container">
- <h2 className="page-subtitle">{t("stoplist.all_stops", "Paradas")}</h2>
+ <h2 className="page-subtitle">{t("stoplist.recents")}</h2>
+
+ <ul className="list">
+ {recentStops.map((stop: Stop) => (
+ <StopItem key={stop.stopId} stop={stop} />
+ ))}
+ </ul>
+ </div>
+ )}
+
+ <div className="list-container">
+ <h2 className="page-subtitle">{t("stoplist.all_stops", "Paradas")}</h2>
<ul className="list">
{data