Front-end/React

[TIL] React Datepicker 시간 선택 커스텀

성중 2021. 12. 23. 02:35

스터디룸 예약 서비스인 'hoops' 개발을 진행하던 중,
예약 시간 선택을 프론트에서 일부 제어할 수 있겠냐는 요청을 받았다

 

할 줄 몰라도 항상 시도는 해본다!

베타테스트는 우선 당일 예약만 진행하기로 했기에, 나는 '사전에 날짜 선택을 위해 구축했던 React Datepicker 라이브러리를 개조해서 시간 선택 알고리즘을 적용할 수 있지 않을까?' 라고 생각해 바로 작업에 들어갔다

조건은 다음과 같다

- 예약 시간은 9:30-5:30 사이에 결정 (임시)
- 사용 시간은 최소 30분에서 최대 2시간
* 즉, 5:00 시작이라면 5:30까지 사용 가능


정리하면, 종료 시간의 최대값은 시작 시간의 2시간 이후로 하되, 5:30을 넘어가면 안된다

 

React Datepicker crafted by HackerOne

 

reactdatepicker.com

다행히도 React Datepicker의 공식문서(?)는 매우 친절해서, 수십 가지 경우의 수에 맞는 예제를 볼 수 있었다

결론적으로 구현한 코드는 다음과 같다

(SDatePicker는 DatePicker를 커스텀 한 것이고, 한글화 및 set(get)Hours 등의 함수들은 import해주면 된다)

const ReserveMain = () => {
    // 시작 시간
    const [startTime, setStartTime] = useState(null);
    // 종료 시간
    const [endTime, setEndTime] = useState(null);
    // 시작 시간을 선택했는지
    const [isSelected, setIsSelected] = useState(false);

    // 시작 시간이 선택되면 해당 시간 적용 및 isSelected를 true, endTime을 null로
    const onSelect = (time) => {
        setStartTime(time);
        setIsSelected(true);
        setEndTime(null);
    };

    return (
        <>
            <div><SDatePicker
                selected={startTime}
                onChange={onSelect}
                locale={ ko }
                showTimeSelect
                showTimeSelectOnly
                timeIntervals={30}
                minTime={setHours(setMinutes(new Date(), 30), 9)}
                maxTime={setHours(setMinutes(new Date(), 0), 17)}
                timeCaption="Time"
                dateFormat="aa h:mm 시작"
                placeholderText="시작 시간"
                className="mt-4"
            /></div>

            {isSelected ? // 시작 시간을 선택해야 종료 시간 선택 가능
                <div><SDatePicker
                selected={endTime}
                onChange={(time) => setEndTime(time)}
                locale={ ko }
                showTimeSelect
                showTimeSelectOnly
                timeIntervals={30}
                minTime={startTime}
                maxTime={setHours(setMinutes(new Date(), getMinutes(startTime)), getHours(startTime)+2)} // 시작 시간부터 2시간
                excludeTimes={[
                    // 시작 시간 제외
                    startTime,
                    // 5:00 선택 기준 최대 7:00까지 예외처리
                    setHours(setMinutes(new Date(), 0), 18),
                    setHours(setMinutes(new Date(), 30), 18),
                    setHours(setMinutes(new Date(), 0), 19)
                ]}
                timeCaption="Time"
                dateFormat="aa h:mm 종료"
                placeholderText="종료 시간"
                className="mt-3"
            /></div>
                
                : null 
            }
        </>
    );
};

다음 3가지 기능들을 묶어 onSelect함수를 임의로 만들었다

  • 입력받은 값을 시작 시간으로 저장함
  • 삼항 연산자로 종료 시간을 숨겼다가 시작 시간을 선택 하면 드러나도록 함
  • 종료 시간 선택 후에 다시 시작 시간을 변경하면 종료 시간을 null로 되돌림


minTime과 maxTime으로 최소/최대 시간을 설정하는데, startTime에서 시간과 분을 추출해 종료 시간의 최대값을 정의하고 시작 시간 5:00 기준 7:00까지 예외처리 하기위해 excludeTimes에 넣어줬다
(이미 예약된 시간 예외처리도 useEffect로 받아와서 excludeTimes에 넣어주면 될 듯 하다)

다음과 같이 잘 구현되었다!

 

+++

filterPassedTime으로 이미 지나간 시간을 선택하지 못하도록 해주자

    // 현재 시간 기준 지나간 시간 선택 불가
    const filterPassedTime = (time) => {
        const currentDate = new Date();
        const selectedDate = new Date(time);
    
        return currentDate.getTime() < selectedDate.getTime();
    };
    
    
    <SDatePicker
    	filterTime={filterPassedTime}
    />

 

예약 시스템의 예외처리가 생각보다 까다로워서 공식문서를 한참 뒤적거렸는데,,
비슷한 작업을 하는 누군가에게는 이 글이 도움이 되지 않을까?

'Front-end > React' 카테고리의 다른 글

[TIL] React Howler 재생바 넓이  (2) 2022.01.07
[코딩애플] #7 Redux  (4) 2022.01.04
[TIL] 첫 React 백엔드 연동  (2) 2021.12.06
[노마드코더] #3 CRA, Effects  (2) 2021.11.17
[노마드코더] #2 State & Props  (2) 2021.11.16