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 all 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
33 changes: 27 additions & 6 deletions src/components/Common/Feed/Feed.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";

import FeedOption from "@/components/Common/Feed/FeedOption";
import {
Expand All @@ -12,6 +13,7 @@ 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,11 +22,12 @@ import {
TopDiv,
InfoDiv,
BottomDiv,
ContentDiv,
IconDiv,
IconItemButton,
} from "./Feed.styles";

const Feed = ({ post, groupId, leaderName }) => {
const Feed = ({ post, groupId, leaderId, isGroupPage }) => {
const dispatch = useDispatch();

const { user } = useSelector((state) => state.auth);
Expand All @@ -35,6 +38,8 @@ const Feed = ({ post, groupId, leaderName }) => {

const optionMenuRef = useRef();

const navigate = useNavigate();

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

const likeClick = async () => {
Expand All @@ -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,28 +79,42 @@ const Feed = ({ post, groupId, leaderName }) => {
};

return (
<FeedArticle key={post.postId}>
<FeedArticle
onClick={() =>
isGroupPage
? dispatch(openFeedDetailModal(post.postId))
: navigate(`/group/${groupId}`)
}
>
{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>
<img src={post.authorImage} alt={`${post.author}님의 프로필 이미지`} />
<InfoDiv>
<h3>
{post.author}
{post.author === leaderName && <CrownIcon />}

{/* 게시글 작성자 id 비교 필요 */}
{post.author === leaderId && <CrownIcon />}
</h3>
<h4>{useTimeStamp(post.createdAt)}</h4>
</InfoDiv>
</TopDiv>
<BottomDiv>
<p>{post.content}</p>
<ContentDiv>
<p>{post.content}</p>
</ContentDiv>

<IconDiv>
<IconItemButton onClick={handleLikeClick}>
{isPostLiked ? <FillHeartIcon /> : <EmptyHeartIcon />}
Expand Down
10 changes: 10 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 All @@ -35,6 +37,12 @@ export const OptionMenuDiv = styled.div`
border-bottom: none;
color: ${({ theme: { colors } }) => colors.text_01};
}

& > button {
width: 100%;
height: 100%;
text-align: center;
}
}
`;

Expand Down Expand Up @@ -78,7 +86,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
110 changes: 110 additions & 0 deletions src/components/Common/Feed/FeedComment/FeedComment.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useState, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";

import {
CommentDiv,
CommentContentDiv,
EditContentDiv,
ButtonDiv,
} from "@/components/Common/Feed/FeedComment/FeedComment.style";
import FeedOption from "@/components/Common/Feed/FeedOption";
import { putComment } from "@/features/comment/comment-service";
import useOutsideClick from "@/hooks/useOutsideClick";
import { useTimeStamp } from "@/hooks/useTimeStamp";

const FeedComment = ({
commentId,
postId,
groupId,
author,
authorImage,
updatedAt,
content,
}) => {
const dispatch = useDispatch();

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

const [isOptionOpen, setIsOptionOpen] = useState(false);
const [newContent, setNewContent] = useState(content);
const [isEdit, setIsEdit] = useState(false);

const optionMenuRef = useRef();
const commentBoxRef = useRef(null);

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

const handleEditCommentMenuClick = () => {
commentBoxRef.current.scrollIntoView({
behavior: "smooth",
block: "center",
});

setIsOptionOpen(false);
setIsEdit(true);
};

const handleEditComment = () => {
dispatch(
putComment({
groupId,
postId,
commentId,
content: newContent,
}),
setIsEdit(false),
);
};

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

{isEdit ? (
<EditContentDiv>
<textarea
value={newContent}
onChange={(e) => setNewContent(e.target.value)}
/>
<ButtonDiv>
<button
type="button"
className="cancelBtn"
onClick={() => setIsEdit(false)}
>
취소
</button>
<button
type="submit"
disabled={content === newContent}
onClick={handleEditComment}
>
수정
</button>
</ButtonDiv>
</EditContentDiv>
) : (
<p>{content}</p>
)}
</CommentContentDiv>

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

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

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

&:last-of-type {
border-bottom: none;
}

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

export const CommentContentDiv = styled.div`
width: 100%;

& > 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;
}
`;

export const EditContentDiv = styled.div`
display: flex;
flex-direction: column;

& > textarea {
margin-top: 10px;
height: 80px;
resize: none;
border: 1px solid ${({ theme: { colors } }) => colors.text_01};
outline: none;
border-radius: 10px;
padding: 10px 18px;
font-family: Inter;
font-size: 12px;
color: ${({ theme: { colors } }) => colors.text_03};
width: 100%;
}
`;

export const ButtonDiv = styled.div`
display: flex;
gap: 10px;
align-self: flex-end;

& > button {
margin-top: 20px;
align-self: flex-end;
width: 102px;
height: 40px;
background-color: ${({ theme: { colors } }) => colors.primary};
color: ${({ theme: { colors } }) => colors.white};
text-align: center;
font-size: 14px;
font-weight: ${({ theme: { typography } }) => typography.weight.medium};
border-radius: 5px;
cursor: pointer;

&:disabled {
cursor: not-allowed;
background-color: ${({ theme: { colors } }) => colors.btn_02};
}

&.cancelBtn {
background-color: ${({ theme: { colors } }) => colors.white};
color: ${({ theme: { colors } }) => colors.primary};
border: 1px solid ${({ theme: { colors } }) => colors.primary_light};
}
}
`;
Loading
Loading