Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

200 front task 그룹 피드 클릭 시 상세 정보 및 댓글 구현 #205

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7e0d3cd
issue #200 design: feed detail modal styling
sikkzz Mar 29, 2024
f9bd915
issue #200 feat: create getComments api
sikkzz Mar 29, 2024
aa40d0e
issue #200 refactor: feed comment change to component
sikkzz Mar 29, 2024
1fb7872
issue #200 refactor: feed comment option menu add
sikkzz Mar 29, 2024
a1dfbaa
issue #200 feat: create delete, put comment
sikkzz Mar 29, 2024
bc31a62
issue #200 design: comment input styling
sikkzz Apr 2, 2024
ccc9f6b
issue #200 feat: create post comment
sikkzz Apr 2, 2024
9777cd8
issue #200 feat: create edit comment
sikkzz Apr 2, 2024
2fa0463
issue #200 refactor: comment count refactoring
sikkzz Apr 2, 2024
48d1a13
issue #200 refactor: feed detail modal refactoring
sikkzz Apr 5, 2024
f8176b0
issue #200 refactor: resetComments reducer add
sikkzz Apr 5, 2024
2b089a8
issue #200 refactor: option menu button size change
sikkzz Apr 5, 2024
53b60ff
issue #200 refactor: edit comment refactoring
sikkzz Apr 8, 2024
bbef0b9
issue #200 refactor: feed detail modal change to form modal
sikkzz Apr 8, 2024
a3769be
issue #200 refactor: button disabled add
sikkzz Apr 9, 2024
dbdee73
issue #200 refactor: commnet box scroll add
sikkzz Apr 9, 2024
71ed475
issue #200 refactor: leader name change to leader id
sikkzz Apr 9, 2024
7be26e4
issue #200 refactor: feed detail modal open refactoring
sikkzz Apr 9, 2024
43dd454
issue #200 refactor: feed navigate add
sikkzz Apr 9, 2024
3e4abd5
issue #200 feat: create group modal trigger
sikkzz Apr 11, 2024
0ba108c
issue #200 refactor: group modal trigger props chnage
sikkzz Apr 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/components/Common/Feed/Feed.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React, { useState, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";

import FeedDetailModal from "@/components/Common/Feed/FeedDetailModal/FeedDetailModal";
import FeedOption from "@/components/Common/Feed/FeedOption";
import {
CrownIcon,
CommentIcon,
EmptyHeartIcon,
FillHeartIcon,
} from "@/constants/iconConstants";
import { UI_TYPE } from "@/constants/uiConstants";
import {
cancelLikeGroupPost,
likeGroupPost,
} from "@/features/post/post-service";
import { openFeedDetailModal } from "@/features/ui/ui-slice";
import useOutsideClick from "@/hooks/useOutsideClick";
import { useTimeStamp } from "@/hooks/useTimeStamp";

Expand All @@ -20,6 +23,7 @@ import {
TopDiv,
InfoDiv,
BottomDiv,
ContentDiv,
IconDiv,
IconItemButton,
} from "./Feed.styles";
Expand All @@ -28,6 +32,7 @@ const Feed = ({ post, groupId, leaderName }) => {
const dispatch = useDispatch();

const { user } = useSelector((state) => state.auth);
const { openedModal } = useSelector((state) => state.ui);

const [isPostLiked, setIsPostLiked] = useState(post.isLiked);
const [postLikesCount, setPostLikesCount] = useState(post.likesCount);
Expand Down Expand Up @@ -59,7 +64,9 @@ const Feed = ({ post, groupId, leaderName }) => {
}
};

const handleLikeClick = () => {
const handleLikeClick = (e) => {
e.stopPropagation();

if (!isPostLiked) {
setIsPostLiked(true);
setPostLikesCount((prev) => prev + 1);
Expand All @@ -72,14 +79,20 @@ const Feed = ({ post, groupId, leaderName }) => {
};

return (
<FeedArticle key={post.postId}>
<FeedArticle
key={post.postId}
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
onClick={() => dispatch(openFeedDetailModal(post.postId))}
>
{user.nickname === post.author && (
<FeedOption
postId={post.postId}
groupId={groupId}
optionMenuRef={optionMenuRef}
isOptionOpen={isOptionOpen}
handleOptionClick={() => setIsOptionOpen((prev) => !prev)}
handleOptionClick={(e) => {
e.stopPropagation();
setIsOptionOpen((prev) => !prev);
}}
/>
)}
<TopDiv>
Expand All @@ -93,7 +106,10 @@ const Feed = ({ post, groupId, leaderName }) => {
</InfoDiv>
</TopDiv>
<BottomDiv>
<p>{post.content}</p>
<ContentDiv>
<p>{post.content}</p>
</ContentDiv>

<IconDiv>
<IconItemButton onClick={handleLikeClick}>
{isPostLiked ? <FillHeartIcon /> : <EmptyHeartIcon />}
Expand All @@ -105,6 +121,21 @@ const Feed = ({ post, groupId, leaderName }) => {
</IconItemButton>
</IconDiv>
</BottomDiv>

{openedModal === UI_TYPE.FEED_DETAIL_MODAL(post.postId) && (
<FeedDetailModal
groupId={groupId}
postId={post.postId}
author={post.author}
authorImage={post.authorImage}
content={post.content}
createdAt={useTimeStamp(post.createdAt)}
likeCount={postLikesCount}
isPostLiked={isPostLiked}
leaderName={leaderName}
handleLikeClick={handleLikeClick}
/>
)}
</FeedArticle>
);
};
Expand Down
4 changes: 4 additions & 0 deletions src/components/Common/Feed/Feed.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const FeedArticle = styled.article`
border: 1px solid ${({ theme: { colors } }) => colors.btn_02};
padding: 24px 18px;
position: relative;
cursor: pointer;
`;

export const OptionDiv = styled.div`
Expand All @@ -19,6 +20,7 @@ export const OptionDiv = styled.div`
export const OptionMenuDiv = styled.div`
position: absolute;
z-index: 2;
right: 0;

& > ul > li {
width: 60px;
Expand Down Expand Up @@ -78,7 +80,9 @@ export const BottomDiv = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
`;

export const ContentDiv = styled.div`
& > p {
color: ${({ theme: { colors } }) => colors.text_03};
font-size: ${({ theme: { typography } }) => typography.size.s1};
Expand Down
56 changes: 56 additions & 0 deletions src/components/Common/Feed/FeedComment/FeedComment.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState, useRef } from "react";
import { useSelector } from "react-redux";

import {
CommentDiv,
CommentContentDiv,
} from "@/components/Common/Feed/FeedComment/FeedComment.style";
import FeedOption from "@/components/Common/Feed/FeedOption";
import useOutsideClick from "@/hooks/useOutsideClick";
import { useTimeStamp } from "@/hooks/useTimeStamp";

const FeedComment = ({
commentId,
postId,
groupId,
author,
authorImage,
updatedAt,
content,
handleEditCommentClick,
}) => {
const { user } = useSelector((state) => state.auth);

const [isOptionOpen, setIsOptionOpen] = useState(false);

const optionMenuRef = useRef();

useOutsideClick(optionMenuRef, () => setIsOptionOpen(false));

return (
<CommentDiv>
<img src={authorImage} alt="profileImg" />
<CommentContentDiv>
<h3>{author}</h3>
<h4>{useTimeStamp(updatedAt)}</h4>
<p>{content}</p>
</CommentContentDiv>

{user.nickname === author && (
<FeedOption
postId={postId}
groupId={groupId}
optionMenuRef={optionMenuRef}
isOptionOpen={isOptionOpen}
handleOptionClick={() => setIsOptionOpen((prev) => !prev)}
isComment
commentId={commentId}
content={content}
handleEditCommentClick={handleEditCommentClick}
/>
)}
</CommentDiv>
);
};

export default FeedComment;
37 changes: 37 additions & 0 deletions src/components/Common/Feed/FeedComment/FeedComment.style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import styled from "styled-components";

export const CommentDiv = styled.div`
padding: 24px 0;
display: flex;
gap: 10px;
border-bottom: 1px solid #d9d9d9;
position: relative;

& > img {
width: 58px;
height: 58px;
border-radius: 50%;
object-fit: cover;
}
`;

export const CommentContentDiv = styled.div`
& > h3 {
font-size: 14px;
font-weight: ${({ theme: { typography } }) => typography.weight.medium};
color: ${({ theme: { colors } }) => colors.text_01};
}

& > h4 {
font-size: 12px;
font-weight: ${({ theme: { typography } }) => typography.weight.medium};
color: ${({ theme: { colors } }) => colors.text_02};
margin-top: 6px;
}

& > p {
font-size: 12px;
color: ${({ theme: { colors } }) => colors.text_03};
margin-top: 12px;
}
`;
155 changes: 155 additions & 0 deletions src/components/Common/Feed/FeedDetailModal/FeedDetailModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { useState, useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";

import FeedOption from "@/components/Common/Feed/FeedOption";
import BaseModal from "@/components/Common/Modal/BaseModal";
import {
CrownIcon,
CommentIcon,
EmptyHeartIcon,
FillHeartIcon,
} from "@/constants/iconConstants";
import {
getComments,
postComment,
putComment,
} from "@/features/comment/comment-service";
import useOutsideClick from "@/hooks/useOutsideClick";

import {
ContainerDiv,
FeedDiv,
ProfileDiv,
ContentDiv,
CommentDiv,
CommentInputDiv,
CommentInputContentDiv,
} from "./FeedDetailModal.style";
import { IconDiv, IconItemButton } from "../Feed.styles";
import FeedComment from "../FeedComment/FeedComment";

const FeedDetailModal = ({
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
groupId,
postId,
author,
authorImage,
content,
createdAt,
likeCount,
isPostLiked,
leaderName,
handleLikeClick,
}) => {
const dispatch = useDispatch();

const { comments } = useSelector((state) => state.comment);
const { user } = useSelector((state) => state.auth);

const [isOptionOpen, setIsOptionOpen] = useState(false);

const [commentContent, setCommentContent] = useState("");
const [commentId, setCommentId] = useState(0);
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
const [commentBtnText, setCommentBtnText] = useState("등록하기");
sikkzz marked this conversation as resolved.
Show resolved Hide resolved

const optionMenuRef = useRef();

useOutsideClick(optionMenuRef, () => setIsOptionOpen(false));

const handleEditCommentClick = (editCommentId, prevContent) => {
setCommentId(editCommentId);
setCommentContent(prevContent);
setCommentBtnText("수정하기");
};

const handleCommentButton = () => {
if (commentBtnText === "등록하기") {
dispatch(postComment({ groupId, postId, content: commentContent }));
setCommentContent("");
} else {
dispatch(
putComment({ groupId, postId, commentId, content: commentContent }),
);
setCommentBtnText("등록하기");
setCommentContent("");
setCommentId(0);
}
};

useEffect(() => {
dispatch(getComments({ groupId, postId }));
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
}, []);

return (
<BaseModal>
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
<ContainerDiv>
<FeedDiv>
<ProfileDiv>
<img src={authorImage} alt="profileImg" />
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
<h3>
{author}
{author === leaderName && <CrownIcon />}
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
</h3>

{user.nickname === author && (
<FeedOption
postId={postId}
groupId={groupId}
optionMenuRef={optionMenuRef}
isOptionOpen={isOptionOpen}
handleOptionClick={() => setIsOptionOpen((prev) => !prev)}
/>
)}
</ProfileDiv>
<ContentDiv>
<p>{content}</p>
<span>{createdAt}</span>
<IconDiv>
<IconItemButton onClick={handleLikeClick}>
{isPostLiked ? <FillHeartIcon /> : <EmptyHeartIcon />}
<span>{likeCount}</span>
</IconItemButton>
<IconItemButton>
<CommentIcon />
<span>{comments.length}</span>
</IconItemButton>
</IconDiv>
</ContentDiv>
</FeedDiv>

<CommentDiv>
{comments.length !== 0 &&
comments.map((commentInfo) => (
<FeedComment
key={commentInfo.commentId}
commentId={commentInfo.commentId}
author={commentInfo.author}
authorImage={commentInfo.authorImage}
updatedAt={commentInfo.updatedAt}
content={commentInfo.content}
postId={postId}
groupId={groupId}
handleEditCommentClick={handleEditCommentClick}
/>
))}
</CommentDiv>

<CommentInputDiv>
<img src={authorImage} alt="profileImg" />
<CommentInputContentDiv>
<h3>{author}</h3>
<textarea
placeholder="댓글을 입력하세요"
value={commentContent}
onChange={(e) => setCommentContent(e.target.value)}
/>
<button type="button" onClick={handleCommentButton}>
sikkzz marked this conversation as resolved.
Show resolved Hide resolved
{commentBtnText}
</button>
</CommentInputContentDiv>
</CommentInputDiv>
</ContainerDiv>
</BaseModal>
);
};

export default FeedDetailModal;
Loading
Loading