aboutsummaryrefslogtreecommitdiff
path: root/src/pages
diff options
context:
space:
mode:
authorAriel Costas Guerrero <94913521+arielcostas@users.noreply.github.com>2024-09-09 18:48:45 +0200
committerAriel Costas Guerrero <94913521+arielcostas@users.noreply.github.com>2024-09-09 18:48:57 +0200
commit9925249bf489ae960189f6daabe59263d1620c89 (patch)
treeda04f135ee1e724491c7cc1c5d128f285a83713e /src/pages
parent663a2a3ff10bf55498a6c8731b1a32e9f98d7343 (diff)
Favourite stops, local stop list
Diffstat (limited to 'src/pages')
-rw-r--r--src/pages/Home.tsx75
-rw-r--r--src/pages/Stop.tsx84
2 files changed, 87 insertions, 72 deletions
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
index 5070e5f..1f5c319 100644
--- a/src/pages/Home.tsx
+++ b/src/pages/Home.tsx
@@ -1,46 +1,16 @@
+import { useEffect, useMemo, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
-import useSWR from "swr";
+import { Stop, StopDataProvider } from "../data/stopDataProvider";
-interface Stop {
- stopId: number
- name: string;
- latitude?: number;
- longitude?: number;
- lines: string[];
-}
-
-interface CachedStopList {
- timestamp: number;
- data: Stop[];
-}
+const sdp = new StopDataProvider();
export function Home() {
- const navigate = useNavigate()
- const { data, error, isLoading } = useSWR<Stop[]>('home', async () => {
- const rawCachedData = localStorage.getItem('cachedStopList');
- if (rawCachedData) {
- const parsedData: CachedStopList = JSON.parse(rawCachedData)
+ const [data, setData] = useState<Stop[] | null>(null)
+ const navigate = useNavigate();
- // Cache for 12 hours
- if (Date.now() - parsedData.timestamp < 1000 * 60 * 60 * 12) {
- return parsedData.data
- } else {
- localStorage.removeItem('cachedStopList')
- }
- }
-
- const response = await fetch('/api/ListStops')
- const body = await response.json();
-
- const cachedData: CachedStopList = {
- timestamp: Date.now(),
- data: body
- }
-
- localStorage.setItem('cachedStopList', JSON.stringify(cachedData));
-
- return body;
- });
+ useEffect(() => {
+ sdp.getStops().then((stops: Stop[]) => setData(stops))
+ }, []);
const handleStopSearch = async (event: React.FormEvent) => {
event.preventDefault()
@@ -54,12 +24,15 @@ export function Home() {
}
}
- if (isLoading) return <h1>Loading...</h1>
- if (error) return <h1>Error</h1>
+ const favouritedStops = useMemo(() => {
+ return data?.filter(stop => stop.favourite) ?? []
+ }, [data])
+
+ if (data === null) return <h1>Loading...</h1>
return (
<>
- <h1>Home</h1>
+ <h1>UrbanoVigo Web</h1>
<form action="none" onSubmit={handleStopSearch}>
<div>
@@ -72,6 +45,26 @@ export function Home() {
<button type="submit">Buscar</button>
</form>
+ <h2>Paradas favoritas</h2>
+
+ {favouritedStops?.length == 1 && (
+ <p>
+ Accede a una parada y márcala como favorita para verla aquí.
+ </p>
+ )}
+
+ <ul>
+ {favouritedStops?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => (
+ <li key={stop.stopId}>
+ <Link to={`/${stop.stopId}`}>
+ ({stop.stopId}) {stop.name} - {stop.lines?.join(', ')}
+ </Link>
+ </li>
+ ))}
+ </ul>
+
+ <h2>Paradas</h2>
+
<ul>
{data?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => (
<li key={stop.stopId}>
diff --git a/src/pages/Stop.tsx b/src/pages/Stop.tsx
index a5effc1..4fa68cf 100644
--- a/src/pages/Stop.tsx
+++ b/src/pages/Stop.tsx
@@ -1,5 +1,6 @@
+import { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";
-import useSWR from "swr";
+import { StopDataProvider } from "../data/stopDataProvider";
interface StopDetails {
stop: {
@@ -8,28 +9,33 @@ interface StopDetails {
latitude: number;
longitude: number;
}
- estimates: [{
+ estimates: {
line: string;
route: string;
minutes: number;
meters: number;
- }]
+ }[]
}
export function Stop(): JSX.Element {
+ const sdp = new StopDataProvider();
+ const [data, setData] = useState<StopDetails | null>(null);
+ const [favourited, setFavourited] = useState(false);
const params = useParams();
- const { data, error, isLoading } = useSWR<StopDetails>(`stop-${params.stopId}`, async () => {
- let response;
+ const loadData = () => {
+ fetch(`/api/GetStopEstimates?id=${params.stopId}`)
+ .then(r => r.json())
+ .then((body: StopDetails) => setData(body));
+ };
- try {
- response = await fetch(`/api/GetStopEstimates?id=${params.stopId}`)
- return response.json()
- } catch (error) {
- console.error(error)
- throw new Error(`Failed to fetch data, status ${response!.status}, body: ${await response!.text()}`)
- }
- });
+ useEffect(() => {
+ loadData();
+
+ setFavourited(
+ sdp.isFavourite(parseInt(params.stopId ?? ""))
+ );
+ })
const absoluteArrivalTime = (minutes: number) => {
const now = new Date()
@@ -40,9 +46,7 @@ export function Stop(): JSX.Element {
}).format(arrival)
}
- if (isLoading) return <h1>Loading...</h1>
- if (error) return <h1>Error: {JSON.stringify(error)}</h1>
- if (data === undefined) return <h1>No data</h1>
+ if (data === null) return <h1>Cargando datos en tiempo real...</h1>
return (
<>
@@ -50,21 +54,31 @@ export function Stop(): JSX.Element {
<h1>{data?.stop.name} ({data?.stop.id})</h1>
</div>
- <Link to="/">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- strokeWidth="2"
- strokeLinecap="round"
- strokeLinejoin="round"
- style={{marginInlineEnd: '0.5em', width: '1em', height: '1em'}}
- >
- <path d="M19 12H5M12 19l-7-7 7-7" />
- </svg>
- Volver al listado de paradas
- </Link>
+ <div style={{display: 'flex', gap: '1rem'}}>
+ <Link to="/" className="button">
+ 🔙 Volver al listado de paradas
+ </Link>
+
+ {!favourited && (
+ <button type="button" onClick={() => {
+ sdp.addFavourite(parseInt(params.stopId ?? ""));
+ setFavourited(true);
+ }}>
+ ⭐ Añadir a favoritos
+ </button>
+ )}
+
+ {favourited && (
+ <button type="button" onClick={() => {
+ sdp.removeFavourite(parseInt(params.stopId ?? ""));
+ setFavourited(false);
+ }}>
+ ⭐Quitar de favoritos
+ </button>
+ )}
+
+ <button onClick={loadData}>⬇️ Recargar</button>
+ </div>
<table>
<caption>Estimaciones de llegadas</caption>
@@ -97,6 +111,14 @@ export function Stop(): JSX.Element {
</tr>
))}
</tbody>
+
+ {data?.estimates.length === 0 && (
+ <tfoot>
+ <tr>
+ <td colSpan={4}>No hay estimaciones disponibles</td>
+ </tr>
+ </tfoot>
+ )}
</table>
<p>