1- import { useMemo , useRef , useState } from "react" ;
1+ import { useRef } from "react" ;
22import clsx from "clsx" ;
33import { MoreVertical , X } from "lucide-react" ;
44import CardDetail from "./CardDetail" ;
55import CommentList from "./CommentList" ;
66import CommentInput from "@/components/modalInput/CardInput" ;
77import { Representative } from "@/components/modalDashboard/Representative" ;
8- import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query" ;
9- import { createComment } from "@/api/comment" ;
10- import { deleteCard , getDashboardMembers } from "@/api/card" ;
11- import type { CardDetailType } from "@/types/cards" ;
128import TaskModal from "@/components/modalInput/TaskModal" ;
139import { DeleteModal } from "@/components/modal/DeleteModal" ;
14- import { useClosePopup } from "@/hooks/useClosePopup" ;
15- import { getColumn } from "@/api/columns" ;
1610import { toast } from "react-toastify" ;
1711import { TEAM_ID } from "@/constants/team" ;
1812import { useDashboardPermission } from "@/hooks/useDashboardPermission" ;
13+ import { useCardDetailState } from "@/hooks/useCardDetailState" ;
14+ import { useCardDetail } from "@/hooks/useCardDetail" ;
15+ import type { CardDetailType } from "@/types/cards" ;
1916
2017interface CardDetailModalProps {
2118 card : CardDetailType ;
@@ -26,12 +23,6 @@ interface CardDetailModalProps {
2623 onChangeCard ?: ( ) => void ;
2724}
2825
29- interface ColumnType {
30- id : number ;
31- title : string ;
32- status : string ;
33- }
34-
3526export default function CardDetailPage ( {
3627 card,
3728 currentUserId,
@@ -41,75 +32,32 @@ export default function CardDetailPage({
4132 onChangeCard,
4233} : CardDetailModalProps ) {
4334 const { canEditCards } = useDashboardPermission ( dashboardId , createdByMe ) ;
44-
45- const [ cardData , setCardData ] = useState < CardDetailType > ( card ) ;
46- const [ commentText , setCommentText ] = useState ( "" ) ;
47- const [ showMenu , setShowMenu ] = useState ( false ) ;
48- const [ isEditModalOpen , setIsEditModalOpen ] = useState ( false ) ;
49- const [ isDeleteModalOpen , setIsDeleteModalOpen ] = useState ( false ) ;
50-
51- const queryClient = useQueryClient ( ) ;
52- const popupRef = useRef ( null ) ;
53- useClosePopup ( popupRef , ( ) => setShowMenu ( false ) ) ;
54-
55- const { data : columns = [ ] } = useQuery < ColumnType [ ] > ( {
56- queryKey : [ "columns" , dashboardId ] ,
57- queryFn : ( ) => getColumn ( { dashboardId, columnId : cardData . columnId } ) ,
58- } ) ;
59-
60- const { data : members = [ ] } = useQuery ( {
61- queryKey : [ "dashboardMembers" , dashboardId ] ,
62- queryFn : ( ) => getDashboardMembers ( { dashboardId } ) ,
63- } ) ;
64-
65- const columnName = useMemo ( ( ) => {
66- return (
67- columns . find ( ( col ) => col . id === cardData . columnId ) ?. title || "알 수 없음"
68- ) ;
69- } , [ columns , cardData . columnId ] ) ;
70-
71- const { mutate : createCommentMutate } = useMutation ( {
72- mutationFn : createComment ,
73- onSuccess : ( ) => {
74- setCommentText ( "" ) ;
75- queryClient . invalidateQueries ( { queryKey : [ "comments" , cardData . id ] } ) ;
76- } ,
77- } ) ;
78-
79- const { mutate : deleteCardMutate } = useMutation ( {
80- mutationFn : ( ) => deleteCard ( cardData . id ) ,
81- onSuccess : ( ) => {
82- queryClient . invalidateQueries ( { queryKey : [ "cards" ] } ) ;
83- if ( onChangeCard ) onChangeCard ( ) ;
84- setIsDeleteModalOpen ( true ) ;
85- } ,
86- } ) ;
87-
88- const handleClose = ( ) => {
89- onClose ( ) ;
90- } ;
91-
92- const handleCommentSubmit = ( ) => {
93- if ( ! commentText . trim ( ) ) return ;
94- createCommentMutate ( {
95- content : commentText ,
96- cardId : cardData . id ,
97- columnId : cardData . columnId ,
98- dashboardId,
99- } ) ;
100- } ;
35+ const { cardData, setCardData, columnName, columns, members } =
36+ useCardDetailState ( card , dashboardId ) ;
37+
38+ const {
39+ commentText,
40+ setCommentText,
41+ isEditModalOpen,
42+ setIsEditModalOpen,
43+ isDeleteModalOpen,
44+ setIsDeleteModalOpen,
45+ showMenu,
46+ setShowMenu,
47+ popupRef,
48+ handleCommentSubmit,
49+ handleConfirmDelete,
50+ } = useCardDetail ( card , dashboardId , onChangeCard , onClose ) ;
10151
10252 return (
10353 < >
104- { /* 모달 고정 div */ }
10554 < div
10655 className = { clsx (
10756 "fixed inset-0 z-50" ,
10857 "flex items-center justify-center px-4 sm:px-6" ,
10958 "bg-black/35"
11059 ) }
11160 >
112- { /* 모달창 */ }
11361 < div
11462 className = { clsx (
11563 "relative flex flex-col overflow-y-auto" ,
@@ -119,20 +67,15 @@ export default function CardDetailPage({
11967 ) }
12068 >
12169 < div className = "flex items-center justify-center px-6 pt-6 pb-2" >
122- { /* 내부 아이템 컨테이너 */ }
12370 < div className = "flex flex-col lg:w-[674px] sm:w-[614px] w-[295px]" >
124- { /* 헤더 컨테이너 */ }
12571 < div className = "flex justify-between sm:mb-4 mb-2" >
126- { /* 제목 */ }
12772 < h2 className = "text-black3 font-bold sm:text-[20px] text-[16px]" >
12873 { cardData . title }
12974 </ h2 >
130- { /* 버튼 컨테이너 */ }
13175 < div
13276 className = "relative flex items-center sm:gap-[24px] gap-[16px]"
13377 ref = { popupRef }
13478 >
135- { /* 메뉴 버튼 */ }
13679 < button
13780 onClick = { ( ) => setShowMenu ( ( prev ) => ! prev ) }
13881 className = "sm:w-[28px] sm:h-[28px] w-[20px] h-[20px] flex items-center justify-center hover:cursor-pointer"
@@ -141,7 +84,6 @@ export default function CardDetailPage({
14184 >
14285 < MoreVertical className = "w-8 h-8 text-black3 cursor-pointer" />
14386 </ button >
144- { /* 수정/삭제 드롭다운 메뉴 */ }
14587 { showMenu && (
14688 < div className = "absolute right-0 top-9.5 p-2 z-40 flex flex-col items-center justify-center sm:gap-[6px] gap-[11px] sm:w-28 w-20 sm:h-24 bg-white border border-[#D9D9D9] rounded-lg" >
14789 < button
@@ -173,21 +115,19 @@ export default function CardDetailPage({
173115 </ button >
174116 </ div >
175117 ) }
176- < button onClick = { handleClose } title = "닫기" >
118+ < button onClick = { onClose } title = "닫기" >
177119 < X className = "sm:w-[28px] sm:h-[28px] w-[20px] h-[20px] flex items-center justify-center hover:cursor-pointer" />
178120 </ button >
179121 </ div >
180122 </ div >
181123
182- { /* 카드 내용 */ }
183124 < div className = "flex flex-col-reverse sm:flex-row gap-4" >
184125 < CardDetail card = { cardData } columnName = { columnName } />
185126 < div >
186127 < Representative card = { cardData } />
187128 </ div >
188129 </ div >
189130
190- { /* 댓글 */ }
191131 < div className = "mt-4 w-full lg:max-w-[445px] md:max-w-[420px]" >
192132 < p className = "mb-1 text-black3 font-medium sm:text-[16px] text-[14px]" >
193133 댓글
@@ -223,8 +163,7 @@ export default function CardDetailPage({
223163 members = { members }
224164 onClose = { ( ) => setIsEditModalOpen ( false ) }
225165 onSubmit = { ( updatedData ) => {
226- if ( onChangeCard ) onChangeCard ( ) ;
227- queryClient . invalidateQueries ( { queryKey : [ "cards" ] } ) ;
166+ onChangeCard ?.( ) ;
228167 setCardData ( ( prev ) => ( {
229168 ...prev ,
230169 title : updatedData . title ,
@@ -253,25 +192,12 @@ export default function CardDetailPage({
253192 } }
254193 />
255194 ) }
195+
256196 < DeleteModal
257197 title = "카드를"
258198 isOpen = { isDeleteModalOpen }
259199 onCancel = { ( ) => setIsDeleteModalOpen ( false ) }
260- onConfirm = { ( ) => {
261- deleteCardMutate ( undefined , {
262- onSuccess : ( ) => {
263- queryClient . invalidateQueries ( { queryKey : [ "cards" ] } ) ;
264- if ( onChangeCard ) onChangeCard ( ) ;
265- setIsDeleteModalOpen ( false ) ;
266- onClose ( ) ;
267- toast . success ( "카드가 삭제되었습니다." ) ;
268- } ,
269- onError : ( ) => {
270- toast . error ( "카드 삭제에 실패했습니다." ) ;
271- setIsDeleteModalOpen ( false ) ;
272- } ,
273- } ) ;
274- } }
200+ onConfirm = { handleConfirmDelete }
275201 />
276202 </ >
277203 ) ;
0 commit comments