요양보호사 스케줄 캘린더
왼쪽에서 근무 조건을 잡고 달력을 클릭하면 그 설정대로 일정이 배정된다. 공휴일은 서버가 알고, 본인부담금은 클릭한 날짜에 따라 갈라진다.
2026년 6월
usePrefetchYearSchedules요양센터 관리자가 수급자에게 일정을 배정하는 화면이다. 흐름은 왼쪽에서 오른쪽으로 — 왼쪽 패널에서 근무 조건을 잡고, 달력의 날짜를 클릭하면 그 설정대로 일정이 들어간다. 들어간 일정을 클릭하면 상세 모달이 열리고 거기서 지울 수도 있다. 글로 풀면 평범해 보이지만, 실제로 만지면 클릭 한 번마다 요금이 갈라지는 게 보인다.
이 화면에서 가장 먼저 부딪힌 고민은 의외로 공휴일이었다. 휴일에는 수가가 가산되니 달력이 빨간 날을 정확히 알아야 하는데, 프론트에 공휴일 표를 하드코딩하면 대체공휴일이나 임시공휴일이 생길 때마다 배포를 다시 해야 한다. 그래서 공휴일은 백엔드가 관리하고 API로 내려주는 데이터로 정했다. 프론트는 월이 바뀔 때 그 달의 공휴일 목록을 받아 Set으로 들고, 날짜를 빨갛게 칠하고 이름을 붙이는 일만 한다. 위 데모도 같은 구조라, 6월로 가면 현충일이 서버 응답(mock)에서 내려와 빨간 날이 된다.
장기요양 수가는 같은 설정이라도 클릭한 날짜가 평일이냐 휴일이냐에 따라 달라진다. 휴일이면 수가에 가산이 붙고, 본인부담금은 그 수가에 수급자의 본인부담률을 곱해 나온다. 비급여는 아예 평일/휴일 시급을 따로 입력받고, 대근비는 본인부담이 아니라 센터가 요양보호사에게 주는 돈이라 계산 축이 다르다. 그래서 왼쪽 패널에 “배정 시 요금” 미리보기를 평일/휴일 두 줄로 두었다 — 클릭하기 전에 이 날짜가 얼마짜리인지 먼저 보이게.
실제 코드는 한 덩어리가 아니라 책임 단위로 나뉘어 있다. ScheduleTab이 모든 설정 상태를 들고, LeftPanel(모드별 하위 패널 InHours/ExtraHours/Shared)과 Calendar → DayCell이 그 상태를 내려받는다. 상세는 ScheduleDetailModal로 분리했다. 상태를 부모 한 곳에 둔 이유는 단순하다 — 왼쪽 패널이 바꾼 값을 오른쪽 달력의 클릭 핸들러가 그대로 써야 하기 때문이다. 유형별 색도 컴포넌트에 흩뿌리지 않고 테마 토큰(--substitute, --non-benefit 등)으로 정의해 라이트/다크를 한 곳에서 관리했다. 데모 곳곳의 mono 라벨을 호버하면 해당 부분의 실제 코드가 뜬다.
시간 입력은 셀렉트 두 개면 끝일 줄 알았는데, 곧바로 “종료가 시작보다 빠른” 조합이 들어왔다. 제출 시점에 검증해서 막을 수도 있지만, 애초에 잘못된 값을 고를 수 없게 하는 쪽이 낫다고 봤다. 그래서 TimePicker를 별도 컴포넌트로 빼고 minTime prop을 두었다 — 종료 셀렉트는 시작 이후의 옵션만 노출하고, 시작을 종료보다 뒤로 옮기면 종료가 자동으로 따라온다. 위 데모의 시간 셀렉트가 그 컴포넌트 그대로다(라벨을 호버하면 핵심 코드가 보인다).
왼쪽 패널의 상태는 그대로 일정 생성 요청의 payload가 된다. 날짜 클릭 → 검증(요양보호사 선택, 시간 순서) → 생성 요청 → 성공 toast → 달력 갱신. 실제 화면은 여기서 낙관적 업데이트를 쓰지 않았는데, 수가 계산이 서버에 있어서 클라이언트가 최종 금액을 미리 알 수 없기 때문이다. 응답을 기다렸다가 react-query 캐시를 무효화해 다시 그리는 쪽이 정확했다.
배정은 서버 계산을 기다리지만, 조회까지 기다리게 할 이유는 없다. 관리자는 달력을 앞뒤로 빠르게 넘기며 한 달 치씩 확인하는데, 월마다 로딩이 끼면 흐름이 끊긴다. 그래서 usePrefetchYearSchedules를 두고 연도가 바뀌는 순간 그 해 12개월치를 전부 prefetchQuery로 미리 받아 둔다. 이후의 월 이동은 전부 react-query 캐시 히트라 즉시 그려진다. 위 데모의 공휴일도 같은 패턴이라, 첫 진입만 서버 응답을 기다리고 그다음 월 이동부터는 지연이 없다(년월 옆 라벨을 호버하면 실제 훅 코드가 보인다).
설정 → 클릭 배정 → 상세 모달 → 삭제로 이어지는 흐름, 공휴일을 서버 응답으로 받아 빨간 날을 칠하는 구조, 평일/휴일에 따라 갈라지는 본인부담금 계산은 실제 화면과 같은 구조다. 다만 여기서는 서버를 두지 않아 공휴일 응답과 배정 호출을 흉내 냈고, 수가는 고시 수가표 대신 단순화한 데모 값을 쓴다.