Skip to content

Commit 5a205c6

Browse files
committed
fix: merge conflict ํ•ด๊ฒฐ
- main.tsx - userInvite.tsx - userInviteDialog.tsx
2 parents a8bf850 + fdbeddd commit 5a205c6

File tree

9 files changed

+238
-86
lines changed

9 files changed

+238
-86
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/Group/GroupForm.tsxโ€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC } from 'react';
1+
import { FC, useState } from 'react';
22
import GroupFormNameInput from './GroupFormNameInput';
33
import GroupFormDescriptionInput from './GroupFormDescriptionInput';
44
import GroupFormDateInput from './GroupFormDateInput';
@@ -22,13 +22,15 @@ const GroupForm: FC<Props> = ({
2222
memo = '',
2323
onSubmit,
2424
}) => {
25+
const [member, setMember] = useState<any[]>([]);
26+
2527
return (
2628
<form onSubmit={onSubmit} className="container mx-auto flex max-w-sm flex-1 flex-col gap-4 pb-[50px] pt-4">
2729
<div className="flex h-full w-full flex-1 flex-col gap-4">
2830
<GroupFormNameInput name={name} />
2931
<GroupFormDescriptionInput description={description ?? ''} />
3032
<GroupFormDateInput startDate={startDate} endDate={endDate} />
31-
<UserInvite />
33+
<UserInvite member={member} setMember={setMember} />
3234
<GroupFormMemoInput memo={memo ?? ''} />
3335
</div>
3436
<button type="submit" className="btn btn-outline btn-primary w-full">

โ€Ž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+

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

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,58 @@
1-
import { FC } from 'react';
1+
import { FC, useState } from 'react';
2+
import { searchUser } from '../../apis/authApis.ts';
23
import DialogButton from '@/components/common/DialogButton';
34
import { IconUserPlus } from '@/assets/icons';
45
import UserInviteDialog from '@/components/common/UserInviteDialog';
6+
import UserInvited from './UserInvited';
7+
import UserInviteList from './UserInviteList.tsx';
8+
9+
interface Props {
10+
member: any;
11+
setMember: any;
12+
}
13+
14+
const UserInvite: FC<Props> = ({ member, setMember }) => {
15+
const [email, setEamil] = useState('');
16+
const [list, setList] = useState<any[]>([]);
17+
18+
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
19+
setEamil(event.target.value);
20+
};
21+
22+
const onSearchClick = () => {
23+
searchUser(email).then((nickNames) => {
24+
if (!nickNames.length) {
25+
alert('ํ•ด๋‹น ๋‹‰๋„ค์ž„์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
26+
return;
27+
}
28+
nickNames.map(({ user_nickname, id }) => {
29+
setList([
30+
<UserInviteList
31+
user_nickname={user_nickname}
32+
id={id}
33+
key={id + '-UserInviteList'}
34+
onClick={() => {
35+
if (!user_nickname.length) return;
36+
setMember([...member, <UserInvited user_nickname={user_nickname} id={id} key={id + '-Member'} />]);
37+
}}
38+
/>,
39+
]);
40+
});
41+
});
42+
};
543

6-
export const UserInvite: FC = () => {
744
return (
845
<div>
946
๋ฉค๋ฒ„ ์ดˆ๋Œ€ํ•˜๊ธฐ *
1047
<ul className="flex gap-2">
48+
{member}
1149
<li>
1250
<DialogButton
1351
classname={'userInvite bg-base-200 hover:bg-base-300'}
1452
name={<IconUserPlus />}
1553
title={'๋ฉค๋ฒ„ ์ฐพ๊ธฐ'}
1654
desc={''}
17-
children={<UserInviteDialog />}
55+
children={<UserInviteDialog list={list} onChange={onChange} onSearchClick={onSearchClick} />}
1856
/>
1957
</li>
2058
</ul>

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

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,13 @@
11
import InputForm from './InputForm.tsx';
2-
import { searchUser } from '../../apis/authApis.ts';
3-
import { FC, useState } from 'react';
2+
import { FC } from 'react';
43
import { IconSearch } from '@/assets/icons';
5-
import UserInviteList from './UserInviteList.tsx';
6-
7-
const UserInvite: FC = () => {
8-
const [email, setEamil] = useState('');
9-
const [list, setList] = useState<any[]>([]);
10-
11-
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
12-
setEamil(event.target.value);
13-
};
14-
15-
const onSearchClick = () => {
16-
searchUser(email).then((nickNames) => {
17-
if (!nickNames.length) {
18-
alert('ํ•ด๋‹น ๋‹‰๋„ค์ž„์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
19-
return;
20-
}
21-
setList(
22-
nickNames.map(({ user_nickname, id }) => {
23-
return <UserInviteList user_nickname={user_nickname} key={id + '-UserInviteList'} />;
24-
}),
25-
);
26-
return list;
27-
});
28-
};
4+
interface Props {
5+
list: any[];
6+
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
7+
onSearchClick: () => void;
8+
}
299

10+
const UserInvite: FC<Props> = ({ list, onChange, onSearchClick }) => {
3011
return (
3112
<div>
3213
<div className="flex items-end">

0 commit comments

Comments
ย (0)