diff --git a/src/components/Map/MapView.jsx b/src/components/Map/MapView.jsx index 5aaf42b..4f3f2c9 100644 --- a/src/components/Map/MapView.jsx +++ b/src/components/Map/MapView.jsx @@ -100,7 +100,7 @@ const CATEGORY_MAP = { export default function MapView() { const containerRef = useRef(null); const mapRef = useRef(null); - const markersRef = useRef([]); + const markersRef = useRef([]); // [{ id, marker, el, compactHTML, expandedHTML }] const expandedElRef = useRef(null); const [status, setStatus] = useState("Loading posts..."); @@ -110,7 +110,6 @@ export default function MapView() { const [subFilter, setSubFilter] = useState(null); // sous-catégorie du bas const [userPosition, setUserPosition] = useState(null); // [lng, lat] - const [reloadToken, setReloadToken] = useState(0); const [viewParams, setViewParams] = useState({ center: null, @@ -307,6 +306,102 @@ export default function MapView() { } }, [mainFilter, bottomCategories, subFilter]); + /* ------------ FACTEUR EN COMMUN: CREATION D'UN MARKER POUR UN POST -------------- */ + const createMarkerForPost = (post) => { + const map = mapRef.current; + if (!map) return; + + const coords = getCoords(post); + if (!coords) return; + + // évite les doublons (même id déjà affiché) + if ( + typeof post.id === "number" && + markersRef.current.some((m) => m.id === post.id) + ) { + return; + } + + const [lngP, latP] = coords; + if ( + typeof lngP !== "number" || + typeof latP !== "number" || + Number.isNaN(lngP) || + Number.isNaN(latP) + ) { + return; + } + + const { title, body, short } = extract(post); + + const compactHTML = ` +
+
+ ${short} +
+ `; + + const expandedHTML = ` +
+
+
+ ${title} +
+
+ ${body} +
+
+ `; + + const el = document.createElement("div"); + el.className = "post-marker post-marker-compact"; + el.innerHTML = compactHTML; + + const marker = new maplibregl.Marker({ + element: el, + anchor: "bottom", + }) + .setLngLat(coords) + .addTo(map); + + const meta = { + id: post.id ?? null, + marker, + el, + compactHTML, + expandedHTML, + }; + markersRef.current.push(meta); + + const toggle = () => { + if (expandedElRef.current && expandedElRef.current !== el) { + const prev = markersRef.current.find( + (m) => m.el === expandedElRef.current + ); + if (prev) { + prev.el.className = "post-marker post-marker-compact"; + prev.el.innerHTML = prev.compactHTML; + } + } + + if (expandedElRef.current === el) { + el.className = "post-marker post-marker-compact"; + el.innerHTML = compactHTML; + expandedElRef.current = null; + } else { + el.className = "post-marker post-marker-expanded"; + el.innerHTML = expandedHTML; + expandedElRef.current = el; + } + }; + + el.addEventListener("click", toggle); + el.addEventListener("touchend", (e) => { + e.preventDefault(); + toggle(); + }); + }; + /* ------------ LOAD POSTS POUR LA ZONE COURANTE + FILTRES -------------- */ useEffect(() => { const map = mapRef.current; @@ -337,86 +432,13 @@ export default function MapView() { if (cancelled) return; + // ici on recharge la vue => on enlève tout puis on remet markersRef.current.forEach((m) => m.marker.remove()); markersRef.current = []; expandedElRef.current = null; posts.forEach((post) => { - const coords = getCoords(post); - if (!coords) return; - - const [lngP, latP] = coords; - if ( - typeof lngP !== "number" || - typeof latP !== "number" || - Number.isNaN(lngP) || - Number.isNaN(latP) - ) { - return; - } - - const { title, body, short } = extract(post); - - const compactHTML = ` -
-
- ${short} -
- `; - - const expandedHTML = ` -
-
-
- ${title} -
-
- ${body} -
-
- `; - - const el = document.createElement("div"); - el.className = "post-marker post-marker-compact"; - el.innerHTML = compactHTML; - - const marker = new maplibregl.Marker({ - element: el, - anchor: "bottom", - }) - .setLngLat(coords) - .addTo(map); - - const meta = { marker, el, compactHTML, expandedHTML }; - markersRef.current.push(meta); - - const toggle = () => { - if (expandedElRef.current && expandedElRef.current !== el) { - const prev = markersRef.current.find( - (m) => m.el === expandedElRef.current - ); - if (prev) { - prev.el.className = "post-marker post-marker-compact"; - prev.el.innerHTML = prev.compactHTML; - } - } - - if (expandedElRef.current === el) { - el.className = "post-marker post-marker-compact"; - el.innerHTML = compactHTML; - expandedElRef.current = null; - } else { - el.className = "post-marker post-marker-expanded"; - el.innerHTML = expandedHTML; - expandedElRef.current = el; - } - }; - - el.addEventListener("click", toggle); - el.addEventListener("touchend", (e) => { - e.preventDefault(); - toggle(); - }); + createMarkerForPost(post); }); setStatus(posts.length ? "" : "No posts found."); @@ -431,9 +453,9 @@ export default function MapView() { return () => { cancelled = true; }; - }, [viewParams, mainFilter, timeFilter, subFilter, reloadToken]); + }, [viewParams, mainFilter, timeFilter, subFilter]); - /* ------------ WEBSOCKET : RELOAD SUR new_post -------------- */ + /* ------------ WEBSOCKET : AJOUTER JUSTE LE NOUVEAU POST -------------- */ useEffect(() => { const proto = window.location.protocol === "https:" ? "wss" : "ws"; const host = @@ -454,10 +476,35 @@ export default function MapView() { ws.onmessage = (ev) => { try { const msg = JSON.parse(ev.data); - if (msg.type === "new_post") { - setReloadToken((n) => n + 1); + if (msg.type === "new_post" && msg.post) { + const p = msg.post; + + // Optionnel: respecter les filtres actuels + const catCode = categoryCode(mainFilter); + if (catCode && p.category && p.category.toUpperCase() !== catCode) { + return; + } + + // Position: ne l'afficher que s'il est dans le rayon courant + if (viewParams.center && viewParams.radiusKm) { + const coords = getCoords(p); + if (coords) { + const [lngP, latP] = coords; + const [lngC, latC] = viewParams.center; + const dKm = haversineKm(latC, lngC, latP, lngP); + if (dKm > viewParams.radiusKm * 1.2) { + // trop loin de la vue actuelle → on ignore + return; + } + } + } + + // On ajoute juste ce post, sans effacer les autres + createMarkerForPost(p); } - } catch (_) {} + } catch (_) { + // ignore + } }; ws.onerror = (e) => { @@ -469,7 +516,7 @@ export default function MapView() { ws.close(); } }; - }, []); + }, [mainFilter, viewParams]); /* ------------ ACTIONS UI -------------- */ @@ -479,7 +526,7 @@ export default function MapView() { map.flyTo({ center: userPosition, zoom: 9, - speed: 1.1, + speed: 1.2, curve: 1.5, essential: true, }); @@ -550,7 +597,7 @@ export default function MapView() { await createPost(payload); setIsSaving(false); setIsCreating(false); - setReloadToken((n) => n + 1); + // On ne refetch pas tout ici, on laisse le WS rajouter le nouveau } catch (e) { console.error("createPost error:", e); setIsSaving(false);