forked from codestates-seb/seb45_main_011
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FE] ✨ Feat : 방명록 관련 하위 컴포넌트 임시 구현 (codestates-seb#352)
- Loading branch information
Showing
3 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,110 @@ | ||
'use client'; | ||
|
||
import { useParams } from 'next/navigation'; | ||
import { useForm } from 'react-hook-form'; | ||
|
||
import usePostStore from '@/stores/postStore'; | ||
import useUserStore from '@/stores/userStore'; | ||
|
||
import useEditCommentMutation from '@/hooks/mutation/useEditCommentMutation'; | ||
|
||
import { PostProfile, DateAndControlSection } from '@/components/post'; | ||
import CommonButton from '../common/CommonButton'; | ||
|
||
import { GuestbookDataInfo } from '@/types/data'; | ||
import { CommentInputValue } from '@/types/common'; | ||
|
||
import { COMMENT } from '@/constants/contents'; | ||
|
||
interface CommentProps { | ||
comment: GuestbookDataInfo | null; | ||
guestbookId: number | null; | ||
} | ||
|
||
export default function Comment({ comment, guestbookId }: CommentProps) { | ||
if (!comment || !guestbookId) return null; | ||
|
||
const { id } = useParams(); | ||
|
||
const { editMode, targetId, setEditMode } = usePostStore(); | ||
const { userId } = useUserStore(); | ||
|
||
const { mutate: editComment } = useEditCommentMutation({ | ||
guestbookId, | ||
targetId, | ||
}); | ||
|
||
const { | ||
register, | ||
handleSubmit, | ||
formState: { isSubmitting }, | ||
} = useForm<CommentInputValue>({ | ||
defaultValues: { | ||
comment: comment.content, | ||
}, | ||
}); | ||
|
||
const isEdit = editMode && String(comment.commentId) === targetId; | ||
|
||
const isOwner = userId === String(comment.accountId); | ||
|
||
const submitCommentForm = (data: CommentInputValue) => { | ||
editComment(data); | ||
setEditMode(false); | ||
}; | ||
|
||
return ( | ||
<li className="pr-[1rem] mb-8 min-w-[248px] w-full"> | ||
<div className="flex justify-between mb-2 relative max-[500px]:items-end"> | ||
<PostProfile | ||
userId={comment.guestbookId} | ||
displayName={comment.displayName} | ||
grade={comment.accountGrade} | ||
profileImageUrl={comment.imageUrl} | ||
usage="comment" | ||
/> | ||
<DateAndControlSection | ||
date={new Date(comment?.createdAt)} | ||
isOwner={isOwner} | ||
usage="comment" | ||
ownerId={String(comment.guestbookId)} | ||
targetId={String(comment.guestbookId)} | ||
/> | ||
</div> | ||
<div className="pl-11 max-[550px]:pl-0"> | ||
{isEdit ? ( | ||
<form onSubmit={handleSubmit(submitCommentForm)}> | ||
<input | ||
autoFocus={true} | ||
className="w-full px-[0.875rem] py-[0.75rem] bg-brown-10 border-2 border-brown-50 rounded-xl text-black-50 text-xs left-3 common-drop-shadow outline-none max-[500px]:py-[0.5rem] max-[500px]:text-[0.5rem]" | ||
{...register('comment', { | ||
maxLength: { | ||
value: COMMENT.maxLength.value, | ||
message: COMMENT.maxLength.errorMessage, | ||
}, | ||
})} | ||
/> | ||
{isEdit && ( | ||
<div className="flex p-2 justify-end gap-2"> | ||
<CommonButton size="sm" type="submit"> | ||
수정 | ||
</CommonButton> | ||
<CommonButton | ||
size="sm" | ||
type="button" | ||
onClick={() => setEditMode(false)} | ||
disabled={isSubmitting}> | ||
취소 | ||
</CommonButton> | ||
</div> | ||
)} | ||
</form> | ||
) : ( | ||
<p className="w-full px-[0.875rem] py-[0.75rem] bg-brown-10 border-2 border-brown-50 rounded-xl text-black-50 text-xs left-3 common-drop-shadow max-[500px]:px-[0.6rem] max-[500px]:py-[0.5rem] max-[500px]:text-[0.75rem]"> | ||
{comment.content} | ||
</p> | ||
)} | ||
</div> | ||
</li> | ||
); | ||
} |
This file contains 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,64 @@ | ||
'use client'; | ||
|
||
import { useForm } from 'react-hook-form'; | ||
import { motion } from 'framer-motion'; | ||
import { ErrorMessage } from '@hookform/error-message'; | ||
|
||
import useAddGuestbookMutation from '@/hooks/mutation/useAddGuestbookMutation'; | ||
|
||
import CommentProfileImage from './CommentProfileImage'; | ||
|
||
import { CommentInputValue } from '@/types/common'; | ||
|
||
import { COMMENT } from '@/constants/contents'; | ||
|
||
export default function CommentForm() { | ||
const { | ||
register, | ||
handleSubmit, | ||
reset, | ||
formState: { errors, isSubmitting }, | ||
} = useForm<CommentInputValue>(); | ||
const { mutate: addGuestbook } = useAddGuestbookMutation(); | ||
|
||
const submitCommentForm = (data: CommentInputValue) => { | ||
addGuestbook(data); | ||
reset(); | ||
}; | ||
|
||
return ( | ||
<form | ||
onSubmit={handleSubmit(submitCommentForm)} | ||
className="relative p-5 w-full h-[90px] flex justify-between items-center gap-3 bg-contain bg-center bg-[url('/assets/img/bg_wood_dark.png')] border-[3px] border-brown-70 rounded-lg shadow-outer/down mb-6 max-[560px]:p-3 max-[560px]:gap-2 max-[560px]:h-[74px]"> | ||
<CommentProfileImage /> | ||
<input | ||
className="px-[1.125rem] w-full py-[0.6875rem] h-[36px] flex-1 rounded-[50px] text-[0.875rem] leading-[0.875rem] font-normal focus:outline-none shadow-outer/down max-[560px]:px-[0.8rem] max-[560px]:py-[0.4rem] max-[560px]:h-[32px] max-[500px]:text-[0.7rem] " | ||
placeholder="댓글을 입력하세요." | ||
required | ||
{...register('comment', { | ||
maxLength: { | ||
value: COMMENT.maxLength.value, | ||
message: COMMENT.maxLength.errorMessage, | ||
}, | ||
})} | ||
/> | ||
<ErrorMessage | ||
errors={errors} | ||
name={'comment'} | ||
render={({ message }) => ( | ||
<div className="absolute w-full -bottom-5 text-[0.6rem] leading-3 text-red-50 text-center"> | ||
{message} | ||
</div> | ||
)} | ||
/> | ||
<motion.button | ||
whileHover={{ scale: 1.05 }} | ||
whileTap={{ scale: 0.95 }} | ||
className="px-[0.6875rem] py-[0.5625rem] bg-contain bg-center bg-[url('/assets/img/bg_wood_light.png')] border-[3px] border-brown-50 rounded-xl text-[1rem] leading-[1rem] font-bold text-brown-40 shadow-outer/down max-[560px]:text-[0.85rem] max-[560px]:px-[0.55rem] max-[560px]:py-[0.5rem] max-[500px]:text-[0.8rem] max-[500px]:px-[0.4rem] max-[500px]:py-[0.3rem]" | ||
type="submit" | ||
disabled={isSubmitting}> | ||
등록 | ||
</motion.button> | ||
</form> | ||
); | ||
} |
This file contains 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,19 @@ | ||
import Image from 'next/image'; | ||
|
||
import useUserStore from '@/stores/userStore'; | ||
|
||
export default function CommentProfileImage() { | ||
const { profileImageUrl } = useUserStore(); | ||
return ( | ||
<div className="w-[44px] h-[44px] rounded-[50%] flex justify-center items-center border-brown-10 border-[3px] overflow-hidden shadow-outer/down max-[500px]:hidden"> | ||
<Image | ||
src={profileImageUrl || '/assets/img/bg_default_profile.png'} | ||
alt="profile_img" | ||
className="h-full bg-brown-20 object-cover object-center isolate" | ||
width={44} | ||
height={44} | ||
style={{ width: 44, height: 44 }} | ||
/> | ||
</div> | ||
); | ||
} |