Auto deploy: 2025-12-09 04:21:25
This commit is contained in:
parent
9814fc411a
commit
ecf2e54778
|
|
@ -1,20 +1,20 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import maplibregl from "maplibre-gl";
|
import maplibregl from "maplibre-gl";
|
||||||
import "maplibre-gl/dist/maplibre-gl.css";
|
import "maplibregl/dist/maplibre-gl.css";
|
||||||
import { fetchPosts, fetchIpLocation, createPost } from "../../api/client";
|
import { fetchPosts, fetchIpLocation, createPost } from "../../api/client";
|
||||||
|
|
||||||
/* ------------ CONSTANTES LOCALSTORAGE -------------- */
|
/* ------------ CONSTANTES LOCALSTORAGE -------------- */
|
||||||
const LAST_POS_KEY = "sociowire:lastPosition"; // position utilisateur (GPS/IP)
|
const LAST_POS_KEY = "sociowire:lastPosition"; // position utilisateur (GPS/IP)
|
||||||
const LAST_VIEW_KEY = "sociowire:lastView"; // dernière vue carte (centre+zoom)
|
const LAST_VIEW_KEY = "sociowire:lastView"; // dernière vue carte (centre+zoom)
|
||||||
|
|
||||||
/* ------------ UTILS -------------- */
|
/* ------------ UTILS GEOMETRIE -------------- */
|
||||||
|
|
||||||
// petite haversine pour estimer le rayon en km en fonction du zoom
|
// Haversine pour calculer un rayon approx (km)
|
||||||
function haversineKm(lat1, lon1, lat2, lon2) {
|
function haversineKm(lat1, lon1, lat2, lon2) {
|
||||||
const R = 6371;
|
const R = 6371;
|
||||||
const toRad = (deg) => (deg * Math.PI) / 180;
|
const toRad = (deg) => (deg * Math.PI) / 180;
|
||||||
const dLat = toRad(lat2 - lat1);
|
const dLat = toRad(lat2 - lat1);
|
||||||
const dLon = toRad(lon2 - lon1);
|
const dLon = toRad(lat2 - lon1);
|
||||||
const a =
|
const a =
|
||||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||||
Math.cos(toRad(lat1)) *
|
Math.cos(toRad(lat1)) *
|
||||||
|
|
@ -41,6 +41,7 @@ function getViewFromMap(map) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extraction [lng, lat] depuis un post
|
||||||
function getCoords(post) {
|
function getCoords(post) {
|
||||||
const lat =
|
const lat =
|
||||||
post.lat ??
|
post.lat ??
|
||||||
|
|
@ -58,6 +59,46 @@ function getCoords(post) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------ UTILS CATEGORIES & TEMPS -------------- */
|
||||||
|
|
||||||
|
// Boutons de filtre principaux (droite)
|
||||||
|
const FILTER_MAIN_CATEGORIES = ["All", "News", "Friends", "Events", "Market"];
|
||||||
|
|
||||||
|
// pour le panneau du bas (sous-cats) – AVEC "All"
|
||||||
|
const FILTER_CATEGORY_MAP = {
|
||||||
|
All: ["All"],
|
||||||
|
News: ["All", "World", "Politics", "Tech", "Finance", "Local"],
|
||||||
|
Friends: ["All", "Nearby", "Chats", "Groups", "Stories", "Favs"],
|
||||||
|
Events: ["All", "Today", "Weekend", "Music", "Sports", "Local"],
|
||||||
|
Market: ["All", "Actu", "Tech", "Finan", "Sport", "Deals"],
|
||||||
|
};
|
||||||
|
|
||||||
|
// pour NEW POST seulement (PAS de "All")
|
||||||
|
const CREATE_CATEGORY_MAP = {
|
||||||
|
News: ["World", "Politics", "Tech", "Finance", "Local"],
|
||||||
|
Friends: ["Nearby", "Chats", "Groups", "Stories", "Favs"],
|
||||||
|
Events: ["Today", "Weekend", "Music", "Sports", "Local"],
|
||||||
|
Market: ["Actu", "Tech", "Finan", "Sport", "Deals"],
|
||||||
|
};
|
||||||
|
|
||||||
|
// map bouton -> code backend
|
||||||
|
function categoryCode(mainFilter) {
|
||||||
|
switch (mainFilter) {
|
||||||
|
case "News":
|
||||||
|
return "NEWS";
|
||||||
|
case "Friends":
|
||||||
|
return "FRIENDS";
|
||||||
|
case "Events":
|
||||||
|
return "EVENT"; // backend: EVENT
|
||||||
|
case "Market":
|
||||||
|
return "MARKET";
|
||||||
|
case "All":
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transforme un post en petits textes pour les bulles
|
||||||
function extract(post) {
|
function extract(post) {
|
||||||
const title = post.title || post.text || post.body || "Post";
|
const title = post.title || post.text || post.body || "Post";
|
||||||
const body =
|
const body =
|
||||||
|
|
@ -70,29 +111,55 @@ function extract(post) {
|
||||||
return { title, body, short };
|
return { title, body, short };
|
||||||
}
|
}
|
||||||
|
|
||||||
// map bouton -> code backend
|
// sous-catégorie: "All" = tout
|
||||||
function categoryCode(mainFilter) {
|
function matchesSubFilter(post, subFilter) {
|
||||||
switch (mainFilter) {
|
if (!subFilter || subFilter.toUpperCase() === "ALL" || subFilter === "All") {
|
||||||
case "News":
|
return true;
|
||||||
return "NEWS";
|
|
||||||
case "Friends":
|
|
||||||
return "FRIENDS";
|
|
||||||
case "Events":
|
|
||||||
return "EVENT"; // backend: EVENT (singulier)
|
|
||||||
case "Market":
|
|
||||||
return "MARKET";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
const raw = post.sub_category ?? post.subCategory ?? "";
|
||||||
|
const sub = raw.toString().toLowerCase();
|
||||||
|
return sub === subFilter.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------ CATEGORIES POUR LES CHIPS -------------- */
|
// time filter local – règles :
|
||||||
const CATEGORY_MAP = {
|
// Live/NOW = 10 minutes
|
||||||
News: ["World", "Politics", "Tech", "Finance", "Local"],
|
// Today/TODAY = 24 heures
|
||||||
Friends: ["Nearby", "Chats", "Groups", "Stories", "Favs"],
|
// Recently/RECENT = 4 heures
|
||||||
Events: ["Today", "Weekend", "Music", "Sports", "Local"],
|
// Past/PAST = plus vieux que 24 h
|
||||||
Market: ["Actu", "Tech", "Finan", "Sport", "Deals"],
|
function matchesTimeFilter(createdAt, timeFilter) {
|
||||||
};
|
if (!timeFilter) return true;
|
||||||
|
if (!createdAt) return true;
|
||||||
|
|
||||||
|
let d;
|
||||||
|
if (typeof createdAt === "string") {
|
||||||
|
if (createdAt.includes(" ")) {
|
||||||
|
d = new Date(createdAt.replace(" ", "T") + "Z");
|
||||||
|
} else {
|
||||||
|
d = new Date(createdAt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d = new Date(createdAt);
|
||||||
|
}
|
||||||
|
if (Number.isNaN(d.getTime())) return true;
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const diffMs = now.getTime() - d.getTime();
|
||||||
|
const diffMin = diffMs / 60000;
|
||||||
|
const diffHours = diffMs / 3600000;
|
||||||
|
|
||||||
|
switch (timeFilter) {
|
||||||
|
case "NOW": // Live = 10 minutes
|
||||||
|
return diffMin <= 10;
|
||||||
|
case "TODAY": // 24h
|
||||||
|
return diffHours <= 24;
|
||||||
|
case "RECENT": // 4h
|
||||||
|
return diffHours <= 4;
|
||||||
|
case "PAST": // plus vieux que 24h
|
||||||
|
return diffHours > 24;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* =====================================================
|
/* =====================================================
|
||||||
COMPONENT
|
COMPONENT
|
||||||
|
|
@ -103,11 +170,14 @@ export default function MapView() {
|
||||||
const markersRef = useRef([]); // [{ id, marker, el, compactHTML, expandedHTML }]
|
const markersRef = useRef([]); // [{ id, marker, el, compactHTML, expandedHTML }]
|
||||||
const expandedElRef = useRef(null);
|
const expandedElRef = useRef(null);
|
||||||
|
|
||||||
|
// posts bruts (sans filtre temps) pour la zone + cat + sous-cat
|
||||||
|
const allPostsRef = useRef([]);
|
||||||
|
|
||||||
const [status, setStatus] = useState("Loading posts...");
|
const [status, setStatus] = useState("Loading posts...");
|
||||||
|
|
||||||
const [mainFilter, setMainFilter] = useState("News"); // News/Friends/Events/Market
|
const [mainFilter, setMainFilter] = useState("All"); // All/News/Friends/Events/Market
|
||||||
const [timeFilter, setTimeFilter] = useState("RECENT"); // NOW/TODAY/RECENT/PAST
|
const [timeFilter, setTimeFilter] = useState("RECENT"); // NOW/TODAY/RECENT/PAST
|
||||||
const [subFilter, setSubFilter] = useState(null); // sous-catégorie du bas
|
const [subFilter, setSubFilter] = useState("All"); // "All" ou sous-cat
|
||||||
|
|
||||||
const [userPosition, setUserPosition] = useState(null); // [lng, lat]
|
const [userPosition, setUserPosition] = useState(null); // [lng, lat]
|
||||||
|
|
||||||
|
|
@ -118,13 +188,13 @@ export default function MapView() {
|
||||||
|
|
||||||
const [hasLastView, setHasLastView] = useState(false);
|
const [hasLastView, setHasLastView] = useState(false);
|
||||||
|
|
||||||
// création de post
|
// NEW POST
|
||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const [draftTitle, setDraftTitle] = useState("");
|
const [draftTitle, setDraftTitle] = useState("");
|
||||||
const [draftBody, setDraftBody] = useState("");
|
const [draftBody, setDraftBody] = useState("");
|
||||||
const [draftCategory, setDraftCategory] = useState("News");
|
const [draftCategory, setDraftCategory] = useState("News");
|
||||||
const [draftSubCategory, setDraftSubCategory] = useState(
|
const [draftSubCategory, setDraftSubCategory] = useState(
|
||||||
CATEGORY_MAP.News[0]
|
CREATE_CATEGORY_MAP.News[0]
|
||||||
);
|
);
|
||||||
const [draftCoords, setDraftCoords] = useState(null); // [lng, lat]
|
const [draftCoords, setDraftCoords] = useState(null); // [lng, lat]
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
@ -195,8 +265,6 @@ export default function MapView() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// à chaque fin de move/zoom :
|
// à chaque fin de move/zoom :
|
||||||
// - on maj viewParams (pour fetch)
|
|
||||||
// - on sauvegarde la vue dans localStorage
|
|
||||||
map.on("moveend", () => {
|
map.on("moveend", () => {
|
||||||
const vp = getViewFromMap(map);
|
const vp = getViewFromMap(map);
|
||||||
setViewParams(vp);
|
setViewParams(vp);
|
||||||
|
|
@ -210,9 +278,7 @@ export default function MapView() {
|
||||||
zoom: map.getZoom(),
|
zoom: map.getZoom(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} catch (_) {
|
} catch (_) {}
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -297,16 +363,16 @@ export default function MapView() {
|
||||||
}, [hasLastView]);
|
}, [hasLastView]);
|
||||||
|
|
||||||
/* ------------ SOUS-CATEGORIES (bas) -------------- */
|
/* ------------ SOUS-CATEGORIES (bas) -------------- */
|
||||||
const bottomCategories = CATEGORY_MAP[mainFilter] || [];
|
const bottomCategories = FILTER_CATEGORY_MAP[mainFilter] || ["All"];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!bottomCategories.length) return;
|
if (!bottomCategories.length) return;
|
||||||
if (!subFilter || !bottomCategories.includes(subFilter)) {
|
if (!subFilter || !bottomCategories.includes(subFilter)) {
|
||||||
setSubFilter(bottomCategories[0]);
|
setSubFilter("All");
|
||||||
}
|
}
|
||||||
}, [mainFilter, bottomCategories, subFilter]);
|
}, [mainFilter, bottomCategories, subFilter]);
|
||||||
|
|
||||||
/* ------------ FACTEUR COMMUN: CREATION D'UN MARKER POUR UN POST -------------- */
|
/* ------------ CRÉATION D'UN MARKER POUR UN POST -------------- */
|
||||||
const createMarkerForPost = (post) => {
|
const createMarkerForPost = (post) => {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
if (!map) return;
|
if (!map) return;
|
||||||
|
|
@ -365,7 +431,7 @@ export default function MapView() {
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
id: post.id ?? null,
|
id: typeof post.id === "number" ? post.id : null,
|
||||||
marker,
|
marker,
|
||||||
el,
|
el,
|
||||||
compactHTML,
|
compactHTML,
|
||||||
|
|
@ -402,7 +468,30 @@ export default function MapView() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------ LOAD POSTS POUR LA ZONE COURANTE + FILTRES -------------- */
|
/* ------------ RECONSTRUIRE LES MARKERS SELON LE TIME FILTER -------------- */
|
||||||
|
const rebuildMarkersForTimeFilter = (tf) => {
|
||||||
|
const map = mapRef.current;
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
// on enlève tous les markers
|
||||||
|
markersRef.current.forEach((m) => m.marker.remove());
|
||||||
|
markersRef.current = [];
|
||||||
|
expandedElRef.current = null;
|
||||||
|
|
||||||
|
const posts = allPostsRef.current || [];
|
||||||
|
|
||||||
|
const visible = posts.filter((p) =>
|
||||||
|
matchesTimeFilter(p.created_at || p.CreatedAt, tf)
|
||||||
|
);
|
||||||
|
|
||||||
|
visible.forEach((post) => {
|
||||||
|
createMarkerForPost(post);
|
||||||
|
});
|
||||||
|
|
||||||
|
setStatus(visible.length ? "" : "No posts found.");
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------ LOAD POSTS POUR LA ZONE COURANTE + CAT + SOUS-CAT -------------- */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
if (!map) return;
|
if (!map) return;
|
||||||
|
|
@ -419,12 +508,15 @@ export default function MapView() {
|
||||||
|
|
||||||
const catCode = categoryCode(mainFilter);
|
const catCode = categoryCode(mainFilter);
|
||||||
const subCatParam =
|
const subCatParam =
|
||||||
subFilter && subFilter.toUpperCase() !== "ALL" ? subFilter : "";
|
subFilter && subFilter.toUpperCase() !== "ALL" && subFilter !== "All"
|
||||||
|
? subFilter
|
||||||
|
: "";
|
||||||
|
|
||||||
|
// on laisse "time" vide -> le backend renvoie tout pour cette zone/cat/sous-cat
|
||||||
const posts = await fetchPosts({
|
const posts = await fetchPosts({
|
||||||
category: catCode,
|
category: catCode,
|
||||||
subCategory: subCatParam,
|
subCategory: subCatParam,
|
||||||
time: timeFilter,
|
time: "",
|
||||||
lat,
|
lat,
|
||||||
lon: lng,
|
lon: lng,
|
||||||
radiusKm,
|
radiusKm,
|
||||||
|
|
@ -432,17 +524,10 @@ export default function MapView() {
|
||||||
|
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
// *** ICI: les filtres contrôlent TOUT ***
|
allPostsRef.current = Array.isArray(posts) ? posts : [];
|
||||||
// On efface tous les markers, et on remet EXACTEMENT ce que le backend renvoie.
|
|
||||||
markersRef.current.forEach((m) => m.marker.remove());
|
|
||||||
markersRef.current = [];
|
|
||||||
expandedElRef.current = null;
|
|
||||||
|
|
||||||
posts.forEach((post) => {
|
// Puis on reconstruit les markers avec le timeFilter ACTUEL
|
||||||
createMarkerForPost(post);
|
rebuildMarkersForTimeFilter(timeFilter);
|
||||||
});
|
|
||||||
|
|
||||||
setStatus(posts.length ? "" : "No posts found.");
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Erreur chargement posts:", err);
|
console.error("Erreur chargement posts:", err);
|
||||||
if (!cancelled) setStatus("Error loading posts.");
|
if (!cancelled) setStatus("Error loading posts.");
|
||||||
|
|
@ -454,9 +539,16 @@ export default function MapView() {
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [viewParams, mainFilter, timeFilter, subFilter]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [viewParams, mainFilter, subFilter]);
|
||||||
|
|
||||||
/* ------------ WEBSOCKET : AJOUTER JUSTE LE NOUVEAU POST -------------- */
|
/* ------------ 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 -------------- */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const proto = window.location.protocol === "https:" ? "wss" : "ws";
|
const proto = window.location.protocol === "https:" ? "wss" : "ws";
|
||||||
const host =
|
const host =
|
||||||
|
|
@ -480,18 +572,25 @@ 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;
|
||||||
|
|
||||||
// Respecte les filtres actuels
|
// 1) catégorie
|
||||||
|
|
||||||
// 1) CATEGORY
|
|
||||||
const catCode = categoryCode(mainFilter);
|
const catCode = categoryCode(mainFilter);
|
||||||
if (catCode && p.category && p.category.toUpperCase() !== catCode) {
|
if (
|
||||||
|
catCode &&
|
||||||
|
p.category &&
|
||||||
|
p.category.toUpperCase() !== catCode
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) TIME filter : on fait confiance au backend (p.created_at récent)
|
// 2) sous-catégorie
|
||||||
// Si ton backend ne renvoie pas created_at, on laisse passer.
|
if (!matchesSubFilter(p, subFilter)) return;
|
||||||
|
|
||||||
// 3) ZONE: ne l'afficher que s'il est dans le rayon courant
|
// 3) temps (10 min / 24h / 4h / >24h)
|
||||||
|
if (!matchesTimeFilter(p.created_at || p.CreatedAt, timeFilter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) zone actuelle
|
||||||
if (viewParams.center && viewParams.radiusKm) {
|
if (viewParams.center && viewParams.radiusKm) {
|
||||||
const coords = getCoords(p);
|
const coords = getCoords(p);
|
||||||
if (coords) {
|
if (coords) {
|
||||||
|
|
@ -499,13 +598,24 @@ export default function MapView() {
|
||||||
const [lngC, latC] = viewParams.center;
|
const [lngC, latC] = viewParams.center;
|
||||||
const dKm = haversineKm(latC, lngC, latP, lngP);
|
const dKm = haversineKm(latC, lngC, latP, lngP);
|
||||||
if (dKm > viewParams.radiusKm * 1.2) {
|
if (dKm > viewParams.radiusKm * 1.2) {
|
||||||
// trop loin de la vue actuelle → on ignore
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On ajoute juste ce post, sans effacer les autres
|
// 5) éviter doublon (dans la liste brute)
|
||||||
|
const id = typeof p.id === "number" ? p.id : null;
|
||||||
|
if (
|
||||||
|
id !== null &&
|
||||||
|
allPostsRef.current.some((post) => post.id === id)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6) ajouter à la liste brute
|
||||||
|
allPostsRef.current = [...allPostsRef.current, p];
|
||||||
|
|
||||||
|
// 7) et si il match le timeFilter courant, on l'ajoute visuellement
|
||||||
createMarkerForPost(p);
|
createMarkerForPost(p);
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
|
@ -522,7 +632,7 @@ export default function MapView() {
|
||||||
ws.close();
|
ws.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [mainFilter, timeFilter, viewParams]);
|
}, [mainFilter, subFilter, timeFilter, viewParams]);
|
||||||
|
|
||||||
/* ------------ ACTIONS UI -------------- */
|
/* ------------ ACTIONS UI -------------- */
|
||||||
|
|
||||||
|
|
@ -551,9 +661,10 @@ export default function MapView() {
|
||||||
setDraftTitle("");
|
setDraftTitle("");
|
||||||
setDraftBody("");
|
setDraftBody("");
|
||||||
|
|
||||||
const main = mainFilter || "News";
|
// pour NEW POST on n'a PAS de catégorie "All"
|
||||||
|
const main = mainFilter === "All" ? "News" : mainFilter;
|
||||||
setDraftCategory(main);
|
setDraftCategory(main);
|
||||||
const list = CATEGORY_MAP[main] || CATEGORY_MAP.News;
|
const list = CREATE_CATEGORY_MAP[main] || CREATE_CATEGORY_MAP.News;
|
||||||
setDraftSubCategory(list[0]);
|
setDraftSubCategory(list[0]);
|
||||||
setDraftCoords(null);
|
setDraftCoords(null);
|
||||||
};
|
};
|
||||||
|
|
@ -603,7 +714,7 @@ export default function MapView() {
|
||||||
await createPost(payload);
|
await createPost(payload);
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
// On laisse le WS rajouter le nouveau
|
// le WS va pousser le nouveau post si il match les filtres
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("createPost error:", e);
|
console.error("createPost error:", e);
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
|
|
@ -632,12 +743,12 @@ export default function MapView() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* LEFT — temps */}
|
{/* LEFT — time filters */}
|
||||||
<div className="map-overlay map-overlay-left">
|
<div className="map-overlay map-overlay-left">
|
||||||
{[
|
{[
|
||||||
["NOW", "Now"],
|
["NOW", "Live"],
|
||||||
["TODAY", "Today"],
|
["TODAY", "Today"],
|
||||||
["RECENT", "Recent"],
|
["RECENT", "Recently"],
|
||||||
["PAST", "Past"],
|
["PAST", "Past"],
|
||||||
].map(([code, label]) => (
|
].map(([code, label]) => (
|
||||||
<button
|
<button
|
||||||
|
|
@ -652,9 +763,9 @@ export default function MapView() {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* RIGHT — filtres principaux */}
|
{/* RIGHT — catégories principales avec All */}
|
||||||
<div className="map-overlay map-overlay-right">
|
<div className="map-overlay map-overlay-right">
|
||||||
{["News", "Friends", "Events", "Market"].map((cat) => (
|
{FILTER_MAIN_CATEGORIES.map((cat) => (
|
||||||
<button
|
<button
|
||||||
key={cat}
|
key={cat}
|
||||||
className={
|
className={
|
||||||
|
|
@ -667,7 +778,7 @@ export default function MapView() {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* BOTTOM — arc courbé inversé autour du globe */}
|
{/* BOTTOM — sous-cats + All */}
|
||||||
<div className="map-overlay map-overlay-bottom">
|
<div className="map-overlay map-overlay-bottom">
|
||||||
{bottomCategories.map((c) => (
|
{bottomCategories.map((c) => (
|
||||||
<button
|
<button
|
||||||
|
|
@ -693,14 +804,14 @@ export default function MapView() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* CROSSHAIR SUR LA MAP (au-dessus du popup) */}
|
{/* CROSSHAIR SUR LA MAP */}
|
||||||
{isCreating && (
|
{isCreating && (
|
||||||
<div className="map-overlay map-crosshair" onClick={handlePickCenter}>
|
<div className="map-overlay map-crosshair" onClick={handlePickCenter}>
|
||||||
<div className="crosshair-aim" />
|
<div className="crosshair-aim" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* PANEL CREATION DE POST (1/5 du bas) */}
|
{/* PANEL CREATION DE POST */}
|
||||||
{isCreating && (
|
{isCreating && (
|
||||||
<div className="map-overlay create-post-panel">
|
<div className="map-overlay create-post-panel">
|
||||||
<div className="create-post-header">
|
<div className="create-post-header">
|
||||||
|
|
@ -727,7 +838,8 @@ export default function MapView() {
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const cat = e.target.value;
|
const cat = e.target.value;
|
||||||
setDraftCategory(cat);
|
setDraftCategory(cat);
|
||||||
const list = CATEGORY_MAP[cat] || CATEGORY_MAP.News;
|
const list =
|
||||||
|
CREATE_CATEGORY_MAP[cat] || CREATE_CATEGORY_MAP.News;
|
||||||
setDraftSubCategory(list[0]);
|
setDraftSubCategory(list[0]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -742,13 +854,13 @@ export default function MapView() {
|
||||||
value={draftSubCategory}
|
value={draftSubCategory}
|
||||||
onChange={(e) => setDraftSubCategory(e.target.value)}
|
onChange={(e) => setDraftSubCategory(e.target.value)}
|
||||||
>
|
>
|
||||||
{(CATEGORY_MAP[draftCategory] || CATEGORY_MAP.News).map(
|
{(CREATE_CATEGORY_MAP[draftCategory] ||
|
||||||
(sub) => (
|
CREATE_CATEGORY_MAP.News
|
||||||
|
).map((sub) => (
|
||||||
<option key={sub} value={sub}>
|
<option key={sub} value={sub}>
|
||||||
{sub}
|
{sub}
|
||||||
</option>
|
</option>
|
||||||
)
|
))}
|
||||||
)}
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue