Auto deploy: 2025-12-09 03:38:30
This commit is contained in:
parent
71368d4a5e
commit
c755c0c9c0
|
|
@ -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 = `
|
||||
<div class="marker-inner">
|
||||
<div class="marker-dot"></div>
|
||||
<span class="marker-text">${short}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const expandedHTML = `
|
||||
<div class="marker-expanded-inner">
|
||||
<div class="marker-expanded-header">
|
||||
<div class="marker-dot"></div>
|
||||
<span class="marker-expanded-title">${title}</span>
|
||||
</div>
|
||||
<div class="marker-expanded-body">
|
||||
${body}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 = `
|
||||
<div class="marker-inner">
|
||||
<div class="marker-dot"></div>
|
||||
<span class="marker-text">${short}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const expandedHTML = `
|
||||
<div class="marker-expanded-inner">
|
||||
<div class="marker-expanded-header">
|
||||
<div class="marker-dot"></div>
|
||||
<span class="marker-expanded-title">${title}</span>
|
||||
</div>
|
||||
<div class="marker-expanded-body">
|
||||
${body}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue