diff --git a/src/pages/CommunityPage/CommunityDetail.jsx b/src/pages/CommunityPage/CommunityDetail.jsx index e9fab6a..b491a7e 100644 --- a/src/pages/CommunityPage/CommunityDetail.jsx +++ b/src/pages/CommunityPage/CommunityDetail.jsx @@ -1,129 +1,178 @@ -import { useEffect, useState } from 'react'; -import { FiHeart } from 'react-icons/fi'; -import { IoChatbubbleEllipsesOutline } from 'react-icons/io5'; -import { VscAccount } from 'react-icons/vsc'; -import { useParams } from 'react-router-dom'; -import styled from 'styled-components'; -import axios from '../../apis/AxiosInstance'; +import { useEffect, useState } from "react"; +import { FiHeart } from "react-icons/fi"; +import { IoChatbubbleEllipsesOutline } from "react-icons/io5"; +import { VscAccount } from "react-icons/vsc"; +import { useParams } from "react-router-dom"; +import styled from "styled-components"; +import axios from "../../apis/AxiosInstance"; const CommunityDetail = () => { const { no } = useParams(); // %% URL에서 글 번호(no)를 가져옴 %% - const [postDetail, setPostDetail] = useState([]); + const [itemDetail, setItemDetail] = useState([]); const [comments, setComments] = useState([]); - const [refreshComments, setRefreshComments] = useState(false); + const [newComment, setNewComment] = useState(""); + const [users, setUsers] = useState({}); + const [itemUserNickname, setItemUserNickname] = useState(""); + const [loading, setLoading] = useState(true); // 로딩 상태 관리 useEffect(() => { - axios - .get(`https://ureca.store/api/communities/${no}`) - .then(response => { - setPostDetail(response.data); - console.log('나눔 상세 :', response.data); - }) - .catch(error => { - console.error('Error fetching data:', error); - }); - }, [no]); - // 댓글 목록 불러오기 -useEffect(( ) => { - const fetchComments = async () => { - try { - const response = await axios.get(`https://ureca.store/api/communityComments`); - setComments(response.data); // 댓글 목록 갱신 - console.log('댓글 목록 :', response.data); - } catch (error) { - console.error('Error:', error); - } - }; + const fetchItemDetail = async () => { + try { + // 나눔 상세 가져오기 + const itemResponse = await axios.get(`/communities/${no}`); + setItemDetail(itemResponse.data); + console.log("나눔 상세 :", itemResponse.data); - fetchComments(); -}, [refreshComments]); + // 작성자의 닉네임 가져오기 + const userResponse = await axios.get(`/user/${itemResponse.data.user}`); + setItemUserNickname(userResponse.data.nickname); + } catch (error) { + console.error("Error fetching item or user data:", error); + } + }; + const fetchComments = async () => { + try { + // 댓글 목록 가져오기 + const commentsResponse = await axios.get(`/communityComments`); + const relevantComments = commentsResponse.data.filter( + (item) => item.post === parseInt(no) + ); + setComments(relevantComments); + console.log("댓글 목록 :", relevantComments); + + // 댓글 작성자들의 유저 정보 가져오기 + const userIds = [...new Set(relevantComments.map((item) => item.user))]; + const userResponses = await Promise.all( + userIds.map((userId) => axios.get(`/user/${userId}`)) + ); + + const userMap = {}; + userResponses.forEach((response) => { + userMap[response.data.userId] = response.data.nickname; + }); + setUsers(userMap); + } catch (error) { + console.error("Error fetching comments or user data:", error); + } finally { + setLoading(false); // 모든 로딩 완료 후 로딩 상태 해제 + } + }; + + setLoading(true); + fetchItemDetail(); + fetchComments(); + }, [no]); // 좋아요 수 증가 함수 const good = () => { - const updatedGood = postDetail.good + 1; + const updatedGood = itemDetail.good + 1; axios - .put(`https://ureca.store/api/communities/${no}`, { ...postDetail, good: updatedGood }) - .then(response => { - console.log('좋아요 업데이트:', response.data); - setPostDetail(prevDetail => ({ ...prevDetail, good: updatedGood })); + .put(`/communities/${no}`, { + ...itemDetail, + good: updatedGood, + }) + .then((response) => { + console.log("좋아요 업데이트:", response.data); + setItemDetail((prevDetail) => ({ ...prevDetail, good: updatedGood })); }) - .catch(error => { - console.error('좋아요 업데이트 실패:', error); + .catch((error) => { + console.error("좋아요 업데이트 실패:", error); }); - } - //댓글 등록 - const handleSubmit = e => { - e.preventDefault(); // 새로고침 방지 - const formData = new FormData(e.target); - const user = localStorage.getItem('userId'); - const data = Object.fromEntries(formData.entries()); //객체로 변환 - data.post = no; - data.user = user; + }; + + // 댓글 등록 + const handleCommentSubmit = (e) => { + e.preventDefault(); + const userId = localStorage.getItem("userId"); axios - .post('https://ureca.store/api/communityComments', data) - .then(response => { - console.log('등록 : ', response.data); - setComments(prevComments => [...prevComments, response.data]); - console.log('등록 data : ', data); - alert('댓글이 등록되었습니다!'); - setRefreshComments(prev => !prev); + .post("/communityComments", { + post: no, + user: userId, + comment: newComment, + }) + .then((response) => { + console.log("댓글 등록 성공:", response.data); + setNewComment(""); + return axios.get(`/communityComments`); + }) + .then((response) => { + const relevantComments = response.data.filter( + (item) => item.post === parseInt(no) + ); + setComments(relevantComments); }) - .catch(error => console.error('오류 발생:', error)); + .catch((error) => { + console.error("댓글 등록 실패:", error); + }); + }; - e.target.reset(); // 입력값 초기화 + // 댓글 입력 핸들러 + const handleCommentChange = (e) => { + setNewComment(e.target.value); }; return ( - + 1 / 5 - 작성자: {postDetail.user} + 작성자: {itemUserNickname || "로딩 중..."} - 제목: {postDetail.title} + 제목: {itemDetail.title} -
+ { good(); }} /> - {postDetail.good || 0} + {itemDetail.good || 0} - {comments.filter(item => item.post === postDetail.postId).length} -
+ {comments.length} +
- {postDetail.price ? `${postDetail.price.toLocaleString()}원` : <나눔>나눔} + + {itemDetail.price ? ( + `${itemDetail.price.toLocaleString()}원` + ) : ( + <나눔>나눔 + )} +
- 작성글: {postDetail.contents} + 작성글: {itemDetail.contents} - {comments - .filter(item => item.post === postDetail.postId) - .map(item => ( -
- - - 작성자: {item.length > 0 && item[0].user} - - {new Date(item.createdAt).toLocaleDateString('ko-KR', { - timeZone: 'Asia/Seoul', - })} - - - {item.comment} -
- ))} + {comments.map((item) => ( +
+ + + 작성자: {users[item.user] || "로딩 중..."} + + {new Date(item.createdAt).toLocaleDateString("ko-KR", { + timeZone: "Asia/Seoul", + })} + + + {item.comment} +
+ ))}
- - + + 등록
@@ -135,7 +184,6 @@ export default CommunityDetail; const ItemTitle = styled.div` display: flex; flex-direction: column; - height: 100%; width: 100%; padding: 64px 25px 0px 25px; `; @@ -146,7 +194,7 @@ const ListImg = styled.img` background-color: #d9d9d9; border-radius: 10px; flex-shrink: calc(); /* 이미지 크기를 고정 */ - background-image: url(${props => props.src}); /* 이미지 URL 설정 */ + background-image: url(${(props) => props.src}); /* 이미지 URL 설정 */ background-size: cover; /* 이미지를 채우도록 설정 */ background-position: center; /* 이미지 중앙 정렬 */ `; @@ -173,13 +221,6 @@ const User1 = styled.div` font-size: 16px; margin-top: 10px; `; - -const VscAccount1 = styled(VscAccount)` - font-size: 12px; - margin-right: 3px; - align-items: center; - justify-content: center; -`; const Title = styled.div` font-size: 20px; font-weight: bold; @@ -223,44 +264,65 @@ const Line = styled.div` border-top: 1px solid #ff6e00; margin: 10px 0px; `; -const User2 = styled.div` + +const LikeCommentBox = styled.div` display: flex; + gap: 3px; align-items: center; + font-size: 14px; +`; + +const CommentST = styled.div` + font-size: 14px; + display: flex; + flex-direction: column; + border-radius: 10px; +`; - font-size: 12px; +const User2 = styled.div` + display: flex; + align-items: center; + font-size: 14px; + font-weight: bold; margin-top: 10px; + color: #333; `; + +const VscAccount1 = styled(VscAccount)` + font-size: 18px; + margin-right: 5px; + color: #ff6e00; + align-items: center; + justify-content: center; +`; + const ListDate = styled.div` - font-size: 8px; - color: #8d8d8d; - display: flex; - margin-left: 5px; - margin-top: 2px; + font-size: 10px; + color: #888; + margin-left: 10px; `; + const Comment = styled.div` - font-size: 12px; - display: flex; -`; -const CommentST = styled.div` - font-size: 12px; - display: flex; - flex-direction: column; + font-size: 14px; + color: #555; + margin-top: 5px; + background: #ffffff; + padding: 10px; + border-radius: 10px; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); + line-height: 1.5; `; + const CommentFrom = styled.form` width: 100%; - position: absolute; display: flex; justify-content: flex-end; bottom: 0px; - margin-top: auto; - margin-bottom: 64px; -`; -const Container = styled.div` - height: 100dvh; - display: flex; - flex-direction: column; - position: relative; + margin-top: 10px; + margin-bottom: 70px; + padding: 0 20px; `; + const CommentCC = styled.input` height: 40px; width: 100%; @@ -268,20 +330,35 @@ const CommentCC = styled.input` border-style: none; outline: none; background-color: #f0f0f0; - border-width: 0.5px; + border-radius: 20px; + padding: 0px 15px; + font-size: 14px; + transition: background-color 0.3s ease; + &:focus { + background-color: #e6e6e6; + } `; + const CommentSubmit = styled.button` - height: 36px; - width: 56px; + height: 40px; + width: 70px; display: flex; - position: absolute; justify-content: center; align-items: center; font-size: 14px; - margin: 2px 2px 2px 0px; + margin: 0px 10px; cursor: pointer; - transition: border-color 0.3s ease, color 0.3s ease; + background-color: #ff6e00; + color: white; + border: none; + border-radius: 15px; + transition: background-color 0.3s ease; &:hover { - text-shadow: 0px 0px 10px #8d8d8d; + background-color: #e65c00; } `; + +const Container = styled.div` + display: flex; + flex-direction: column; +`;