import { useReducer, useCallback, useEffect, useRef } from "react"; import type { CartesSnapshot, CartesKpiPeriodMode } from "../shared/types"; import { getCartesSnapshot } from "../services/reportService"; import { defaultReferencePeriod } from "../utils/referencePeriod"; export const CARTES_PERIOD_MODE_STORAGE_KEY = "reports-cartes-period-mode"; interface State { year: number; month: number; mode: CartesKpiPeriodMode; snapshot: CartesSnapshot | null; isLoading: boolean; error: string | null; } type Action = | { type: "SET_REFERENCE_PERIOD"; payload: { year: number; month: number } } | { type: "SET_MODE"; payload: CartesKpiPeriodMode } | { type: "SET_LOADING"; payload: boolean } | { type: "SET_SNAPSHOT"; payload: CartesSnapshot } | { type: "SET_ERROR"; payload: string }; /** * Re-exported so older imports keep working. New code should import * `defaultReferencePeriod` from `../utils/referencePeriod`. */ export const defaultCartesReferencePeriod = defaultReferencePeriod; /** * Read the persisted period mode from localStorage. Unrecognised values fall * back to "month" so a corrupted/legacy key never breaks the page. */ export function readCartesPeriodMode( storageKey: string = CARTES_PERIOD_MODE_STORAGE_KEY, fallback: CartesKpiPeriodMode = "month", ): CartesKpiPeriodMode { if (typeof localStorage === "undefined") return fallback; const saved = localStorage.getItem(storageKey); return saved === "month" || saved === "ytd" ? saved : fallback; } const defaultRef = defaultReferencePeriod(); const initialState: State = { year: defaultRef.year, month: defaultRef.month, mode: "month", snapshot: null, isLoading: false, error: null, }; function reducer(state: State, action: Action): State { switch (action.type) { case "SET_REFERENCE_PERIOD": return { ...state, year: action.payload.year, month: action.payload.month }; case "SET_MODE": return { ...state, mode: action.payload }; case "SET_LOADING": return { ...state, isLoading: action.payload }; case "SET_SNAPSHOT": return { ...state, snapshot: action.payload, isLoading: false, error: null }; case "SET_ERROR": return { ...state, error: action.payload, isLoading: false }; default: return state; } } export function useCartes() { const [state, dispatch] = useReducer(reducer, initialState, (init) => ({ ...init, mode: readCartesPeriodMode(), })); const fetchIdRef = useRef(0); const fetch = useCallback(async (year: number, month: number, mode: CartesKpiPeriodMode) => { const id = ++fetchIdRef.current; dispatch({ type: "SET_LOADING", payload: true }); try { const snapshot = await getCartesSnapshot(year, month, mode); if (id !== fetchIdRef.current) return; dispatch({ type: "SET_SNAPSHOT", payload: snapshot }); } catch (e) { if (id !== fetchIdRef.current) return; dispatch({ type: "SET_ERROR", payload: e instanceof Error ? e.message : String(e) }); } }, []); useEffect(() => { fetch(state.year, state.month, state.mode); }, [fetch, state.year, state.month, state.mode]); const setReferencePeriod = useCallback((year: number, month: number) => { dispatch({ type: "SET_REFERENCE_PERIOD", payload: { year, month } }); }, []); const setMode = useCallback((mode: CartesKpiPeriodMode) => { if (typeof localStorage !== "undefined") { localStorage.setItem(CARTES_PERIOD_MODE_STORAGE_KEY, mode); } dispatch({ type: "SET_MODE", payload: mode }); }, []); return { ...state, setReferencePeriod, setMode, }; }