From d051a9337c4c5b4ac46b37669ee1bf6b7b1a4b71 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 20 Jan 2026 06:53:52 +0000 Subject: [PATCH] Add commenter avatars & category colors to comments (v0.0.89) - Fetch profile avatars for commenters - Apply post category gradient to comment avatars - Add events, friends, market to CATEGORY_CONFIG - Fix first comment race condition with setTimeout Co-Authored-By: Claude Opus 4.5 --- package.json | 2 +- src/components/Posts/PostDetailModal.jsx | 33 +++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e0761f2..6b5b631 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sociowire-frontend", "private": true, - "version": "0.0.88", + "version": "0.0.89", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/src/components/Posts/PostDetailModal.jsx b/src/components/Posts/PostDetailModal.jsx index 3206cfa..d57af68 100644 --- a/src/components/Posts/PostDetailModal.jsx +++ b/src/components/Posts/PostDetailModal.jsx @@ -138,6 +138,10 @@ const CATEGORY_CONFIG = { traffic: { icon: "fa-car", gradient: "from-yellow-500 to-amber-500", color: "#fbbf24" }, live: { icon: "fa-broadcast-tower", gradient: "from-red-500 to-rose-500", color: "#ef4444" }, camera: { icon: "fa-video", gradient: "from-red-500 to-rose-500", color: "#ef4444" }, + events: { icon: "fa-calendar", gradient: "from-yellow-500 to-orange-500", color: "#eab308" }, + event: { icon: "fa-calendar", gradient: "from-yellow-500 to-orange-500", color: "#eab308" }, + friends: { icon: "fa-user-group", gradient: "from-green-500 to-emerald-500", color: "#22c55e" }, + market: { icon: "fa-store", gradient: "from-amber-500 to-orange-500", color: "#f59e0b" }, default: { icon: "fa-newspaper", gradient: "from-blue-500 to-cyan-500", color: "#60a5fa" }, }; @@ -486,6 +490,7 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe const [liked, setLiked] = useState(false); const [truth, setTruth] = useState({ score: 50, count: 0 }); const [authorAvatar, setAuthorAvatar] = useState(""); + const [commenterAvatars, setCommenterAvatars] = useState({}); const [comments, setComments] = useState([]); const [commentInput, setCommentInput] = useState(""); const [commentSending, setCommentSending] = useState(false); @@ -535,6 +540,22 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe }); }, [post?.author, post?.username]); + // Fetch commenter avatars + useEffect(() => { + if (!comments.length) return; + const usernames = [...new Set(comments.map(c => c.username).filter(Boolean))]; + // Only fetch for usernames we don't already have + const toFetch = usernames.filter(u => !commenterAvatars[u]); + if (!toFetch.length) return; + toFetch.forEach(username => { + fetchProfile(username).then(res => { + if (res?.avatar_url) { + setCommenterAvatars(prev => ({ ...prev, [username]: res.avatar_url })); + } + }); + }); + }, [comments]); + // Fetch comments const refreshComments = useCallback(async (autoOpen = false) => { if (!postId) return; @@ -592,8 +613,8 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe } else { setComments(prev => prev.map(c => c.id === tempId ? { ...c, _pending: false } : c)); } - // Refresh comments to get the real list - refreshComments(); + // Delay refresh to let backend commit + setTimeout(() => refreshComments(), 500); } else { setComments(prev => prev.map(c => c.id === tempId ? { ...c, _failed: true, _pending: false } : c)); } @@ -874,8 +895,12 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe
-
- {(c.username || "?")[0]?.toUpperCase()} +
+ {commenterAvatars[c.username] ? ( + {c.username} + ) : ( + (c.username || "?")[0]?.toUpperCase() + )}