1
+ /* eslint-disable react-hooks/exhaustive-deps */
1
2
import FullCalendar from '@fullcalendar/react' ;
2
- import { EventClickArg } from '@fullcalendar/core' ;
3
+ // import { EventClickArg } from '@fullcalendar/core';
3
4
import dayGridPlugin from '@fullcalendar/daygrid' ;
4
5
import interactionPlugin from '@fullcalendar/interaction' ;
5
- import { useRef , useState , useEffect } from 'react' ;
6
+ import { useRef , useState , useEffect , useCallback } from 'react' ;
6
7
import { useEventState } from '@/stores/myEventsStore' ;
7
8
import { getPersonalSchedule } from '@/apis/personalScheduleApi' ;
8
-
9
+ import { Events } from '../../utils/index.ts' ;
10
+ /*
9
11
type Event = {
10
12
title: string;
11
- start : Date | string ;
13
+ start: string;
14
+ end: string;
15
+ backgroundColor?: string;
16
+ borderColor?: string;
17
+ textColor?: string;
12
18
};
13
- interface EventCardsProps {
14
- events : Event [ ] ;
15
- date : Date | string | null ;
19
+ */
20
+
21
+ interface EventInfo {
22
+ timeText : string ;
23
+ event : {
24
+ title : string ;
25
+ } ;
16
26
}
17
27
18
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
19
- const events = [
20
- { title : 'Meeting' , start : new Date ( ) } ,
21
- { title : 'Meeting' , start : '2024-05-08' } ,
22
- { title : 'Meeting' , start : '2024-05-08' } ,
23
- { title : 'Meeting' , start : '2024-05-08' } ,
24
- ] ;
28
+ interface EventCardsProps {
29
+ events : Events [ ] ;
30
+ date : string | null ;
31
+ }
25
32
26
33
export default function Calendar ( ) {
27
34
const [ calendarHeight , setCalendarHeight ] = useState < string | number > ( 'auto' ) ;
28
35
const calendarRef = useRef < FullCalendar | null > ( null ) ;
29
- const [ selectedEvents , setSelectedEvents ] = useState < Event [ ] > ( [ ] ) ;
30
- const [ selectedDate , setSelectedDate ] = useState < Date | null > ( null ) ;
36
+ const [ selectedEvents , setSelectedEvents ] = useState < Events [ ] > ( [ ] ) ;
37
+ const [ selectedDate , setSelectedDate ] = useState < string | null > ( null ) ;
38
+ const { events, addEvents } = useEventState ( ) ;
31
39
40
+
41
+ /*
32
42
const handleDateClick = (clickInfo: EventClickArg) => {
33
43
if (clickInfo.event.start) {
34
44
const clickStartDate = new Date(clickInfo.event.start);
@@ -40,6 +50,17 @@ export default function Calendar() {
40
50
console.log('not available');
41
51
}
42
52
};
53
+ */
54
+
55
+ const handleDateSelection = ( dateClickInfo : { dateStr : string } ) => {
56
+ console . log ( dateClickInfo )
57
+ const clickedDateStr = dateClickInfo . dateStr ;
58
+ setSelectedDate ( clickedDateStr ) ;
59
+ setSelectedEvents ( events . filter ( event =>
60
+ clickedDateStr >= event . start . split ( 'T' ) [ 0 ] &&
61
+ clickedDateStr <= ( event . end ? event . end . split ( 'T' ) [ 0 ] : event . start . split ( 'T' ) [ 0 ] )
62
+ ) ) ;
63
+ } ;
43
64
44
65
const handlePrev = ( ) => {
45
66
const calendarApi = calendarRef ?. current ?. getApi ( ) ;
@@ -61,17 +82,27 @@ export default function Calendar() {
61
82
}
62
83
} ;
63
84
64
- // eslint-disable-next-line react-hooks/exhaustive-deps
65
- const updateSize = ( ) => {
66
- const isMobile = window . innerWidth < 768 ;
67
- setCalendarHeight ( isMobile ? 500 : 'auto' ) ;
68
- updateTitle ( ) ;
69
- } ;
85
+ const updateSize = useCallback ( ( ) => {
86
+ setCalendarHeight ( window . innerWidth < 768 ? 500 : 'auto' ) ;
87
+ } , [ ] ) ;
88
+
89
+ function convertEvents ( events : { title : string , start_date : string , end_date : string , backgroundColor ?: string , borderColor ?: string , textColor ?: string } [ ] ) : Events [ ] {
90
+ return events . map ( event => ( {
91
+ title : event . title ,
92
+ start : event . start_date ,
93
+ end : event . end_date ,
94
+ backgroundColor : event . backgroundColor || '#3788d8' ,
95
+ borderColor : event . borderColor || '#296c98' ,
96
+ textColor : event . textColor || '#ffffff'
97
+ } ) ) ;
98
+ }
70
99
100
+ /*
71
101
const updateTitle = () => {
72
102
const calendarApi = calendarRef?.current?.getApi();
73
103
if (calendarApi) {
74
104
const calendarView = calendarApi.view;
105
+ console.log('View start date:', calendarView.currentStart);
75
106
76
107
const date = new Date(calendarView.currentStart);
77
108
const year = date.getFullYear();
@@ -84,34 +115,51 @@ export default function Calendar() {
84
115
}
85
116
}
86
117
};
118
+ */
87
119
88
- const { events, addEvents } = useEventState ( ) ;
89
120
90
121
useEffect ( ( ) => {
122
+ /*
91
123
const calendarApi = calendarRef?.current?.getApi();
92
-
93
124
if (calendarApi) {
94
125
calendarApi.on('datesSet', updateTitle);
95
126
}
96
127
97
128
updateTitle(); // 컴포넌트 마운트 시 제목 업데이트
129
+ */
98
130
99
131
/* 캘린더 - 반응형 사이즈 */
100
132
window . addEventListener ( 'resize' , updateSize ) ;
101
133
updateSize ( ) ; // 컴포넌트 마운트 시 화면 크기에 따른 업데이트
102
134
103
- const data = getPersonalSchedule ( ) ;
104
- data . then ( ( schedule ) => {
105
- schedule . map ( ( x ) => addEvents ( { ...x , start : x . start_date , end : x . end_date } ) ) ;
106
- } ) ;
107
-
108
135
return ( ) => {
109
136
window . removeEventListener ( 'resize' , updateSize ) ;
137
+ /*
110
138
if (calendarApi) {
111
139
calendarApi.off('datesSet', updateTitle);
112
140
}
141
+ */
113
142
} ;
114
- } , [ updateSize , addEvents ] ) ;
143
+ } , [ updateSize ] ) ;
144
+
145
+ const [ isLoaded , setIsLoaded ] = useState ( false ) ; // 데이터 로딩 상태
146
+
147
+ useEffect ( ( ) => {
148
+ if ( ! isLoaded ) {
149
+ getPersonalSchedule ( ) . then ( schedule => {
150
+ const uniqueEvents = schedule . filter ( newEvent =>
151
+ ! events . some ( existingEvent =>
152
+ existingEvent . start === newEvent . start_date && existingEvent . title === newEvent . title
153
+ )
154
+ ) ;
155
+ if ( uniqueEvents . length > 0 ) {
156
+ const eventsToAdd = convertEvents ( uniqueEvents ) ;
157
+ eventsToAdd . forEach ( eventToAdd => addEvents ( eventToAdd ) ) ;
158
+ setIsLoaded ( true ) ;
159
+ }
160
+ } ) ;
161
+ }
162
+ } , [ events , addEvents ] ) ;
115
163
116
164
return (
117
165
< div >
@@ -121,7 +169,8 @@ export default function Calendar() {
121
169
plugins = { [ dayGridPlugin , interactionPlugin ] }
122
170
initialView = "dayGridMonth"
123
171
events = { events }
124
- eventClick = { handleDateClick }
172
+ // eventClick={handleDateClick}
173
+ dateClick = { handleDateSelection }
125
174
dayMaxEvents = { 2 } //Max개수까지보이고 나머지는 more
126
175
//navLinks={true} // 날짜/주 이름을 클릭하여 뷰를 변경할 수 있습니다.
127
176
editable = { true } // 이벤트를 수정할 수 있습니다.
@@ -150,17 +199,11 @@ export default function Calendar() {
150
199
} }
151
200
/>
152
201
</ div >
153
- < div className = "mt-10" > { selectedDate && < EventCards events = { selectedEvents } date = { selectedDate } /> } </ div >
202
+ < div className = "mt-10" > { selectedDate && < EventCards events = { selectedEvents } date = { selectedDate } /> } </ div >
154
203
</ div >
155
204
) ;
156
205
}
157
206
158
- interface EventInfo {
159
- timeText : string ;
160
- event : {
161
- title : string ;
162
- } ;
163
- }
164
207
165
208
function renderEventContent ( eventInfo : EventInfo ) {
166
209
return (
@@ -174,50 +217,47 @@ function renderEventContent(eventInfo: EventInfo) {
174
217
}
175
218
176
219
function EventCards ( { events, date } : EventCardsProps ) {
220
+ console . log ( events , date ) ;
177
221
const [ menuOpen , setMenuOpen ] = useState ( - 1 ) ;
178
222
179
- if ( ! date ) {
180
- return < div > No date provided</ div > ; // date가 null인 경우 처리
223
+ if ( ! events . length ) {
224
+ return < div className = 'min-h-[150px] min-w-[240px] bg-white p-4 text-black' >
225
+ 일정이 없습니다. < br /> 일정을 등록해주세요!
226
+ </ div > ;
181
227
}
182
228
183
- const formattedDate = new Date ( date )
184
- . toLocaleDateString ( 'ko-KR' , {
185
- year : 'numeric' ,
186
- month : '2-digit' ,
187
- day : '2-digit' ,
188
- } )
189
- . replace ( / \. / g, '.' )
190
- . slice ( 0 , - 1 ) ;
191
-
192
229
return (
193
230
< div >
194
- < h2 className = "ml-2" > { formattedDate } </ h2 >
231
+ < h2 className = "ml-2" > { date } </ h2 >
195
232
< div className = "flex gap-5 overflow-x-auto" >
196
- { events . map ( ( event , index ) => (
197
- < div key = { index } className = "relative min-h-[150px] min-w-[240px] bg-white p-4 text-black" >
198
- < h3 > { event . title } </ h3 >
199
- < p className = "mt-1 text-xs" > { new Date ( event . start ) . toLocaleTimeString ( ) } </ p >
200
- { /* 메뉴 버튼 */ }
201
- < div
202
- className = "absolute right-2 top-2 flex cursor-pointer flex-col items-center justify-center"
203
- onClick = { ( ) => setMenuOpen ( menuOpen === index ? - 1 : index ) }
204
- >
205
- < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
206
- < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
207
- < div className = "h-1 w-1 rounded-full bg-[#429400]" > </ div >
208
- </ div >
209
- { /* 메뉴 */ }
210
- { menuOpen === index && (
211
- < div className = "absolute right-0 top-10 z-10 rounded-lg bg-white shadow-md" >
212
- < ul >
213
- < li className = "cursor-pointer p-2 hover:bg-gray-100" > 편집</ li >
214
- < li className = "cursor-pointer p-2 hover:bg-gray-100" > 삭제</ li >
215
- </ ul >
233
+ { events . map ( ( event , index ) => {
234
+ return (
235
+ < div key = { index } className = "relative min-h-[150px] min-w-[240px] bg-white p-4 text-black" >
236
+ < h3 > { event . title } </ h3 >
237
+ < p className = "mt-1 text-xs" > { event . start === event . end ? event . start : `${ event . start } ~${ event . end } ` } </ p >
238
+ { /* 메뉴 버튼 */ }
239
+ < div
240
+ className = "absolute right-2 top-2 flex cursor-pointer flex-col items-center justify-center"
241
+ onClick = { ( ) => setMenuOpen ( menuOpen === index ? - 1 : index ) }
242
+ >
243
+ < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
244
+ < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
245
+ < div className = "h-1 w-1 rounded-full bg-[#429400]" > </ div >
216
246
</ div >
217
- ) }
218
- </ div >
219
- ) ) }
247
+ { /* 메뉴 */ }
248
+ { menuOpen === index && (
249
+ < div className = "absolute right-0 top-10 z-10 rounded-lg bg-white shadow-md" >
250
+ < ul >
251
+ < li className = "cursor-pointer p-2 hover:bg-gray-100" > 편집</ li >
252
+ < li className = "cursor-pointer p-2 hover:bg-gray-100" > 삭제</ li >
253
+ </ ul >
254
+ </ div >
255
+ ) }
256
+ </ div >
257
+ ) ;
258
+ } ) }
220
259
</ div >
221
260
</ div >
222
261
) ;
223
262
}
263
+
0 commit comments