From 7c0509466c84c9526061d65ad7e6fe201f87423e Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 9 Dec 2025 05:35:48 +0000 Subject: [PATCH] Auto deploy: 2025-12-09 05:35:44 --- src/components/Map/MapView.jsx | 93 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/src/components/Map/MapView.jsx b/src/components/Map/MapView.jsx index 6aa5d8c..9fbb12f 100644 --- a/src/components/Map/MapView.jsx +++ b/src/components/Map/MapView.jsx @@ -1,7 +1,8 @@ import React, { useEffect, useRef, useState } from "react"; import maplibregl from "maplibre-gl"; -import "../../styles/maplibre.css"; // CSS locale copiée depuis maplibre-gl +import "../../styles/maplibre.css"; import "../../styles/mapMarkers.css"; + import { fetchPosts, fetchIpLocation, createPost } from "../../api/client"; import { @@ -19,34 +20,30 @@ import { } from "./mapFilter"; import { createMarkerForPost, clearAllMarkers } from "./markerManager"; -/* ===================================================== - COMPONENT - ===================================================== */ export default function MapView() { const containerRef = useRef(null); const mapRef = useRef(null); const markersRef = useRef([]); // [{ id, marker, el, ... }] const expandedElRef = useRef(null); - // posts bruts accumulés (sans filtre temps) + // posts bruts accumulés const allPostsRef = useRef([]); - // dernière zone fetchée (centre/rayon + filtres) pour éviter de spam le backend + // dernière zone fetchée const lastFetchRef = useRef({ - center: null, // [lng, lat] + center: null, // [lng, lat] radiusKm: null, - filterKey: "", // `${mainFilter}|${subFilter}` + filterKey: "", }); const [status, setStatus] = useState("Loading posts..."); - const [mainFilter, setMainFilter] = useState("All"); // All/News/Friends/Events/Market + const [mainFilter, setMainFilter] = useState("All"); // All/News/Friends/Events/Market const [timeFilter, setTimeFilter] = useState("RECENT"); // NOW/TODAY/RECENT/PAST - const [subFilter, setSubFilter] = useState("All"); // "All" ou sous-cat + const [subFilter, setSubFilter] = useState("All"); const [userPosition, setUserPosition] = useState(null); // [lng, lat] - // juste pour mémoriser centre/zoom et les sauver dans localStorage const [viewParams, setViewParams] = useState({ center: null, radiusKm: 250, @@ -66,7 +63,8 @@ export default function MapView() { const [isSaving, setIsSaving] = useState(false); const [saveError, setSaveError] = useState(""); - /* ------------ INIT MAP (THEME BLEU NUIT + LAST VIEW) -------------- */ + /* ================= INIT MAP ================= */ + useEffect(() => { if (!containerRef.current) return; @@ -87,6 +85,7 @@ export default function MapView() { layers: [ { id: "carto-dark-layer", + type: "raster", source: "carto-dark", }, ], @@ -114,19 +113,19 @@ export default function MapView() { hadLastView = true; } } - } catch (_) {} + } catch { + // ignore + } setHasLastView(hadLastView); map.addControl(new maplibregl.NavigationControl(), "top-right"); mapRef.current = map; - // première vue → viewParams map.on("load", () => { const vp = getViewFromMap(map); setViewParams(vp); }); - // update viewParams à chaque move (pour sauvegarder vue + servir de zone) map.on("moveend", () => { const vp = getViewFromMap(map); setViewParams(vp); @@ -140,7 +139,9 @@ export default function MapView() { zoom: map.getZoom(), }) ); - } catch (_) {} + } catch { + // ignore + } }); return () => { @@ -150,7 +151,8 @@ export default function MapView() { }; }, []); - /* ------------ POSITION UTILISATEUR (GPS/IP) -------------- */ + /* ================= POSITION UTILISATEUR (GPS / IP) ================= */ + useEffect(() => { const map = mapRef.current; if (!map) return; @@ -163,7 +165,9 @@ export default function MapView() { setUserPosition(coords); try { localStorage.setItem(LAST_POS_KEY, JSON.stringify({ lat, lon })); - } catch (_) {} + } catch { + // ignore + } if (!hasLastView) { map.flyTo({ @@ -185,7 +189,9 @@ export default function MapView() { setUserPosition([p.lon, p.lat]); } } - } catch (_) {} + } catch { + // ignore + } // 2) GPS → 3) IP backend function viaIpFallback() { @@ -222,7 +228,8 @@ export default function MapView() { }; }, [hasLastView]); - /* ------------ SOUS-CATEGORIES (bas) -------------- */ + /* ================= FILTRES (bas) ================= */ + const bottomCategories = FILTER_CATEGORY_MAP[mainFilter] || ["All"]; useEffect(() => { @@ -232,7 +239,8 @@ export default function MapView() { } }, [mainFilter, bottomCategories, subFilter]); - /* ------------ RECONSTRUIRE LES MARKERS SELON LE TIME FILTER -------------- */ + /* ================= MARKERS & TIME FILTER ================= */ + const rebuildMarkersForTimeFilter = (tf) => { const map = mapRef.current; if (!map) return; @@ -252,7 +260,8 @@ export default function MapView() { setStatus(visible.length ? "" : "No posts found."); }; - /* ------------ LOAD POSTS PAR ZONE + FILTRES (ACCUMULATIF) -------------- */ + /* ================= FETCH PAR ZONE (ACCUMULATIF) ================= */ + useEffect(() => { const map = mapRef.current; if (!map) return; @@ -267,13 +276,11 @@ export default function MapView() { const last = lastFetchRef.current; - // Si les filtres n'ont pas changé, on regarde la distance if (last.center && last.filterKey === filterKey) { const [lastLng, lastLat] = last.center; const distKm = haversineKm(lastLat, lastLng, viewParams.center[1], lng); - // Distance trop petite → même zone -> pas de refetch - const minMoveKm = Math.max(100, radiusKm * 0.4); // ex: 100 km ou 40% du rayon + const minMoveKm = Math.max(100, radiusKm * 0.4); if (distKm < minMoveKm) { return; } @@ -288,11 +295,10 @@ export default function MapView() { ? subFilter : ""; - // ici on utilise lat/lon/radius pour que le backend renvoie les posts de la zone const newPosts = await fetchPosts({ category: catCode, subCategory: subCatParam, - time: "", // on gère le temps en front + time: "", lat, lon: lng, radiusKm, @@ -303,14 +309,12 @@ export default function MapView() { const existing = allPostsRef.current || []; const byId = new Map(); - // garde tout ce qu'on avait déjà for (const p of existing) { if (p && typeof p.id !== "undefined") { byId.set(p.id, p); } } - // ajoute les nouveaux posts (sans écraser ceux déjà présents) if (Array.isArray(newPosts)) { for (const p of newPosts) { if (p && typeof p.id !== "undefined" && !byId.has(p.id)) { @@ -321,7 +325,6 @@ export default function MapView() { allPostsRef.current = Array.from(byId.values()); - // On se souvient de la dernière zone fetchée lastFetchRef.current = { center: [...viewParams.center], radiusKm, @@ -340,20 +343,16 @@ export default function MapView() { return () => { cancelled = true; }; - // on refetch SI: - // - la vue change assez (seuil calculé) - // - OU filtres changent - // (PAS quand timeFilter change, lui ne fait que rebuild côté front) // eslint-disable-next-line react-hooks/exhaustive-deps }, [viewParams, mainFilter, subFilter]); - /* ------------ QUAND LE TIME FILTER CHANGE, ON RECONSTRUIT JUSTE LES MARKERS -------------- */ useEffect(() => { rebuildMarkersForTimeFilter(timeFilter); // eslint-disable-next-line react-hooks/exhaustive-deps }, [timeFilter]); - /* ------------ WEBSOCKET : AJOUTE JUSTE LES POSTS QUI MATCH LES FILTRES -------------- */ + /* ================= WEBSOCKET ================= */ + useEffect(() => { const proto = window.location.protocol === "https:" ? "wss" : "ws"; const host = @@ -377,7 +376,6 @@ export default function MapView() { if (msg.type === "new_post" && msg.post) { const p = msg.post; - // Filtrage live: cat + sous-cat + temps const catCode = categoryCode(mainFilter); if ( catCode && @@ -392,7 +390,6 @@ export default function MapView() { return; } - // éviter doublon dans la liste const id = typeof p.id === "number" ? p.id : null; if ( id !== null && @@ -403,10 +400,11 @@ export default function MapView() { allPostsRef.current = [...allPostsRef.current, p]; - // et on l’ajoute visuellement createMarkerForPost(p, mapRef, markersRef, expandedElRef); } - } catch (_) {} + } catch { + // ignore + } }; ws.onerror = (e) => { @@ -420,7 +418,7 @@ export default function MapView() { }; }, [mainFilter, subFilter, timeFilter]); - /* ------------ ACTIONS UI -------------- */ + /* ================= ACTIONS UI ================= */ const handleFlyToMe = () => { const map = mapRef.current; @@ -506,7 +504,7 @@ export default function MapView() { } }; - /* ------------ RENDER -------------- */ + /* ================= RENDER ================= */ return (
@@ -547,7 +545,7 @@ export default function MapView() { ))}
- {/* RIGHT — catégories principales avec All */} + {/* RIGHT — main categories */}
{FILTER_MAIN_CATEGORIES.map((cat) => (
- {/* CROSSHAIR SUR LA MAP */} + {/* CROSSHAIR */} {isCreating && (
)} - {/* PANEL CREATION DE POST */} + {/* CREATE POST PANEL */} {isCreating && (
@@ -672,6 +670,7 @@ export default function MapView() { disabled={isSaving} > {isSaving ? "Posting..." : "Post as tommy"} +
)}