Amba-Agent-App/lib/stores/uiStore.ts
2026-01-16 00:22:35 +03:00

86 lines
2.2 KiB
TypeScript

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<UiState>((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 <T>(
operation: () => Promise<T> | T
): Promise<T> => {
showGlobalLoader();
try {
const result = operation();
return await Promise.resolve(result);
} finally {
hideGlobalLoader();
}
};