import { useReducer, useEffect, useRef, useCallback } from "react"; import type { CategoryZoomData } from "../shared/types"; import { getCategoryZoom } from "../services/reportService"; import { useReportsPeriod } from "./useReportsPeriod"; interface State { zoomedCategoryId: number | null; rollupChildren: boolean; data: CategoryZoomData | null; isLoading: boolean; error: string | null; } type Action = | { type: "SET_CATEGORY"; payload: number | null } | { type: "TOGGLE_ROLLUP"; payload: boolean } | { type: "SET_LOADING"; payload: boolean } | { type: "SET_DATA"; payload: CategoryZoomData } | { type: "SET_ERROR"; payload: string }; const initialState: State = { zoomedCategoryId: null, rollupChildren: true, data: null, isLoading: false, error: null, }; function reducer(state: State, action: Action): State { switch (action.type) { case "SET_CATEGORY": return { ...state, zoomedCategoryId: action.payload, data: null }; case "TOGGLE_ROLLUP": return { ...state, rollupChildren: action.payload }; case "SET_LOADING": return { ...state, isLoading: action.payload }; case "SET_DATA": return { ...state, data: action.payload, isLoading: false, error: null }; case "SET_ERROR": return { ...state, error: action.payload, isLoading: false }; default: return state; } } export function useCategoryZoom() { const { from, to } = useReportsPeriod(); const [state, dispatch] = useReducer(reducer, initialState); const fetchIdRef = useRef(0); const fetch = useCallback( async (categoryId: number | null, includeChildren: boolean, dateFrom: string, dateTo: string) => { if (categoryId === null) return; const id = ++fetchIdRef.current; dispatch({ type: "SET_LOADING", payload: true }); try { const data = await getCategoryZoom(categoryId, dateFrom, dateTo, includeChildren); if (id !== fetchIdRef.current) return; dispatch({ type: "SET_DATA", payload: data }); } catch (e) { if (id !== fetchIdRef.current) return; dispatch({ type: "SET_ERROR", payload: e instanceof Error ? e.message : String(e) }); } }, [], ); useEffect(() => { fetch(state.zoomedCategoryId, state.rollupChildren, from, to); }, [fetch, state.zoomedCategoryId, state.rollupChildren, from, to]); const setCategory = useCallback((id: number | null) => { dispatch({ type: "SET_CATEGORY", payload: id }); }, []); const setRollupChildren = useCallback((flag: boolean) => { dispatch({ type: "TOGGLE_ROLLUP", payload: flag }); }, []); const refetch = useCallback(() => { fetch(state.zoomedCategoryId, state.rollupChildren, from, to); }, [fetch, state.zoomedCategoryId, state.rollupChildren, from, to]); return { ...state, setCategory, setRollupChildren, refetch, from, to }; }