import { create } from "zustand"; type ShowLoaderFn = (options?: { opaque?: boolean }) => void; type HideLoaderFn = () => void; type SetLoadingFn = (loading: boolean, options?: { opaque?: boolean }) => void; interface UiState { loadingCount: number; isLoading: boolean; isOpaque: boolean; showLoader: ShowLoaderFn; hideLoader: HideLoaderFn; setLoading: SetLoadingFn; setOpaque: (opaque: boolean) => void; resetLoading: () => void; } export const useUiStore = create((set) => ({ loadingCount: 0, isLoading: false, isOpaque: false, showLoader: (options) => set((state) => { const nextCount = state.loadingCount + 1; return { loadingCount: nextCount, isLoading: true, // Only set opaque if explicitly passed, otherwise keep current state isOpaque: options?.opaque ?? state.isOpaque, }; }), hideLoader: () => set((state) => { const nextCount = Math.max(state.loadingCount - 1, 0); return { loadingCount: nextCount, isLoading: nextCount > 0, // Reset opaque when no more loaders isOpaque: nextCount > 0 ? state.isOpaque : false, }; }), setLoading: (loading: boolean, options) => set(() => loading ? { loadingCount: 1, isLoading: true, isOpaque: options?.opaque ?? false, } : { loadingCount: 0, isLoading: false, isOpaque: false, } ), setOpaque: (opaque: boolean) => set({ isOpaque: opaque }), resetLoading: () => set({ loadingCount: 0, isLoading: false, isOpaque: false }), })); export const showGlobalLoader: ShowLoaderFn = (options) => { useUiStore.getState().showLoader(options); }; export const hideGlobalLoader: HideLoaderFn = () => { useUiStore.getState().hideLoader(); }; export const setGlobalLoading: SetLoadingFn = (loading: boolean, options) => { useUiStore.getState().setLoading(loading, options); }; export const withGlobalLoading = async ( operation: () => Promise | T ): Promise => { showGlobalLoader(); try { const result = operation(); return await Promise.resolve(result); } finally { hideGlobalLoader(); } };