From f6ea5dd10b4da0d963608f294706028ff70257f6 Mon Sep 17 00:00:00 2001 From: hjlee2778 Date: Mon, 30 Sep 2024 20:56:36 +0900 Subject: [PATCH] =?UTF-8?q?#21=20[feat]:=20=ED=8F=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=B3=B4=EA=B8=B0=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=A0=84=EC=B2=B4=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/Next-Btn.png | Bin 0 -> 471 bytes src/assets/icons/Previous-Btn.png | Bin 0 -> 529 bytes src/auth/Dashboard.jsx | 65 +++-- src/components/modals/PostDetailModal.jsx | 332 ++++++++++++++++++++++ 4 files changed, 374 insertions(+), 23 deletions(-) create mode 100644 src/assets/icons/Next-Btn.png create mode 100644 src/assets/icons/Previous-Btn.png create mode 100644 src/components/modals/PostDetailModal.jsx diff --git a/src/assets/icons/Next-Btn.png b/src/assets/icons/Next-Btn.png new file mode 100644 index 0000000000000000000000000000000000000000..c9e21ae26e6cfbc6b18a5f04bc04ea6370265cee GIT binary patch literal 471 zcmV;|0Vw{7P)EE700009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yP#iKKksJN{_&IcVCH+rl#JZ?HCH5{*&P+*xbJ1q!$6B#&$%E>O70R}!6%EyV@)8%UCmjuzuAh1*f1v>InEi2Q2R za-4NTgx2Gtv>x|CgqGuaGZPV7jhoCo5~;YH%C4qiyC zX55#VCo|9fesVS9vPT7_<9ggKI8i{UxB+)wy;0DdxQXKpRERp%CujPn>|am#-`E$y z{x5PxK6-1-Bx`lljSB1<8^3NxLJIc_*$}sU9A+(U9B1C>jOj21e14dx2~R=FmFN zJy1?54Gf`qSZyIolqFwbfD|Y3mU00RZBdYvZH5Lii^U{!^iUeg8KmfB-8OPHh**k? z4of!3MDFfai=U#?AdaY25Rkqp%Z;NIru8ku*u_irEj#%2jhE`aMW=y6ky=CU5_g3I z(lhUk`B!+RRr)gl@)>D{yl~@oD7nF&9cs(p=a}>F-w((#G!{H00000NkvXXu0mjf7AM$; literal 0 HcmV?d00001 diff --git a/src/auth/Dashboard.jsx b/src/auth/Dashboard.jsx index 6589797..ffb5c66 100644 --- a/src/auth/Dashboard.jsx +++ b/src/auth/Dashboard.jsx @@ -6,12 +6,14 @@ import PostCard from '../components/PostCard'; import { getUserData } from '../utils/api'; import UserCard from '../components/UserCard'; import UserProfile from '../components/UserProfile'; +import PostDetailModal from '../components/modals/PostDetailModal'; const Dashboard = () => { const [user, setUser] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); + const [isPostModalOpen, setIsPostModalOpen] = useState(false); const navigate = useNavigate(); const fetchUserData = useCallback(async () => { @@ -27,17 +29,14 @@ const Dashboard = () => { const parsedUser = JSON.parse(userData); console.log('Parsed user data from localStorage:', parsedUser); - // 사용자 ID 확인 const userId = parsedUser.id || parsedUser._id; if (!userId) { throw new Error('User ID is missing'); } - // 서버에서 최신 데이터 가져오기 const freshUserData = await getUserData(userId, token); console.log('Fresh user data from server:', freshUserData); - // 서버 데이터로 상태와 로컬 스토리지를 업데이트 const updatedUser = { ...parsedUser, ...freshUserData, @@ -59,26 +58,7 @@ const Dashboard = () => { }, [navigate]); useEffect(() => { - let isMounted = true; - const controller = new AbortController(); - - const loadData = async () => { - try { - await fetchUserData(); - } catch (error) { - if (isMounted) { - console.error('Error in useEffect:', error); - setError('Failed to load user data'); - } - } - }; - - loadData(); - - return () => { - isMounted = false; - controller.abort(); - }; + fetchUserData(); }, [fetchUserData]); const updateUserDetails = useCallback((updatedUser) => { @@ -90,6 +70,31 @@ const Dashboard = () => { const openModalHandler = () => setIsModalOpen(true); const closeModalHandler = () => setIsModalOpen(false); + // 테스트용 포스트 데이터 + const testPost = { + userImage: 'https://example.com/user-image.jpg', + username: 'TestUser', + title: 'Test Post Title', + albums: [ + { + coverImage: 'https://example.com/album1.jpg', + title: 'Album 1', + artist: 'Artist 1', + }, + { + coverImage: 'https://example.com/album2.jpg', + title: 'Album 2', + artist: 'Artist 2', + }, + ], + content: 'This is a test post content.', + likes: 10, + comments: [ + { username: 'Commenter1', content: 'Great post!' }, + { username: 'Commenter2', content: 'Nice music selection!' }, + ], + }; + if (isLoading) return Loading...; if (error) return {error}; if (!user) @@ -132,6 +137,12 @@ const Dashboard = () => { + + {/* PostDetailModal 테스트를 위한 버튼 */} + + {isModalOpen && ( { setUser={updateUserDetails} /> )} + + {isPostModalOpen && ( + setIsPostModalOpen(false)} + /> + )} ); }; diff --git a/src/components/modals/PostDetailModal.jsx b/src/components/modals/PostDetailModal.jsx new file mode 100644 index 0000000..2e62df3 --- /dev/null +++ b/src/components/modals/PostDetailModal.jsx @@ -0,0 +1,332 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import PreviousBtn from '../../assets/icons/Previous-Btn.png'; +import NextBtn from '../../assets/icons/Next-Btn.png'; + +const PostDetailModal = ({ onClose, postId }) => { + const [currentImage, setCurrentImage] = useState(0); + const dummyPost = { + userImage: 'https://example.com/user-image.jpg', + username: 'Heeju_2778', + title: '# 신나는 노래가 듣고 싶을 때', + images: [ + 'https://i.namu.wiki/i/ZnqnnxZVzQv6faDBAcVqFf45RndE96JhzuohVFoC-pakkFpeavz_Hg9g-CJJupseMAZ_Cgroq7zRBViOtBM2xQ.webp', + 'https://example.com/another-image.jpg', + 'https://example.com/third-image.jpg', + ], + songTitle: 'Merry-go-round', + artist: '녹황색사회 緑黄色社会', + content: + '많은 국내 J-pop 리버들이 좋아하는 그룹이죠!! 녹황색사회 ! 저는 이 그룹 노래중에서도 흔하지 않은 이 노래를 참 좋아합니다!\n\n혹시 여러분들은 Merry-go-round 의 뜻을 아시나요? 바로 회전목마라는 뜻 인데요. 회전목마를 탄 듯이 둥둥 뜨는 멜로디가 이 음악이 매력적으로 느껴지게 하는 것 같습니다 ㅎㅎㅎ', + likes: 2, + comments: 1, + }; + + const handlePrevImage = () => { + setCurrentImage((prev) => + prev > 0 ? prev - 1 : dummyPost.images.length - 1, + ); + }; + + const handleNextImage = () => { + setCurrentImage((prev) => + prev < dummyPost.images.length - 1 ? prev + 1 : 0, + ); + }; + + return ( + + e.stopPropagation()}> +
+ + + + {dummyPost.title} + {dummyPost.username} + + + + ✏️ + 🗑️ + × + +
+ + + + + + Previous + + + + Next + + + + {/* 점(페이지네이션) 추가 */} + + {dummyPost.images.map((_, index) => ( + + ))} + + + + {dummyPost.songTitle} + {dummyPost.artist} + + + {dummyPost.content} + + + + + ❤ {dummyPost.likes} + 💬 {dummyPost.comments} + + + + + + + + + + 댓글 달기... + + + + + 통통 뛰는 리듬감이 좋네요! 제 플레이에 꼭 넣어 주겠습니다! + 감사해요! + + + +
+
+ ); +}; + +// Styled components +const ModalContainer = styled.div` + width: 90%; + max-width: 800px; + max-height: 90vh; + overflow-y: auto; + background-color: white; + padding: 30px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + position: relative; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } +`; + +const Header = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +`; + +const UserInfo = styled.div` + display: flex; + align-items: center; +`; + +const UserImage = styled.img` + width: 50px; + height: 50px; + border-radius: 50%; + border: 2px solid #ccc; + margin-right: 10px; +`; + +const TextContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + margin-top: -19px; +`; + +const Title = styled.h2` + font-size: 18px; + font-weight: bold; + margin-bottom: 2px; + text-align: left; +`; + +const Username = styled.span` + font-weight: bold; + font-size: 14px; + color: #888; + text-align: left; +`; + +const ActionButtonsWrapper = styled.div` + display: flex; + align-items: center; + margin-bottom: 10px; +`; + +const ActionButton = styled.button` + background: none; + border: none; + font-size: 18px; + cursor: pointer; + margin-left: 10px; +`; + +const CloseButton = styled.button` + background: none; + border: none; + font-size: 30px; + cursor: pointer; + margin-left: 15px; +`; + +const Divider = styled.hr` + border: none; + border-top: 1px solid #ddd; + margin: 10px 0; +`; + +const ImageContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + position: relative; +`; + +const PostImage = styled.img` + margin-top: 30px; + width: 50%; /* 이미지 크기를 줄임 */ + border-radius: 10px; + margin-bottom: 10px; +`; + +const ImageButton = styled.button` + position: absolute; + top: 50%; + transform: translateY(-50%); + background: none; + color: white; + border: none; + font-size: 20px; + cursor: pointer; + padding: 5px 10px; + z-index: 1; + + img { + width: 20px; /* 이미지 버튼 크기 */ + } + + &:first-of-type { + left: 50px; + } + &:last-of-type { + right: 50px; + } +`; + +const DotsContainer = styled.div` + display: flex; + justify-content: center; + margin-top: 10px; +`; + +const Dot = styled.div` + width: 8px; + height: 8px; + border-radius: 50%; + background-color: ${(props) => (props.active ? '#3897f0' : '#dbdbdb')}; + margin: 0 5px; + transition: background-color 0.3s ease; +`; + +const SongInfo = styled.div` + margin-bottom: 10px; +`; + +const SongTitle = styled.h3` + margin: 15px; +`; + +const Artist = styled.p` + margin: 5px 0; + color: #666; +`; + +const Content = styled.p` + width: 60%; /* 앨범 이미지와 동일한 가로 너비 */ + margin: 0 auto; /* 가운데 정렬 */ + margin-top: 45px; + margin-bottom: 30px; + background-color: #f0e6ff; + padding: 20px; + border-radius: 10px; + text-align: left; + word-wrap: break-word; /* 글이 길어지면 자동 줄바꿈 */ + box-sizing: border-box; /* padding을 포함한 전체 너비 조정 */ + font-weight: bold; +`; + +const Interactions = styled.div` + display: flex; + margin-bottom: 15px; +`; + +const InteractionButton = styled.button` + background: none; + border: none; + cursor: pointer; + margin-right: 15px; +`; + +const CommentSection = styled.div` + margin-bottom: 15px; +`; + +const CommentInput = styled.input` + width: 95%; + padding: 10px; + border: 1px solid #dbdbdb; + border-radius: 20px; + margin-bottom: 10px; +`; + +const Comments = styled.div``; + +const Comment = styled.div` + display: flex; + align-items: center; + margin-bottom: 15px; +`; + +const CommentUserImage = styled.img` + width: 30px; + height: 30px; + border-radius: 50%; + margin-right: 10px; +`; + +const CommentText = styled.p` + margin: 0; + font-size: 14px; +`; + +const ModalOverlay = styled.div` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +`; + +export default PostDetailModal;