-
Notifications
You must be signed in to change notification settings - Fork 4
✨ feat: 게시글 상세 댓글ui추가 #364
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
Open
jungmyunggi
wants to merge
5
commits into
main
Choose a base branch
from
feature/detail-comment
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
40 changes: 40 additions & 0 deletions
40
client/src/components/common/Card/detail/CommentAction.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { useState } from "react"; | ||
|
||
export default function CommentAction({ id, handleModify }: { id: number; handleModify: (id: number) => void }) { | ||
const [isOpen, setIsOpen] = useState<boolean>(false); | ||
const handleOpen = () => { | ||
setIsOpen(!isOpen); | ||
}; | ||
return ( | ||
<div className="flex gap-2 text-sm"> | ||
<button onClick={() => handleModify(id)} className="text-gray-400"> | ||
수정 | ||
</button> | ||
<button onClick={handleOpen} className="text-gray-400"> | ||
삭제 | ||
</button> | ||
{isOpen && <DeleteButton id={id} handleOpen={handleOpen} />} | ||
</div> | ||
); | ||
} | ||
|
||
function DeleteButton({ id, handleOpen }: { id: number; handleOpen: () => void }) { | ||
return ( | ||
<div className="w-[100%] h-[100%] absolute top-0 left-0 z-[1000] bg-white/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"> | ||
<div className="flex flex-col fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] w-full max-w-xs md:max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg"> | ||
<header className="flex flex-col space-y-2 text-center sm:text-left"> | ||
<span className="text-lg font-semibold">댓글 삭제</span> | ||
</header> | ||
<section> | ||
<p className="text-sm text-muted-foreground text-center md:text-start">댓글을 정말로 삭제하시겠습니까?</p> | ||
</section> | ||
<footer className="flex flex-row justify-end space-x-2"> | ||
<button onClick={handleOpen} className="py-2 px-4 rounded-sm hover:bg-gray-100"> | ||
취소 | ||
</button> | ||
<button className="bg-primary py-2 px-4 text-white rounded-sm hover:bg-primary/90">확인</button> | ||
</footer> | ||
</div> | ||
</div> | ||
); | ||
} |
108 changes: 108 additions & 0 deletions
108
client/src/components/common/Card/detail/PostComment.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { useState } from "react"; | ||
|
||
import { Heart } from "lucide-react"; | ||
|
||
import CommentAction from "@/components/common/Card/detail/CommentAction"; | ||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; | ||
|
||
import { timeAgo } from "@/utils/timeago"; | ||
|
||
import { PostCommentType } from "@/types/post"; | ||
|
||
type PostCommentProps = { | ||
comments: PostCommentType[]; | ||
}; | ||
export default function PostComment({ comments }: PostCommentProps) { | ||
const [modifyId, setModifyId] = useState<number | null>(null); | ||
const handleModify = (id: number | null) => { | ||
setModifyId(id); | ||
}; | ||
return ( | ||
<div className="w-full space-y-6"> | ||
{/* 댓글 입력 영역 */} | ||
<div className="bg-gray-50 rounded-lg shadow-sm border border-gray-200 overflow-hidden"> | ||
<div className="p-4"> | ||
<div className="flex items-start gap-3"> | ||
<Avatar className="w-10 h-10"> | ||
<AvatarImage src="https://github.com/shadcn.png" alt="사용자 프로필" /> | ||
<AvatarFallback>CN</AvatarFallback> | ||
</Avatar> | ||
<textarea | ||
placeholder="댓글을 입력하세요..." | ||
className="flex-1 bg-transparent p-2 rounded-md h-20 focus:outline-none focus:ring-2 focus:ring-gray-300 focus:border-transparent resize-none" | ||
></textarea> | ||
</div> | ||
</div> | ||
<div className="flex justify-end px-4 pb-4"> | ||
<button className="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-full transition-colors"> | ||
등록 | ||
</button> | ||
</div> | ||
</div> | ||
jungmyunggi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
{/* 댓글 목록 헤더 */} | ||
<div className="flex items-center border-b border-gray-200 pb-2"> | ||
<h3 className="font-bold text-lg"> | ||
댓글 <span className="text-yellow-500">{comments.length}</span> | ||
</h3> | ||
</div> | ||
|
||
{/* 댓글 목록 */} | ||
<ul className="space-y-4"> | ||
{comments | ||
.sort((a, b) => Number(new Date(b.createdAt)) - Number(new Date(a.createdAt))) | ||
.map((comment) => ( | ||
<li key={comment.id} className="border-b border-gray-100 pb-4"> | ||
<div className="flex items-start gap-3"> | ||
<Avatar className="w-8 h-8"> | ||
<AvatarImage src={comment.authorImage} alt={comment.author} /> | ||
<AvatarFallback>{comment.author.substring(0, 2)}</AvatarFallback> | ||
</Avatar> | ||
<div className="flex-1"> | ||
<div className="flex items-center gap-2"> | ||
<div className="flex justify-between w-full"> | ||
<div className="flex gap-2 items-center"> | ||
<p className="font-semibold text-sm">{comment.author}</p> | ||
<p className="text-sm text-gray-400">{timeAgo(comment.createdAt)}</p> | ||
<span className="flex text-[10px] items-center gap-1 border rounded-sm p-1 hover:bg-red-300"> | ||
<Heart size={15} color="red" fill={comment.isLiked ? `red` : "#fff"} /> | ||
{comment.likes} | ||
</span> | ||
</div> | ||
{modifyId !== comment.id && <CommentAction id={comment.id} handleModify={handleModify} />} | ||
</div> | ||
</div> | ||
{modifyId !== comment.id ? ( | ||
<p className="mt-1 text-gray-800">{comment.content}</p> | ||
) : ( | ||
<div className=""> | ||
<textarea className="w-[100%] mt-2 flex-1 bg-transparent p-2 rounded-md h-20 outline-none ring-2 ring-gray-300 border-transparent resize-none"> | ||
{comment.content} | ||
</textarea> | ||
<div className="flex justify-end gap-3 text-sm"> | ||
<button onClick={() => handleModify(null)} className="hover:bg-gray-200 py-2 px-4 rounded-lg"> | ||
취소 | ||
</button> | ||
<button className="bg-primary hover:bg-primary/80 py-2 px-4 text-white rounded-lg"> | ||
댓글 수정 | ||
</button> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</li> | ||
))} | ||
</ul> | ||
|
||
{/* 더보기 버튼 */} | ||
{comments.length > 1 && ( | ||
<div className="flex justify-center"> | ||
<button className="px-4 py-2 border border-gray-200 rounded-full text-sm text-black hover:bg-gray-200 transition-colors"> | ||
댓글 더보기 | ||
</button> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,13 @@ import React from "react"; | |
import Markdown from "react-markdown"; | ||
|
||
import LikeButton from "@/components/common/Card/detail/LikeButton"; | ||
import PostComment from "@/components/common/Card/detail/PostComment"; | ||
import ShareButton from "@/components/common/Card/detail/ShareButton"; | ||
|
||
import { usePostCardActions } from "@/hooks/common/usePostCardActions"; | ||
|
||
import { POST_COMMENT_DATA } from "@/constants/dummyData"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P5) 혹시 실제로 배포된 페이지에서 댓글이 사용될 때도 dummy data가 쓰이는걸까요? |
||
|
||
import { useMediaStore } from "@/store/useMediaStore"; | ||
import { Post } from "@/types/post"; | ||
|
||
|
@@ -51,10 +54,11 @@ export const PostContent = React.memo(({ post }: PostContentProps) => { | |
<p className="text-gray-400">💡 인공지능이 요약한 내용입니다. 오류가 포함될 수 있으니 참고 바랍니다.</p> | ||
)} | ||
</div> | ||
<div className="flex gap-3"> | ||
<div className="flex gap-3 border-b pb-5"> | ||
<LikeButton /> | ||
<ShareButton post={post} /> | ||
</div> | ||
<PostComment comments={POST_COMMENT_DATA} /> | ||
</div> | ||
); | ||
}); | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export function timeAgo(dateString: string) { | ||
const now = new Date(); | ||
const past = new Date(dateString); | ||
const diff = Number(now) - Number(past); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P5) 파일명과 함수명이 달라요 ! |
||
|
||
const diffMin = Math.floor(diff / (1000 * 60)); | ||
const diffHour = Math.floor(diff / (1000 * 60 * 60)); | ||
const diffDay = Math.floor(diff / (1000 * 60 * 60 * 24)); | ||
|
||
if (diffMin < 60) return `${diffMin}분 전`; | ||
if (diffHour < 24) return `${diffHour}시간 전`; | ||
return `${diffDay}일 전`; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.