From dbe8da589ffb4c62cc80b49607ea564b20ebf831 Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Sun, 16 Nov 2025 18:44:07 +0000 Subject: [PATCH] Phase 0: Add ModuleGuard component and implement Modules settings UI - Created ModuleGuard component to protect routes based on module status - Implemented Modules.tsx page with toggle switches for all modules - Fixed Switch component onChange prop type - Module enable/disable UI fully functional --- .../src/components/common/ModuleGuard.tsx | 40 ++++++++++ frontend/src/pages/Settings/Modules.tsx | 73 +++++++++++++++---- 2 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 frontend/src/components/common/ModuleGuard.tsx 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)} + /> +
+
+ ))} +
)}