'use client'; import React, { useState, useRef, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { cn } from '../utils/cn'; import { RocketIcon, ChartIcon, TrendingUpIcon, RobotIcon, SettingsIcon, } from '../components/icons'; // --- Types --- export interface NavItem { href: string; label: string; icon: React.ElementType; } export interface User { id: string; name?: string | null; email?: string | null; image?: string | null; } export interface Team { id: string; name: string; } export interface TeamMember { teamId: string; team: Team; } export interface PlatformShellProps { children: React.ReactNode; user: User | null; teams?: TeamMember[]; overallScore?: number | null; activePage?: string; pathname?: string; onNavigate?: (href: string) => void; onSignOut?: () => void; onSwitchTeam?: (teamId: string | 'personal') => void; logoUrl?: string; navItems?: NavItem[]; LinkComponent?: React.ElementType; } // --- Internal Components --- function NavItemComponent({ href, label, icon: Icon, isActive, onClick, LinkComponent = 'a', }: NavItem & { isActive: boolean; onClick?: (e: React.MouseEvent) => void; LinkComponent?: any; }) { const Component = LinkComponent; return ( {label} {isActive && ( )} ); } function UserMenu({ user, teams = [], currentTeamId, onSwitchTeam, onSignOut, }: { user: User; teams: TeamMember[]; currentTeamId: string | 'personal'; onSwitchTeam?: (teamId: string | 'personal') => void; onSignOut?: () => void; }) { const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); useEffect(() => { function handleClickOutside(event: MouseEvent) { if ( dropdownRef.current && !dropdownRef.current.contains(event.target as Node) ) { setIsOpen(false); } } document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const currentWorkspaceName = currentTeamId === 'personal' ? 'Personal Workspace' : teams.find((t) => t.teamId === currentTeamId)?.team.name || 'Team Workspace'; return ( setIsOpen(!isOpen)} className="flex items-center gap-2 p-1.5 rounded-xl hover:bg-slate-800/50 transition-all border border-transparent hover:border-slate-700/50" > {user.image ? ( ) : ( {user.name?.[0] || user.email?.[0]} )} {user.name || user.email?.split('@')[0]} {currentWorkspaceName} {isOpen && ( {user.name} {user.email} Workspaces { onSwitchTeam?.('personal'); setIsOpen(false); }} className={cn( 'w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors', currentTeamId === 'personal' ? 'bg-cyan-500/10 text-cyan-400' : 'text-slate-400 hover:bg-slate-800 hover:text-white' )} > P Personal {teams.map((t) => ( { onSwitchTeam?.(t.teamId); setIsOpen(false); }} className={cn( 'w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors', currentTeamId === t.teamId ? 'bg-purple-500/10 text-purple-400' : 'text-slate-400 hover:bg-slate-800 hover:text-white' )} > {t.team.name[0]} {t.team.name} ))} Sign out )} ); } // --- Main Shell --- export function PlatformShell({ children, user, teams = [], overallScore, activePage, pathname = '', onNavigate, onSignOut, onSwitchTeam, logoUrl = '/logo-text-transparent-dark-theme.png', navItems = [ { href: '/dashboard', label: 'Dashboard', icon: RocketIcon }, { href: '/strategy', label: 'Scan Strategy', icon: SettingsIcon }, { href: '/trends', label: 'Trends Explorer', icon: TrendingUpIcon }, { href: '/map', label: 'Codebase Map', icon: RobotIcon }, { href: '/metrics', label: 'Methodology', icon: ChartIcon }, ], LinkComponent = 'a', }: PlatformShellProps) { const [currentTeamId, setCurrentTeamId] = useState( 'personal' ); const handleSwitchTeam = (teamId: string | 'personal') => { setCurrentTeamId(teamId); onSwitchTeam?.(teamId); }; const Sidebar = () => ( ); const Navbar = () => ( {activePage || 'Dashboard'} {user && ( )} ); return ( {user && } {user && } {user && ( <> > )} {children} ); }
{user.name || user.email?.split('@')[0]}
{currentWorkspaceName}
{user.name}
{user.email}
Workspaces
{activePage || 'Dashboard'}