diff --git a/apps/rowboat/app/projects/layout/components/sidebar.tsx b/apps/rowboat/app/projects/layout/components/sidebar.tsx index 5f6cf324..8dc1f730 100644 --- a/apps/rowboat/app/projects/layout/components/sidebar.tsx +++ b/apps/rowboat/app/projects/layout/components/sidebar.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { Tooltip } from "@heroui/react"; +import { Tooltip, Modal, ModalContent, ModalHeader, ModalBody, useDisclosure } from "@heroui/react"; import { UserButton } from "@/app/lib/components/user_button"; import { SettingsIcon, @@ -15,10 +15,12 @@ import { Sun, HelpCircle } from "lucide-react"; -import { getProjectConfig } from "@/app/actions/project_actions"; +import { getProjectConfig, listProjects } from "@/app/actions/project_actions"; import { useTheme } from "@/app/providers/theme-provider"; import { USE_PRODUCT_TOUR } from '@/app/lib/feature_flags'; import { useHelpModal } from "@/app/providers/help-modal-provider"; +import { Project } from "@/app/lib/types/project_types"; +import { z } from "zod"; interface SidebarProps { projectId?: string; @@ -34,9 +36,12 @@ const COLLAPSED_ICON_SIZE = 20; // DO NOT CHANGE THIS export default function Sidebar({ projectId, useAuth, collapsed = false, onToggleCollapse, useBilling }: SidebarProps) { const pathname = usePathname(); const [projectName, setProjectName] = useState("Select Project"); + const [allProjects, setAllProjects] = useState[]>([]); + const [isLoadingProjects, setIsLoadingProjects] = useState(false); const isProjectsRoute = pathname === '/projects'; const { theme, toggleTheme } = useTheme(); const { showHelpModal } = useHelpModal(); + const { isOpen: isAssistantsModalOpen, onOpen: onAssistantsModalOpen, onClose: onAssistantsModalClose } = useDisclosure(); useEffect(() => { async function fetchProjectName() { @@ -53,18 +58,36 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl fetchProjectName(); }, [projectId, isProjectsRoute]); + // Load projects when modal opens + useEffect(() => { + async function loadProjects() { + if (isAssistantsModalOpen && !isProjectsRoute) { + setIsLoadingProjects(true); + try { + const projects = await listProjects(); + // Filter out current project and sort by creation date + const otherProjects = projects.filter(p => p._id !== projectId); + const sortedProjects = [...otherProjects].sort((a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + ); + setAllProjects(sortedProjects); + } catch (error) { + console.error('Failed to fetch projects:', error); + } finally { + setIsLoadingProjects(false); + } + } + } + + loadProjects(); + }, [isAssistantsModalOpen, projectId, isProjectsRoute]); + const navItems = [ { href: 'workflow', label: 'Build', icon: WorkflowIcon, requiresProject: true - }, - { - href: 'config', - label: 'Settings', - icon: SettingsIcon, - requiresProject: true } ]; @@ -82,10 +105,10 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl {/* Project Selector */}
- @@ -98,7 +121,7 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl {projectName} )} - +
@@ -175,6 +198,28 @@ export default function Sidebar({ projectId, useAuth, collapsed = false, onToggl {/* Theme and Auth Controls */}
+ {/* Settings */} + {!isProjectsRoute && projectId && ( + + + + {!collapsed && Settings} + + + )} + {USE_PRODUCT_TOUR && !isProjectsRoute && (
+ + {/* Assistants Modal */} + + + + Select Assistant + + +
+ {/* Current project option */} + +
Create New Assistant
+
+ Start building a new assistant from scratch +
+ + + {isLoadingProjects ? ( +
+ Loading assistants... +
+ ) : allProjects.length > 0 ? ( + <> +
+ Existing Assistants ({allProjects.length}) +
+
+ {allProjects.map((project) => ( + +
{project.name}
+
+ Created {new Date(project.createdAt).toLocaleDateString()} +
+ + ))} +
+ + ) : ( +
+ No other assistants found +
+ )} +
+
+
+
); } \ No newline at end of file