diff --git a/src/app/features/dashboard_Id/Card/Card.tsx b/src/app/features/dashboard_Id/Card/Card.tsx index 24218ae..948bbb8 100644 --- a/src/app/features/dashboard_Id/Card/Card.tsx +++ b/src/app/features/dashboard_Id/Card/Card.tsx @@ -6,6 +6,8 @@ import { Avatar } from '@/app/shared/components/common/Avatar' import { useDragStore } from '../store/useDragStore' import type { Card as CardType } from '../type/Card.type' import type { Column as ColumnType } from '../type/Column.type' +import CreateCardModal from './cardFormModals/CreateCardModal' +import ModifyCardForm from './cardFormModals/ModifyCardForm' import CardContent from './cardModal/CardContent' import CardModal from './cardModal/CardModal' import Tags from './Tags' @@ -20,6 +22,9 @@ export default function Card({ const { id, imageUrl, title, tags, dueDate, assignee } = card const { setDraggingCard } = useDragStore() const [openCard, setOpenCard] = useState(false) //card.tsx + const [openModifyCard, setOpenModifyCard] = useState(false) + const { title: columnTitle, id: columnId } = column + const currentColumn = { columnTitle, columnId } return (
setOpenCard(false)} + openModifyModal={() => setOpenModifyCard(true)} card={card} column={column} /> )} + + {/* 카드 수정 모달 */} + {openModifyCard && ( + + setOpenModifyCard(false)} + // columnId={column.id} + currentColumn={currentColumn} + card={card} + /> + + )}
) } diff --git a/src/app/features/dashboard_Id/Card/ColumnTitle.tsx b/src/app/features/dashboard_Id/Card/ColumnTitle.tsx index 9311ac5..810fdbd 100644 --- a/src/app/features/dashboard_Id/Card/ColumnTitle.tsx +++ b/src/app/features/dashboard_Id/Card/ColumnTitle.tsx @@ -2,7 +2,7 @@ export default function ColumnTitle({ title }: { title: string }) { return (
-
+
{title}
diff --git a/src/app/features/dashboard_Id/Card/cardFormModals/CreateCardModal.tsx b/src/app/features/dashboard_Id/Card/cardFormModals/CreateCardModal.tsx index 2d8c868..66ffc66 100644 --- a/src/app/features/dashboard_Id/Card/cardFormModals/CreateCardModal.tsx +++ b/src/app/features/dashboard_Id/Card/cardFormModals/CreateCardModal.tsx @@ -1,10 +1,15 @@ import { createPortal } from 'react-dom' +import { useLockBodyScroll } from '@/app/shared/hooks/useLockBodyScroll' + interface ModalProps { children: React.ReactNode } export default function CreateCardModal({ children }: ModalProps) { const modalRoot = document.getElementById('modal-root') + + useLockBodyScroll() + if (!modalRoot) return null return createPortal( diff --git a/src/app/features/dashboard_Id/Card/cardFormModals/ModifyCardForm.tsx b/src/app/features/dashboard_Id/Card/cardFormModals/ModifyCardForm.tsx index 61ca09d..14dbcd3 100644 --- a/src/app/features/dashboard_Id/Card/cardFormModals/ModifyCardForm.tsx +++ b/src/app/features/dashboard_Id/Card/cardFormModals/ModifyCardForm.tsx @@ -63,14 +63,14 @@ export default function ModifyCardForm({ formState: { errors, isValid, isSubmitting, isDirty }, } = useForm({ defaultValues: { - assigneeUserId: card.assignee.id, + assigneeUserId: card.assignee?.id, dashboardId: card.dashboardId, columnId: card.columnId, title: card.title, description: card.description, - dueDate: card.dueDate, - tags: card.tags, - imageUrl: card.imageUrl, + dueDate: card.dueDate ? card.dueDate : '', + tags: card.tags ? card.tags : [], + imageUrl: card.imageUrl ? card.imageUrl : '', }, mode: 'onChange', // isValid와 isDirty가 입력 즉시 반영되도록 }) @@ -78,7 +78,6 @@ export default function ModifyCardForm({ // React Hook Form 과 tags 값 연결 useEffect(() => { setValue('tags', tags) - console.log(tags) }, [tags, tags.length, setValue]) // 상태(컬럼) 선택 시 / assignee 선택 시 드롭다운 닫기 @@ -125,7 +124,11 @@ export default function ModifyCardForm({ // ✅ JSX return ( -
+ e.stopPropagation()} + >

할 일 수정

@@ -188,9 +191,11 @@ export default function ModifyCardForm({ id="assigneeUserId" type="text" /> -
- -
+ {selectedAssignee && ( +
+ +
+ )} 화살표 void - card: Card - column: Column -} +import CommentForm from './CommentForm' +import Comments from './Comments' + export default function CardContent({ onClose, + openModifyModal, card, column, -}: CardContentProps) { - const { id, imageUrl, title, tags, dueDate, assignee } = card +}: { + onClose: () => void + openModifyModal: () => void + card: Card + column: Column +}) { + // const { id, imageUrl, title, tags, dueDate, assignee, description } = card const [openModifyCard, setOpenModifyCard] = useState(false) - const { title: columnTitle, id: columnId } = column - const currentColumn = { columnTitle, columnId } + // const { title: columnTitle, id: columnId } = column + // const currentColumn = { columnTitle, columnId } + const isMobile = useIsMobile() + const { mutate: deleteCard, isPending } = useDeleteCardMutation() return ( - <> -

{title}

-
+ //
+
+

+ {card.title} +

+ + {/* 카드 우측 상단의 케밥 버튼, X 버튼 */} +
} > - {/* 드롭다운 내부 메뉴 아이템 */} -
setOpenModifyCard(true)} + {/* 트리거의(케밥) 드롭다운 - 수정하기, 삭제하기 */} +
-
+ +
+
- 카드 닫기 { + {/* X 버튼 (카드 닫기)*/} +
+ {/* 카드 상단 */}
- 그리드로 관리하기 / 컬럼명은 따로 컴포넌트로 만들어 빼기 -
{column.title}
- -

설명~~~~~~~~

-
-
{assignee.nickname}
-
{dueDate}
+
+ {/* 컬럼명 / 태그 // 설명 // 이미지 */} +
+
+ +
+ {card.tags && } +
+ {card.description && ( +

+ {card.description} +

+ )} + {card.imageUrl && ( + 카드 이미지 + )} +
+ {/* 담당자 / 마감일 박스 */} +
+
+
+ + 담당자 + + {card.assignee && ( +
+ <> + + + {card.assignee.nickname} + + +
+ )} +
+
+ + 마감일 + + {card.dueDate && ( + + {card.dueDate} + + )} +
+
+
+
-
이미지 있으면 이미지
-
댓글 컴포넌트
- {/* 카드 수정 모달 */} - {openModifyCard && ( - - setOpenModifyCard(false)} - // columnId={column.id} - currentColumn={currentColumn} - card={card} - /> - - )} - + + +
) } diff --git a/src/app/features/dashboard_Id/Card/cardModal/CardContentCopy.tsx b/src/app/features/dashboard_Id/Card/cardModal/CardContentCopy.tsx new file mode 100644 index 0000000..933b48c --- /dev/null +++ b/src/app/features/dashboard_Id/Card/cardModal/CardContentCopy.tsx @@ -0,0 +1,110 @@ +// import { useModalStore } from '@store/useModalStore' +// import Image from 'next/image' +// import { useState } from 'react' + +// import Dropdown from '@/app/shared/components/common/Dropdown/Dropdown' + +// import { Card } from '../../type/Card.type' +// import { Column } from '../../type/Column.type' +// import CreateCardModal from '../cardFormModals/CreateCardModal' +// import ModifyCardForm from '../cardFormModals/ModifyCardForm' +// import Tags from '../Tags' +// interface CardContentProps { +// onClose: () => void +// card: Card +// column: Column +// } +// export default function CardContent({ +// onClose, +// card, +// column, +// }: CardContentProps) { +// const { id, imageUrl, title, tags, dueDate, assignee } = card +// const [openModifyCard, setOpenModifyCard] = useState(false) +// const { title: columnTitle, id: columnId } = column +// const currentColumn = { columnTitle, columnId } +// const { modalType, closeModal } = useModalStore() + +// const handleBackdropClick = (e: React.MouseEvent) => { +// if (e.target === e.currentTarget) { +// closeModal() +// } +// } + +// if (!modalType) return null + +// return ( +// <> +//
+//
+//

초대하기

+ +//

{title}

+//
+// +// } +// > +// {/* 드롭다운 내부 메뉴 아이템 */} +//
setOpenModifyCard(true)} +// > +// 수정하기 +//
+//
+// 삭제하기 +//
+//
+// 카드 닫기 { +// onClose() +// console.log('sdfadfdsgreggsfds') +// }} +// /> +//
+ +//
+// 그리드로 관리하기 / 컬럼명은 따로 컴포넌트로 만들어 빼기 +//
{column.title}
+// +//

설명~~~~~~~~

+//
+//
{assignee.nickname}
+//
{dueDate}
+//
+//
+//
이미지 있으면 이미지
+//
댓글 컴포넌트
+ +// {/* 카드 수정 모달 */} +// {openModifyCard && ( +// +// setOpenModifyCard(false)} +// // columnId={column.id} +// currentColumn={currentColumn} +// card={card} +// /> +// +// )} +//
+//
+// +// ) +// } diff --git a/src/app/features/dashboard_Id/Card/cardModal/CardModal.tsx b/src/app/features/dashboard_Id/Card/cardModal/CardModal.tsx index 9f8b32b..11b3353 100644 --- a/src/app/features/dashboard_Id/Card/cardModal/CardModal.tsx +++ b/src/app/features/dashboard_Id/Card/cardModal/CardModal.tsx @@ -1,15 +1,20 @@ import { createPortal } from 'react-dom' +import { useLockBodyScroll } from '@/app/shared/hooks/useLockBodyScroll' + interface ModalProps { children: React.ReactNode } export default function CardModal({ children }: ModalProps) { const modalRoot = document.getElementById('modal-root') + + useLockBodyScroll() + if (!modalRoot) return null return createPortal(
-
+
{children}
, diff --git a/src/app/features/dashboard_Id/Card/cardModal/Comment.tsx b/src/app/features/dashboard_Id/Card/cardModal/Comment.tsx new file mode 100644 index 0000000..a681885 --- /dev/null +++ b/src/app/features/dashboard_Id/Card/cardModal/Comment.tsx @@ -0,0 +1,58 @@ +import { format } from 'date-fns' +import { useState } from 'react' + +import { Avatar } from '@/app/shared/components/common/Avatar' +import { useIsMobile } from '@/app/shared/hooks/useIsmobile' + +import { useDeleteCommentMutation } from '../../api/useDeleteCommentMutation' +import { Comment as CommentType } from '../../type/Comment.type' +import CommentModifyForm from './CommentModifyForm' + +export default function Comment({ comment }: { comment: CommentType }) { + const isMobile = useIsMobile() + const [modifyComment, setModifyComment] = useState(false) + const { mutate: deleteComment, isPending } = useDeleteCommentMutation() + + return ( +
+ {isMobile ? ( + + ) : ( + + )} +
+
+ + {comment.author.nickname} + + + {format(new Date(comment.createdAt), 'yyyy.MM.dd HH:mm')} + +
+ {modifyComment ? ( + setModifyComment(false)} + commentId={comment.id} + content={comment.content} + /> + ) : ( +

{comment.content}

+ )} + {!modifyComment && ( +
+ + +
+ )} +
+
+ ) +} diff --git a/src/app/features/dashboard_Id/Card/cardModal/CommentForm.tsx b/src/app/features/dashboard_Id/Card/cardModal/CommentForm.tsx new file mode 100644 index 0000000..08cc66f --- /dev/null +++ b/src/app/features/dashboard_Id/Card/cardModal/CommentForm.tsx @@ -0,0 +1,69 @@ +import { useForm } from 'react-hook-form' + +import { usePostCommentMutation } from '../../api/usePostCommentMutation' +import { CommentFormData } from '../../type/CommentFormData.type' + +export default function CommentForm({ + cardId, + columnId, + dashboardId, +}: { + cardId: number + columnId: number + dashboardId: number +}) { + const { + register, + handleSubmit, + reset, + formState: { errors, isValid, isSubmitting }, + } = useForm({ + mode: 'onChange', + }) + + // 폼 제출 핸들러 함수 + const { mutate: createComment, isPending } = usePostCommentMutation() + + function onSubmit(data: CommentFormData) { + const payload = { + ...data, + cardId, + columnId, + dashboardId, + } + console.log(payload) + createComment(payload) + reset() + } + + return ( + + +
+