added post modal for feed on map
This commit is contained in:
99
src/components/PostDetailModal.jsx
Normal file
99
src/components/PostDetailModal.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { API_URL } from "../config/authConstants";
|
||||
import { apiFetch } from "../api/apiClient";
|
||||
import { useAuthContext } from "../context/AuthContext";
|
||||
import { useFavorites } from "../hooks/useFavorites";
|
||||
import PostOnFeed from "../pages/PostOnFeed";
|
||||
import CloseIcon from "./icons/CloseIcon";
|
||||
|
||||
export default function PostDetailModal({ postId, onClose, onImageClick, onLocationClick, onAuthRequired }) {
|
||||
const { t } = useTranslation();
|
||||
const { user, isAuthenticated } = useAuthContext();
|
||||
const { toggleFavorite } = useFavorites();
|
||||
const [post, setPost] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [liked, setLiked] = useState(false);
|
||||
const [likeCountAdj, setLikeCountAdj] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!postId) return;
|
||||
let cancelled = false;
|
||||
|
||||
const fetchPost = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await apiFetch(`${API_URL}/api/v1/posts/detail/${postId}`);
|
||||
if (!res.ok) throw new Error("Failed to load post");
|
||||
const data = await res.json();
|
||||
if (!cancelled) {
|
||||
setPost({ ...data, type: data.type ? data.type.toLowerCase() : "loss" });
|
||||
setLiked(!!data.liked);
|
||||
setLikeCountAdj(0);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!cancelled) setError(e.message);
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPost();
|
||||
return () => { cancelled = true; };
|
||||
}, [postId]);
|
||||
|
||||
const handleLike = async (id) => {
|
||||
if (!isAuthenticated) {
|
||||
if (onAuthRequired) onAuthRequired();
|
||||
return;
|
||||
}
|
||||
const prev = liked;
|
||||
setLiked((v) => !v);
|
||||
setLikeCountAdj((v) => (prev ? v - 1 : v + 1));
|
||||
const result = await toggleFavorite(id);
|
||||
if (!result.success) {
|
||||
setLiked(prev);
|
||||
setLikeCountAdj((v) => (prev ? v + 1 : v - 1));
|
||||
}
|
||||
};
|
||||
|
||||
const isOwner = post && user && (post.authorId === user.id || post.userId === user.id);
|
||||
|
||||
return (
|
||||
<div className="f-modal-bg" onClick={(e) => e.target === e.currentTarget && onClose()}>
|
||||
<div className="f-modal f-post-detail-modal" onClick={(e) => e.stopPropagation()}>
|
||||
<button type="button" className="f-close-btn f-post-detail-close" onClick={onClose} aria-label={t("common.close")}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
|
||||
{loading && (
|
||||
<div className="f-post-detail-status">
|
||||
<div className="f-spinner" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="f-post-detail-status f-post-detail-error">
|
||||
{t("common.error")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{post && (
|
||||
<PostOnFeed
|
||||
ad={post}
|
||||
liked={liked}
|
||||
likeCountAdj={likeCountAdj}
|
||||
onLike={handleLike}
|
||||
isOwner={isOwner}
|
||||
onImageClick={onImageClick}
|
||||
onLocationClick={onLocationClick}
|
||||
onAuthRequired={onAuthRequired}
|
||||
compact
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user