VIVITRIP 프로젝트 회고_캘린더 및 예약 시스템 구현

Kingdwan·2025년 4월 14일
post-thumbnail

캘린더 및 예약 시스템 구현


체험 등록/수정 기능이 사용자 중심의 콘텐츠를 생성하는 과정이라면, 이번 캘린더 및 예약 시스템 구현은 그 콘텐츠에 사용자들이 실제로 참여하고 예약할 수 있는 흐름을 완성하는 단계였다.

특히 사용자 입장에서는 “언제 가능한지”, “예약했는지”, “상태는 어떤지”를 한눈에 확인할 수 있는 UI의 직관성이 매우 중요했고, 관리자 입장에서도 예약 현황을 효율적으로 관리할 수 있어야 했기 때문에 이번 파트에서는 날짜 기반 UI 구성, 예약 시각화, 전역 상태 및 비동기 처리가 핵심이 되었다.

구현 목표

1. 사용자 친화적인 날짜 선택 UI 구성

  • react-datepicker를 활용하여 간결하고 직관적인 달력 UI 제공
  • 예약 가능한 날짜만 강조되도록 highlightDates 기능 활용
  • 달 변경 시 자동으로 예약 상태 갱신 (onMonthChange 이벤트 활용)

2. 예약 일정을 시각적으로 한눈에 확인

  • react-big-calendar를 통해 월간/주간 단위의 일정 시각화
  • 예약 상태(대기, 승인, 완료)에 따라 색상으로 구분
  • 예약 항목 클릭 시 상세 정보를 모달로 표시하여 관리 편의성 강화

3. 상태 동기화 및 비동기 예약 처리

  • Zustand를 사용해 선택된 날짜, 예약 상태 등을 전역에서 일관되게 관리
  • React Query를 활용해 예약 목록 및 상세 데이터를 캐싱 기반 비동기 처리
  • 예약 신청 후, 모달 안내 및 UI 갱신까지의 흐름을 자연스럽게 연결

1. 사용자 친화적인 날짜 선택 UI 구성

[react-datepicker를 사용한 예약하기 모달]

react-datepicker을 사용하는 이유?

체험 예약 기능에서 핵심이 되는 요소 중 하나는 날짜 선택 UI다. 사용자는 본인이 원하는 날짜를 명확하게 선택할 수 있어야 하며, 예약 가능한 날짜와 불가능한 날짜를 구분할 수 있어야 한다. 이를 위해 처음에는 단순한 input type="date"를 고려했으나, 다음과 같은 한계가 있었다

  • 디자인 커스터마이징 제한
    브라우저마다 input type="date"의 스타일이 다르며, 이를 커스터마이징하려면 복잡한 CSS 작업이 필요

  • 예약 가능/불가 날짜 표시 기능 미제공
    특정 날짜만 활성화하거나 비활성화하는 기능을 기본적으로 지원하지 않으며, 추가적인 자바스크립트 로직이 필요

  • 월 변경 시 동적 예약 정보 반영
    월 변경 시 예약 가능 여부 등 동적 데이터를 반영하려면 별도의 이벤트 핸들링과 상태 관리가 필요 기본 input type="date"는 이러한 동작을 미지원

결론 input을 사용하면 CSS가 복잡해지고 예약 가능/불가능 로직을 구현 하며 유지보수 분리 함을 느껴 이러한 요구사항을 충족시키기 위해 react-datepicker를 도입하게 되었다.

react-datepicker 이란 ?

"react-datepicker" 사용자에게 날짜를 시각적으로 선택하게 해주는 React 기반의 달력 컴포넌트 라이브러리

react-datepicker는 리액트 프로젝트에서 가장 많이 사용되는 날짜 선택 UI 컴포넌트 중 하나로, 간결한 디자인, 높은 커스터마이징 유연성, 그리고 시간 선택, 범위 선택, 필터링 등 다양한 기능을 제공한다.

기능설명
날짜 선택사용자가 클릭으로 날짜를 선택할 수 있는 달력 제공
🕓 시간 선택 지원시간(Time) 선택 기능도 함께 제공 가능
📅 범위 선택 지원시작일-종료일(date range) 선택 기능
🛠 커스터마이징스타일, 포맷, 언어(localization) 등 다양한 옵션 지원
📌 날짜 필터링특정 날짜만 선택 가능하도록 제약 가능 (예: 예약 가능한 날짜만 표시)
📆 월 이동 제어onMonthChange 이벤트로 월 변경 시점 추적 가능

사용방법

react-datepicker 현 프로젝트에서 사용 할 기능들

  1. highlightDates
  2. onMonthChange
  3. renderCustomHeader
  4. dayClassName
  5. minDate
  6. locale

코드

1. highlightDates

예약 가능한 날짜 강조하는 기능으로 data.schedules을 외부에서 받아 예약 가능한 날짜들을 하이라이트

2. onMonthChange

현재 보고 있는 달이 변경되었을 때 이벤트 감지 → 전역 상태 관리(Zustand)를 통해 selectMonth 업데이트

  • 예약 데이터는 월 단위로 조회됨
  • 달이 바뀔 때마다 서버에 데이터 요청 혹은 상태 갱신 필요

3. renderCustomHeader

기본 캘린더 헤더 대신 커스텀 컴포넌트로 교체 → 좌우 버튼, 월/년 표시 디자인 자유롭게 구현 가능

  • 디자인 시스템 통일성 유지
  • 사용자 편의에 맞는 월 이동 버튼

4. dayClassName


개별 날짜 스타일을 지정할 수 있는 함수 → 현재 달은 기본 스타일, 이전/다음 달은 흐리게 표시

5. minDate

선택할 수 있는 최소 날짜 제한 → 오늘 이전 날짜는 모두 비활성화

6. locale


요일 표시 포맷 등 현지화 설정 → 영어 요일을 Su, Mo 등 짧은 형식으로 커스터마이징

2.예약 일정을 시각적으로 한눈에 확인

날짜만 선택할 수 있었던 기존의 datepicker 방식은 전체 일정을 파악하는 데 한계가 있었고, 특히 날짜별 예약 수나 상태를 확인하기엔 부적합했다.(예약 상태에 따른 이벤트 처리) react-datepicker 대신 react-big-calendar를 도입하여 월간 단위의 예약 현황을 시각적으로 한눈에 확인할 수 있는 UI를 구성했다.

왜 react-datepicker 대신 big-calendar를 썼는가?

  • 전체 예약 현황을 한눈에 시각화하기 어렵다
    → datepicker는 단일 날짜 중심이며, 다수의 이벤트(예약)를 직관적으로 표현하기에 한계가 있음

  • 예약 상태에 따라 색상 구분 등 복잡한 UI 조건을 구현하기 어려움
    → dayClassName이나 highlightDates만으로는 정보 표현의 한계

  • 이벤트 클릭, 월간 전환, 사용자 정의 헤더 등의 유연한 캘린더 구성 필요
    → UX/기능 확장을 위해 react-big-calendar 도입

    react-big-calendar란?

"react-big-calendar"는 구글 캘린더와 유사한 레이아웃을 제공하며, 일정 표시, 날짜 탐색, 커스텀 이벤트 렌더링 등 다양한 캘린더 기능을 갖춘 강력한 라이브러리이다.

date-fns나 moment와 함께 사용하여 로케일 설정과 날짜 계산도 수월하게 처리할 수 있다.

사용방법

react-big-calendar 현 프로젝트에서 사용 할 기능들

  1. CustomEvent
  2. CustomToolbar
  3. handleSelectSlot
  4. dateHeader

1. CustomEvent

예약은 세 가지 상태(대기, 승인, 완료)로 나뉘며, 각각을 다른 색상 박스로 시각화하였다.
이렇게 각 이벤트에 대해 시각적으로 구분된 정보를 제공하여 예약 현황 파악을 쉽게 했다.

2. CustomToolbar

기본 툴바 대신 직접 만든 툴바를 적용하여, 사용자 경험에 맞춘 내비게이션을 제공했다.

3. handleSelectSlot

사용자가 날짜를 클릭하면 해당 날짜의 예약 정보를 모달로 보여주는 구조를 구현했다

4. dateHeader

날짜 셀 위에 예약 상태에 따른 작은 원 아이콘을 표시하여, 한눈에 해당 날짜에 예약이 있는지 시각적으로 표현했다

react-big-calendar 을 사용하면서 느낀점

높은 커스터마이징 유연성 (이벤트, 툴바, 헤더 등) 특히 이벤트 부분은 UI 부분에서 react-datepicker 보다 할 수 있는 영역이 많아 좋았다.

3.상태 동기화

사용자가 날짜를 선택하거나 상세 예약 정보를 확인하는 흐름은 단순한 UI 상호작용을 넘어 다양한 상태와 비동기 데이터의 흐름이 얽혀 있는 구조다. 이를 보다 일관성 있게 관리하기 위해, Zustand사용했다.

  • 프로젝트에서는 두 개의 달력 시스템(react-datepicker, react-big-calendar)을 사용했는데, 각각의 상태 구조가 달랐기 때문에 상태 스토어를 분리했다.

1. Zustand로 날짜·스케줄 등 UI 상태 관리

Zustand 사용

사용자가 날짜를 클릭하거나 예약 상세를 선택할 때마다 전역 상태가 일관되게 유지될 수 있도록 Zustand를 활용했다. 이 덕분에 복잡한 prop 전달 없이도 다양한 컴포넌트 간 데이터 연동이 가능했다.

◼ 데이트 피커용 상태 관리: useCalendarStore

  • 체험 상세 데이터가 함께 관리되어, 날짜에 따른 예약 가능 여부나 시간 선택까지 포함해 UI 제어 가능
  • 월 변경 시 서버에 요청할 수 있도록 selectMonth와 onMonthChange 연결

◼ 빅 캘린더용 상태 관리: useReservationStore

  • 예약 현황 대시보드에서는 월별 예약 상태(완료, 승인, 대기)를 종합적으로 보여줘야 하므로 간단한 구조로 구성
  • 월이 바뀔 때 useQuery로 서버에 요청하여 setData()를 통해 store에 갱신
  • 해당 데이터를 기반으로 이벤트 컬러 표시, 예약 상세 모달 연결, 일자별 원형 인디케이터 표현 등 구현 가능

캘린더 및 예약 시스템 구현 트러블 슈팅

1. 라이브러리 기반 컴포넌트의 CSS 커스터마이징 어려움

react-datepicker와 react-big-calendar 모두 사용자 친화적이고 강력한 기능을 제공하지만, 디자인 시스템에 맞춰 커스터마이징하려고 할 때 큰 장벽이 있었다.

  • 원인 분석

▪ 라이브러리 내부에서 컴포넌트 구조가 정해져 있음
▪ className만 던져주는 구조로, 세부 엘리먼트 접근이 제한적
▪ 특히 react-big-calendar는 각 날짜 셀, 이벤트 항목, 툴바 등의 마크업 구조가 고정돼 있어 디자인 시스템과 정확히 일치하는 UI를 만들기 어려움

  • 해결 방법

1. 강제적으로 CSS 덮어쓰기

▪ 라이브러리에서 내부적으로 사용 중인 클래스명을 파악하여 CSS를 override하는 방식으로 처리

2. components prop으로 커스텀 렌더링 컴포넌트 주입

▪ react-big-calendar는 components prop을 통해 각 UI 부분을 커스터마이징할 수 있도록 되어 있어서, 아래와 같이 CustomToolbar, CustomEvent, dateHeader 등을 직접 정의해 대체

3. className 분기와 조건부 스타일 대응

▪ dayPropGetter, eventPropGetter 등을 활용해서 날짜 또는 이벤트 별로 조건부 스타일링을 적용할 수 있도록 설계

  • 회고

기성 라이브러리를 사용하면 개발 속도는 빨라지지만, 진행하고 있는 프로젝트의 디자인 시스템과의 통일성을 맞추려면 CSS 커스터마이징은 반드시 넘어야 할 허들이라는 걸 실감했다. 특히 react-big-calendar는 구조 자체가 유연하게 열려 있지 않기 때문에, override 방식 + component 분리 렌더링 전략을 병행해야 했다. 결과적으로는 커스텀 컴포넌트 분리 덕분에 유지보수도 용이해졌고, 동일한 구조에서 다양한 뷰포트 대응까지 확장 가능했다.

캘린더 및 예약 시스템 구현을 마치며 느낀 점

라이브러리는 빠른 개발을 가능하게 해주지만, 커스터마이징과 유지보수 측면에서는 신중한 판단이 필요하다는 점을 절실히 체감했다. react-big-calendar와 react-datepicker 모두 UI 구성에는 강력했지만, 내부 클래스나 컴포넌트 구조에 접근하는 데 제한이 있었고, 디자인 시스템과의 통일성을 확보하기 위해 많은 시간과 고민이 필요했다.

결국 커스텀 컴포넌트 렌더링(components, renderHeader, dayClassName 등)을 적극 활용하며 라이브러리를 우리 UI 설계에 맞게 가져오는 방식으로 해결해야 했다. 이 과정에서 단순 사용자가 아닌, 라이브러리를 통제하는 설계자로서의 시야를 확장할 수 있었다.

0개의 댓글