183 lines
4.8 KiB
TypeScript
183 lines
4.8 KiB
TypeScript
import { createContext, useContext, useCallback, type ReactNode } from "react";
|
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { moduleService } from "../services/moduleService";
|
|
import type {
|
|
ModuleDto,
|
|
EnableModuleRequest,
|
|
SubscriptionDto,
|
|
} from "../types/module";
|
|
|
|
// ==================== TYPES ====================
|
|
|
|
export interface ModuleContextValue {
|
|
/** Lista di tutti i moduli disponibili */
|
|
modules: ModuleDto[];
|
|
/** Lista dei moduli attualmente attivi */
|
|
activeModules: ModuleDto[];
|
|
/** Codici dei moduli attivi (per filtro veloce) */
|
|
activeModuleCodes: string[];
|
|
/** Stato di caricamento */
|
|
isLoading: boolean;
|
|
/** Errore di caricamento */
|
|
error: Error | null;
|
|
/** Verifica se un modulo è abilitato */
|
|
isModuleEnabled: (code: string) => boolean;
|
|
/** Ottiene un modulo per codice */
|
|
getModule: (code: string) => ModuleDto | undefined;
|
|
/** Attiva un modulo */
|
|
enableModule: (
|
|
code: string,
|
|
request: EnableModuleRequest,
|
|
) => Promise<SubscriptionDto>;
|
|
/** Disattiva un modulo */
|
|
disableModule: (code: string) => Promise<void>;
|
|
/** Ricarica i dati dei moduli */
|
|
refreshModules: () => Promise<void>;
|
|
}
|
|
|
|
const ModuleContext = createContext<ModuleContextValue | null>(null);
|
|
|
|
// ==================== PROVIDER ====================
|
|
|
|
interface ModuleProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export function ModuleProvider({ children }: ModuleProviderProps) {
|
|
const queryClient = useQueryClient();
|
|
|
|
// Query per tutti i moduli
|
|
const {
|
|
data: modules = [],
|
|
isLoading: isLoadingModules,
|
|
error: modulesError,
|
|
} = useQuery({
|
|
queryKey: ["modules"],
|
|
queryFn: moduleService.getAll,
|
|
staleTime: 5 * 60 * 1000, // 5 minuti
|
|
refetchOnWindowFocus: false,
|
|
});
|
|
|
|
// Query per moduli attivi
|
|
const {
|
|
data: activeModules = [],
|
|
isLoading: isLoadingActive,
|
|
error: activeError,
|
|
} = useQuery({
|
|
queryKey: ["modules", "active"],
|
|
queryFn: moduleService.getActive,
|
|
staleTime: 5 * 60 * 1000,
|
|
refetchOnWindowFocus: false,
|
|
});
|
|
|
|
// Calcola i codici dei moduli attivi
|
|
const activeModuleCodes = activeModules.map((m) => m.code);
|
|
|
|
// Verifica se un modulo è abilitato
|
|
const isModuleEnabled = useCallback(
|
|
(code: string): boolean => {
|
|
return activeModuleCodes.includes(code);
|
|
},
|
|
[activeModuleCodes],
|
|
);
|
|
|
|
// Ottiene un modulo per codice
|
|
const getModule = useCallback(
|
|
(code: string): ModuleDto | undefined => {
|
|
return modules.find((m) => m.code === code);
|
|
},
|
|
[modules],
|
|
);
|
|
|
|
// Attiva un modulo
|
|
const enableModule = useCallback(
|
|
async (
|
|
code: string,
|
|
request: EnableModuleRequest,
|
|
): Promise<SubscriptionDto> => {
|
|
const subscription = await moduleService.enable(code, request);
|
|
// Invalida le query per ricaricare i dati
|
|
await queryClient.invalidateQueries({ queryKey: ["modules"] });
|
|
return subscription;
|
|
},
|
|
[queryClient],
|
|
);
|
|
|
|
// Disattiva un modulo
|
|
const disableModule = useCallback(
|
|
async (code: string): Promise<void> => {
|
|
await moduleService.disable(code);
|
|
// Invalida le query per ricaricare i dati
|
|
await queryClient.invalidateQueries({ queryKey: ["modules"] });
|
|
},
|
|
[queryClient],
|
|
);
|
|
|
|
// Ricarica i dati dei moduli
|
|
const refreshModules = useCallback(async (): Promise<void> => {
|
|
await queryClient.invalidateQueries({ queryKey: ["modules"] });
|
|
}, [queryClient]);
|
|
|
|
const value: ModuleContextValue = {
|
|
modules,
|
|
activeModules,
|
|
activeModuleCodes,
|
|
isLoading: isLoadingModules || isLoadingActive,
|
|
error: modulesError || activeError,
|
|
isModuleEnabled,
|
|
getModule,
|
|
enableModule,
|
|
disableModule,
|
|
refreshModules,
|
|
};
|
|
|
|
return (
|
|
<ModuleContext.Provider value={value}>{children}</ModuleContext.Provider>
|
|
);
|
|
}
|
|
|
|
// ==================== HOOKS ====================
|
|
|
|
/**
|
|
* Hook per accedere al context dei moduli
|
|
*/
|
|
export function useModules(): ModuleContextValue {
|
|
const context = useContext(ModuleContext);
|
|
if (!context) {
|
|
throw new Error("useModules must be used within a ModuleProvider");
|
|
}
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Hook per verificare se un singolo modulo è abilitato
|
|
*/
|
|
export function useModuleEnabled(code: string): boolean {
|
|
const { isModuleEnabled } = useModules();
|
|
return isModuleEnabled(code);
|
|
}
|
|
|
|
/**
|
|
* Hook per ottenere solo i moduli attivi
|
|
*/
|
|
export function useActiveModules(): ModuleDto[] {
|
|
const { activeModules } = useModules();
|
|
return activeModules;
|
|
}
|
|
|
|
/**
|
|
* Hook per ottenere i codici dei moduli attivi
|
|
*/
|
|
export function useActiveModuleCodes(): string[] {
|
|
const { activeModuleCodes } = useModules();
|
|
return activeModuleCodes;
|
|
}
|
|
|
|
/**
|
|
* Hook per ottenere un modulo specifico
|
|
*/
|
|
export function useModule(code: string): ModuleDto | undefined {
|
|
const { getModule } = useModules();
|
|
return getModule(code);
|
|
}
|