import { useEffect, useMemo, useRef, useState, useCallback } from "react"; import StopDataProvider, { type Stop } from "../data/StopDataProvider"; import StopItem from "../components/StopItem"; import StopItemSkeleton from "../components/StopItemSkeleton"; import Fuse from "fuse.js"; import "./stoplist.css"; import { useTranslation } from "react-i18next"; import { useApp } from "../AppContext"; export default function StopList() { const { t } = useTranslation(); const { region } = useApp(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [searchResults, setSearchResults] = useState(null); const [favouriteIds, setFavouriteIds] = useState([]); const [recentIds, setRecentIds] = useState([]); const [favouriteStops, setFavouriteStops] = useState([]); const [recentStops, setRecentStops] = useState([]); const searchTimeout = useRef(null); const randomPlaceholder = useMemo( () => t("stoplist.search_placeholder"), [t], ); const fuse = useMemo( () => new Fuse(data || [], { threshold: 0.3, keys: ["name.original"] }), [data], ); // Load favourite and recent IDs immediately from localStorage useEffect(() => { setFavouriteIds(StopDataProvider.getFavouriteIds(region)); setRecentIds(StopDataProvider.getRecent(region)); }, [region]); // Load stops from network const loadStops = useCallback(async () => { try { setLoading(true); const stops = await StopDataProvider.loadStopsFromNetwork(region); // Add favourite flags to stops const favouriteStopsIds = StopDataProvider.getFavouriteIds(region); const stopsWithFavourites = stops.map(stop => ({ ...stop, favourite: favouriteStopsIds.includes(stop.stopId) })); setData(stopsWithFavourites); // Update favourite and recent stops with full data const favStops = stopsWithFavourites.filter(stop => favouriteStopsIds.includes(stop.stopId) ); setFavouriteStops(favStops); const recIds = StopDataProvider.getRecent(region); const recStops = recIds .map(id => stopsWithFavourites.find(stop => stop.stopId === id)) .filter(Boolean) as Stop[]; setRecentStops(recStops.reverse()); } catch (error) { console.error("Failed to load stops:", error); } finally { setLoading(false); } }, [region]); useEffect(() => { loadStops(); }, [loadStops]); const handleStopSearch = (event: React.ChangeEvent) => { const stopName = event.target.value || ""; if (searchTimeout.current) { clearTimeout(searchTimeout.current); } searchTimeout.current = setTimeout(() => { if (stopName.length === 0) { setSearchResults(null); 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); }; return (

UrbanoVigo Web

{searchResults && searchResults.length > 0 && (

{t("stoplist.search_results", "Resultados de la búsqueda")}

    {searchResults.map((stop: Stop) => ( ))}
)}

{t("stoplist.favourites")}

{favouriteIds.length === 0 && (

{t( "stoplist.no_favourites", "Accede a una parada y márcala como favorita para verla aquí.", )}

)}
    {loading && favouriteIds.length > 0 && favouriteIds.map((id) => ( )) } {!loading && favouriteStops .sort((a, b) => a.stopId - b.stopId) .map((stop) => )}
{(recentIds.length > 0 || (!loading && recentStops.length > 0)) && (

{t("stoplist.recents")}

    {loading && recentIds.length > 0 && recentIds.map((id) => ( )) } {!loading && recentStops.map((stop) => ( ))}
)}

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

    {loading && ( <> {Array.from({ length: 8 }, (_, index) => ( ))} )} {!loading && data ?.sort((a, b) => a.stopId - b.stopId) .map((stop) => )}
); }