728x90
캘린더
fullCalendar 라이브러리를 이용한 일정 구현
캘린더 라이브러리를 설치해줍니다.
npm i @fullcalendar/core
npm i @fullcalendar/daygrid
npm i @fullcalendar/interaction
npm i @fullcalendar/react
npm i @fullcalendar/timegrid
// 스타일적용을 위한 bootstrap
npm i react-bootstrap
그룹 상세 페이지에 캘린더를 띄울 곳을 만들어줍니다.
import Calendar from '../components/group/calendar.jsx';
<div id="calendar-container">
<Card id="group-calendar">
<Calendar />
</Card>
</div>
이제 본격적으로 calendar.jsx 파일을 만들어봅시다.
우선 달력, 일정 을 위한 라이브러리와 css파일을 불러와줍니다.
import React, { useState } from 'react';
import FullCalendar from '@fullcalendar/react';
import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid";
import dayGridPlugin from '@fullcalendar/daygrid';
import '../../css/group/calendar.css';
import { Modal, Button, Form } from 'react-bootstrap';
기본설정을 해줍니다.
function Calendar() {
return (
<></>
)
}
export default Calendar
앞으로의 모든 코드는 calendar함수의 중괄호 {} 내부에서 작성됩니다.
- 달력 그리기
기본적인 달력을 불러오는 코드입니다.이렇게만 하면 달력이 생성되어 나타납니다.
return ( <FullCalendar plugin = dayGridPlugin initialView = "dayGridmonth" /> )
- 달력 세부 설정하기
불러온 플러그인들 설정하기
const plugins = [dayGridPlugin, timeGridPlugin, interactionPlugin];
return ( <FullCalendar plugins = {plugins} initialView = "dayGridmonth" />
헤더 툴바 설정하기
const plugins = [dayGridPlugin, timeGridPlugin, interactionPlugin];
return (
<FullCalendar plugins = {plugins}
initialView = "dayGridmonth"
headerToolbar = {{
left: "title", // 왼쪽에는 제목
right: "dayGridMonth, timeGridWeek, timeGridDay today" // 오른쪽에는 보기 전환 표시
}}
>
버튼 텍스트 설정하기
const plugins = [dayGridPlugin, timeGridPlugin, interactionPlugin];
return (
<FullCalendar
plugins = {plugins}
initialView = "dayGridmonth"
headerToolbar = {{
left: "title", // 왼쪽에는 제목
right: "dayGridMonth, timeGridWeek, timeGridDay today" // 오른쪽에는 보기 전환 표시
}}
buttonText={{
today: "오늘", // 오늘 버튼의 텍스트
month: "월별", // 월 버튼의 텍스트
week: "주별", // 주 버튼의 텍스트
day: "일별", // 일 버튼의 텍스트
list: "리스트" // 리스트 보기 버튼의 텍스트
}}
/>
푸터 툴바 설정하기
footerToolbar={{ // 풋터 툴바 설정
left: "prev", // 왼쪽에는 이전 버튼을 표시
center: "", // 중앙에는 아무것도 표시하지 않음
right: "next" // 오른쪽에는 다음 버튼을 표시
}}
- 일정 설정하기
이벤트의 상태를 표시할 변수들을 만들어줍니다.
// 상태 훅을 사용하여 이벤트, 모달 표시 여부, 새 이벤트 정보, 편집 상태, 현재 이벤트 ID를 관리
const [events, setEvents] = useState([]); // 캘린더에 표시할 이벤트 목록
const [showModal, setShowModal] = useState(false); // 모달의 표시 여부
const [newEvent, setNewEvent] = useState({ title: '', start: '', end: '', description: '' }); // 새 이벤트 정보
const [isEditing, setIsEditing] = useState(false); // 편집 모드 여부
const [currentEventId, setCurrentEventId] = useState(null); // 현재 편집 중인 이벤트의 ID
날짜를 클릭했을 때 이벤트 설정
- 이미 설정된 이벤트를 클릭했을 때 이벤트 수정
- 이 두가지의 함수와 UI를 제공해야 합니다.
날짜 클릭
// 날짜를 클릭했을 때 호출되는 핸들러
const handleDateClick = (date) => {
setNewEvent({
title: '',
start: date.dateStr,
end: date.dateStr,
description: ''
});
// 새 이벤트 초기화
setIsEditing(false); // 편집 모드 해제
setShowModal(true); // 모달 표시 };
이벤트 클릭
// 이벤트를 클릭했을 때 호출되는 핸들러
const handleEventClick = (clickInfo) => {
const event = clickInfo.event; // 클릭한 이벤트 정보 가져오기
setNewEvent({
title: event.title, // 이벤트 제목 설정
start: event.startStr, // 이벤트 시작 시간 설정
end: event.endStr, // 이벤트 종료 시간 설정
description: event.extendedProps.description || '' // 이벤트 설명 설정
});
setCurrentEventId(event.id); // 현재 이벤트 ID 설정
setIsEditing(true); // 편집 모드 활성화
setShowModal(true); // 모달 표시 };
이벤트 저장
// 이벤트 저장 버튼을 클릭했을 때 호출되는 핸들러
const handleSaveEvent = () => {
if (isEditing) {
// 편집 모드인 경우, 기존 이벤트를 업데이트
setEvents(events.map(event => event.id === currentEventId ? { ...newEvent, id: currentEventId } : event ));
} else { // 새 이벤트를 추가 setEvents(\[...events, { ...newEvent, id: Date.now().toString() }\]); }
setShowModal(false); // 모달 닫기
setNewEvent({ title: '', start: '', end: '', description: '' }); // 새 이벤트 정보 초기화 };
이벤트 커스터마이징
// 이벤트 콘텐츠를 커스터마이즈하는 함수
const renderEventContent = (eventInfo) => {
return (
**{eventInfo.timeText}** {/\* 이벤트의 시간 정보를 굵게 표시 _/}
{eventInfo.view.type !== 'dayGridMonth' && _{eventInfo.event.title}_}
{/_ 월 보기에서는 제목 숨김 \*/}
);
};
이제부턴 return 내부의 코드입니다.
추가버튼을 만들어줍니다.이 버튼을 사용하기 위해 헤더 툴바를 수정해줍니다.
headerToolbar={{
left: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay today,addEventButton"
}}
customButtons={{
addEventButton: {
text: '+',
click: () => {
setNewEvent({
title: '',
start: '',
end: '',
description: ''
});
setIsEditing(false);
setShowModal(true);
}
}
}}
=
클릭이벤트에 대한 핸들러 설정
dateClick={handleDateClick}
eventClick={handleEventClick}
eventContent={renderEventContent} // 이벤트 콘텐츠 커스터마이즈 함수 추가
expandRows={true} // 행 확장을 활성화하여 모든 이벤트 표시
dayMaxEventRows={false} // 최대 이벤트 행 수를 비활성화
dayMaxEvents={false} // 최대 이벤트 수를 비활성화
일정을 추가, 수정하는 창은 모달로 띄웁니다.
전체 모달 설정
<Modal show={showModal} onHide={() => setShowModal(false)}>
<Modal.Header closeButton>
<Modal.Title>{isEditing ? '일정 수정' : '새 일정 추가'}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group controlId="formEventTitle">
<Form.Label>제목</Form.Label>
<Form.Control
type="text"
value={newEvent.title}
onChange={(e) => setNewEvent({ ...newEvent, title: e.target.value })}
/>
</Form.Group>
<Form.Group controlId="formEventDescription">
<Form.Label>내용</Form.Label>
<Form.Control
type="text"
value={newEvent.description}
onChange={(e) => setNewEvent({ ...newEvent, description: e.target.value })}
/>
</Form.Group>
<Form.Group controlId="formEventStart">
<Form.Label>시작 시간</Form.Label>
<Form.Control
type="datetime-local"
value={newEvent.start}
onChange={(e) => setNewEvent({ ...newEvent, start: e.target.value })}
/>
</Form.Group>
<Form.Group controlId="formEventEnd">
<Form.Label>종료 시간</Form.Label>
<Form.Control
type="datetime-local"
value={newEvent.end}
onChange={(e) => setNewEvent({ ...newEvent, end: e.target.value })}
/>
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => setShowModal(false)}>
취소
저장
</Modal.Footer>
전체 코드
// calendar.jsx
import React, { useState } from 'react';
import FullCalendar from '@fullcalendar/react';
import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid";
import dayGridPlugin from '@fullcalendar/daygrid';
import '../../css/group/calendar.css';
import { Modal, Button, Form } from 'react-bootstrap';
function Calendar() {
const [events, setEvents] = useState([]);
const [showModal, setShowModal] = useState(false);
const [newEvent, setNewEvent] = useState({ title: '', start: '', end: '', description: '' });
const [isEditing, setIsEditing] = useState(false);
const [currentEventId, setCurrentEventId] = useState(null);
const handleDateClick = (date) => {
setNewEvent({ title: '', start: date.dateStr, end: date.dateStr, description: '' });
setIsEditing(false);
setShowModal(true);
};
const handleEventClick = (clickInfo) => {
const event = clickInfo.event;
setNewEvent({
title: event.title,
start: event.startStr,
end: event.endStr,
description: event.extendedProps.description || ''
});
setCurrentEventId(event.id);
setIsEditing(true);
setShowModal(true);
};
const handleSaveEvent = () => {
if (isEditing) {
setEvents(events.map(event =>
event.id === currentEventId ? { ...newEvent, id: currentEventId } : event
));
} else {
setEvents([...events, { ...newEvent, id: Date.now().toString() }]);
}
setShowModal(false);
setNewEvent({ title: '', start: '', end: '', description: '' });
};
const plugins = [dayGridPlugin, timeGridPlugin, interactionPlugin];
const renderEventContent = (eventInfo) => {
return (
<div>
<b>{eventInfo.timeText}</b>
{eventInfo.view.type !== 'dayGridMonth' && <i>{eventInfo.event.title}</i>}
</div>
);
};
return (
<div className="fullcalendar-wrapper">
<FullCalendar
plugins={plugins}
initialView="dayGridMonth"
events={events}
headerToolbar={{
left: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay today,addEventButton"
}}
customButtons={{
addEventButton: {
text: '+',
click: () => {
setNewEvent({ title: '', start: '', end: '', description: '' });
setIsEditing(false);
setShowModal(true);
}
}
}}
footerToolbar={{
left: "prev",
center: "",
right: "next"
}}
buttonText={{
today: "오늘",
month: "월별",
week: "주별",
day: "일별",
list: "리스트"
}}
dateClick={handleDateClick}
eventClick={handleEventClick}
eventContent={renderEventContent} // 이벤트 콘텐츠 커스터마이즈 함수 추가
expandRows={true} // 행 확장을 활성화하여 모든 이벤트 표시
dayMaxEventRows={false} // 최대 이벤트 행 수를 비활성화
dayMaxEvents={false} // 최대 이벤트 수를 비활성화
/>
<Modal show={showModal} onHide={() => setShowModal(false)}>
<Modal.Header closeButton>
<Modal.Title>{isEditing ? '일정 수정' : '새 일정 추가'}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formEventTitle">
<Form.Label>제목</Form.Label>
<Form.Control
type="text"
value={newEvent.title}
onChange={(e) => setNewEvent({ ...newEvent, title: e.target.value })}
/>
</Form.Group>
<Form.Group controlId="formEventDescription">
<Form.Label>내용</Form.Label>
<Form.Control
type="text"
value={newEvent.description}
onChange={(e) => setNewEvent({ ...newEvent, description: e.target.value })}
/>
</Form.Group>
<Form.Group controlId="formEventStart">
<Form.Label>시작 시간</Form.Label>
<Form.Control
type="datetime-local"
value={newEvent.start}
onChange={(e) => setNewEvent({ ...newEvent, start: e.target.value })}
/>
</Form.Group>
<Form.Group controlId="formEventEnd">
<Form.Label>종료 시간</Form.Label>
<Form.Control
type="datetime-local"
value={newEvent.end}
onChange={(e) => setNewEvent({ ...newEvent, end: e.target.value })}
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => setShowModal(false)}>
취소
</Button>
<Button variant="primary" onClick={handleSaveEvent}>
저장
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
export default Calendar;
css도 추가해봤습니다!
.fullcalendar-wrapper {
width: 100%;
border: 1px solid #2F95DC;
border-radius: 5%;
padding: 10px 10px 10px 10px;
box-sizing: border-box;
background-color: transparent;
}
.fc-day a {
color: white;
}
.fc-day-sun a {
color: red;
text-decoration: none;
}
.fc-day-sat a {
color: blue;
text-decoration: none;
}
.fc-toolbar-title {
color: white;
}
반응형
'React' 카테고리의 다른 글
[React] Zustand를 사용해서 State 관리하기 02 (0) | 2024.07.26 |
---|---|
[React] Zustand를 사용해서 State 관리하기 01 (0) | 2024.07.26 |
[React] 리액트에서 부트스트랩 사용하기 (1) | 2024.07.23 |
[React] Axios 를 이용한 Api 호출 (0) | 2024.07.23 |