update frontend
This commit is contained in:
parent
f6957f347f
commit
666ca2bc1d
|
|
@ -1,39 +0,0 @@
|
|||
import React from "react";
|
||||
|
||||
function getKmFromPost(post) {
|
||||
return (
|
||||
post.km ??
|
||||
post.distance_km ??
|
||||
post.distanceKm ??
|
||||
post.dist_km ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
export default function PostCard({ post, selected, onSelect }) {
|
||||
const title = post.title || post.name || "Post";
|
||||
|
||||
const fullBody =
|
||||
post.body || post.content || post.text || "";
|
||||
|
||||
// texte court dans le Sociowall
|
||||
const body =
|
||||
fullBody.length > 80 ? fullBody.slice(0, 77) + "..." : fullBody;
|
||||
|
||||
const km = getKmFromPost(post);
|
||||
|
||||
function handleClick() {
|
||||
if (onSelect) onSelect(post);
|
||||
}
|
||||
|
||||
return (
|
||||
<article
|
||||
className={"post-card" + (selected ? " selected" : "")}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<h3>{title}</h3>
|
||||
<p>{body}</p>
|
||||
{km != null && <span className="post-km">{km} km</span>}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
import React, { useState, useMemo } from "react";
|
||||
import PostCard from "./PostCard";
|
||||
|
||||
function getKmFromPost(post) {
|
||||
return (
|
||||
post.km ??
|
||||
post.distance_km ??
|
||||
post.distanceKm ??
|
||||
post.dist_km ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
export default function PostList({
|
||||
posts,
|
||||
loading,
|
||||
error,
|
||||
selectedPost,
|
||||
onSelectPost,
|
||||
}) {
|
||||
const [kmFilter, setKmFilter] = useState(1000);
|
||||
|
||||
const filtered = useMemo(
|
||||
() =>
|
||||
posts.filter((p) => {
|
||||
const km = getKmFromPost(p);
|
||||
if (km == null) return true;
|
||||
return km <= kmFilter;
|
||||
}),
|
||||
[posts, kmFilter]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="post-list">
|
||||
<div className="post-list-header">
|
||||
<div className="km-filter">
|
||||
<label>
|
||||
Rayon : <span>{kmFilter} km</span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={1000}
|
||||
value={kmFilter}
|
||||
onChange={(e) => setKmFilter(Number(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{loading && <p className="status-text">Chargement...</p>}
|
||||
{error && <p className="status-text status-error">{error}</p>}
|
||||
|
||||
{filtered.map((p) => (
|
||||
<PostCard
|
||||
key={p.id ?? p._id}
|
||||
post={p}
|
||||
selected={selectedPost && (selectedPost.id ?? selectedPost._id) === (p.id ?? p._id)}
|
||||
onSelect={onSelectPost}
|
||||
/>
|
||||
))}
|
||||
|
||||
{!loading && filtered.length === 0 && (
|
||||
<p className="status-text">Aucun post dans ce rayon.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { fetchPosts } from "../../api/client";
|
||||
|
||||
function useHashParams() {
|
||||
const [hash, setHash] = useState(window.location.hash || "");
|
||||
useEffect(() => {
|
||||
const onHash = () => setHash(window.location.hash || "");
|
||||
window.addEventListener("hashchange", onHash);
|
||||
return () => window.removeEventListener("hashchange", onHash);
|
||||
}, []);
|
||||
const q = new URLSearchParams(hash.replace(/^#wall\??/, ""));
|
||||
return { hash, params: q };
|
||||
}
|
||||
|
||||
export default function WallPage() {
|
||||
const { params } = useHashParams();
|
||||
const [posts, setPosts] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const filters = useMemo(() => {
|
||||
const f = {};
|
||||
if (params.get("category")) f.category = params.get("category");
|
||||
if (params.get("sub")) f.subCategory = params.get("sub");
|
||||
if (params.get("time")) f.time = params.get("time");
|
||||
if (params.get("lat")) f.lat = Number(params.get("lat"));
|
||||
if (params.get("lon")) f.lon = Number(params.get("lon"));
|
||||
if (params.get("r")) f.radiusKm = Number(params.get("r"));
|
||||
return f;
|
||||
}, [params]);
|
||||
|
||||
useEffect(() => {
|
||||
let off = false;
|
||||
(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await fetchPosts(filters);
|
||||
if (!off) setPosts(Array.isArray(data) ? data : []);
|
||||
} finally {
|
||||
if (!off) setLoading(false);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
off = true;
|
||||
};
|
||||
}, [filters]);
|
||||
|
||||
return (
|
||||
<section className="wall-page">
|
||||
<div className="wall-header">
|
||||
<button className="wall-back" onClick={() => (window.location.hash = "")}>
|
||||
← Back to map
|
||||
</button>
|
||||
<div className="wall-title">SOCIOWALL — full view</div>
|
||||
</div>
|
||||
|
||||
<div className="wall-content">
|
||||
{loading && <div>Loading…</div>}
|
||||
{!loading && posts.length === 0 && <div>No posts with these filters.</div>}
|
||||
{posts.map((p) => (
|
||||
<article key={p.id ?? p._id} className="wall-post">
|
||||
<h3>{p.title || "Post"}</h3>
|
||||
<p>{p.snippet || p.body || p.text || ""}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue