"use client"; import { useState, useCallback, useEffect, useRef } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { cn } from "@/lib/utils"; import { LayoutDashboard, Target, ListChecks, Palette, Code2, Server, Zap, ChevronDown, ChevronRight, Github, MessageSquare, Image, Globe, FolderOpen, Inbox, Users, Eye, Plus, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { MCPConnectModal } from "./mcp-connect-modal"; import { ConnectSourcesModal } from "./connect-sources-modal"; import { OpenAIIcon, V0Icon, CursorIcon } from "@/components/icons/custom-icons"; interface ProjectSidebarProps { projectId: string; activeSection?: string; // From left rail: 'projects', 'inbox', 'clients', etc. workspace?: string; } // Map section IDs to display names const SECTION_NAMES: Record = { home: 'Home', product: 'Product', site: 'Site', pricing: 'Pricing', content: 'Content', social: 'Social', inbox: 'Inbox', people: 'People', settings: 'Settings', }; // Section-specific navigation items const SECTION_ITEMS: Record> = { home: [ // { title: "Vision", icon: Eye, href: "/vision" }, // Hidden per user request { title: "Context", icon: FolderOpen, href: "/context" }, ], product: [ { title: "Product Vision", icon: Target, href: "/plan" }, { title: "Progress", icon: ListChecks, href: "/progress" }, { title: "UI UX", icon: Palette, href: "/design" }, { title: "Code", icon: Code2, href: "/code" }, { title: "Deployment", icon: Server, href: "/deployment" }, { title: "Automation", icon: Zap, href: "/automation" }, ], site: [ { title: "Pages", icon: Globe, href: "/site/pages" }, { title: "Templates", icon: Palette, href: "/site/templates" }, { title: "Settings", icon: Target, href: "/site/settings" }, ], pricing: [ { title: "Plans", icon: Target, href: "/pricing/plans" }, { title: "Billing", icon: Code2, href: "/pricing/billing" }, { title: "Invoices", icon: ListChecks, href: "/pricing/invoices" }, ], content: [ { title: "Blog Posts", icon: Target, href: "/content/blog" }, { title: "Case Studies", icon: Code2, href: "/content/cases" }, { title: "Documentation", icon: ListChecks, href: "/content/docs" }, ], social: [ { title: "Posts", icon: MessageSquare, href: "/social/posts" }, { title: "Analytics", icon: Target, href: "/social/analytics" }, { title: "Schedule", icon: ListChecks, href: "/social/schedule" }, ], inbox: [ { title: "All", icon: Inbox, href: "/inbox/all" }, { title: "Unread", icon: Target, href: "/inbox/unread" }, { title: "Archived", icon: ListChecks, href: "/inbox/archived" }, ], people: [ { title: "Team", icon: Users, href: "/people/team" }, { title: "Clients", icon: Users, href: "/people/clients" }, { title: "Contacts", icon: Users, href: "/people/contacts" }, ], }; type ConnectionStatus = 'inactive' | 'connected' | 'live'; export function ProjectSidebar({ projectId, activeSection = 'projects', workspace = 'marks-account' }: ProjectSidebarProps) { const minWidth = 200; const maxWidth = 500; const [width, setWidth] = useState(minWidth); const [isResizing, setIsResizing] = useState(false); const [mcpModalOpen, setMcpModalOpen] = useState(false); const [connectModalOpen, setConnectModalOpen] = useState(false); const [isUserFlowsExpanded, setIsUserFlowsExpanded] = useState(true); const [isProductScreensExpanded, setIsProductScreensExpanded] = useState(true); const [getStartedCompleted, setGetStartedCompleted] = useState(false); const pathname = usePathname(); const sidebarRef = useRef(null); // Connection states - mock data, would come from API/database in production const [connectionStates, setConnectionStates] = useState<{ github: ConnectionStatus; openai: ConnectionStatus; v0: ConnectionStatus; cursor: ConnectionStatus; }>({ github: 'connected', openai: 'live', v0: 'inactive', cursor: 'connected', }); // Helper function to get icon classes based on connection status const getIconClasses = (status: ConnectionStatus) => { switch (status) { case 'inactive': return 'text-muted-foreground/40'; case 'connected': return 'text-muted-foreground'; case 'live': return 'text-foreground'; default: return 'text-muted-foreground/40'; } }; const startResizing = useCallback((e: React.MouseEvent) => { setIsResizing(true); e.preventDefault(); }, []); const stopResizing = useCallback(() => { setIsResizing(false); }, []); const resize = useCallback( (e: MouseEvent) => { if (isResizing) { const newWidth = e.clientX - 64; // Subtract left rail width (64px) if (newWidth >= minWidth && newWidth <= maxWidth) { setWidth(newWidth); } } }, [isResizing] ); useEffect(() => { window.addEventListener("mousemove", resize); window.addEventListener("mouseup", stopResizing); return () => { window.removeEventListener("mousemove", resize); window.removeEventListener("mouseup", stopResizing); }; }, [resize, stopResizing]); // Determine header title based on active section const isVAIPage = pathname?.includes('/v_ai_chat'); const headerTitle = isVAIPage ? 'v_ai' : (SECTION_NAMES[activeSection] || 'Home'); // Get section-specific items const currentSectionItems = SECTION_ITEMS[activeSection] || SECTION_ITEMS['home']; return ( <> ); }