Skip to content

Commit 7e9b2f5

Browse files
authored
Merge branch 'dev' into 138-초대회원을-멤버에-추가할-수-있다
2 parents a53aa5b + 294f170 commit 7e9b2f5

File tree

13 files changed

+576
-270
lines changed

13 files changed

+576
-270
lines changed

pnpm-lock.yaml

Lines changed: 220 additions & 155 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,7 @@
1-
import { Calendar } from './components/common/Calendar.tsx';
1+
import MyCalendarPage from './pages/MyCalendarPage';
22

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

597
export default App;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { useEventState } from '@/stores/myEventsStore.ts';
2+
import DialogButton from '@/components/common/DialogButton';
3+
import { InputRef } from '../common/InputForm.tsx';
4+
import { useState, useRef } from 'react';
5+
6+
const CreateEventButton = () => {
7+
const { addEvents } = useEventState();
8+
const [eventTitle, setTitle] = useState('');
9+
const [startDate, setStartDate] = useState('');
10+
const [endDate, setEndDate] = useState('');
11+
const titleRef = useRef<HTMLInputElement>(null);
12+
const startRef = useRef<HTMLInputElement>(null);
13+
const endRef = useRef<HTMLInputElement>(null);
14+
15+
const onTitleChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
16+
setTitle(event.target.value);
17+
};
18+
19+
const onStartDateChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
20+
setStartDate(event.target.value);
21+
};
22+
23+
const onEndDateChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
24+
setEndDate(event.target.value);
25+
};
26+
27+
const onCreateClicked = () => {
28+
if (eventTitle !== '' && startDate !== '') {
29+
addEvents({ title: eventTitle, start: startDate, end: endDate === '' ? startDate : endDate });
30+
}
31+
setTitle('');
32+
setStartDate('');
33+
setEndDate('');
34+
if (titleRef.current) {
35+
titleRef.current.value = '';
36+
}
37+
if (startRef.current) {
38+
startRef.current.value = '';
39+
}
40+
if (endRef.current) {
41+
endRef.current.value = '';
42+
}
43+
};
44+
45+
const eventForm = (
46+
<div>
47+
<hr className="mt-1" />
48+
<InputRef title="일정 제목" placeholder="새 일정 제목" onChange={onTitleChanged} ref={titleRef} />
49+
<InputRef title="시작 날짜" placeholder="YYYY-MM-DD" onChange={onStartDateChanged} ref={startRef} />
50+
<InputRef title="끝 날짜" placeholder="YYYY-MM-DD" onChange={onEndDateChanged} ref={endRef} />
51+
<hr className="mb-2 mt-2" />
52+
<button className="btn w-full bg-primary text-base-100" onClick={onCreateClicked}>
53+
추가하기
54+
</button>
55+
</div>
56+
);
57+
return (
58+
<div className="p-8">
59+
<DialogButton
60+
classname="btn bg-primary text-base-100 w-full"
61+
name={'새 일정 추가하기'}
62+
title={'일정 추가'}
63+
desc={''}
64+
children={eventForm}
65+
/>
66+
</div>
67+
);
68+
};
69+
export default CreateEventButton;

src/components/common/Calendar.tsx

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,9 @@ import FullCalendar from '@fullcalendar/react';
22
import dayGridPlugin from '@fullcalendar/daygrid';
33
import interactionPlugin from '@fullcalendar/interaction';
44
import { useRef, useState, useEffect } from 'react';
5+
import { useEventState } from '@/stores/myEventsStore';
56

6-
const events = [
7-
{ title: 'Meeting', start: new Date() },
8-
{ title: 'Meeting', start: '2024-05-08' },
9-
{ title: 'Meeting', start: '2024-05-08' },
10-
{ title: 'Meeting', start: '2024-05-08' },
11-
];
12-
13-
export function Calendar() {
7+
const Calendar: React.FC = () => {
148
const [calendarHeight, setCalendarHeight] = useState<string | number>('auto');
159
const calendarRef = useRef<FullCalendar | null>(null);
1610
const handlePrev = () => {
@@ -31,18 +25,52 @@ export function Calendar() {
3125
}
3226
};
3327

28+
// eslint-disable-next-line react-hooks/exhaustive-deps
29+
const updateSize = () => {
30+
const isMobile = window.innerWidth < 768;
31+
setCalendarHeight(isMobile ? 500 : 'auto');
32+
updateTitle();
33+
};
34+
35+
const updateTitle = () => {
36+
const calendarApi = calendarRef?.current?.getApi();
37+
if (calendarApi) {
38+
const calendarView = calendarApi.view;
39+
40+
const date = new Date(calendarView.currentStart);
41+
const year = date.getFullYear();
42+
const month = (date.getMonth() + 1).toString().padStart(2, '0');
43+
const newTitle = `${year}.${month}`;
44+
45+
const titleElement = document.querySelector('.fc-toolbar-title');
46+
if (titleElement) {
47+
titleElement.textContent = newTitle;
48+
}
49+
}
50+
};
51+
3452
useEffect(() => {
35-
const updateSize = () => {
36-
const isMobile = window.innerWidth < 768;
37-
setCalendarHeight(isMobile ? 500 : 'auto');
38-
};
53+
const calendarApi = calendarRef?.current?.getApi();
54+
55+
if (calendarApi) {
56+
calendarApi.on('datesSet', updateTitle);
57+
}
3958

59+
updateTitle(); // 컴포넌트 마운트 시 제목 업데이트
60+
61+
/* 캘린더 - 반응형 사이즈 */
4062
window.addEventListener('resize', updateSize);
41-
updateSize();
63+
updateSize(); // 컴포넌트 마운트 시 화면 크기에 따른 업데이트
4264

43-
return () => window.removeEventListener('resize', updateSize);
44-
}, []);
65+
return () => {
66+
window.removeEventListener('resize', updateSize);
67+
if (calendarApi) {
68+
calendarApi.off('datesSet', updateTitle);
69+
}
70+
};
71+
}, [updateSize]);
4572

73+
const events = useEventState();
4674
return (
4775
<div>
4876
<FullCalendar
@@ -58,6 +86,10 @@ export function Calendar() {
5886
titleFormat={{
5987
year: 'numeric',
6088
month: '2-digit',
89+
}}
90+
eventTimeFormat={{
91+
hour: '2-digit',
92+
minute: '2-digit',
6193
meridiem: false,
6294
}}
6395
dayHeaderFormat={{
@@ -70,18 +102,16 @@ export function Calendar() {
70102
}}
71103
customButtons={{
72104
prevButton: {
73-
icon: 'chevron-left',
74105
click: handlePrev,
75106
},
76107
nextButton: {
77-
icon: 'chevron-right',
78108
click: handleNext,
79109
},
80110
}}
81111
/>
82112
</div>
83113
);
84-
}
114+
};
85115

86116
interface EventInfo {
87117
timeText: string;
@@ -93,8 +123,12 @@ interface EventInfo {
93123
function renderEventContent(eventInfo: EventInfo) {
94124
return (
95125
<>
96-
<b>{eventInfo.timeText}</b>
97-
<i>{eventInfo.event.title}</i>
126+
<div className="w-full border-0 bg-secondary p-0.5 text-white">
127+
<b className="border-0">{eventInfo.timeText}</b>
128+
<i> {eventInfo.event.title}</i>
129+
</div>
98130
</>
99131
);
100132
}
133+
134+
export default Calendar;

src/components/common/InputForm.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { HTMLProps } from 'react';
1+
import { HTMLProps, forwardRef } from 'react';
22

33
interface Props extends HTMLProps<HTMLInputElement> {
44
title: string;
55
placeholder: string;
6-
hint: string;
6+
hint?: string;
77
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
88
error?: boolean;
99
errorText?: string;
@@ -33,4 +33,31 @@ const InputForm: React.FC<Props> = ({ title, placeholder, hint, onChange, error
3333
);
3434
};
3535

36+
export const InputRef: React.FC<Props> = forwardRef(
37+
({ title, placeholder, hint, onChange, error = false, errorText = '', ...rest }, ref) => {
38+
return (
39+
<label htmlFor={rest.id} className="form-control w-full">
40+
<div className="label">
41+
<span className="label-text">{title}</span>
42+
</div>
43+
<input
44+
id={rest.id}
45+
placeholder={placeholder}
46+
className="input input-bordered w-full"
47+
onChange={onChange}
48+
ref={ref}
49+
{...rest}
50+
/>
51+
{error || hint ? (
52+
<div className="label flex h-8 flex-row items-center">
53+
<span className={`label-text-alt ${error ? 'text-error' : ''}`}>{error ? errorText : hint}</span>
54+
</div>
55+
) : (
56+
''
57+
)}
58+
</label>
59+
);
60+
},
61+
);
62+
3663
export default InputForm;

src/img/icon_arrow_left.png

563 Bytes
Loading

src/img/icon_arrow_right.png

553 Bytes
Loading

0 commit comments

Comments
 (0)