Files
zentral/frontend/src/contexts/ModuleContext.tsx
2025-11-29 13:30:28 +01:00

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);
}