diff --git a/.vscode/settings.json b/.vscode/settings.json index 02b2b65..f4fbe17 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "Française", "Lente", "localisation", + "moveend", "randomisation", "Rapide", "Rees", diff --git a/app/[lang]/tournois/SearchBar.tsx b/app/[lang]/tournois/SearchBar.tsx index bec0624..8332ed9 100644 --- a/app/[lang]/tournois/SearchBar.tsx +++ b/app/[lang]/tournois/SearchBar.tsx @@ -8,7 +8,7 @@ const SearchBar = () => { const [searchString, setSearchString] = useAtom(searchStringAtom); return ( -
+
diff --git a/app/[lang]/tournois/TournamentMap.tsx b/app/[lang]/tournois/TournamentMap.tsx index f875d6e..1a5f1a1 100644 --- a/app/[lang]/tournois/TournamentMap.tsx +++ b/app/[lang]/tournois/TournamentMap.tsx @@ -7,18 +7,28 @@ import { TileLayer, LayersControl, LayerGroup, + useMapEvent, } from "react-leaflet"; -import { useAtomValue } from "jotai"; +import { useAtomValue, useSetAtom } from "jotai"; import "leaflet/dist/leaflet.css"; import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css"; import "leaflet-defaulticon-compatibility"; -import { tournamentsAtom } from "@/app/atoms"; +import { tournamentsAtom, mapBoundsAtom } from "@/app/atoms"; import Legend from "./Legend"; import { TournamentMarker } from "./TournamentMarker"; +const MapEvents = () => { + const setMapBounds = useSetAtom(mapBoundsAtom); + const map = useMapEvent("moveend", () => { + setMapBounds(map.getBounds()); + }); + + return null; +}; + export default function TournamentMap() { const tournaments = useAtomValue(tournamentsAtom); const center: LatLngLiteral = { lat: 47.0844, lng: 2.3964 }; @@ -68,6 +78,7 @@ export default function TournamentMap() { height: "100%", }} > + -
+
-
- +
+
+ + + ([]); export const searchStringAtom = atom(''); +export const mapBoundsAtom = atom(null); +export const syncVisibleAtom = atom(true); export const { currentValueAtom: hoveredMapTournamentIdAtom, @@ -18,7 +21,16 @@ export const { export const filteredTournamentsAtom = atom((get) => { const tournaments = get(tournamentsAtom); const searchString = get(searchStringAtom).trim(); + const mapBounds = get(mapBoundsAtom); + const syncVisible = get(syncVisibleAtom); - if (searchString === '') return tournaments; - return tournaments.filter((t) => t.town.includes(searchString.toUpperCase())) + // When searching, we search all the tournament, regardless of the map display + if (searchString !== '') + return tournaments.filter((t) => t.town.includes(searchString.toUpperCase())) + + // If we not syncing to the map, return all tournaments + if (mapBounds === null || !syncVisible) return tournaments; + + // Filter by those in the current map bounds + return tournaments.filter(tournament => mapBounds.contains({ lat: tournament.coordinates[0], lng: tournament.coordinates[1]})) }) diff --git a/messages/en.json b/messages/en.json index bff781b..d8a8f9c 100644 --- a/messages/en.json +++ b/messages/en.json @@ -35,6 +35,7 @@ "loading": "Loading...", "searchLabel": "Search", "searchPlaceholder": "Search", + "syncWithMapCheckbox": "Tournaments visible on the map", "noneFound": "No tournaments found", "date": "Date", "town": "Town", diff --git a/messages/fr.json b/messages/fr.json index 7041bda..06edfdb 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -35,6 +35,7 @@ "loading": "Téléchargement...", "searchLabel": "Rechercher", "searchPlaceholder": "Rechercher", + "syncWithMapCheckbox": "Tournois visibles sur la carte", "noneFound": "Pas de tournois trouvé", "date": "Date", "town": "Ville", diff --git a/utils/atomWithDebounce.ts b/utils/atomWithDebounce.ts index fbf076a..8b94bc8 100644 --- a/utils/atomWithDebounce.ts +++ b/utils/atomWithDebounce.ts @@ -52,7 +52,7 @@ export default function atomWithDebounce( ); // exported atom setter to clear timeout if needed - const clearTimeoutAtom = atom(null, (get, set, _arg) => { + const clearTimeoutAtom = atom(null, (get, set) => { clearTimeout(get(prevTimeoutAtom)); set(isDebouncingAtom, false); });