mingg IT

[Calendar] react-big-calendar custom(커스텀) 하기 본문

FrontEnd

[Calendar] react-big-calendar custom(커스텀) 하기

mingg123 2024. 3. 31. 12:03

목적

 

  • 아래와 같은 calendar 형식으로 커스텀이 필요한 상황 이였다. 
     
    • 클릭 시 일자, 가격, 배경 색 변경
    • 헤더영역, 일자 영역 border 제거 필요
    • 달력 내 일자 영역을 둥근 border 필요 

 

 

 

react-big-calendar 사용한 이유 

 

 

사용 기술 스택

 

  • Nextjs v13
  • Tailwind css 
  • react v18 
  • react-big-calendar v1.10.1

 

커스텀 전의 캘린더 모습

 

 

(참고: 토, 일 색 변형 등은 내가 수정해주었음) 

import "moment-timezone/builds/moment-timezone-with-data";
import "moment/locale/ko";
import { useEffect, useState } from "react";

import { Calendar, momentLocalizer } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";

const events = [
    {
      title: Number(972000).toLocaleString(),
      start: new Date(2024, 2, 17),
      end: new Date(2024, 2, 17),
    },
    {
      title: Number(973000).toLocaleString(),
      start: new Date(2024, 2, 18),
      end: new Date(2024, 2, 18),
    },
..생략
];

return (
    <div style={{ height: 360 }}>
        <Calendar
          backgroundColor={"#fff"}
          localizer={localizer}
          events={events}
          startAccessor="start"
          endAccessor="end"
          eventPropGetter={dayOfWeekStyleGetter}
          views={["month"]}
          formats={formats}
        />
      </div>
    </div>
 )

 

 

 

 

1.  css 파일 작성 

 

우선 커스텀을 하기 위해선 css 파일을 만들어 주어야함.

customer.css 를 만들고 import 해서 불러오자. 

 

배경색

 

 

 

확인해보면 배경부분을 가르키는 클래스명은 rbbc-day-bg 이다. 

25~ 29, 01 ~ 06 와 같이 이번달에 포함되지 않는 영역은 또 클래스명이 다르기 때문에 아래에서 논의 하겠음. 

 

custom-calendar.css

.rbc-day-bg {
  border: 1px solid white !important;
  border-radius: 5px !important;
  background-color: green !important;
  opacity: 0.1;
}

배경색 클래스명:  rbc-day-bg 수정 

 

 

이렇게 수정하게 되면 배경색이 바뀌어 있다. 

 

 

 


 

 

이번달에 포함되지 않는 배경색

 

custom-calendar.css

.rbc-off-range-bg {
  background-color: #e6e6e6 !important;
  border-radius: 5px !important;
}

 

배경색 클래스명:  rbc-off-range-bg 수정 

 

 

확인해보면 이번달에 포함되지 않는 영역의 배경색이 변경 되어있다. 

 

 

 

이제부터 클릭 할 때마다 색이 변경되는 영역을 커스텀 해보도록 하겠다. 

이건 class를 확인해보면 알 겠지만 css파일만 수정해서는 할 수가 없다. 

 

 

 

2. Customer 컴포넌트 작성 

 

클릭시 배경색 변경

 

 

아래와 같이 일자 하나에 대한 커스텀이 필요할 경우에는 

 dateCellWrapper: CustomDateCellWrapper 를 이용해준다.  

 

 <Calendar
      backgroundColor={"#fff"}
      localizer={localizer}
      events={events}
      startAccessor="start"
      endAccessor="end"
      eventPropGetter={dayOfWeekStyleGetter}
      views={["month"]}
      formats={formats}
      selectable={true}
      onSelectSlot={(slot) => {
        setSelectedDate(slot.start);
      }}
      components={{
        month: {
          dateCellWrapper: CustomDateCellWrapper, // 커스텀 컴포넌트 추가 
        },
      }}
    />
         
  // 여기가 핵심 
  const CustomDateCellWrapper = (props) => {
    const isSelected = isSameDate(props.value, selectedDate);
    return (
      <div
        className={
          isSelected
            ? `${props.children.props.className}-selected`
            : props.children.props.className
        }
      >
        {props.children}
      </div>
    );
  };
  
  
const isSameDate = (date, selectedDate) => {
    const calendarDay = new Date(date).getDay();
    const calendarDate = new Date(date).getDate();

    const selectedDay = selectedDate && new Date(selectedDate).getDay();
    const selectDate = selectedDate && new Date(selectedDate).getDate();

    const isSame =
    `${calendarDay}_${calendarDate}` === `${selectedDay}_${selectDate}`;
    return isSame;
};

 

CustomerDateCellWrapper내 props를 콘솔로 찍어보면 어떤 데이터가 나오는지 확인이 가능하다. 

 

우리가 살펴볼 부분은 바로 className과 내려오는 날짜 값인 value 이다. 

 

className: 'rbc-day-bg' 를 기억하겠지만 바로 위에서 커스텀 했던 클래스 부분이다. 

value: 내가 클릭한 날짜와 해당 날짜가 일치하는지 찾는데 이용된다. 

 

 

그렇다면 내가 클릭했다면 rbc-day-bg-selected 클래스를 만들어주고, default는 rbc-day-bg 클래스를 이용하면 된다. 

  // 여기가 핵심 
  const CustomDateCellWrapper = (props) => {
    const isSelected = isSameDate(props.value, selectedDate);
    return (
      <div
        className={
          isSelected
            ? `${props.children.props.className}-selected`
            : props.children.props.className
        }
      >
        {props.children}
      </div>
    );
  };

 

 

custom-calendar.css

.rbc-day-bg-selected {
  flex: 1 0 0% !important;
  border: 1px solid white !important;
  border-radius: 5px !important;
  background-color: green !important;
  color: white !important;
}

 

 


 

 

클릭시 일자색 변경

 

 

클릭시 black -> white 색 변경 

 

모든게 한번에 되면 좋겠지만.. 이 캘린더는 일자 영역을 잘게 쪼게어 놓았다. 

클릭시 1, 2, 3 과 같은 일자색(day) 색을 변경하기 위해선 추가 작업이 필요하다.

 

 

dateHeader: CustomDateHeader 를 이용해준다.  

 <Calendar
    backgroundColor={"#fff"}
    localizer={localizer}
    events={events}
    startAccessor="start"
    endAccessor="end"
    eventPropGetter={dayOfWeekStyleGetter}
    views={["month"]}
    formats={formats}
    selectable={true}
    onSelectSlot={(slot) => {
    setSelectedDate(slot.start);
    }}
    components={{
    toolbar: CustomToolbar,
    month: {
      dateCellWrapper: CustomDateCellWrapper,
      dateHeader: CustomDateHeader, // 추가 
    },
    }}
  />

 

  const CustomDateHeader = (props) => {
    const isSelected = isSameDate(props.date, selectedDate);
    return (
      <div
        style={{
          color: isSelected ? "white" : "black",
        }}
      >
        {props.label}
      </div>
    );
  };

 

CustomerDateCellWrapper 와 차이점은 props내 label로 01, 02 와 같은 day 정보가 내려오는 것이다. 

마찬가지로 console.log(props)로 찍어보면 쉽게 확인 가능하다. 

 

 


 

 

클릭시 가격 정보 색 변경

 

 

마찬가지로 클릭시 black -> white로 가격색이 변경 되면 좋겠다. 

해당 영역은 이벤트가 발생하는 영역이라고 해서

event: CustomEventContent 를 추가해주었다. 

 

 

<Calendar
  backgroundColor={"#fff"}
  localizer={localizer}
  events={events}
  startAccessor="start"
  endAccessor="end"
  eventPropGetter={dayOfWeekStyleGetter}
  views={["month"]}
  formats={formats}
  selectable={true}
  onSelectSlot={(slot) => {
    setSelectedDate(slot.start);
  }}
  components={{
    month: {
      dateCellWrapper: CustomDateCellWrapper,
      dateHeader: CustomDateHeader,
      event: CustomEventContent, // 추가 
    },
  }}
/>

//핵심 로직 
const CustomEventContent = (props) => {
    const isSelected = isSameDate(props.event.start, selectedDate);
    return (
      <div
        style={{
          color: isSelected ? "white" : "black",
        }}
      >
        {props.event.title}
      </div>
    );
};

 

(이제 똑같은 것을 3번 정도 반복 했으니 지겨울 수도 있겠지만 ..)  

event의 날짜 정보는 props.event.start로 들어와서 클릭한 날짜와 동일 날짜인지 비교하는데 사용해준다. 

 

 

핵심 로직은 이정도이고 외에 border 제거 등 내가 이용한 css는 아래에 첨부해두도록 하겠다. 

혹시나 필요한 사람 있으면 참고하기를 바란다. 

툴바도 커스텀한 부분이 있는데 그건 다음장에 작성하도록 하겠음. 

 

 

결과물

커스텀한 Calendar

 

custom-calendar.css

.rbc-day-bg {
  border: 1px solid white !important;
  border-radius: 5px !important;
  background-color: green !important;
  opacity: 0.1;
}

.rbc-off-range-bg {
  background-color: #e6e6e6 !important;
  border-radius: 5px !important;
}

.rbc-day-bg-selected {
  flex: 1 0 0% !important;
  border: 1px solid white !important;
  border-radius: 5px !important;
  background-color: green !important;
  color: white !important;
}

.rbc-date-cell {
  text-align: left !important;
  padding-left: 5px !important;
}

.rbc-month-row + .rbc-month-row {
  border: none !important;
}

.rbc-month-view {
  border: none !important;
}

.rbc-header {
  border-bottom: 1px solid white !important;
}

.rbc-header + .rbc-header {
  border-left: 1px solid white !important;
}

.rbc-day-bg rbc-off-range-bg {
  background-color: #e6e6e6 !important;
}

 

 

요약

 

  • 사실 저번주엔 커스텀에 실패했었다. 그 이유는 css 파일로만 수정하려고 했기 때문임 
  • Calendar 같은 경우엔 라이브러리를 그대로 사용할 경우는 많이 없을 것 같다. (커스텀 필수) 이번 기회에 내맛대로 커스텀하면서 재밌었음
  • react-big-calendar말고 react-calendar도 있던데 다음에 사용해 봐야겠다. 

 

 

 

 

이벤트 커스텀 했던 포스팅 추가로 작성했다. 

https://mingg123.tistory.com/287

 

[Calendar] react-big-calendar event custom(커스텀) 하기 2

https://mingg123.tistory.com/286 [Calendar] react-big-calendar custom(커스텀) 하기 목적 아래와 같은 calendar 형식으로 커스텀이 필요한 상황 이였다. 클릭 시 일자, 가격, 배경 색 변경 헤더영역, 일자 영역 border

mingg123.tistory.com

 

Comments