Skip to content

Commit de3664b

Browse files
authored
Merge pull request #147 from imaginer-dev/127--ui--calendarmain
127 UI calendarmain - ์ผ์ • ํด๋ฆญ์‹œ - ํ•ด๋‹น๋‚ ์งœ์˜ ์ผ์ •๋ฆฌ์ŠคํŠธ ๋…ธ์ถœ
2 parents 584d026 + eecb8e3 commit de3664b

File tree

3 files changed

+180
-39
lines changed

3 files changed

+180
-39
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## ์บ˜๋ฆฐ๋” ๋ฉ”์ธ ๋ Œ๋”๋ง ์„ฑ๋Šฅ ์ง€ํ‘œ
2+
3+
- ์ •์˜: ์บ˜๋ฆฐ๋”๊ฐ€ ๋ชจ๋‘ ๊ทธ๋ ค์ง„ ์‹œ๊ฐ„
4+
- ๋ชฉํ‘œ: 0.1s
5+
- ์ฐธ๊ณ : FCP ๊ถŒ์žฅ๊ฐ’ ์ฐธ๊ณ 

โ€Žsrc/App.tsxโ€Ž

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,59 @@
11
import MyCalendarPage from './pages/MyCalendarPage';
22

33
function App() {
4-
return <MyCalendarPage />;
4+
5+
return (
6+
<div>
7+
<header className="relative z-10">
8+
<div className="drawer">
9+
<input id="my-drawer-3" type="checkbox" className="drawer-toggle" />
10+
<div className="drawer-content flex flex-col">
11+
{/* Navbar */}
12+
<div className="navbar w-full">
13+
<div className="flex-none lg:hidden">
14+
<label htmlFor="my-drawer-3" aria-label="open sidebar" className="btn btn-square btn-ghost">
15+
<svg
16+
xmlns="http://www.w3.org/2000/svg"
17+
fill="none"
18+
viewBox="0 0 24 24"
19+
className="inline-block h-6 w-6 stroke-current"
20+
>
21+
<path
22+
strokeLinecap="round"
23+
strokeLinejoin="round"
24+
strokeWidth="2"
25+
d="M4 6h16M4 12h16M4 18h16"
26+
></path>
27+
</svg>
28+
</label>
29+
</div>
30+
<div className="flex-1 justify-end">
31+
<h1 className="min-w-40 rounded bg-base-200 p-2 text-center text-sm">๊ฐœ์ธ ์ผ์ • ์บ˜๋ฆฐ๋”</h1>
32+
</div>
33+
</div>
34+
</div>
35+
<div className="drawer-side">
36+
<label htmlFor="my-drawer-3" aria-label="close sidebar" className="drawer-overlay"></label>
37+
<ul className="menu min-h-full w-80 bg-base-200 p-4">
38+
{/* Sidebar content here */}
39+
<li>
40+
<a>๊ทธ๋ฃน ์ผ์ • ์บ˜๋ฆฐ๋” 1</a>
41+
</li>
42+
<li>
43+
<a>๊ทธ๋ฃน ์ผ์ • ์บ˜๋ฆฐ๋” 2</a>
44+
</li>
45+
</ul>
46+
</div>
47+
</div>
48+
</header>
49+
<main className="z-1 relative flex-grow">
50+
<div className="ml-auto max-w-7xl px-4 sm:px-6 lg:px-8">
51+
<Calendar />
52+
</div>
53+
</main>
54+
</div>
55+
);
56+
557
}
658

759
export default App;

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

Lines changed: 122 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,52 @@
11
import FullCalendar from '@fullcalendar/react';
2+
import { EventClickArg } from '@fullcalendar/core';
23
import dayGridPlugin from '@fullcalendar/daygrid';
34
import interactionPlugin from '@fullcalendar/interaction';
45
import { useRef, useState, useEffect } from 'react';
56
import { useEventState } from '@/stores/myEventsStore';
67
import { getPersonalSchedule } from '@/apis/personalScheduleApi';
78

8-
const Calendar: React.FC = () => {
9+
10+
type Event = {
11+
title: string;
12+
start: Date | string;
13+
};
14+
interface EventCardsProps {
15+
events: Event[];
16+
date: Date | string | null;
17+
}
18+
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+
];
25+
26+
export function Calendar() {
27+
928
const [calendarHeight, setCalendarHeight] = useState<string | number>('auto');
1029
const calendarRef = useRef<FullCalendar | null>(null);
30+
const [selectedEvents, setSelectedEvents] = useState<Event[]>([]);
31+
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
32+
33+
const handleDateClick = (clickInfo: EventClickArg) => {
34+
if (clickInfo.event.start) {
35+
const clickStartDate = new Date(clickInfo.event.start);
36+
setSelectedDate(clickStartDate);
37+
38+
const clickedStartDate = new Date(clickInfo.event.start).toDateString();
39+
setSelectedEvents(events.filter((event) => new Date(event.start).toDateString() === clickedStartDate));
40+
} else {
41+
console.log('not available');
42+
}
43+
};
44+
1145
const handlePrev = () => {
1246
const calendarApi = calendarRef?.current?.getApi();
1347
if (calendarApi) {
1448
calendarApi.prev();
49+
setSelectedDate(null);
1550
} else {
1651
console.error('Calendar API is not available.');
1752
}
@@ -21,6 +56,7 @@ const Calendar: React.FC = () => {
2156
const calendarApi = calendarRef?.current?.getApi();
2257
if (calendarApi) {
2358
calendarApi.next();
59+
setSelectedDate(null);
2460
} else {
2561
console.error('Calendar API is not available.');
2662
}
@@ -80,42 +116,42 @@ const Calendar: React.FC = () => {
80116

81117
return (
82118
<div>
83-
<FullCalendar
84-
ref={calendarRef}
85-
plugins={[dayGridPlugin, interactionPlugin]}
86-
initialView="dayGridMonth"
87-
events={events}
88-
dayMaxEvents={2} //Max๊ฐœ์ˆ˜๊นŒ์ง€๋ณด์ด๊ณ  ๋‚˜๋จธ์ง€๋Š” more
89-
navLinks={true} // ๋‚ ์งœ/์ฃผ ์ด๋ฆ„์„ ํด๋ฆญํ•˜์—ฌ ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
90-
editable={true} // ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
91-
eventContent={renderEventContent}
92-
contentHeight={calendarHeight}
93-
titleFormat={{
94-
year: 'numeric',
95-
month: '2-digit',
96-
}}
97-
eventTimeFormat={{
98-
hour: '2-digit',
99-
minute: '2-digit',
100-
meridiem: false,
101-
}}
102-
dayHeaderFormat={{
103-
weekday: 'short',
104-
}}
105-
headerToolbar={{
106-
left: 'prevButton',
107-
center: 'title',
108-
right: 'nextButton',
109-
}}
110-
customButtons={{
111-
prevButton: {
112-
click: handlePrev,
113-
},
114-
nextButton: {
115-
click: handleNext,
116-
},
117-
}}
118-
/>
119+
<div className="rounded bg-white p-6 px-4 sm:px-0">
120+
<FullCalendar
121+
ref={calendarRef}
122+
plugins={[dayGridPlugin, interactionPlugin]}
123+
initialView="dayGridMonth"
124+
events={events}
125+
eventClick={handleDateClick}
126+
dayMaxEvents={2} //Max๊ฐœ์ˆ˜๊นŒ์ง€๋ณด์ด๊ณ  ๋‚˜๋จธ์ง€๋Š” more
127+
//navLinks={true} // ๋‚ ์งœ/์ฃผ ์ด๋ฆ„์„ ํด๋ฆญํ•˜์—ฌ ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
128+
editable={true} // ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
129+
eventContent={renderEventContent}
130+
contentHeight={calendarHeight}
131+
titleFormat={{
132+
year: 'numeric',
133+
month: '2-digit',
134+
}}
135+
eventTimeFormat={{
136+
hour: '2-digit',
137+
minute: '2-digit',
138+
meridiem: false,
139+
}}
140+
dayHeaderFormat={{
141+
weekday: 'short',
142+
}}
143+
headerToolbar={{
144+
left: 'prevButton',
145+
center: 'title',
146+
right: 'nextButton',
147+
}}
148+
customButtons={{
149+
prevButton: { click: handlePrev },
150+
nextButton: { click: handleNext },
151+
}}
152+
/>
153+
</div>
154+
<div className="mt-10">{selectedDate && <EventCards events={selectedEvents} date={selectedDate} />}</div>
119155
</div>
120156
);
121157
};
@@ -138,4 +174,52 @@ function renderEventContent(eventInfo: EventInfo) {
138174
);
139175
}
140176

141-
export default Calendar;
177+
178+
function EventCards({ events, date }: EventCardsProps) {
179+
const [menuOpen, setMenuOpen] = useState(-1);
180+
181+
if (!date) {
182+
return <div>No date provided</div>; // date๊ฐ€ null์ธ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ
183+
}
184+
185+
const formattedDate = new Date(date)
186+
.toLocaleDateString('ko-KR', {
187+
year: 'numeric',
188+
month: '2-digit',
189+
day: '2-digit',
190+
})
191+
.replace(/\. /g, '.')
192+
.slice(0, -1);
193+
194+
return (
195+
<div>
196+
<h2 className="ml-2">{formattedDate}</h2>
197+
<div className="flex gap-5 overflow-x-auto">
198+
{events.map((event, index) => (
199+
<div key={index} className="relative min-h-[150px] min-w-[240px] bg-white p-4 text-black">
200+
<h3>{event.title}</h3>
201+
<p className="mt-1 text-xs">{new Date(event.start).toLocaleTimeString()}</p>
202+
{/* ๋ฉ”๋‰ด ๋ฒ„ํŠผ */}
203+
<div
204+
className="absolute right-2 top-2 flex cursor-pointer flex-col items-center justify-center"
205+
onClick={() => setMenuOpen(menuOpen === index ? -1 : index)}
206+
>
207+
<div className="mb-1 h-1 w-1 rounded-full bg-[#429400]"></div>
208+
<div className="mb-1 h-1 w-1 rounded-full bg-[#429400]"></div>
209+
<div className="h-1 w-1 rounded-full bg-[#429400]"></div>
210+
</div>
211+
{menuOpen === index && (
212+
<div className="absolute right-0 top-10 z-10 rounded-lg bg-white shadow-md">
213+
<ul>
214+
<li className="cursor-pointer p-2 hover:bg-gray-100">ํŽธ์ง‘</li>
215+
<li className="cursor-pointer p-2 hover:bg-gray-100">์‚ญ์ œ</li>
216+
</ul>
217+
</div>
218+
)}
219+
</div>
220+
))}
221+
</div>
222+
</div>
223+
);
224+
}
225+

0 commit comments

Comments
ย (0)