Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 18 additions & 0 deletions src/app/features/dashboard_Id/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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 (
<div
Expand Down Expand Up @@ -84,11 +89,24 @@ export default function Card({
<CardModal>
<CardContent
onClose={() => setOpenCard(false)}
openModifyModal={() => setOpenModifyCard(true)}
card={card}
column={column}
/>
</CardModal>
)}

{/* 카드 수정 모달 */}
{openModifyCard && (
<CreateCardModal>
<ModifyCardForm
onClose={() => setOpenModifyCard(false)}
// columnId={column.id}
currentColumn={currentColumn}
card={card}
/>
</CreateCardModal>
)}
</div>
)
}
2 changes: 1 addition & 1 deletion src/app/features/dashboard_Id/Card/ColumnTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export default function ColumnTitle({ title }: { title: string }) {
return (
<div className="BG-lightblue flex w-fit items-center gap-6 rounded-16 px-10 py-4">
<div className="size-6 rounded-25 bg-[#228DFF]"></div>
<div className="Text-deepblue pb-4 pt-6 text-14 font-medium leading-none">
<div className="Text-deepblue whitespace-nowrap pb-4 pt-6 text-14 font-medium leading-none">
{title}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,22 +63,21 @@ export default function ModifyCardForm({
formState: { errors, isValid, isSubmitting, isDirty },
} = useForm<CardFormData>({
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가 입력 즉시 반영되도록
})

// React Hook Form 과 tags 값 연결
useEffect(() => {
setValue('tags', tags)
console.log(tags)
}, [tags, tags.length, setValue])

// 상태(컬럼) 선택 시 / assignee 선택 시 드롭다운 닫기
Expand Down Expand Up @@ -125,7 +124,11 @@ export default function ModifyCardForm({

// ✅ JSX
return (
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-32">
<form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-col gap-32"
onClick={(e) => e.stopPropagation()}
>
<h2 className="Text-black text-24 font-bold">할 일 수정</h2>

<div className="flex gap-32">
Expand Down Expand Up @@ -188,9 +191,11 @@ export default function ModifyCardForm({
id="assigneeUserId"
type="text"
/>
<div className="BG-white absolute left-16 top-1/2 -translate-y-1/2">
<MyAssignee assignee={selectedAssignee} />
</div>
{selectedAssignee && (
<div className="BG-white absolute left-16 top-1/2 -translate-y-1/2">
<MyAssignee assignee={selectedAssignee} />
</div>
)}
<Image
src="/images/arrow-dropdown.svg"
alt="화살표"
Expand Down
177 changes: 129 additions & 48 deletions src/app/features/dashboard_Id/Card/cardModal/CardContent.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,47 @@
import Image from 'next/image'
import { useState } from 'react'

import { Avatar } from '@/app/shared/components/common/Avatar'
import Dropdown from '@/app/shared/components/common/Dropdown/Dropdown'
import { useIsMobile } from '@/app/shared/hooks/useIsmobile'

import { useDeleteCardMutation } from '../../api/useDeleteCardMutation'
import { Card } from '../../type/Card.type'
import { Column } from '../../type/Column.type'
import CreateCardModal from '../cardFormModals/CreateCardModal'
import ModifyCardForm from '../cardFormModals/ModifyCardForm'
import ColumnTitle from '../ColumnTitle'
import Tags from '../Tags'
interface CardContentProps {
onClose: () => 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 (
<>
<h2 className="Text-black bt-24 text-24 font-bold">{title}</h2>
<div className="flex items-center gap-24">
// <div className="relative">
<div>
<h2 className="Text-black mb-24 text-24 font-bold mobile:mt-40 mobile:text-20">
{card.title}
</h2>

{/* 카드 우측 상단의 케밥 버튼, X 버튼 */}
<div className="absolute right-38 top-30 flex items-center gap-24 mobile:right-16 mobile:top-16 mobile:gap-16 tablet:right-32 tablet:top-24">
<Dropdown
width="w-6"
align="right"
Expand All @@ -36,56 +51,122 @@ export default function CardContent({
alt="드롭 옵션 보기"
width={28}
height={28}
className="mobile:size-20"
/>
}
>
{/* 드롭다운 내부 메뉴 아이템 */}
<div
className="Text-black cursor-pointer whitespace-nowrap rounded-6 px-22 py-11 text-center text-14 font-medium hover:bg-[#dbf0ff] hover:text-[#228DFF] dark:hover:bg-[#02406d]"
onClick={() => setOpenModifyCard(true)}
{/* 트리거의(케밥) 드롭다운 - 수정하기, 삭제하기 */}
<button
className="Text-black w-full whitespace-nowrap rounded-6 px-22 py-11 text-center text-14 font-medium hover:bg-[#dbf0ff] hover:text-[#228DFF] dark:hover:bg-[#02406d]"
onClick={(e) => {
e.stopPropagation() // 클릭 이벤트가 부모 컴포넌트(Card)까지 번지지 않도록 (Card-> onClick->isOpen 주의)
openModifyModal()
onClose()
}}
>
수정하기
</div>
<div className="Text-black cursor-pointer whitespace-nowrap rounded-6 px-22 py-11 text-center text-14 font-medium hover:bg-[#dbf0ff] hover:text-[#228DFF] dark:hover:bg-[#02406d]">
</button>
<button
className="Text-black w-full whitespace-nowrap rounded-6 px-22 py-11 text-center text-14 font-medium hover:bg-[#dbf0ff] hover:text-[#228DFF] dark:hover:bg-[#02406d]"
onClick={(e) => {
e.stopPropagation()
deleteCard(card.id)
}}
>
삭제하기
</div>
</button>
</Dropdown>
<Image
src={'/images/close.svg'}
alt="카드 닫기"
width={32}
height={32}
onClick={() => {
{/* X 버튼 (카드 닫기)*/}
<button
onClick={(e) => {
e.stopPropagation() //
onClose()
console.log('sdfadfdsgreggsfds')
}}
/>
>
<Image
src="/images/close.svg"
alt="카드 닫기"
width={32}
height={32}
className="mobile:size-24"
/>
</button>
</div>

{/* 카드 상단 */}
<div>
그리드로 관리하기 / 컬럼명은 따로 컴포넌트로 만들어 빼기
<div>{column.title}</div>
<Tags tags={tags} />
<p>설명~~~~~~~~</p>
<div>
<div>{assignee.nickname}</div>
<div>{dueDate}</div>
<div className="flex gap-14 mobile:flex-col-reverse mobile:gap-16">
{/* 컬럼명 / 태그 // 설명 // 이미지 */}
<div className="w-470 mobile:w-295 tablet:w-420">
<div className="mb-16 flex items-start gap-20 mobile:gap-12">
<ColumnTitle title={column.title} />
<div className="mt-6 h-20 w-1 bg-[#D9D9D9] dark:bg-[#454545]"></div>
{card.tags && <Tags tags={card.tags} />}
</div>
{card.description && (
<p
className={
'font-regular Text-black mb-16 text-14 mobile:mb-32 mobile:text-12'
}
>
{card.description}
</p>
)}
{card.imageUrl && (
<Image
alt="카드 이미지"
src={card.imageUrl}
width={420}
height={300}
className="mb-24 h-auto w-full rounded-6 object-contain"
priority
/>
)}
</div>
{/* 담당자 / 마감일 박스 */}
<div>
<div className="Border-section flex w-200 flex-col gap-16 rounded-8 px-16 py-14 mobile:w-full mobile:flex-row mobile:py-9 tablet:w-181">
<div className="mobile:w-120">
<span className="Text-black moblie:mb-0 mb-6 block text-12 font-semibold">
담당자
</span>
{card.assignee && (
<div className="flex items-center gap-8">
<>
<Avatar
size={isMobile ? 24 : 32}
name={card.assignee.nickname}
imageUrl={card.assignee.profileImageUrl}
/>
<span className="regular Text-black block pt-1 text-14 leading-none mobile:text-12">
{card.assignee.nickname}
</span>
</>
</div>
)}
</div>
<div>
<span className="Text-black mb-6 block text-12 font-semibold mobile:mb-8">
마감일
</span>
{card.dueDate && (
<span className="regular Text-black block pt-1 text-14 leading-none mobile:text-12">
{card.dueDate}
</span>
)}
</div>
</div>
</div>
</div>
<div></div>
</div>
<div> 이미지 있으면 이미지</div>
<div>댓글 컴포넌트</div>

{/* 카드 수정 모달 */}
{openModifyCard && (
<CreateCardModal>
<ModifyCardForm
onClose={() => setOpenModifyCard(false)}
// columnId={column.id}
currentColumn={currentColumn}
card={card}
/>
</CreateCardModal>
)}
</>
<CommentForm
cardId={card.id}
columnId={card.columnId}
dashboardId={card.dashboardId}
/>
<Comments cardId={card.id} />
</div>
)
}
Loading