diff options
Diffstat (limited to 'src/frontend/app/routes/stoplist.tsx')
| -rw-r--r-- | src/frontend/app/routes/stoplist.tsx | 214 |
1 files changed, 116 insertions, 98 deletions
diff --git a/src/frontend/app/routes/stoplist.tsx b/src/frontend/app/routes/stoplist.tsx index 9404b39..58cdab4 100644 --- a/src/frontend/app/routes/stoplist.tsx +++ b/src/frontend/app/routes/stoplist.tsx @@ -2,125 +2,143 @@ import { useEffect, useMemo, useRef, useState } from "react"; import StopDataProvider, { type Stop } from "../data/StopDataProvider"; import StopItem from "../components/StopItem"; import Fuse from "fuse.js"; -import './stoplist.css'; +import "./stoplist.css"; import { useTranslation } from "react-i18next"; export default function StopList() { - const { t } = useTranslation(); - const [data, setData] = useState<Stop[] | null>(null) - const [searchResults, setSearchResults] = useState<Stop[] | null>(null); - const searchTimeout = useRef<NodeJS.Timeout | null>(null); + const { t } = useTranslation(); + const [data, setData] = useState<Stop[] | null>(null); + const [searchResults, setSearchResults] = useState<Stop[] | null>(null); + const searchTimeout = useRef<NodeJS.Timeout | null>(null); - const randomPlaceholder = useMemo(() => t('stoplist.search_placeholder'), [t]); - const fuse = useMemo(() => new Fuse(data || [], { threshold: 0.3, keys: ['name.original'] }), [data]); + const randomPlaceholder = useMemo( + () => t("stoplist.search_placeholder"), + [t], + ); + const fuse = useMemo( + () => new Fuse(data || [], { threshold: 0.3, keys: ["name.original"] }), + [data], + ); - useEffect(() => { - StopDataProvider.getStops().then((stops: Stop[]) => setData(stops)) - }, []); + useEffect(() => { + StopDataProvider.getStops().then((stops: Stop[]) => setData(stops)); + }, []); - const handleStopSearch = (event: React.ChangeEvent<HTMLInputElement>) => { - const stopName = event.target.value || ""; + const handleStopSearch = (event: React.ChangeEvent<HTMLInputElement>) => { + const stopName = event.target.value || ""; - if (searchTimeout.current) { - clearTimeout(searchTimeout.current); - } + if (searchTimeout.current) { + clearTimeout(searchTimeout.current); + } - searchTimeout.current = setTimeout(() => { - if (stopName.length === 0) { - setSearchResults(null); - return; - } + searchTimeout.current = setTimeout(() => { + if (stopName.length === 0) { + setSearchResults(null); + return; + } - if (!data) { - console.error("No data available for search"); - return; - } + if (!data) { + console.error("No data available for search"); + return; + } - const results = fuse.search(stopName); - const items = results.map(result => result.item); - setSearchResults(items); - }, 300); - } + const results = fuse.search(stopName); + const items = results.map((result) => result.item); + setSearchResults(items); + }, 300); + }; - const favouritedStops = useMemo(() => { - return data?.filter(stop => stop.favourite) ?? [] - }, [data]) + const favouritedStops = useMemo(() => { + return data?.filter((stop) => stop.favourite) ?? []; + }, [data]); - const recentStops = useMemo(() => { - // no recent items if data not loaded - if (!data) return null; - const recentIds = StopDataProvider.getRecent(); - if (recentIds.length === 0) return null; - // map and filter out missing entries - const stopsList = recentIds - .map(id => data.find(stop => stop.stopId === id)) - .filter((s): s is Stop => Boolean(s)); - return stopsList.reverse(); - }, [data]); + const recentStops = useMemo(() => { + // no recent items if data not loaded + if (!data) return null; + const recentIds = StopDataProvider.getRecent(); + if (recentIds.length === 0) return null; + // map and filter out missing entries + const stopsList = recentIds + .map((id) => data.find((stop) => stop.stopId === id)) + .filter((s): s is Stop => Boolean(s)); + return stopsList.reverse(); + }, [data]); - if (data === null) return <h1 className="page-title">{t('common.loading')}</h1> + if (data === null) + return <h1 className="page-title">{t("common.loading")}</h1>; - return ( - <div className="page-container"> - <h1 className="page-title">UrbanoVigo Web</h1> + return ( + <div className="page-container"> + <h1 className="page-title">UrbanoVigo Web</h1> - <form className="search-form"> - <div className="form-group"> - <label className="form-label" htmlFor="stopName"> - {t('stoplist.search_label', 'Buscar paradas')} - </label> - <input className="form-input" type="text" placeholder={randomPlaceholder} id="stopName" onChange={handleStopSearch} /> - </div> - </form> + <form className="search-form"> + <div className="form-group"> + <label className="form-label" htmlFor="stopName"> + {t("stoplist.search_label", "Buscar paradas")} + </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> - )} + {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> + )} - <div className="list-container"> - <h2 className="page-subtitle">{t('stoplist.favourites')}</h2> + <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> - )} + {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> + <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.recents')}</h2> + {recentStops && recentStops.length > 0 && ( + <div className="list-container"> + <h2 className="page-subtitle">{t("stoplist.recents")}</h2> - <ul className="list"> - {recentStops.map((stop: Stop) => ( - <StopItem key={stop.stopId} stop={stop} /> - ))} - </ul> - </div> - )} + <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> + <div className="list-container"> + <h2 className="page-subtitle">{t("stoplist.all_stops", "Paradas")}</h2> - <ul className="list"> - {data?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => ( - <StopItem key={stop.stopId} stop={stop} /> - ))} - </ul> - </div> - </div> - ) + <ul className="list"> + {data + ?.sort((a, b) => a.stopId - b.stopId) + .map((stop: Stop) => <StopItem key={stop.stopId} stop={stop} />)} + </ul> + </div> + </div> + ); } |
