diff --git a/frontend/src/components/common/ModuleGuard.tsx b/frontend/src/components/common/ModuleGuard.tsx new file mode 100644 index 00000000..02bd0ab5 --- /dev/null +++ b/frontend/src/components/common/ModuleGuard.tsx @@ -0,0 +1,40 @@ +import { ReactNode, useEffect } from 'react'; +import { Navigate } from 'react-router-dom'; +import { useSettingsStore } from '../../store/settingsStore'; +import { isModuleEnabled } from '../../config/modules.config'; + +interface ModuleGuardProps { + module: string; + children: ReactNode; + redirectTo?: string; +} + +/** + * ModuleGuard - Protects routes based on module enable status + * Redirects to settings page if module is disabled + */ +export default function ModuleGuard({ module, children, redirectTo = '/settings/modules' }: ModuleGuardProps) { + const { moduleEnableSettings, loadModuleEnableSettings, loading } = useSettingsStore(); + + useEffect(() => { + // Load module enable settings if not already loaded + if (!moduleEnableSettings && !loading) { + loadModuleEnableSettings(); + } + }, [moduleEnableSettings, loading, loadModuleEnableSettings]); + + // While loading, show children (optimistic rendering) + if (loading || !moduleEnableSettings) { + return <>{children}>; + } + + // Check if module is enabled + const enabled = isModuleEnabled(module, moduleEnableSettings as any); + + if (!enabled) { + return ; + } + + return <>{children}>; +} + diff --git a/frontend/src/pages/Settings/Modules.tsx b/frontend/src/pages/Settings/Modules.tsx index 16276b8a..7952be3b 100644 --- a/frontend/src/pages/Settings/Modules.tsx +++ b/frontend/src/pages/Settings/Modules.tsx @@ -1,36 +1,48 @@ -import { useState, useEffect } from 'react'; +import { useEffect } from 'react'; import PageMeta from '../../components/common/PageMeta'; import { useToast } from '../../components/ui/toast/ToastContainer'; -import { fetchAPI } from '../../services/api'; +import { useSettingsStore } from '../../store/settingsStore'; +import { MODULES } from '../../config/modules.config'; import { Card } from '../../components/ui/card'; +import Switch from '../../components/form/switch/Switch'; export default function ModuleSettings() { const toast = useToast(); - const [settings, setSettings] = useState([]); - const [loading, setLoading] = useState(true); + const { + moduleEnableSettings, + loadModuleEnableSettings, + updateModuleEnableSettings, + loading, + } = useSettingsStore(); useEffect(() => { - loadSettings(); - }, []); + loadModuleEnableSettings(); + }, [loadModuleEnableSettings]); - const loadSettings = async () => { + const handleToggle = async (moduleName: string, enabled: boolean) => { try { - setLoading(true); - const response = await fetchAPI('/v1/system/settings/modules/'); - setSettings(response.results || []); + const enabledKey = `${moduleName}_enabled` as keyof typeof moduleEnableSettings; + await updateModuleEnableSettings({ + [enabledKey]: enabled, + } as any); + toast.success(`${MODULES[moduleName]?.name || moduleName} ${enabled ? 'enabled' : 'disabled'}`); } catch (error: any) { - toast.error(`Failed to load module settings: ${error.message}`); - } finally { - setLoading(false); + toast.error(`Failed to update module: ${error.message}`); } }; + const getModuleEnabled = (moduleName: string): boolean => { + if (!moduleEnableSettings) return true; // Default to enabled + const enabledKey = `${moduleName}_enabled` as keyof typeof moduleEnableSettings; + return moduleEnableSettings[enabledKey] !== false; + }; + return ( Module Settings - Module-specific configuration + Enable or disable modules for your account {loading ? ( @@ -39,7 +51,38 @@ export default function ModuleSettings() { ) : ( - Module settings management interface coming soon. + + {Object.entries(MODULES).map(([key, module]) => ( + + + {module.icon} + + + {module.name} + + {module.description && ( + + {module.description} + + )} + + + + + {getModuleEnabled(key) ? 'Enabled' : 'Disabled'} + + handleToggle(key, enabled)} + /> + + + ))} + )}
Module-specific configuration
Enable or disable modules for your account
Module settings management interface coming soon.
+ {module.description} +