import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useRef } from 'react'; import type { GlobalStateStoreType } from './GlobalStateStore.types'; import { GetGlobalState, GlobalStateStore } from './GlobalStateStore'; interface GlobalStateStoreContextValue { fetchData: (url?: string) => Promise; getState: () => GlobalStateStoreType; refetch: () => Promise; } const GlobalStateStoreContext = createContext(null); interface GlobalStateStoreProviderProps { apiURL?: string; autoFetch?: boolean; children: ReactNode; fetchOnMount?: boolean; throttleMs?: number; } export function GlobalStateStoreProvider({ apiURL, autoFetch = true, children, fetchOnMount = true, throttleMs = 0, }: GlobalStateStoreProviderProps) { const lastFetchTime = useRef(0); const fetchInProgress = useRef(false); const mounted = useRef(false); const throttledFetch = useCallback( async (url?: string) => { const now = Date.now(); const timeSinceLastFetch = now - lastFetchTime.current; if (fetchInProgress.current) { return; } if (throttleMs > 0 && timeSinceLastFetch < throttleMs) { return; } try { fetchInProgress.current = true; lastFetchTime.current = now; await GlobalStateStore.getState().fetchData(url); } finally { fetchInProgress.current = false; } }, [throttleMs] ); const refetch = useCallback(async () => { await throttledFetch(); }, [throttledFetch]); useEffect(() => { if (apiURL) { GlobalStateStore.getState().setApiURL(apiURL); } }, [apiURL]); useEffect(() => { if (!mounted.current) { mounted.current = true; if (autoFetch && fetchOnMount) { throttledFetch(apiURL).catch((e) => { console.error('Failed to fetch on mount:', e); }); } } }, [apiURL, autoFetch, fetchOnMount, throttledFetch]); const context = useMemo(() => { return { fetchData: throttledFetch, getState: GetGlobalState, refetch, }; }, [throttledFetch, refetch]); return ( {children} ); } // eslint-disable-next-line react-refresh/only-export-components export function useGlobalStateStoreContext(): GlobalStateStoreContextValue { const context = useContext(GlobalStateStoreContext); if (!context) { throw new Error('useGlobalStateStoreContext must be used within GlobalStateStoreProvider'); } return context; }