From e51cdd89afc08274ca622e18b8127feca29e90a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 22:49:47 +0000 Subject: Add gallery components and improve search functionality Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com> --- src/frontend/app/routes/stoplist.tsx | 99 +++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 46 deletions(-) (limited to 'src/frontend/app/routes/stoplist.tsx') diff --git a/src/frontend/app/routes/stoplist.tsx b/src/frontend/app/routes/stoplist.tsx index e77dfb8..80267ea 100644 --- a/src/frontend/app/routes/stoplist.tsx +++ b/src/frontend/app/routes/stoplist.tsx @@ -2,6 +2,8 @@ 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 StopGallery from "../components/StopGallery"; +import ServiceAlerts from "../components/ServiceAlerts"; import Fuse from "fuse.js"; import "./stoplist.css"; import { useTranslation } from "react-i18next"; @@ -30,7 +32,10 @@ export default function StopList() { ); const fuse = useMemo( - () => new Fuse(data || [], { threshold: 0.3, keys: ["name.original"] }), + () => new Fuse(data || [], { + threshold: 0.3, + keys: ["name.original", "name.intersect", "stopId"] + }), [data], ); @@ -188,14 +193,14 @@ export default function StopList() { }, [loadStops]); const handleStopSearch = (event: React.ChangeEvent) => { - const stopName = event.target.value || ""; + const searchQuery = event.target.value || ""; if (searchTimeout.current) { clearTimeout(searchTimeout.current); } searchTimeout.current = setTimeout(() => { - if (stopName.length === 0) { + if (searchQuery.length === 0) { setSearchResults(null); return; } @@ -205,8 +210,27 @@ export default function StopList() { return; } - const results = fuse.search(stopName); - const items = results.map((result) => result.item); + // Check if search query is a number (stop code search) + const isNumericSearch = /^\d+$/.test(searchQuery.trim()); + + let items: Stop[]; + if (isNumericSearch) { + // Direct match for stop codes + const stopId = parseInt(searchQuery.trim(), 10); + const exactMatch = data.filter(stop => stop.stopId === stopId); + if (exactMatch.length > 0) { + items = exactMatch; + } else { + // Fuzzy search if no exact match + const results = fuse.search(searchQuery); + items = results.map((result) => result.item); + } + } else { + // Text search using Fuse.js + const results = fuse.search(searchQuery); + items = results.map((result) => result.item); + } + setSearchResults(items); }, 300); }; @@ -243,60 +267,43 @@ export default function StopList() { )} -
-

{t("stoplist.favourites")}

- - {favouriteIds.length === 0 && ( -

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

- )} - - -
- - {(recentIds.length > 0 || (!loading && recentStops.length > 0)) && ( -
-

{t("stoplist.recents")}

+ {!loading && ( + + )} -
    - {loading && recentIds.length > 0 && - recentIds.map((id) => ( - - )) - } - {!loading && recentStops.map((stop) => ( - - ))} -
-
+ {!loading && ( + a.stopId - b.stopId)} + title={t("stoplist.favourites")} + emptyMessage={t("stoplist.no_favourites")} + /> )} + +
-

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

+

+ {userLocation + ? t("stoplist.nearby_stops", "Nearby stops") + : t("stoplist.all_stops", "Paradas") + } +

    {loading && ( <> - {Array.from({ length: 8 }, (_, index) => ( + {Array.from({ length: 6 }, (_, index) => ( ))} )} {!loading && data - ? sortedAllStops.map((stop) => ) + ? (userLocation ? sortedAllStops.slice(0, 6) : sortedAllStops).map((stop) => ( + + )) : null}
-- cgit v1.3