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
};
19
+ */
20
+
21
+
22
+ interface EventInfo {
23
+ timeText : string ;
24
+ event : {
25
+ title : string ;
26
+ } ;
27
+ }
28
+
13
29
interface EventCardsProps {
14
- events : Event [ ] ;
15
- date : Date | string | null ;
30
+ events : Events [ ] ;
31
+ date : string | null ;
16
32
}
17
33
18
34
export default function Calendar ( ) {
19
35
const [ calendarHeight , setCalendarHeight ] = useState < string | number > ( 'auto' ) ;
20
36
const calendarRef = useRef < FullCalendar | null > ( null ) ;
21
- const [ selectedEvents , setSelectedEvents ] = useState < Event [ ] > ( [ ] ) ;
22
- const [ selectedDate , setSelectedDate ] = useState < Date | null > ( null ) ;
37
+ const [ selectedEvents , setSelectedEvents ] = useState < Events [ ] > ( [ ] ) ;
38
+ const [ selectedDate , setSelectedDate ] = useState < string | null > ( null ) ;
39
+ const { events, addEvents } = useEventState ( ) ;
23
40
41
+ /*
24
42
const handleDateClick = (clickInfo: EventClickArg) => {
25
43
if (clickInfo.event.start) {
26
44
const clickStartDate = new Date(clickInfo.event.start);
@@ -32,6 +50,20 @@ export default function Calendar() {
32
50
console.log('not available');
33
51
}
34
52
};
53
+ */
54
+
55
+ const handleDateSelection = ( dateClickInfo : { dateStr : string } ) => {
56
+ console . log ( dateClickInfo ) ;
57
+ const clickedDateStr = dateClickInfo . dateStr ;
58
+ setSelectedDate ( clickedDateStr ) ;
59
+ setSelectedEvents (
60
+ events . filter (
61
+ ( event ) =>
62
+ clickedDateStr >= event . start . split ( 'T' ) [ 0 ] &&
63
+ clickedDateStr <= ( event . end ? event . end . split ( 'T' ) [ 0 ] : event . start . split ( 'T' ) [ 0 ] ) ,
64
+ ) ,
65
+ ) ;
66
+ } ;
35
67
36
68
const handlePrev = ( ) => {
37
69
const calendarApi = calendarRef ?. current ?. getApi ( ) ;
@@ -53,17 +85,36 @@ export default function Calendar() {
53
85
}
54
86
} ;
55
87
56
- // eslint-disable-next-line react-hooks/exhaustive-deps
57
- const updateSize = ( ) => {
58
- const isMobile = window . innerWidth < 768 ;
59
- setCalendarHeight ( isMobile ? 500 : 'auto' ) ;
60
- updateTitle ( ) ;
61
- } ;
88
+ const updateSize = useCallback ( ( ) => {
89
+ setCalendarHeight ( window . innerWidth < 768 ? 500 : 'auto' ) ;
90
+ } , [ ] ) ;
91
+
92
+ function convertEvents (
93
+ events : {
94
+ title : string ;
95
+ start_date : string ;
96
+ end_date : string ;
97
+ backgroundColor ?: string ;
98
+ borderColor ?: string ;
99
+ textColor ?: string ;
100
+ } [ ] ,
101
+ ) : Events [ ] {
102
+ return events . map ( ( event ) => ( {
103
+ title : event . title ,
104
+ start : event . start_date ,
105
+ end : event . end_date ,
106
+ backgroundColor : event . backgroundColor || '#3788d8' ,
107
+ borderColor : event . borderColor || '#296c98' ,
108
+ textColor : event . textColor || '#ffffff' ,
109
+ } ) ) ;
110
+ }
62
111
112
+ /*
63
113
const updateTitle = () => {
64
114
const calendarApi = calendarRef?.current?.getApi();
65
115
if (calendarApi) {
66
116
const calendarView = calendarApi.view;
117
+ console.log('View start date:', calendarView.currentStart);
67
118
68
119
const date = new Date(calendarView.currentStart);
69
120
const year = date.getFullYear();
@@ -76,34 +127,51 @@ export default function Calendar() {
76
127
}
77
128
}
78
129
};
79
-
80
- const { events, addEvents } = useEventState ( ) ;
130
+ */
81
131
82
132
useEffect ( ( ) => {
133
+ /*
83
134
const calendarApi = calendarRef?.current?.getApi();
84
-
85
135
if (calendarApi) {
86
136
calendarApi.on('datesSet', updateTitle);
87
137
}
88
138
89
139
updateTitle(); // ์ปดํฌ๋ํธ ๋ง์ดํธ ์ ์ ๋ชฉ ์
๋ฐ์ดํธ
140
+ */
90
141
91
142
/* ์บ๋ฆฐ๋ - ๋ฐ์ํ ์ฌ์ด์ฆ */
92
143
window . addEventListener ( 'resize' , updateSize ) ;
93
144
updateSize ( ) ; // ์ปดํฌ๋ํธ ๋ง์ดํธ ์ ํ๋ฉด ํฌ๊ธฐ์ ๋ฐ๋ฅธ ์
๋ฐ์ดํธ
94
145
95
- const data = getPersonalSchedule ( ) ;
96
- data . then ( ( schedule ) => {
97
- schedule . map ( ( x ) => addEvents ( { ...x , start : x . start_date , end : x . end_date } ) ) ;
98
- } ) ;
99
-
100
146
return ( ) => {
101
147
window . removeEventListener ( 'resize' , updateSize ) ;
148
+ /*
102
149
if (calendarApi) {
103
150
calendarApi.off('datesSet', updateTitle);
104
151
}
152
+ */
105
153
} ;
106
- } , [ updateSize , addEvents ] ) ;
154
+ } , [ updateSize ] ) ;
155
+
156
+ const [ isLoaded , setIsLoaded ] = useState ( false ) ; // ๋ฐ์ดํฐ ๋ก๋ฉ ์ํ
157
+
158
+ useEffect ( ( ) => {
159
+ if ( ! isLoaded ) {
160
+ getPersonalSchedule ( ) . then ( ( schedule ) => {
161
+ const uniqueEvents = schedule . filter (
162
+ ( newEvent ) =>
163
+ ! events . some (
164
+ ( existingEvent ) => existingEvent . start === newEvent . start_date && existingEvent . title === newEvent . title ,
165
+ ) ,
166
+ ) ;
167
+ if ( uniqueEvents . length > 0 ) {
168
+ const eventsToAdd = convertEvents ( uniqueEvents ) ;
169
+ eventsToAdd . forEach ( ( eventToAdd ) => addEvents ( eventToAdd ) ) ;
170
+ setIsLoaded ( true ) ;
171
+ }
172
+ } ) ;
173
+ }
174
+ } , [ events , addEvents ] ) ;
107
175
108
176
return (
109
177
< div >
@@ -113,7 +181,8 @@ export default function Calendar() {
113
181
plugins = { [ dayGridPlugin , interactionPlugin ] }
114
182
initialView = "dayGridMonth"
115
183
events = { events }
116
- eventClick = { handleDateClick }
184
+ // eventClick={handleDateClick}
185
+ dateClick = { handleDateSelection }
117
186
dayMaxEvents = { 2 } //Max๊ฐ์๊น์ง๋ณด์ด๊ณ ๋๋จธ์ง๋ more
118
187
//navLinks={true} // ๋ ์ง/์ฃผ ์ด๋ฆ์ ํด๋ฆญํ์ฌ ๋ทฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
119
188
editable = { true } // ์ด๋ฒคํธ๋ฅผ ์์ ํ ์ ์์ต๋๋ค.
@@ -145,13 +214,7 @@ export default function Calendar() {
145
214
< div className = "mt-10" > { selectedDate && < EventCards events = { selectedEvents } date = { selectedDate } /> } </ div >
146
215
</ div >
147
216
) ;
148
- }
149
217
150
- interface EventInfo {
151
- timeText : string ;
152
- event : {
153
- title : string ;
154
- } ;
155
218
}
156
219
157
220
function renderEventContent ( eventInfo : EventInfo ) {
@@ -166,48 +229,48 @@ function renderEventContent(eventInfo: EventInfo) {
166
229
}
167
230
168
231
function EventCards ( { events, date } : EventCardsProps ) {
232
+ console . log ( events , date ) ;
169
233
const [ menuOpen , setMenuOpen ] = useState ( - 1 ) ;
170
234
171
- if ( ! date ) {
172
- return < div > No date provided</ div > ; // date๊ฐ null์ธ ๊ฒฝ์ฐ ์ฒ๋ฆฌ
235
+ if ( ! events . length ) {
236
+ return (
237
+ < div className = "min-h-[150px] min-w-[240px] bg-white p-4 text-black" >
238
+ ์ผ์ ์ด ์์ต๋๋ค. < br />
239
+ ์ผ์ ์ ๋ฑ๋กํด์ฃผ์ธ์!
240
+ </ div >
241
+ ) ;
173
242
}
174
243
175
- const formattedDate = new Date ( date )
176
- . toLocaleDateString ( 'ko-KR' , {
177
- year : 'numeric' ,
178
- month : '2-digit' ,
179
- day : '2-digit' ,
180
- } )
181
- . replace ( / \. / g, '.' )
182
- . slice ( 0 , - 1 ) ;
183
-
184
244
return (
185
245
< div >
186
- < h2 className = "ml-2" > { formattedDate } </ h2 >
246
+ < h2 className = "ml-2" > { date } </ h2 >
187
247
< div className = "flex gap-5 overflow-x-auto" >
188
- { events . map ( ( event , index ) => (
189
- < div key = { index } className = "relative min-h-[150px] min-w-[240px] bg-white p-4 text-black" >
190
- < h3 > { event . title } </ h3 >
191
- < p className = "mt-1 text-xs" > { new Date ( event . start ) . toLocaleTimeString ( ) } </ p >
192
- { /* ๋ฉ๋ด ๋ฒํผ */ }
193
- < div
194
- className = "absolute right-2 top-2 flex cursor-pointer flex-col items-center justify-center"
195
- onClick = { ( ) => setMenuOpen ( menuOpen === index ? - 1 : index ) }
196
- >
197
- < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
198
- < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
199
- < div className = "h-1 w-1 rounded-full bg-[#429400]" > </ div >
200
- </ div >
201
- { menuOpen === index && (
202
- < div className = "absolute right-0 top-10 z-10 rounded-lg bg-white shadow-md" >
203
- < ul >
204
- < li className = "cursor-pointer p-2 hover:bg-gray-100" > ํธ์ง</ li >
205
- < li className = "cursor-pointer p-2 hover:bg-gray-100" > ์ญ์ </ li >
206
- </ ul >
248
+ { events . map ( ( event , index ) => {
249
+ return (
250
+ < div key = { index } className = "relative min-h-[150px] min-w-[240px] bg-white p-4 text-black" >
251
+ < h3 > { event . title } </ h3 >
252
+ < p className = "mt-1 text-xs" > { event . start === event . end ? event . start : `${ event . start } ~${ event . end } ` } </ p >
253
+ { /* ๋ฉ๋ด ๋ฒํผ */ }
254
+ < div
255
+ className = "absolute right-2 top-2 flex cursor-pointer flex-col items-center justify-center"
256
+ onClick = { ( ) => setMenuOpen ( menuOpen === index ? - 1 : index ) }
257
+ >
258
+ < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
259
+ < div className = "mb-1 h-1 w-1 rounded-full bg-[#429400]" > </ div >
260
+ < div className = "h-1 w-1 rounded-full bg-[#429400]" > </ div >
207
261
</ div >
208
- ) }
209
- </ div >
210
- ) ) }
262
+ { /* ๋ฉ๋ด */ }
263
+ { menuOpen === index && (
264
+ < div className = "absolute right-0 top-10 z-10 rounded-lg bg-white shadow-md" >
265
+ < ul >
266
+ < li className = "cursor-pointer p-2 hover:bg-gray-100" > ํธ์ง</ li >
267
+ < li className = "cursor-pointer p-2 hover:bg-gray-100" > ์ญ์ </ li >
268
+ </ ul >
269
+ </ div >
270
+ ) }
271
+ </ div >
272
+ ) ;
273
+ } ) }
211
274
</ div >
212
275
</ div >
213
276
) ;
0 commit comments