/** * 달력 일정 Zustand Store * * 달력관리(CalendarManagement)에서 등록한 공휴일/세무일정/회사일정을 * 프로젝트 전체 ScheduleCalendar, DatePicker 등에 전파하는 공유 스토어. * * 데이터 흐름: * 1. ScheduleCalendar 마운트 시 해당 연도 fetchSchedules(year) 호출 * 2. API 응답 → schedulesByYear에 캐시 * 3. calendarEvents.ts 유틸 함수(isHoliday 등)가 스토어에서 읽음 * 4. API 미응답 시 하드코딩된 calendarEvents.ts 상수를 폴백으로 사용 */ import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; import type { CalendarSchedule } from '@/components/hr/CalendarManagement/types'; import { getCalendarSchedules } from '@/components/hr/CalendarManagement/actions'; interface CalendarScheduleStore { /** 연도별 캐시된 일정 */ schedulesByYear: Record; /** 연도별 로딩 완료 여부 */ loadedYears: Record; /** 연도별 로딩 중 여부 */ loadingYears: Record; /** 연도별 일정 조회 (캐시 히트 시 API 호출 안 함) */ fetchSchedules: (year: number) => Promise; /** 이미 가져온 데이터를 스토어에 직접 설정 (추가 API 호출 없음) */ setSchedulesForYear: (year: number, schedules: CalendarSchedule[]) => void; /** 특정 연도 캐시 무효화 (달력관리에서 등록/수정/삭제 후 호출) */ invalidateYear: (year: number) => void; } export const useCalendarScheduleStore = create()( devtools( (set, get) => ({ schedulesByYear: {}, loadedYears: {}, loadingYears: {}, fetchSchedules: async (year: number) => { const { loadedYears, loadingYears, schedulesByYear } = get(); // 이미 로드됨 if (loadedYears[year]) { return schedulesByYear[year] || []; } // 이미 로딩 중 (중복 호출 방지) if (loadingYears[year]) { return schedulesByYear[year] || []; } set( (state) => ({ loadingYears: { ...state.loadingYears, [year]: true }, }), false, 'fetchSchedules/start' ); try { const result = await getCalendarSchedules(year); const schedules = result.success && result.data ? result.data : []; set( (state) => ({ schedulesByYear: { ...state.schedulesByYear, [year]: schedules }, loadedYears: { ...state.loadedYears, [year]: true }, loadingYears: { ...state.loadingYears, [year]: false }, }), false, 'fetchSchedules/success' ); return schedules; } catch { // API 실패 시에도 loaded 처리 → 같은 연도 반복 호출 방지 // (폴백 상수 데이터 사용, 달력관리에서 등록 시 invalidateYear로 재시도) set( (state) => ({ schedulesByYear: { ...state.schedulesByYear, [year]: [] }, loadedYears: { ...state.loadedYears, [year]: true }, loadingYears: { ...state.loadingYears, [year]: false }, }), false, 'fetchSchedules/error' ); return []; } }, setSchedulesForYear: (year: number, schedules: CalendarSchedule[]) => { set( (state) => ({ schedulesByYear: { ...state.schedulesByYear, [year]: schedules }, loadedYears: { ...state.loadedYears, [year]: true }, loadingYears: { ...state.loadingYears, [year]: false }, }), false, 'setSchedulesForYear' ); }, invalidateYear: (year: number) => { set( (state) => { const newSchedules = { ...state.schedulesByYear }; const newLoaded = { ...state.loadedYears }; delete newSchedules[year]; delete newLoaded[year]; return { schedulesByYear: newSchedules, loadedYears: newLoaded }; }, false, 'invalidateYear' ); }, }), { name: 'CalendarScheduleStore' } ) );