diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 86d94459..0d09dbb0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,6 +4,7 @@ import { HelmetProvider } from "react-helmet-async"; import AppLayout from "./layout/AppLayout"; import { ScrollToTop } from "./components/common/ScrollToTop"; import ProtectedRoute from "./components/auth/ProtectedRoute"; +import ModuleGuard from "./components/common/ModuleGuard"; import GlobalErrorDisplay from "./components/common/GlobalErrorDisplay"; import LoadingStateMonitor from "./components/common/LoadingStateMonitor"; @@ -133,90 +134,122 @@ export default function App() { {/* Planner Module */} - + + + } /> - + + + } /> - + + + } /> - + + + } /> {/* Writer Module */} + - + + } /> + - + + } /> {/* Writer Content Routes - Order matters: list route must come before detail route */} + - + + } /> {/* Content detail view - matches /writer/content/:id (e.g., /writer/content/10) */} + - + + } /> } /> + - + + } /> + - + + } /> {/* Thinker Module */} + - + + } /> + - + + } /> + - + + } /> + - + + } /> + - + + } /> + - + + } /> {/* Billing Module */} @@ -256,8 +289,10 @@ export default function App() { {/* Other Pages */} + - + + } /> diff --git a/frontend/src/layout/AppSidebar.tsx b/frontend/src/layout/AppSidebar.tsx index 10f3bee0..549fe0c3 100644 --- a/frontend/src/layout/AppSidebar.tsx +++ b/frontend/src/layout/AppSidebar.tsx @@ -20,6 +20,8 @@ import { useSidebar } from "../context/SidebarContext"; import SidebarWidget from "./SidebarWidget"; import { APP_VERSION } from "../config/version"; import { useAuthStore } from "../store/authStore"; +import { useSettingsStore } from "../store/settingsStore"; +import { isModuleEnabled } from "../config/modules.config"; import ApiStatusIndicator from "../components/sidebar/ApiStatusIndicator"; type NavItem = { @@ -38,12 +40,19 @@ const AppSidebar: React.FC = () => { const { isExpanded, isMobileOpen, isHovered, setIsHovered } = useSidebar(); const location = useLocation(); const { user } = useAuthStore(); + const { moduleEnableSettings, isModuleEnabled: checkModuleEnabled } = useSettingsStore(); // Show admin menu only for users in aws-admin account const isAwsAdminAccount = Boolean( user?.account?.slug === 'aws-admin' || user?.role === 'developer' // Also show for developers as fallback ); + + // Helper to check if module is enabled + const moduleEnabled = (moduleName: string): boolean => { + if (!moduleEnableSettings) return true; // Default to enabled if not loaded + return checkModuleEnabled(moduleName); + }; const [openSubmenu, setOpenSubmenu] = useState<{ sectionIndex: number; @@ -60,77 +69,98 @@ const AppSidebar: React.FC = () => { ); // Define menu sections with useMemo to prevent recreation on every render - const menuSections: MenuSection[] = useMemo(() => [ - { - label: "OVERVIEW", - items: [ - { - icon: , - name: "Dashboard", - path: "/", - }, - { - icon: , - name: "Industry / Sectors", - path: "/reference/industries", - }, - ], - }, - { - label: "WORKFLOWS", - items: [ - { - icon: , - name: "Setup", - subItems: [ - { name: "Sites", path: "/settings/sites" }, - { name: "Keywords Opportunities", path: "/planner/keyword-opportunities" }, - ], - }, - { - icon: , - name: "Planner", - subItems: [ - { name: "Dashboard", path: "/planner" }, - { name: "Keywords", path: "/planner/keywords" }, - { name: "Clusters", path: "/planner/clusters" }, - { name: "Ideas", path: "/planner/ideas" }, - ], - }, - { - icon: , - name: "Writer", - subItems: [ - { name: "Dashboard", path: "/writer" }, - { name: "Tasks", path: "/writer/tasks" }, - { name: "Content", path: "/writer/content" }, - { name: "Images", path: "/writer/images" }, - { name: "Published", path: "/writer/published" }, - ], - }, - { - icon: , - name: "Thinker", - subItems: [ - { name: "Dashboard", path: "/thinker" }, - { name: "Prompts", path: "/thinker/prompts" }, - { name: "Author Profiles", path: "/thinker/author-profiles" }, - { name: "Strategies", path: "/thinker/strategies" }, - { name: "Image Testing", path: "/thinker/image-testing" }, - ], - }, - { - icon: , - name: "Automation", - path: "/automation", - }, - { - icon: , - name: "Schedules", - path: "/schedules", - }, - ], - }, + // Filter out disabled modules based on module enable settings + const menuSections: MenuSection[] = useMemo(() => { + const workflowItems: NavItem[] = [ + { + icon: , + name: "Setup", + subItems: [ + { name: "Sites", path: "/settings/sites" }, + { name: "Keywords Opportunities", path: "/planner/keyword-opportunities" }, + ], + }, + ]; + + // Add Planner if enabled + if (moduleEnabled('planner')) { + workflowItems.push({ + icon: , + name: "Planner", + subItems: [ + { name: "Dashboard", path: "/planner" }, + { name: "Keywords", path: "/planner/keywords" }, + { name: "Clusters", path: "/planner/clusters" }, + { name: "Ideas", path: "/planner/ideas" }, + ], + }); + } + + // Add Writer if enabled + if (moduleEnabled('writer')) { + workflowItems.push({ + icon: , + name: "Writer", + subItems: [ + { name: "Dashboard", path: "/writer" }, + { name: "Tasks", path: "/writer/tasks" }, + { name: "Content", path: "/writer/content" }, + { name: "Images", path: "/writer/images" }, + { name: "Published", path: "/writer/published" }, + ], + }); + } + + // Add Thinker if enabled + if (moduleEnabled('thinker')) { + workflowItems.push({ + icon: , + name: "Thinker", + subItems: [ + { name: "Dashboard", path: "/thinker" }, + { name: "Prompts", path: "/thinker/prompts" }, + { name: "Author Profiles", path: "/thinker/author-profiles" }, + { name: "Strategies", path: "/thinker/strategies" }, + { name: "Image Testing", path: "/thinker/image-testing" }, + ], + }); + } + + // Add Automation if enabled + if (moduleEnabled('automation')) { + workflowItems.push({ + icon: , + name: "Automation", + path: "/automation", + }); + } + + workflowItems.push({ + icon: , + name: "Schedules", + path: "/schedules", + }); + + return [ + { + label: "OVERVIEW", + items: [ + { + icon: , + name: "Dashboard", + path: "/", + }, + { + icon: , + name: "Industry / Sectors", + path: "/reference/industries", + }, + ], + }, + { + label: "WORKFLOWS", + items: workflowItems, + }, { label: "ACCOUNT & SETTINGS", items: [ @@ -165,7 +195,8 @@ const AppSidebar: React.FC = () => { }, ], }, - ], []); + ]; + }, [moduleEnableSettings, moduleEnabled]); // Admin section - only shown for users in aws-admin account const adminSection: MenuSection = useMemo(() => ({