import { useEffect, useState } from 'react'; import { Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom'; import { AnimatePresence, motion } from 'framer-motion'; import { useStore } from '@/store/useStore'; import { Sidebar } from '@/components/layout/Sidebar'; import { LoginScreen } from '@/components/layout/LoginScreen'; import { Dashboard } from '@/components/modules/Dashboard'; import { Oracle } from '@/components/modules/Oracle'; import { Sentinel } from '@/components/modules/Sentinel'; import { Inventory } from '@/components/modules/Inventory'; import { Settings } from '@/components/modules/Settings'; import { Catalyst } from '@/components/modules/Catalyst'; import { CRM } from '@/components/modules/CRM'; import { NotificationCenter } from '@/components/layout/NotificationCenter'; import { useCrmBootstrap } from '@/hooks/useCrmBootstrap'; import type { ModuleId } from '@/types'; import AdminPage from '@/app/admin/page'; import { clearVelocityToken, getVelocityMe, getVelocityToken, isAdminRole, normalizeVelocityRole, resolveVelocityFirstName, } from '@/lib/velocityPlatformClient'; import { MoreVertical, LogOut, Settings2 } from 'lucide-react'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; // ── Route map ───────────────────────────────────────────────────────────────── // Single source of truth: module id → URL path → page title → component export const MODULE_ROUTES: Array<{ id: ModuleId; path: string; title: string; component: React.ComponentType; adminOnly?: boolean; }> = [ { id: 'dashboard', path: '/dashboard', title: 'Dashboard', component: Dashboard }, { id: 'oracle', path: '/oracle', title: 'The Oracle', component: Oracle }, { id: 'sentinel', path: '/sentinel', title: 'The Sentinel', component: Sentinel }, { id: 'inventory', path: '/inventory', title: 'Inventory', component: Inventory }, { id: 'catalyst', path: '/catalyst', title: 'The Catalyst', component: Catalyst }, { id: 'crm', path: '/crm', title: 'CRM', component: CRM }, { id: 'settings', path: '/settings', title: 'Settings', component: Settings }, { id: 'admin', path: '/admin', title: 'Admin', component: AdminPage, adminOnly: true }, ]; export const PATH_TO_MODULE = Object.fromEntries( MODULE_ROUTES.map((r) => [r.path, r.id]) ) as Record; // ── Protected Route guard ───────────────────────────────────────────────────── function ProtectedRoute({ children }: { children: React.ReactNode }) { const { isAuthenticated } = useStore(); if (!isAuthenticated) return ; return <>{children}; } // ── Sync URL → Zustand activeModule ────────────────────────────────────────── // This keeps the Zustand store in sync with the URL so existing module // components that read `activeModule` from the store continue to work. function RouteModuleSync() { const { pathname } = useLocation(); const { setActiveModule } = useStore(); useEffect(() => { const moduleId = PATH_TO_MODULE[pathname]; if (moduleId) setActiveModule(moduleId); }, [pathname, setActiveModule]); return null; } // ── Main authenticated layout ───────────────────────────────────────────────── function MainLayout() { const { activeModule, setActiveModule, sidebarExpanded, logout, user } = useStore(); useCrmBootstrap(); const navigate = useNavigate(); const location = useLocation(); const availableRoutes = MODULE_ROUTES.filter((route) => !route.adminOnly || isAdminRole(user?.role)); // Current route title const currentRoute = availableRoutes.find((r) => r.path === location.pathname); const pageTitle = currentRoute?.title ?? 'Velocity'; const roleLabel = formatRoleLabel(user?.role); const userLabel = user?.name?.trim() || user?.fullName?.trim() || user?.email?.trim() || user?.id || 'Authenticated User'; const initials = userLabel .split(/\s+/) .filter(Boolean) .slice(0, 2) .map((part) => part[0]?.toUpperCase() ?? '') .join('') || 'AU'; // Navigate to settings from dropdown (keeps router in sync) const goToSettings = () => { setActiveModule('settings'); navigate('/settings'); }; return (
{/* Sync URL → store */} {/* Sidebar */} {/* Main Content Area */} {/* Top Bar */}

{pageTitle}

Project Velocity · v.1.1

{/* User Profile */}
{/* Active Notification Center */}

{userLabel}

{roleLabel}

{initials}
Settings { clearVelocityToken(); logout(); }} > Log out
{/* Module Content — animated on route change */}
{/* Nested module routes rendered here */} {availableRoutes.map(({ path, component: Component, adminOnly }) => ( : } /> ))} {/* Default: redirect / → /dashboard */} } /> {/* Catch-all: any unknown path → dashboard */} } />
); } // ── Root App ────────────────────────────────────────────────────────────────── function App() { const { isAuthenticated, login, logout, user } = useStore(); const [authBootstrapped, setAuthBootstrapped] = useState(false); useEffect(() => { let cancelled = false; const token = getVelocityToken(); if (!token) { setAuthBootstrapped(true); if (isAuthenticated) { logout(); } return () => { cancelled = true; }; } void getVelocityMe() .then((me) => { if (cancelled) return; const resolvedEmail = me.email?.trim() || user?.email?.trim() || undefined; const resolvedFullName = me.full_name?.trim() || user?.fullName?.trim() || undefined; login({ id: me.user_id, name: resolveVelocityFirstName({ ...me, email: resolvedEmail ?? null, full_name: resolvedFullName ?? null, }), fullName: resolvedFullName, email: resolvedEmail, avatar: me.avatar_url?.trim() || user?.avatar?.trim() || undefined, role: normalizeVelocityRole(me.role), }); setAuthBootstrapped(true); }) .catch(() => { if (cancelled) return; clearVelocityToken(); logout(); setAuthBootstrapped(true); }); return () => { cancelled = true; }; }, [isAuthenticated, login, logout]); useEffect(() => { if (!isAuthenticated || !authBootstrapped) { return; } let cancelled = false; void getVelocityMe() .then((me) => { if (cancelled) return; const resolvedEmail = me.email?.trim() || user?.email?.trim() || undefined; const resolvedFullName = me.full_name?.trim() || user?.fullName?.trim() || undefined; login({ id: me.user_id, name: resolveVelocityFirstName({ ...me, email: resolvedEmail ?? null, full_name: resolvedFullName ?? null, }), fullName: resolvedFullName, email: resolvedEmail, avatar: me.avatar_url?.trim() || user?.avatar?.trim() || undefined, role: normalizeVelocityRole(me.role), }); }) .catch(() => { if (cancelled) return; clearVelocityToken(); logout(); }); return () => { cancelled = true; }; }, [authBootstrapped, isAuthenticated, login, logout, user]); if (!authBootstrapped) { return (
Validating live Velocity session...
); } return ( {!isAuthenticated ? ( } /> } /> ) : ( } /> )} ); } export default App; function formatRoleLabel(role: string | undefined) { const normalized = normalizeVelocityRole(role); if (!normalized) { return 'Authenticated User'; } return normalized .toLowerCase() .split('_') .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(' '); }