Auto deploy: 2025-12-09 04:54:16
This commit is contained in:
parent
45eda7126f
commit
421b7ab20b
|
|
@ -11,7 +11,7 @@ import {
|
||||||
FILTER_CATEGORY_MAP,
|
FILTER_CATEGORY_MAP,
|
||||||
CREATE_CATEGORY_MAP,
|
CREATE_CATEGORY_MAP,
|
||||||
} from "./mapConfig";
|
} from "./mapConfig";
|
||||||
import { getViewFromMap } from "./mapGeo";
|
import { getViewFromMap, haversineKm } from "./mapGeo";
|
||||||
import {
|
import {
|
||||||
categoryCode,
|
categoryCode,
|
||||||
matchesSubFilter,
|
matchesSubFilter,
|
||||||
|
|
@ -28,9 +28,16 @@ export default function MapView() {
|
||||||
const markersRef = useRef([]); // [{ id, marker, el, ... }]
|
const markersRef = useRef([]); // [{ id, marker, el, ... }]
|
||||||
const expandedElRef = useRef(null);
|
const expandedElRef = useRef(null);
|
||||||
|
|
||||||
// posts bruts (sans filtre temps) – maintenant indépendants du zoom
|
// posts bruts accumulés (sans filtre temps)
|
||||||
const allPostsRef = useRef([]);
|
const allPostsRef = useRef([]);
|
||||||
|
|
||||||
|
// dernière zone fetchée (centre/rayon + filtres) pour éviter de spam le backend
|
||||||
|
const lastFetchRef = useRef({
|
||||||
|
center: null, // [lng, lat]
|
||||||
|
radiusKm: null,
|
||||||
|
filterKey: "", // `${mainFilter}|${subFilter}`
|
||||||
|
});
|
||||||
|
|
||||||
const [status, setStatus] = useState("Loading posts...");
|
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
|
||||||
|
|
@ -39,7 +46,7 @@ export default function MapView() {
|
||||||
|
|
||||||
const [userPosition, setUserPosition] = useState(null); // [lng, lat]
|
const [userPosition, setUserPosition] = useState(null); // [lng, lat]
|
||||||
|
|
||||||
// on garde ça juste pour mémoriser la vue & lastView
|
// juste pour mémoriser centre/zoom et les sauver dans localStorage
|
||||||
const [viewParams, setViewParams] = useState({
|
const [viewParams, setViewParams] = useState({
|
||||||
center: null,
|
center: null,
|
||||||
radiusKm: 250,
|
radiusKm: 250,
|
||||||
|
|
@ -120,7 +127,7 @@ export default function MapView() {
|
||||||
setViewParams(vp);
|
setViewParams(vp);
|
||||||
});
|
});
|
||||||
|
|
||||||
// update viewParams à chaque move (juste pour sauvegarder centre/zoom)
|
// update viewParams à chaque move (pour sauvegarder vue + servir de zone)
|
||||||
map.on("moveend", () => {
|
map.on("moveend", () => {
|
||||||
const vp = getViewFromMap(map);
|
const vp = getViewFromMap(map);
|
||||||
setViewParams(vp);
|
setViewParams(vp);
|
||||||
|
|
@ -246,11 +253,33 @@ export default function MapView() {
|
||||||
setStatus(visible.length ? "" : "No posts found.");
|
setStatus(visible.length ? "" : "No posts found.");
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------ LOAD POSTS (cat + sous-cat) – PLUS LIÉ AU ZOOM -------------- */
|
/* ------------ LOAD POSTS PAR ZONE + FILTRES (ACCUMULATIF) -------------- */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const map = mapRef.current;
|
||||||
|
if (!map) return;
|
||||||
|
if (!viewParams.center) return;
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
|
const [lng, lat] = viewParams.center;
|
||||||
|
const radiusKm = viewParams.radiusKm || 250;
|
||||||
|
const filterKey = `${mainFilter}|${subFilter}`;
|
||||||
|
|
||||||
|
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
|
||||||
|
if (distKm < minMoveKm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setStatus("Loading posts...");
|
setStatus("Loading posts...");
|
||||||
|
|
||||||
|
|
@ -260,16 +289,45 @@ export default function MapView() {
|
||||||
? subFilter
|
? subFilter
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
// ⚠️ PAS de lat/lon/radius → backend renvoie tout (limité à 500)
|
// ici on utilise lat/lon/radius pour que le backend renvoie les posts de la zone
|
||||||
const posts = await fetchPosts({
|
const newPosts = await fetchPosts({
|
||||||
category: catCode,
|
category: catCode,
|
||||||
subCategory: subCatParam,
|
subCategory: subCatParam,
|
||||||
time: "", // on gère le temps en front
|
time: "", // on gère le temps en front
|
||||||
|
lat,
|
||||||
|
lon: lng,
|
||||||
|
radiusKm,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
allPostsRef.current = Array.isArray(posts) ? posts : [];
|
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)) {
|
||||||
|
byId.set(p.id, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allPostsRef.current = Array.from(byId.values());
|
||||||
|
|
||||||
|
// On se souvient de la dernière zone fetchée
|
||||||
|
lastFetchRef.current = {
|
||||||
|
center: [...viewParams.center],
|
||||||
|
radiusKm,
|
||||||
|
filterKey,
|
||||||
|
};
|
||||||
|
|
||||||
rebuildMarkersForTimeFilter(timeFilter);
|
rebuildMarkersForTimeFilter(timeFilter);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -283,9 +341,12 @@ export default function MapView() {
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
// déclenche seulement quand la catégorie ou sous-cat change
|
// 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
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [mainFilter, subFilter]);
|
}, [viewParams, mainFilter, subFilter]);
|
||||||
|
|
||||||
/* ------------ QUAND LE TIME FILTER CHANGE, ON RECONSTRUIT JUSTE LES MARKERS -------------- */
|
/* ------------ QUAND LE TIME FILTER CHANGE, ON RECONSTRUIT JUSTE LES MARKERS -------------- */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -317,7 +378,7 @@ export default function MapView() {
|
||||||
if (msg.type === "new_post" && msg.post) {
|
if (msg.type === "new_post" && msg.post) {
|
||||||
const p = msg.post;
|
const p = msg.post;
|
||||||
|
|
||||||
// Filtrage live: cat + sous-cat + temps (plus de rayon)
|
// Filtrage live: cat + sous-cat + temps
|
||||||
const catCode = categoryCode(mainFilter);
|
const catCode = categoryCode(mainFilter);
|
||||||
if (
|
if (
|
||||||
catCode &&
|
catCode &&
|
||||||
|
|
@ -332,7 +393,7 @@ export default function MapView() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// évite doublon dans la liste
|
// éviter doublon dans la liste
|
||||||
const id = typeof p.id === "number" ? p.id : null;
|
const id = typeof p.id === "number" ? p.id : null;
|
||||||
if (
|
if (
|
||||||
id !== null &&
|
id !== null &&
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue