1- import { useState } from "react" ;
1+ import { useEffect , useState } from "react" ;
22import Image from "next/image" ;
33import Modal from "@/components/common/modal/Modal" ;
44import TagInput from "@/components/common/input/TagInput" ;
55import Input from "@/components/common/input/Input" ;
6+ import DateInput from "@/components/common/input/DateInput" ;
67import ImageInput from "@/components/common/input/ImageInput" ;
78import Textarea from "@/components/common/textarea/Textarea" ;
9+ import UserIcon from "@/components/common/user-icon/UserIcon" ;
810import dropdownIcon from "../../../../public/icon/dropdown_icon.svg" ;
11+ import { fetchDashboardMember } from "@/lib/apis/membersApi" ;
12+ import { DashboardMember } from "@/lib/types" ;
13+ import { useDashboardStore } from "@/lib/store/useDashboardStore" ;
14+ import { useColumnStore } from "@/lib/store/useColumnStore" ;
15+ import checkItem from "../../../../public/icon/check_icon.svg" ;
16+ import { createCard } from "@/lib/apis/cardsApi" ;
917
1018export default function CreateDashboardModal ( ) {
19+ const { dashboardId } = useDashboardStore ( ) ;
20+ const { selectedColumnId } = useColumnStore ( ) ;
21+ const [ assignees , setAssignees ] = useState < DashboardMember | null > ( null ) ;
22+ const [ form , setForm ] = useState < { title : string ; description : string } > ( {
23+ title : "" ,
24+ description : "" ,
25+ } ) ;
26+ const [ dueDate , setDueDate ] = useState < string > ( "" ) ;
27+ const [ tags , setTags ] = useState < string [ ] > ( [ ] ) ;
28+ const [ imageUrl , setImageUrl ] = useState < string | null > ( null ) ;
29+ const [ items , setItems ] = useState < DashboardMember [ ] > ( [ ] ) ;
30+
1131 // 해당 폼이 유효성 검사 후 제출 가능해질 때 해당 state 값이 true가 되도록 하기
1232 const [ isFormValid , setIsFormValid ] = useState ( false ) ;
13-
14- // TagInput 컴포넌트에 전달할 state
15- const [ tags , setTags ] = useState < string [ ] > ( [ ] ) ;
16- const [ selectedManager , setSelectedManager ] = useState < string | null > ( null ) ;
33+ // const [selectedColumn, setSelectedColumn] = useState(0);
1734 const [ isDropdownOpen , setIsDropdownOpen ] = useState ( false ) ;
1835
19- const managers = [ "김경민" , "노현지" , "이아름" , "이재혁" , "임지혜" ] ;
36+ const accessToken = localStorage . getItem ( "accessToken" ) ?? "" ;
37+
38+ const fetchMembers = async ( ) => {
39+ if ( ! dashboardId ) return ;
40+
41+ try {
42+ const res = await fetchDashboardMember ( {
43+ token : accessToken ,
44+ id : dashboardId ,
45+ page : 1 ,
46+ size : 20 ,
47+ } ) ;
48+ console . log ( "Fetched members:" , res . members ) ; // 데이터 확인용
49+
50+ setItems ( res . members ) ;
51+ } catch ( error ) {
52+ console . error ( "Failed to load members:" , error ) ;
53+ }
54+ } ;
55+
56+ useEffect ( ( ) => {
57+ if ( dashboardId !== undefined && dashboardId !== null ) {
58+ fetchMembers ( ) ;
59+ }
60+ } , [ dashboardId ] ) ;
61+
62+ // useEffect(() => {}, [items]);
63+
64+ const handleAssigneeSelect = ( selectedAssignee : DashboardMember ) => {
65+ if ( ! selectedAssignee ) {
66+ console . error ( "선택된 담당자가 없습니다." ) ;
67+ return ;
68+ }
69+ setAssignees ( selectedAssignee ) ; // 선택된 담당자 정보를 assignee 상태로 업데이트
70+ setIsDropdownOpen ( false ) ;
71+ } ;
72+
73+ const handleInputChange = (
74+ e : React . ChangeEvent < HTMLInputElement | HTMLTextAreaElement >
75+ ) => {
76+ const { name, value } = e . target ;
77+ setForm ( ( prev ) => ( {
78+ ...prev ,
79+ [ name ] : value , // 변경된 값만 업데이트
80+ } ) ) ;
81+ } ;
82+
83+ const selected = items . find (
84+ ( assignee ) => assignees ?. userId === assignee . userId
85+ ) ;
86+
87+ useEffect ( ( ) => {
88+ const isNotEmpty =
89+ form . title . trim ( ) !== "" &&
90+ form . description . trim ( ) !== "" &&
91+ assignees !== null &&
92+ dueDate . trim ( ) !== "" &&
93+ tags . join ( ) !== "" ;
94+ setIsFormValid ( isNotEmpty ) ;
95+ } , [ form . title , form . description , assignees , dueDate , tags ] ) ;
2096
2197 // 활성화된 모달 버튼 클릭 시 실행할 함수
22- const buttonClick = ( ) => {
23- alert ( "Hi" ) ; // 이 부분 바꿔주시면 됩니다
24- setIsFormValid ( false ) ; // 이 코드는 배포할 때 문제가 있어서 임시로 넣어놓은 코드라 삭제하시면 됩니다
98+ const buttonClick = async ( ) => {
99+ if ( ! dashboardId ) return ;
100+ if ( ! selectedColumnId ) return ;
101+
102+ // 생성된 데이터 값 확인용 입니당
103+ console . log ( "카드 생성 데이터:" , {
104+ dashboardId,
105+ selectedColumnId,
106+ assigneeUserId : assignees ?. userId ,
107+ title : form . title ,
108+ description : form . description ,
109+ dueDate,
110+ tags,
111+ imageUrl,
112+ } ) ;
113+
114+ try {
115+ await createCard ( {
116+ token : accessToken ,
117+ assigneeUserId : Number ( assignees ?. userId ) ,
118+ dashboardId : Number ( dashboardId ) ,
119+ columnId : selectedColumnId ,
120+ title : form . title ,
121+ description : form . description ,
122+ dueDate,
123+ tags,
124+ imageUrl,
125+ } ) ;
126+ } catch ( error ) {
127+ console . error ( "카드 생성 실패:" , error ) ;
128+ }
129+
130+ window . location . reload ( ) ;
25131 } ;
26132
133+ // dashboardId가 number로 잘나오는지 확인하려고 작성한 코드입니당
134+ useEffect ( ( ) => {
135+ console . log ( "🔍 dashboardId 값:" , dashboardId ) ;
136+ console . log ( "🔍 dashboardId 타입:" , typeof dashboardId ) ;
137+ } , [ dashboardId ] ) ;
138+
139+ if ( ! selectedColumnId ) return ;
140+
27141 return (
28142 < Modal
29143 button = { {
30144 onConfirm : buttonClick ,
31145 disabled : ! isFormValid ,
32146 } }
33147 >
34- < div className = "flex flex-col w-[271px] gap-6 tablet:w-[520px] tablet:gap-8" >
148+ < div className = "relative flex flex-col w-[271px] gap-6 tablet:w-[520px] tablet:gap-8" >
35149 < div className = "relative flex flex-col" >
36150 < label className = "block mb-2.5 text-lg font-medium text-gray-800 tablet:mb-2 tablet:text-2lg" >
37151 담당자
@@ -41,40 +155,88 @@ export default function CreateDashboardModal() {
41155 onClick = { ( ) => setIsDropdownOpen ( ( prev ) => ! prev ) }
42156 >
43157 < div className = "flex justify-between" >
44- < span > { selectedManager || "이름을 입력해 주세요" } </ span >
158+ { selected ? (
159+ < div className = "flex items-center gap-[6px]" >
160+ < UserIcon
161+ name = { selected . nickname }
162+ img = { selected . profileImageUrl }
163+ size = "sm"
164+ />
165+ < div className = "font-normal text-lg text-gray-800" >
166+ { selected . nickname }
167+ </ div >
168+ </ div >
169+ ) : (
170+ < span className = "text-gray-500" > 담당자 선택</ span >
171+ ) }
45172 < Image src = { dropdownIcon } width = { 8 } height = { 8 } alt = "" />
46173 </ div >
47174 </ button >
48175 </ div >
49176
50177 { isDropdownOpen && (
51- < ul className = "border border-gray-400 rounded-md" >
52- { managers . map ( ( manager ) => (
178+ < ul className = "border border-gray-400 rounded-md w-full tablet:w-[520px] absolute top-[89px] z-10 bg-white " >
179+ { items . map ( ( assignee ) => (
53180 < li
54- key = { manager }
181+ key = { assignee . userId }
55182 className = "px-4 py-2 hover:text-violet hover:bg-violet-8 cursor-pointer"
56183 onClick = { ( ) => {
57- setSelectedManager ( manager ) ;
58- setIsDropdownOpen ( false ) ;
184+ handleAssigneeSelect ( assignee ) ;
59185 } }
60186 >
61- { manager }
187+ < div className = "flex gap-2 items-center" >
188+ < div className = "relative invert brightness-75 w-4 h-3" >
189+ { assignees ?. userId === assignee . userId && (
190+ < Image
191+ src = { checkItem }
192+ fill
193+ alt = "checkIcon"
194+ className = "mr-2"
195+ />
196+ ) }
197+ </ div >
198+ < div className = "flex items-center gap-1.5" >
199+ < UserIcon
200+ name = { assignee . nickname }
201+ img = { assignee . profileImageUrl }
202+ size = "sm"
203+ />
204+ { assignee . nickname }
205+ </ div >
206+ </ div >
62207 </ li >
63208 ) ) }
64209 </ ul >
65210 ) }
66- < Input label = "제목" placeholder = "제목을 입력해 주세요" required />
211+ < Input
212+ label = "제목"
213+ name = "title"
214+ value = { form . title }
215+ onChange = { handleInputChange }
216+ placeholder = "제목을 입력해 주세요"
217+ required
218+ />
67219 < Textarea
68220 label = "설명"
221+ name = "description"
222+ value = { form . description }
223+ onChange = { handleInputChange }
69224 placeholder = "설명을 입력해 주세요"
70225 required
71226 spanClassName = "ml-0.5"
72227 containerClassName = "gap-2.5 tablet:gap-2"
73228 labelClassName = "font-medium text-lg tablet:text-2lg"
74229 textareaClassName = "font-normal placeholder:text-gray-500 rounded-md text-md h-[84px] px-4 py-[13px] tablet:rounded-lg tablet:h-[126px] tablet:py-[15px] tablet:text-lg"
75230 />
231+ < DateInput value = { dueDate } onChange = { setDueDate } />
76232 < TagInput label = "태그" tags = { tags } setTags = { setTags } />
77- < ImageInput label = "이미지" variant = "task" columnId = { 46355 } />
233+ < ImageInput
234+ label = "이미지"
235+ variant = "task"
236+ columnId = { selectedColumnId }
237+ token = { accessToken }
238+ onImageUrlChange = { ( url ) => setImageUrl ( url ) }
239+ />
78240 </ div >
79241 </ Modal >
80242 ) ;
0 commit comments