프로젝트 기능 개발 중, 내가 참여한 스터디의 방장이 캘린더에 일정 등록을 하면
메인 페이지의 나의 캘린더에 자동으로 일정 등록이 되도록 하는 방법을 고민했다.
메인페이지 클릭 시 백엔드에서 API를 호출해 일정에 대한 데이터를 받은 후, 해당 데이터에 대한 상태관리를 통해 캘린더에 나타나도록 했다. 그런데 기존의 캘린더 라이브러리를 원하는대로 커스터마이징 하는게 어렵게 느껴져서 직접 캘린더를 만들어보기로 했다.
0-1) 백엔드 api를 다음과 같이 호출하였다. ''data''변수에 호출된 데이터가 저장된다.
function getCalendar(){
async function requestCalendar(): Promise<void> {
try {
const response: AxiosResponse<CalendarData> = await authHttp.get<CalendarData>(`/calendar/study?user=${pk}`);
const {calendar} = response.data;
if(calendar){
setData(calendar)
}
} catch (error) {
const err = error as AxiosError
console.log(err);
}
}
requestCalendar()
}
0-2) liTags라는 JSX.Element 배열 타입의 변수를 생성하였다. 이 변수는 캘린더에 들어갈 날짜별 li태그의 바구니로 활용된다.
let liTags:JSX.Element[] = [];
1) 먼저, 해당 월의 1일이 몇요일인지 & 지난 달의 마지막 날짜가 몇일인지 구한다.
//1=월 2=화 ... 7=일
const firstDayOfMonth = new Date(currYear, currMonth, 1).getDay();
const lastDateOfLastMonth = new Date(currYear, currMonth, 0).getDate();
2) for문을 돌면서 1일 전의 (지난달) 날짜들이 첫줄에 들어오도록 한다.
(style에 inactive를 넣어 이번달이 아닌 날짜들은 흐리게 표시되도록 하였다)
for (let i = firstDayOfMonth; i > 0; i--) {
liTags.push(<li key={`prev-${i}`} className={style.inactive}>{lastDateOfLastMonth - i + 1}</li>);
}
3) 1-2번과 비슷한 로직으로 다음달의 날짜들로 마지막줄을 채운다.
const lastDayOfMonth = new Date(currYear, currMonth, lastDateOfMonth).getDay();
for (let i = lastDayOfMonth; i < 6; i++) {
liTags.push(<li key={`next-${i}`} className={style.inactive}>{i - lastDayOfMonth + 1}</li>);
}
4) 이번 달의 날짜들은 1일부터 마지막날까지 for문을 돌면서 li태그로 채워준다.
오늘 날짜에는 style에 active를 넣어 위 사진과 같이 동그랗게 표시되도록 하였다.
또한 갖고있는 data 배열을 탐색하면서 해당 날짜의 일정이라면 filter 되도록 한 후에 daySchedules 변수에 저장하였다.
이 daySchedules를 활용하여 해당 날짜에 일정이 있는지 판단하고, 있다면 hasSchedule이라는 스타일 클래스를 넣어 일정표시가 되도록 하였다.
const lastDateOfMonth = new Date(currYear, currMonth + 1, 0).getDate();
for (let i = 1; i <= lastDateOfMonth; i++) {
const isToday = i === currentDate.getDate() && currMonth === currentDate.getMonth() && currYear === currentDate.getFullYear();
const daySchedules = data.filter(schedule => {
const scheduleDate = new Date(schedule.startTime);
return scheduleDate.getFullYear() === currYear && scheduleDate.getMonth() === currMonth && scheduleDate.getDate() === i;
});
liTags.push(
<li key={`curr-${i}`}
className={`${isToday ? style.active : ''} ${daySchedules.length > 0 ? style.hasSchedule : ''}`}
onClick={() => handleDateClick(i, daySchedules)}
>{i}
</li>
);
}
5) 위 모든 과정은 renderCalendar이라는 함수에 들어있다! 이 함수는 liTags를 리턴한다. tsx 파일에서 이를 아래와 같은 형태로 불러올 수 있다.
const months = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
<div>
<header className={style.header}>
<p className={style.current_date}>{months[currMonth]} {currYear}</p>
<div className={style.icons}>
//< > 월 바꾸는 버튼
<span id="prev" className={style.material_symbols_rounded} onClick={() => handleIconClick("prev")}>◀</span>
<span id="next" className={style.material_symbols_rounded} onClick={() => handleIconClick("next")}>▶</span>
</div>
</header>
<div className={style.calendar}>
<ul className={style.weeks}>
<li>Sun</li>
<li>Mon</li>
<li>Tue</li>
<li>Wed</li>
<li>Thu</li>
<li>Fri</li>
<li>Sat</li>
</ul>
<ul className={style.days}>
//renderCalendar() 함수 호출!
{renderCalendar()}
</ul>
</div>
이렇게 하면, 추후에 달력 클릭 시 팝오버가 뜨게 한다거나 해당 날짜에 스케줄 미리보기를 추가한다던가.. 여러가지 활용성이 생긴다!
'Project' 카테고리의 다른 글
[2023 Summer Project] 시니어를 위한 일상 플랫폼 - The SecondLife (1) | 2023.07.03 |
---|---|
2) 코딩컨벤션 적용하기 (0) | 2023.06.27 |
[삼성 청년 SW아카데미 경진대회] 내 손안의 요가도우미, YogaMate (2) | 2023.06.12 |
1) AWS EC2(Elastic Compute Cloud)를 활용해 Ubuntu 서버를 구축해보자 (2) | 2023.06.01 |
댓글