Skip to content

Commit d54a436

Browse files
authored
Merge pull request #152 from imaginer-dev/127--ui--calendarmain
127 UI calendarmain - ์บ˜๋ฆฐ๋” ์ผ์ • ๋ฆฌ์ŠคํŠธ UI ์ถ”๊ฐ€ ๋ฐ ์ผ์ • ๋ฉ”๋‰ด๋ฒ„ํŠผ ์ถ”๊ฐ€
2 parents 2ca3741 + a9efe32 commit d54a436

File tree

3 files changed

+148
-65
lines changed

3 files changed

+148
-65
lines changed

โ€Žsrc/App.tsxโ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Calendar from './components/common/Calendar';
22

3+
34
function App() {
45
return (
56
<div>
@@ -46,7 +47,7 @@ function App() {
4647
</div>
4748
</header>
4849
<main className="z-1 relative flex-grow">
49-
<div className="ml-auto max-w-7xl px-4 sm:px-6 lg:px-8">
50+
<div className="ml-auto max-w-7xl p-4 pb-10 sm:px-6 lg:px-8">
5051
<Calendar />
5152
</div>
5253
</main>

โ€Žsrc/components/common/Calendar.tsxโ€Ž

Lines changed: 127 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,44 @@
1+
/* eslint-disable react-hooks/exhaustive-deps */
12
import FullCalendar from '@fullcalendar/react';
2-
import { EventClickArg } from '@fullcalendar/core';
3+
// import { EventClickArg } from '@fullcalendar/core';
34
import dayGridPlugin from '@fullcalendar/daygrid';
45
import interactionPlugin from '@fullcalendar/interaction';
5-
import { useRef, useState, useEffect } from 'react';
6+
import { useRef, useState, useEffect, useCallback } from 'react';
67
import { useEventState } from '@/stores/myEventsStore';
78
import { getPersonalSchedule } from '@/apis/personalScheduleApi';
8-
9+
import { Events } from '../../utils/index.ts';
10+
/*
911
type Event = {
1012
title: string;
11-
start: Date | string;
13+
start: string;
14+
end: string;
15+
backgroundColor?: string;
16+
borderColor?: string;
17+
textColor?: string;
1218
};
19+
*/
20+
21+
22+
interface EventInfo {
23+
timeText: string;
24+
event: {
25+
title: string;
26+
};
27+
}
28+
1329
interface EventCardsProps {
14-
events: Event[];
15-
date: Date | string | null;
30+
events: Events[];
31+
date: string | null;
1632
}
1733

1834
export default function Calendar() {
1935
const [calendarHeight, setCalendarHeight] = useState<string | number>('auto');
2036
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();
2340

41+
/*
2442
const handleDateClick = (clickInfo: EventClickArg) => {
2543
if (clickInfo.event.start) {
2644
const clickStartDate = new Date(clickInfo.event.start);
@@ -32,6 +50,20 @@ export default function Calendar() {
3250
console.log('not available');
3351
}
3452
};
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+
};
3567

3668
const handlePrev = () => {
3769
const calendarApi = calendarRef?.current?.getApi();
@@ -53,17 +85,36 @@ export default function Calendar() {
5385
}
5486
};
5587

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+
}
62111

112+
/*
63113
const updateTitle = () => {
64114
const calendarApi = calendarRef?.current?.getApi();
65115
if (calendarApi) {
66116
const calendarView = calendarApi.view;
117+
console.log('View start date:', calendarView.currentStart);
67118
68119
const date = new Date(calendarView.currentStart);
69120
const year = date.getFullYear();
@@ -76,34 +127,51 @@ export default function Calendar() {
76127
}
77128
}
78129
};
79-
80-
const { events, addEvents } = useEventState();
130+
*/
81131

82132
useEffect(() => {
133+
/*
83134
const calendarApi = calendarRef?.current?.getApi();
84-
85135
if (calendarApi) {
86136
calendarApi.on('datesSet', updateTitle);
87137
}
88138
89139
updateTitle(); // ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ์ œ๋ชฉ ์—…๋ฐ์ดํŠธ
140+
*/
90141

91142
/* ์บ˜๋ฆฐ๋” - ๋ฐ˜์‘ํ˜• ์‚ฌ์ด์ฆˆ */
92143
window.addEventListener('resize', updateSize);
93144
updateSize(); // ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ํ™”๋ฉด ํฌ๊ธฐ์— ๋”ฐ๋ฅธ ์—…๋ฐ์ดํŠธ
94145

95-
const data = getPersonalSchedule();
96-
data.then((schedule) => {
97-
schedule.map((x) => addEvents({ ...x, start: x.start_date, end: x.end_date }));
98-
});
99-
100146
return () => {
101147
window.removeEventListener('resize', updateSize);
148+
/*
102149
if (calendarApi) {
103150
calendarApi.off('datesSet', updateTitle);
104151
}
152+
*/
105153
};
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]);
107175

108176
return (
109177
<div>
@@ -113,7 +181,8 @@ export default function Calendar() {
113181
plugins={[dayGridPlugin, interactionPlugin]}
114182
initialView="dayGridMonth"
115183
events={events}
116-
eventClick={handleDateClick}
184+
// eventClick={handleDateClick}
185+
dateClick={handleDateSelection}
117186
dayMaxEvents={2} //Max๊ฐœ์ˆ˜๊นŒ์ง€๋ณด์ด๊ณ  ๋‚˜๋จธ์ง€๋Š” more
118187
//navLinks={true} // ๋‚ ์งœ/์ฃผ ์ด๋ฆ„์„ ํด๋ฆญํ•˜์—ฌ ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
119188
editable={true} // ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
@@ -145,13 +214,7 @@ export default function Calendar() {
145214
<div className="mt-10">{selectedDate && <EventCards events={selectedEvents} date={selectedDate} />}</div>
146215
</div>
147216
);
148-
}
149217

150-
interface EventInfo {
151-
timeText: string;
152-
event: {
153-
title: string;
154-
};
155218
}
156219

157220
function renderEventContent(eventInfo: EventInfo) {
@@ -166,48 +229,48 @@ function renderEventContent(eventInfo: EventInfo) {
166229
}
167230

168231
function EventCards({ events, date }: EventCardsProps) {
232+
console.log(events, date);
169233
const [menuOpen, setMenuOpen] = useState(-1);
170234

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+
);
173242
}
174243

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-
184244
return (
185245
<div>
186-
<h2 className="ml-2">{formattedDate}</h2>
246+
<h2 className="ml-2">{date}</h2>
187247
<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>
207261
</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+
})}
211274
</div>
212275
</div>
213276
);

โ€Žsrc/styles/index.cssโ€Ž

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,22 @@
7171
.fc .fc-h-event {
7272
border: var(--fc-event-text-color);
7373
}
74+
.fc-daygrid-day {
75+
cursor: pointer;
76+
}
77+
78+
.fc-daygrid-day-frame {
79+
height: 100%;
80+
z-index: 10;
81+
&:hover {
82+
&::before {
83+
content: '';
84+
position: absolute;
85+
width: 100%;
86+
height: 100%;
87+
background-color: #bec00038;
88+
top: 0;
89+
left: 0;
90+
}
91+
}
92+
}

0 commit comments

Comments
ย (0)