import { Outlet, useNavigate, useLocation } from 'react-router'; import { AppShell, Sidebar, TopBar, } from '@cameleer/design-system'; import { LayoutDashboard, ShieldCheck, Server, Users, Settings, Shield, Building, ScrollText } from 'lucide-react'; import { useAuth } from '../auth/useAuth'; import { useScopes } from '../auth/useScopes'; import { useOrgStore } from '../auth/useOrganization'; import cameleerLogo from '@cameleer/design-system/assets/cameleer3-logo.svg'; function CameleerLogo() { return ( ); } function isActive(location: ReturnType, path: string) { return location.pathname === path || location.pathname.startsWith(path + '/'); } export function Layout() { const navigate = useNavigate(); const location = useLocation(); const { logout } = useAuth(); const scopes = useScopes(); const { username, organizations, currentOrgId } = useOrgStore(); const isVendor = scopes.has('platform:admin'); const isTenantAdmin = scopes.has('tenant:manage'); const onVendorRoute = location.pathname.startsWith('/vendor'); // Vendor on vendor routes: show only TENANTS. On tenant routes: show tenant portal too (for debugging). const showTenantPortal = isTenantAdmin && (!isVendor || !onVendorRoute); // Determine current org slug for server dashboard link const currentOrg = organizations.find((o) => o.id === currentOrgId); const serverDashboardHref = currentOrg?.slug ? `/t/${currentOrg.slug}/` : '/server/'; // Build breadcrumbs from path const segments = location.pathname.replace(/^\//, '').split('/').filter(Boolean); const breadcrumb = segments.map((seg) => { const label = seg.charAt(0).toUpperCase() + seg.slice(1).replace(/-/g, ' '); return { label }; }); const sidebar = ( {}}> } title="Cameleer SaaS" onClick={() => navigate(isVendor ? '/vendor/tenants' : '/tenant')} /> {/* Vendor console — only visible to platform:admin */} {isVendor && ( } label="Vendor" open={onVendorRoute} active={isActive(location, '/vendor')} onToggle={() => navigate('/vendor/tenants')} >
navigate('/vendor/tenants')} > Tenants
navigate('/vendor/audit')} > Audit Log
window.open(`${window.location.protocol}//${window.location.hostname}:3002`, '_blank', 'noopener')} > Identity (Logto)
)} {/* Tenant portal — visible to tenant admins; hidden for vendor on vendor routes */} {showTenantPortal && ( <> } label="Dashboard" open={false} active={location.pathname === '/tenant'} onToggle={() => navigate('/tenant')} > {null} } label="License" open={false} active={isActive(location, '/tenant/license')} onToggle={() => navigate('/tenant/license')} > {null} } label="SSO" open={false} active={isActive(location, '/tenant/sso')} onToggle={() => navigate('/tenant/sso')} > {null} } label="Team" open={false} active={isActive(location, '/tenant/team')} onToggle={() => navigate('/tenant/team')} > {null} } label="Audit Log" open={false} active={isActive(location, '/tenant/audit')} onToggle={() => navigate('/tenant/audit')} > {null} } label="Settings" open={false} active={isActive(location, '/tenant/settings')} onToggle={() => navigate('/tenant/settings')} > {null} )} {showTenantPortal && ( } label="Open Server Dashboard" onClick={() => window.open(serverDashboardHref, '_blank', 'noopener')} /> )}
); return ( ); }