일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Styled Components
- 밸류즈
- ui탬플릿
- Typesciprt
- 스프링시큐리티
- RCPS
- Update
- jsonwebtoken
- mypage
- 로그인
- 달력 라이브러리
- register
- 인증처리
- stock option
- MRC
- 밸류즈 홈페이지
- 빌드 및 배포
- 공통메서드
- 파생상품평가
- 로그인 로직
- react
- 캘린더 라이브러리
- 이미지 업로드
- 회원가입로직
- 배포
- 관리자페이지
- 마이페이지
- Ajax
- userManagement
- Token
- Today
- Total
I T H
[MySchedule project] 15. React-big-Calendar 사용하기 (1) 본문
이번 시간은 react big calendar 라이브러리를 사용해서 스케줄관리에 대한 코드를 작성해 보겠다.
구현에 들어가기 앞서 react-big-calendar 라이브러리를 설치한다.
추가적으로 날짜관리 라이브러리인 moment.js도 같이 설치 해준다.
[ 설치 ]
npm install --save react-big-calendar
npm install moment
[ import ]
- "react-big-calendar" 라이브러리와 "moment.js"를 설치 했다면 아래 부분을 import 해준다.
import { Calendar, View, DateLocalizer } from "react-big-calendar";
import moment from "moment";
import { momentLocalizer } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";
[ 참고자료 ]
https://www.npmjs.com/package/react-big-calendar
react-big-calendar
Calendar! with events. Latest version: 1.10.2, last published: 12 hours ago. Start using react-big-calendar in your project by running `npm i react-big-calendar`. There are 270 other projects in the npm registry using react-big-calendar.
www.npmjs.com
Frontend
[ src / types / myscheduleType.ts ]
- 마이스케줄 페이지에서 사용할 타입들을 지정해준다.
export interface CalendarEvent {
title: string;
allDay: boolean;
start: Date;
end: Date;
desc: string;
resourceId?: string;
tooltip?: string;
userId: string;
calenderType: number;
}
export interface CalendarModalData {
title: string;
start: Date;
end: Date;
calendarType: number;
}
[ react-big-calendar 구조 ]
● 캘린더 라이브러리의 중요한 포인트 4가지
- localizer : 현재 시간을 가져온다. 날짜와 시간관리 라이브러리인 moment.js를 사용해서 localizer에 넣어주었다.
const localizer = momentLocalizer(moment);
- events : 화면에 출력될 캘린더 데이터로, db에서 데이터를 조회해오고 조회한 데이터를 이부분에 넣어주면 된다.
- onSelectSlot : 해당부분을 선택하면 데이터를 넣을 수 있다. 데이터를 db로 전달해서 저장한다.
- onSelectEvent: 화면에 출력된 데이터를 클릭하면 해당 데이터를 볼수 있다. 이부분은 modal을 사용해서 수정, 삭제과정까지 진행하였다.
[ src / pages / myschedule /index.tsx ]
1. 캘린더 데이터 입력
- 데이터를 파라미터로 보낼 useState를 만들고, useEffect hook을 통해 데이터가 입력받을때(변할때) dataInsert함수가 실행되게 한다.
- axios를 이용해 백앤드로 데이터를 전달한다. 이때 필수 값은 "title, start, end" 이므로 꼭 넣도록 하자. 추가적으로 userId와 캘린더의 타입도 같이 전달했다.
2. 캘린더 데이터 조회
- db에 저장된 캘린더의 데이터들을 조회해 온다.
- 데이터 조회는 캘린더 페이지에 들어왔을때 바로 눈에 보여야 하므로, useEffect()를 사용해서 조회 함수를 넣어준다.
- 사용자에 따라 데이터가 다 다르므로, userId를 파라미터로 보내 해당 사용자에 맞는 데이터를 조회해온다. 캘린더의 타입도 같이 보내주었다.
예를 들어서 "타입 0일땐 기본스케줄, 타입 1일땐 운동스케줄, 타입2일땐 식비관리" 처럼 나눌 수 있다.
3. modal 컴포넌트로 연결된 수정, 삭제 기능
- 위에서 캘린더의 구조에 대해 살펴봤을때 "onSelectEvent" 기능을 통해 클릭하면 해당 데이터를 볼 수 있는데, 데이터를 modal 컴포넌트로 같이 전달해 준다.
- modal에 대한 라이브러리에 대한 설명은 "챕터 11"에서 했으므로, 아래부분을 클릭하면 자세히 볼 수 있다.
[MySchedule project] 11. 관리자 - 사용자관리 로직 mui x-data-grid와 mui modal 사용
관리자용 페이지중에서 사용자 데이터를 관리하는 페이지를 만들려고 한다. 먼저 db에 저장되있는 사용자 데이터들을 조회해 오고, 조회해온 데이터를 수정, 삭제하는 기능과 사용자를 등록하
devth.tistory.com
import React, { useEffect, useState } from "react";
import { Calendar, View, DateLocalizer } from "react-big-calendar";
import moment from "moment";
import { momentLocalizer } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";
import axiosInstance from "../../utils/axios";
import { useAddSelector } from "../../store/redux";
import { CalendarEvent } from "../../types/myscheduleType";
import CalendarModalPage from "./CalendarModalPage";
const localizer = momentLocalizer(moment);
const allViews: View[] = ["agenda", "day", "week", "month"];
interface Props {
localizer: DateLocalizer;
}
const SelectableCalendar = ({ localizer }: Props) => {
const userId = useAddSelector((state) => state.user?.userData?.userId);
//modal
const [open, setOpen] = useState(false);
const handleUpdateOpen = () => setOpen(true);
const [calenderModalData, setCalenderModalData] = useState<CalendarEvent>(); //모달에 넣을 데이터
//조회한 스케줄 데이터를 담을 state
const [events, setEvents] = useState([
{
id: "",
start: "",
end: "",
title: "",
calenderType: 0,
},
] as unknown as CalendarEvent[]);
//스케줄 데이터를 backend에 보낼 parameter값 관리
const [newDateInsert, setNewDateInsert] = useState<CalendarEvent>();
//데이터 조회 start ==================================================
useEffect(() => {
CalenderDataSelect();
}, []);
const CalenderDataSelect = async () => {
const body = {
userId: userId,
calenderType: 0,
};
try {
const response = await axiosInstance.post(`/mySchedule/dataSelect`, body);
for (let index in response.data) {
setEvents(response.data[index]);
}
// setEvents(response.data);
} catch (error) {
console.log(error);
}
};
//화면에 출력할 calenderData
const calenderData = events?.map((data) => ({
start: new Date(data.start),
end: new Date(data.end),
title: data.title,
calenderType: data.calenderType,
}));
//데이터 조회 end ===================================================
// 데이터 입력 start=================================================
useEffect(() => {
dataInsert();
}, [newDateInsert]);
//onSelectSlot event
const handleSelectNewData = ({ start, end }: CalendarEvent | any) => {
const title = window.prompt("스케줄을 입력해주세요.");
console.log("1");
if (title) {
let newEvent = {} as CalendarEvent;
newEvent.start = moment(start).toDate();
newEvent.end = moment(end).toDate();
//newEvent.end = moment(end).subtract(1, "days").toDate();
newEvent.title = title;
newEvent.calenderType = 0;
newEvent.userId = userId;
//console.log(newEvent);
setNewDateInsert(newEvent);
//dataInsert();
}
};
//데이터 입력 함수
const dataInsert = async () => {
// backend 전달
const body = {
...newDateInsert,
};
console.log(body);
if (body?.start) {
//body로 값이 들어올때만 insert
try {
const response = await axiosInstance.post(
`/mySchedule/dataInsert`,
body
);
console.log("OK");
if (response.data === "OK") {
CalenderDataSelect(); //재조회
}
} catch (error) {
console.log(error);
}
}
};
// 데이터 입력 end ==============================================
//modal open start ==============================================
const modalHandle = (event: any) => {
console.log(event);
setCalenderModalData(event); //모달에 넣을 데이터
//console.log(calenderModalData);
handleUpdateOpen();
};
//modal open end ==============================================
return (
<>
<div className="my-6">
<p className="text-[20px] font-semibold text-center my-6">
기본 스케줄 관리
</p>
<p className="text-sm font-md ">
- 달력안을 클릭하면 스케줄을 등록하실 수 있습니다.
</p>
</div>
<Calendar
selectable
localizer={localizer}
events={calenderData}
defaultView="month"
views={allViews}
defaultDate={new Date()}
//onSelectEvent={(event) => alert(event.title)}
onSelectEvent={modalHandle}
onSelectSlot={handleSelectNewData}
startAccessor="start"
endAccessor="end"
titleAccessor="title"
/>
{/* modal update 호출 */}
{calenderModalData && (
<CalendarModalPage
open={open}
setOpen={setOpen}
calenderModalData={calenderModalData}
CalenderDataSelect={CalenderDataSelect} //데이터 조회
/>
)}
</>
);
};
const MySchedule = () => {
return (
<div style={{ height: "100vh" }}>
<SelectableCalendar localizer={localizer} />
</div>
);
};
export default MySchedule;
[ src / pages / myschedule / CalendarModalPage.tsx ]
1. 캘린더 데이터 수정
- 전달받은 props 중에서 캘린더 데이터는 useEffect의 의존성배열("[ ]")에 넣어서 데이터가 바뀔때마다 setState에 넣어 상태값을 관리해준다. 전달받은 데이터를 담은 state는 input태그의 value에 넣어 modal의 화면에 출력되게 한다.
- 사용자로부터 수정된 데이터를 전달받아 axios를 통해 백앤드로 데이터를 전달한다. 이때 userId는 필수로 전달해야된다. 사용자마다 캘린더의 데이터가 다 다르기 때문이다. userId는 redux의 useSelector를 사용해서 가져왔다.
2. 캘린더 데이터 삭제
- userId와 삭제할 데이터를 백앤드로 보낸다.
- 데이터가 정상적으로 삭제되었다면 props로 전달받은 데이터 재조회 함수를 실행한다.
import React, { ChangeEvent, useEffect, useState } from "react";
import { Backdrop, Box, Fade, Modal, Typography } from "@mui/material";
import axiosInstance from "../../utils/axios";
import { toast } from "react-toastify";
import { MdOutlineUpdate } from "react-icons/md";
import { CalendarEvent, CalendarModalData } from "../../types/myscheduleType";
import { style } from "../UserManagement/ModalStyle";
import { useAddSelector } from "../../store/redux";
interface ownProps {
open: boolean;
setOpen: any;
calenderModalData: CalendarEvent;
CalenderDataSelect(): void;
}
const CalendarModalPage = ({
calenderModalData,
open,
setOpen,
CalenderDataSelect,
}: ownProps) => {
// 클릭 이벤트로 받아온 캘린더 데이터
const [calenderData, setCalenderData] = useState<CalendarModalData | any>({
title: "",
start: "",
end: "",
calenderType: "",
});
const userId = useAddSelector((state) => state.user?.userData?.userId);
const handleClose = () => setOpen(false);
useEffect(() => {
console.log(calenderModalData);
setCalenderData({
title: calenderModalData.title,
start: calenderModalData.start,
end: calenderModalData.end,
calenderType: calenderModalData.calenderType,
});
}, [calenderModalData]);
//onChange함수
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
// console.log(e.target);
const { name, value } = e.target;
setCalenderData((prevState: CalendarModalData) => ({
...prevState,
[name]: value,
}));
};
//데이터 업데이트
const calenderhandleUpdate = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.preventDefault();
const body = {
...calenderData,
userId: userId,
};
try {
const response = await axiosInstance.post(
`/mySchedule/calenderDataUpdate`,
body
);
//console.log(response);
if (response.data.title !== null && response.data.title !== "") {
toast.success("캘린더 스케줄이 수정되었습니다.");
handleClose();
CalenderDataSelect(); //데이터 재조회
}
} catch (error) {
console.log(error);
}
};
//데이터 삭제
const calenderhandleDelete = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.preventDefault();
const body = {
...calenderData,
userId: userId,
};
try {
const response = await axiosInstance.post(
`/mySchedule/calenderDataDelete`,
body
);
console.log(response);
if (response.data.deleteYn === true) {
toast.success("캘린더 스케줄이 삭제되었습니다.");
handleClose();
CalenderDataSelect(); //데이터 재조회
}
} catch (error) {
console.log(error);
}
};
return (
<div>
{/* <Button onClick={handleOpen}>Open modal</Button> */}
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={handleClose}
closeAfterTransition
slots={{ backdrop: Backdrop }}
slotProps={{
backdrop: {
timeout: 500,
},
}}
>
<Fade in={open}>
<Box sx={style} className="rounded-md border-[1px] border-gray-300 ">
<button onClick={handleClose} className="float-right text-md ">
X
</button>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="text-center"
>
스케줄 관리
</Typography>
{calenderData && (
<>
<div className="w-full my-4">
<div className="my-2">
<label className="text-left text-sm ">
<MdOutlineUpdate className="inline size-5 mb-1" /> 일정을
수정 또는 삭제할 수 있습니다.
</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none"
type="text"
onChange={handleChange}
value={calenderData.title}
name="title"
/>
</div>
</div>
<div className="w-full my-3">
<div className="flex gap-4 justify-center">
<button
onClick={calenderhandleUpdate}
className="bg-blue-600 w-6/12 text-gray-50 rounded-md h-10 hover:bg-blue-700"
>
수정
</button>
<button
onClick={calenderhandleDelete}
className="bg-blue-600 w-6/12 text-gray-50 rounded-md h-10 hover:bg-blue-700"
>
삭제
</button>
</div>
</div>
</>
)}
</Box>
</Fade>
</Modal>
</div>
);
};
export default CalendarModalPage;
[결과화면]
- 다음 챕터에서는 캘린더 라이브러리를 사용해서 내스케줄관리에 대한 백앤드 로직을 작성하겠다.
'React + Node.js' 카테고리의 다른 글
[MySchedule project] 17. styled components 사용하기 / Footer (0) | 2024.02.20 |
---|---|
[MySchedule project] 16. React-big-Calendar 사용하기 (2) (0) | 2024.02.20 |
[MySchedule project] 14. 카카오 로그아웃 or unlink 로직 (0) | 2024.02.12 |
[MySchedule project] 13. 카카오 로그인 구현 (2) - Backend (0) | 2024.02.12 |
[MySchedule project] 12. 카카오 로그인 구현 (1) - Frontend (0) | 2024.02.12 |