import { useReducer, useEffect, useRef, useCallback } from "react"; import type { MonthlyTrendItem, CategoryOverTimeData } from "../shared/types"; import { getMonthlyTrends, getCategoryOverTime } from "../services/reportService"; import { useReportsPeriod } from "./useReportsPeriod"; export type TrendsSubView = "global" | "byCategory"; interface State { subView: TrendsSubView; monthlyTrends: MonthlyTrendItem[]; categoryOverTime: CategoryOverTimeData; isLoading: boolean; error: string | null; } type Action = | { type: "SET_SUBVIEW"; payload: TrendsSubView } | { type: "SET_LOADING"; payload: boolean } | { type: "SET_TRENDS"; payload: MonthlyTrendItem[] } | { type: "SET_CATEGORY_OVER_TIME"; payload: CategoryOverTimeData } | { type: "SET_ERROR"; payload: string }; const initialState: State = { subView: "byCategory", monthlyTrends: [], categoryOverTime: { categories: [], data: [], colors: {}, categoryIds: {}, types: {} }, isLoading: false, error: null, }; function reducer(state: State, action: Action): State { switch (action.type) { case "SET_SUBVIEW": return { ...state, subView: action.payload }; case "SET_LOADING": return { ...state, isLoading: action.payload }; case "SET_TRENDS": return { ...state, monthlyTrends: action.payload, isLoading: false, error: null }; case "SET_CATEGORY_OVER_TIME": return { ...state, categoryOverTime: action.payload, isLoading: false, error: null }; case "SET_ERROR": return { ...state, error: action.payload, isLoading: false }; default: return state; } } export function useTrends() { const { from, to } = useReportsPeriod(); const [state, dispatch] = useReducer(reducer, initialState); const fetchIdRef = useRef(0); const fetch = useCallback(async (subView: TrendsSubView, dateFrom: string, dateTo: string) => { const id = ++fetchIdRef.current; dispatch({ type: "SET_LOADING", payload: true }); try { if (subView === "global") { const data = await getMonthlyTrends(dateFrom, dateTo); if (id !== fetchIdRef.current) return; dispatch({ type: "SET_TRENDS", payload: data }); } else { const data = await getCategoryOverTime(dateFrom, dateTo); if (id !== fetchIdRef.current) return; dispatch({ type: "SET_CATEGORY_OVER_TIME", payload: data }); } } catch (e) { if (id !== fetchIdRef.current) return; dispatch({ type: "SET_ERROR", payload: e instanceof Error ? e.message : String(e) }); } }, []); useEffect(() => { fetch(state.subView, from, to); }, [fetch, state.subView, from, to]); const setSubView = useCallback((sv: TrendsSubView) => { dispatch({ type: "SET_SUBVIEW", payload: sv }); }, []); return { ...state, setSubView, from, to }; }