diff --git a/frontend/src/app/dashboard/_page.tsx b/frontend/src/app/dashboard/_page.tsx deleted file mode 100644 index 74211616..00000000 --- a/frontend/src/app/dashboard/_page.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client" - -import { useRouter } from "next/navigation" -import { useState } from "react" -import { AppSidebar } from "@/components/dashboard/sidebar/app-sidebar" -import { NavActions } from "@/components/dashboard/sidebar/nav-actions" -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbList, - BreadcrumbPage, -} from "@/components/ui/breadcrumb" -import { Separator } from "@/components/ui/separator" -import { - SidebarInset, - SidebarProvider, - SidebarTrigger, -} from "@/components/ui/sidebar" - -export default function Page() { - const router = useRouter() - const [currentTeamId, setCurrentTeamId] = useState() - - const handleTeamSelected = (team: any) => { - setCurrentTeamId(team.account_id) - // Navigate to the team dashboard if it has a slug - if (team.slug) { - router.push(`/dashboard/${team.slug}`) - } - } - - return ( - - - -
-
- - - - - - - Project Management & Task Tracking - - - - -
-
- -
-
-
-
-
-
- - - ) -} diff --git a/frontend/src/app/dashboard/agents/[threadId]/page.tsx b/frontend/src/app/dashboard/agents/[threadId]/page.tsx index c2fe6273..15a6f40d 100644 --- a/frontend/src/app/dashboard/agents/[threadId]/page.tsx +++ b/frontend/src/app/dashboard/agents/[threadId]/page.tsx @@ -222,7 +222,8 @@ function MessageContent({ content }: { content: string }) { } export default function AgentPage({ params }: AgentPageProps) { - const { threadId } = params; + const resolvedParams = React.use(params as any) as { threadId: string }; + const { threadId } = resolvedParams; const router = useRouter(); const searchParams = useSearchParams(); const initialMessage = searchParams.get('message'); diff --git a/frontend/src/app/dashboard/layout.tsx b/frontend/src/app/dashboard/layout.tsx index 3d3ad82e..14adb467 100644 --- a/frontend/src/app/dashboard/layout.tsx +++ b/frontend/src/app/dashboard/layout.tsx @@ -1,28 +1,25 @@ -import DashboardLayout from "@/components/dashboard/DashboardLayout"; -import { createClient } from "@/lib/supabase/server"; - -interface DashboardRootLayoutProps { - children: React.ReactNode; +import { SidebarLeft } from "@/components/dashboard/sidebar/sidebar-left" +import { SidebarRight } from "@/components/dashboard/sidebar/sidebar-right" +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from "@/components/ui/sidebar" +interface DashboardLayoutProps { + children: React.ReactNode } -export default async function DashboardRootLayout({ +export default async function DashboardLayout({ children, -}: DashboardRootLayoutProps) { - // Get the current user via Supabase - const supabaseClient = await createClient(); - const { data: { user } } = await supabaseClient.auth.getUser(); - - // Get the personal account details - const { data: personalAccount } = await supabaseClient.rpc('get_personal_account'); +}: DashboardLayoutProps) { return ( - - {children} - - ); + + + + {children} + + {/* */} + + ) } \ No newline at end of file diff --git a/frontend/src/app/dashboard/layout_og.tsx b/frontend/src/app/dashboard/layout_og.tsx new file mode 100644 index 00000000..3d3ad82e --- /dev/null +++ b/frontend/src/app/dashboard/layout_og.tsx @@ -0,0 +1,28 @@ +import DashboardLayout from "@/components/dashboard/DashboardLayout"; +import { createClient } from "@/lib/supabase/server"; + +interface DashboardRootLayoutProps { + children: React.ReactNode; +} + +export default async function DashboardRootLayout({ + children, +}: DashboardRootLayoutProps) { + // Get the current user via Supabase + const supabaseClient = await createClient(); + const { data: { user } } = await supabaseClient.auth.getUser(); + + // Get the personal account details + const { data: personalAccount } = await supabaseClient.rpc('get_personal_account'); + + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx index 2404ffc2..82c67973 100644 --- a/frontend/src/app/dashboard/page.tsx +++ b/frontend/src/app/dashboard/page.tsx @@ -1,85 +1,37 @@ -"use client"; - -import React, { useState, Suspense } from 'react'; -import { Skeleton } from "@/components/ui/skeleton"; -import { useRouter } from 'next/navigation'; -import { ChatInput } from '@/components/chat/chat-input'; -import { createProject, addUserMessage, startAgent, createThread } from "@/lib/api"; - -function DashboardContent() { - const [inputValue, setInputValue] = useState(""); - const [isSubmitting, setIsSubmitting] = useState(false); - const router = useRouter(); - - const handleSubmit = async (message: string) => { - if (!message.trim() || isSubmitting) return; - - setIsSubmitting(true); - - try { - // 1. Create a new project with the message as the name - const newAgent = await createProject({ - name: message.trim().length > 50 - ? message.trim().substring(0, 47) + "..." - : message.trim(), - description: "", - }); - - // 2. Create a new thread for this project - const thread = await createThread(newAgent.id); - - // 3. Add the user message to the thread - await addUserMessage(thread.thread_id, message.trim()); - - // 4. Start the agent with the thread ID - const agentRun = await startAgent(thread.thread_id); - - // 5. Navigate to the new agent's thread page - router.push(`/dashboard/agents/${thread.thread_id}`); - } catch (error) { - console.error("Error creating agent:", error); - setIsSubmitting(false); - } - }; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbList, + BreadcrumbPage, +} from "@/components/ui/breadcrumb" +import { Separator } from "@/components/ui/separator" +import { SidebarTrigger } from "@/components/ui/sidebar" +export default function Page() { return ( -
-
-
-

Hello.

-

What can I help with?

+ <> +
+
+ + + + + + + Project Management & Task Tracking + + + +
- - +
+
+
+
-
- ); + + ) } - -export default function DashboardPage() { - return ( - -
-
- - -
- - -
- -
-
-
- }> - - - ); -} \ No newline at end of file diff --git a/frontend/src/app/dashboard/page_og.tsx b/frontend/src/app/dashboard/page_og.tsx new file mode 100644 index 00000000..2404ffc2 --- /dev/null +++ b/frontend/src/app/dashboard/page_og.tsx @@ -0,0 +1,85 @@ +"use client"; + +import React, { useState, Suspense } from 'react'; +import { Skeleton } from "@/components/ui/skeleton"; +import { useRouter } from 'next/navigation'; +import { ChatInput } from '@/components/chat/chat-input'; +import { createProject, addUserMessage, startAgent, createThread } from "@/lib/api"; + +function DashboardContent() { + const [inputValue, setInputValue] = useState(""); + const [isSubmitting, setIsSubmitting] = useState(false); + const router = useRouter(); + + const handleSubmit = async (message: string) => { + if (!message.trim() || isSubmitting) return; + + setIsSubmitting(true); + + try { + // 1. Create a new project with the message as the name + const newAgent = await createProject({ + name: message.trim().length > 50 + ? message.trim().substring(0, 47) + "..." + : message.trim(), + description: "", + }); + + // 2. Create a new thread for this project + const thread = await createThread(newAgent.id); + + // 3. Add the user message to the thread + await addUserMessage(thread.thread_id, message.trim()); + + // 4. Start the agent with the thread ID + const agentRun = await startAgent(thread.thread_id); + + // 5. Navigate to the new agent's thread page + router.push(`/dashboard/agents/${thread.thread_id}`); + } catch (error) { + console.error("Error creating agent:", error); + setIsSubmitting(false); + } + }; + + return ( +
+
+
+

Hello.

+

What can I help with?

+
+ + +
+
+ ); +} + +export default function DashboardPage() { + return ( + +
+
+ + +
+ + +
+ +
+
+
+ }> + + + ); +} \ No newline at end of file diff --git a/frontend/src/components/app-sidebar.tsx b/frontend/src/components/app-sidebar.tsx deleted file mode 100644 index e5513cb8..00000000 --- a/frontend/src/components/app-sidebar.tsx +++ /dev/null @@ -1,276 +0,0 @@ -"use client" - -import * as React from "react" -import { - AudioWaveform, - Blocks, - Calendar, - Command, - Home, - Inbox, - MessageCircleQuestion, - Search, - Settings2, - Sparkles, - Trash2, -} from "lucide-react" - -import { NavFavorites } from "@/components/nav-favorites" -import { NavMain } from "@/components/nav-main" -import { NavSecondary } from "@/components/nav-secondary" -import { NavWorkspaces } from "@/components/nav-workspaces" -import { TeamSwitcher } from "@/components/dashboard/sidebar/team-switcher" -import { - Sidebar, - SidebarContent, - SidebarHeader, - SidebarRail, -} from "@/components/ui/sidebar" - -// This is sample data. -const data = { - teams: [ - { - name: "Acme Inc", - logo: Command, - plan: "Enterprise", - }, - { - name: "Acme Corp.", - logo: AudioWaveform, - plan: "Startup", - }, - { - name: "Evil Corp.", - logo: Command, - plan: "Free", - }, - ], - navMain: [ - { - title: "Search", - url: "#", - icon: Search, - }, - { - title: "Ask AI", - url: "#", - icon: Sparkles, - }, - { - title: "Home", - url: "#", - icon: Home, - isActive: true, - }, - { - title: "Inbox", - url: "#", - icon: Inbox, - badge: "10", - }, - ], - navSecondary: [ - { - title: "Calendar", - url: "#", - icon: Calendar, - }, - { - title: "Settings", - url: "#", - icon: Settings2, - }, - { - title: "Templates", - url: "#", - icon: Blocks, - }, - { - title: "Trash", - url: "#", - icon: Trash2, - }, - { - title: "Help", - url: "#", - icon: MessageCircleQuestion, - }, - ], - favorites: [ - { - name: "Project Management & Task Tracking", - url: "#", - emoji: "πŸ“Š", - }, - { - name: "Family Recipe Collection & Meal Planning", - url: "#", - emoji: "🍳", - }, - { - name: "Fitness Tracker & Workout Routines", - url: "#", - emoji: "πŸ’ͺ", - }, - { - name: "Book Notes & Reading List", - url: "#", - emoji: "πŸ“š", - }, - { - name: "Sustainable Gardening Tips & Plant Care", - url: "#", - emoji: "🌱", - }, - { - name: "Language Learning Progress & Resources", - url: "#", - emoji: "πŸ—£οΈ", - }, - { - name: "Home Renovation Ideas & Budget Tracker", - url: "#", - emoji: "🏠", - }, - { - name: "Personal Finance & Investment Portfolio", - url: "#", - emoji: "πŸ’°", - }, - { - name: "Movie & TV Show Watchlist with Reviews", - url: "#", - emoji: "🎬", - }, - { - name: "Daily Habit Tracker & Goal Setting", - url: "#", - emoji: "βœ…", - }, - ], - workspaces: [ - { - name: "Personal Life Management", - emoji: "🏠", - pages: [ - { - name: "Daily Journal & Reflection", - url: "#", - emoji: "πŸ“”", - }, - { - name: "Health & Wellness Tracker", - url: "#", - emoji: "🍏", - }, - { - name: "Personal Growth & Learning Goals", - url: "#", - emoji: "🌟", - }, - ], - }, - { - name: "Professional Development", - emoji: "πŸ’Ό", - pages: [ - { - name: "Career Objectives & Milestones", - url: "#", - emoji: "🎯", - }, - { - name: "Skill Acquisition & Training Log", - url: "#", - emoji: "🧠", - }, - { - name: "Networking Contacts & Events", - url: "#", - emoji: "🀝", - }, - ], - }, - { - name: "Creative Projects", - emoji: "🎨", - pages: [ - { - name: "Writing Ideas & Story Outlines", - url: "#", - emoji: "✍️", - }, - { - name: "Art & Design Portfolio", - url: "#", - emoji: "πŸ–ΌοΈ", - }, - { - name: "Music Composition & Practice Log", - url: "#", - emoji: "🎡", - }, - ], - }, - { - name: "Home Management", - emoji: "🏑", - pages: [ - { - name: "Household Budget & Expense Tracking", - url: "#", - emoji: "πŸ’°", - }, - { - name: "Home Maintenance Schedule & Tasks", - url: "#", - emoji: "πŸ”§", - }, - { - name: "Family Calendar & Event Planning", - url: "#", - emoji: "πŸ“…", - }, - ], - }, - { - name: "Travel & Adventure", - emoji: "🧳", - pages: [ - { - name: "Trip Planning & Itineraries", - url: "#", - emoji: "πŸ—ΊοΈ", - }, - { - name: "Travel Bucket List & Inspiration", - url: "#", - emoji: "🌎", - }, - { - name: "Travel Journal & Photo Gallery", - url: "#", - emoji: "πŸ“Έ", - }, - ], - }, - ], -} - -export function AppSidebar({ ...props }: React.ComponentProps) { - return ( - - - - - - - - - - - - - ) -} diff --git a/frontend/src/components/calendars.tsx b/frontend/src/components/dashboard/sidebar/calendars.tsx similarity index 100% rename from frontend/src/components/calendars.tsx rename to frontend/src/components/dashboard/sidebar/calendars.tsx diff --git a/frontend/src/components/date-picker.tsx b/frontend/src/components/dashboard/sidebar/date-picker.tsx similarity index 100% rename from frontend/src/components/date-picker.tsx rename to frontend/src/components/dashboard/sidebar/date-picker.tsx diff --git a/frontend/src/components/dashboard/sidebar/nav-agents.tsx b/frontend/src/components/dashboard/sidebar/nav-agents.tsx new file mode 100644 index 00000000..82b247b7 --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/nav-agents.tsx @@ -0,0 +1,172 @@ +"use client" + +import { useEffect, useState } from "react" +import { + ArrowUpRight, + Link as LinkIcon, + MoreHorizontal, + Trash2, + StarOff, +} from "lucide-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarGroup, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" +import { getProjects, getThreads } from "@/lib/api" +import Link from "next/link" + +export function NavAgents() { + const { isMobile } = useSidebar() + const [agents, setAgents] = useState<{name: string, url: string, emoji: string}[]>([]) + const [isLoading, setIsLoading] = useState(true) + + // Load agents dynamically from the API + useEffect(() => { + async function loadAgents() { + try { + const projectsData = await getProjects() + const agentsList = [] + + for (const project of projectsData) { + const threads = await getThreads(project.id) + if (threads && threads.length > 0) { + // For each thread in the project, create an agent entry + for (const thread of threads) { + // Generate a simple emoji based on the project name hash + const emoji = getEmojiFromName(project.name) + + agentsList.push({ + name: project.name, + url: `/dashboard/agents/${thread.thread_id}`, + emoji: emoji + }) + } + } + } + + setAgents(agentsList) + } catch (err) { + console.error("Error loading agents for sidebar:", err) + } finally { + setIsLoading(false) + } + } + + loadAgents() + }, []) + + // Function to generate emoji from name + const getEmojiFromName = (name: string) => { + const emojis = ["πŸ“Š", "πŸ“", "πŸ’Ό", "πŸ”", "βœ…", "πŸ“ˆ", "πŸ’‘", "🎯", "πŸ—‚οΈ", "πŸ€–", "πŸ’¬", "πŸ“š"] + // Simple hash function to pick a consistent emoji for the same name + let hash = 0 + for (let i = 0; i < name.length; i++) { + hash = name.charCodeAt(i) + ((hash << 5) - hash) + } + return emojis[Math.abs(hash) % emojis.length] + } + + // Get only the latest 20 agents for the sidebar + const recentAgents = agents.slice(0, 20) + + return ( + +
+ Agents +
+ + + {isLoading ? ( + // Show skeleton loaders while loading + Array.from({length: 3}).map((_, index) => ( + + +
+
+
+
+ )) + ) : recentAgents.length > 0 ? ( + // Show agents + <> + {recentAgents.map((item, index) => ( + + + + {item.emoji} + {item.name} + + + + + + + More + + + + + + Remove from agents + + + + + Copy Link + + + + + Open in New Tab + + + + + + Delete + + + + + ))} + + {agents.length > 20 && ( + + + + + See all agents + + + + )} + + ) : ( + // Empty state + + + No agents yet + + + )} +
+
+ ) +} diff --git a/frontend/src/components/dashboard/sidebar/nav-main.tsx b/frontend/src/components/dashboard/sidebar/nav-main.tsx new file mode 100644 index 00000000..31edc972 --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/nav-main.tsx @@ -0,0 +1,35 @@ +"use client" + +import { type LucideIcon } from "lucide-react" + +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" + +export function NavMain({ + items, +}: { + items: { + title: string + url: string + icon: LucideIcon + isActive?: boolean + }[] +}) { + return ( + + {items.map((item) => ( + + + + + {item.title} + + + + ))} + + ) +} diff --git a/frontend/src/components/dashboard/sidebar/nav-secondary.tsx b/frontend/src/components/dashboard/sidebar/nav-secondary.tsx new file mode 100644 index 00000000..71d2ebf1 --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/nav-secondary.tsx @@ -0,0 +1,43 @@ +import React from "react" +import { type LucideIcon } from "lucide-react" + +import { + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuBadge, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" + +export function NavSecondary({ + items, + ...props +}: { + items: { + title: string + url: string + icon: LucideIcon + badge?: React.ReactNode + }[] +} & React.ComponentPropsWithoutRef) { + return ( + + + + {items.map((item) => ( + + + + + {item.title} + + + {item.badge && {item.badge}} + + ))} + + + + ) +} diff --git a/frontend/src/components/dashboard/sidebar/nav-user.tsx b/frontend/src/components/dashboard/sidebar/nav-user.tsx new file mode 100644 index 00000000..cd830e1a --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/nav-user.tsx @@ -0,0 +1,126 @@ +"use client" + +import { + BadgeCheck, + Bell, + ChevronsUpDown, + CreditCard, + LogOut, + Settings, + User, +} from "lucide-react" + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/components/ui/avatar" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" +import Link from "next/link" +import { useRouter } from "next/navigation" +import { createClient } from "@/lib/supabase/client" + +export function NavUser({ + user, +}: { + user: { + name: string + email: string + avatar: string + } +}) { + const { isMobile } = useSidebar() + const router = useRouter() + + const handleLogout = async () => { + const supabase = createClient() + await supabase.auth.signOut() + router.push("/auth") + } + + const getInitials = (name: string) => { + return name.split(' ') + .map(part => part.charAt(0)) + .join('') + .toUpperCase() + .substring(0, 2) + } + + return ( + + + + + + + + {getInitials(user.name)} + +
+ {user.name} + {user.email} +
+ +
+
+ + +
+ + + {getInitials(user.name)} + +
+ {user.name} + {user.email} +
+
+
+ + + + + + Billing + + + + + + Settings + + + + + + + Log out + +
+
+
+
+ ) +} diff --git a/frontend/src/components/dashboard/sidebar/sidebar-left.tsx b/frontend/src/components/dashboard/sidebar/sidebar-left.tsx new file mode 100644 index 00000000..9f2ca57d --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/sidebar-left.tsx @@ -0,0 +1,90 @@ +"use client" + +import * as React from "react" +import { + BookOpen, + CalendarClock, + HelpCircle, + MessageCircleQuestion, +} from "lucide-react" + +import { NavAgents } from "@/components/dashboard/sidebar/nav-agents" +import { NavUser } from "@/components/dashboard/sidebar/nav-user" +import { NavSecondary } from "@/components/dashboard/sidebar/nav-secondary" +import { TeamSwitcher } from "@/components/dashboard/sidebar/team-switcher" +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarRail, +} from "@/components/ui/sidebar" +import { useEffect, useState } from "react" +import { createClient } from "@/lib/supabase/client" + +// Only keep necessary data +const navSecondaryItems = [ + { + title: "Help", + url: "#", + icon: HelpCircle, + }, + { + title: "Careers", + url: "#", + icon: BookOpen, + }, + { + title: "Book Demo", + url: "#", + icon: CalendarClock, + }, +] + +export function SidebarLeft({ + ...props +}: React.ComponentProps) { + const [user, setUser] = useState<{ + name: string; + email: string; + avatar: string; + }>({ + name: "Loading...", + email: "loading@example.com", + avatar: "" + }) + + // Fetch user data + useEffect(() => { + const fetchUserData = async () => { + const supabase = createClient() + const { data } = await supabase.auth.getUser() + + if (data.user) { + setUser({ + name: data.user.user_metadata?.name || data.user.email?.split('@')[0] || 'User', + email: data.user.email || '', + avatar: data.user.user_metadata?.avatar_url || '' + }) + } + } + + fetchUserData() + }, []) + + return ( + + + + + + + + + + + + + + ) +} diff --git a/frontend/src/components/dashboard/sidebar/sidebar-right.tsx b/frontend/src/components/dashboard/sidebar/sidebar-right.tsx new file mode 100644 index 00000000..5d409cdd --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/sidebar-right.tsx @@ -0,0 +1,71 @@ +import * as React from "react" +import { Plus } from "lucide-react" + +import { Calendars } from "@/components/dashboard/sidebar/calendars" +import { DatePicker } from "@/components/dashboard/sidebar/date-picker" +import { NavUser } from "@/components/dashboard/sidebar/nav-user" +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, + SidebarSeparator, +} from "@/components/ui/sidebar" + +// This is sample data. +const data = { + user: { + name: "shadcn", + email: "m@example.com", + avatar: "/avatars/shadcn.jpg", + }, + calendars: [ + { + name: "My Calendars", + items: ["Personal", "Work", "Family"], + }, + { + name: "Favorites", + items: ["Holidays", "Birthdays"], + }, + { + name: "Other", + items: ["Travel", "Reminders", "Deadlines"], + }, + ], +} + +export function SidebarRight({ + ...props +}: React.ComponentProps) { + return ( + + + + + + + + + + + + + + + New Calendar + + + + + + ) +} diff --git a/frontend/src/components/dashboard/sidebar/team-switcher.tsx b/frontend/src/components/dashboard/sidebar/team-switcher.tsx new file mode 100644 index 00000000..3f4d0e52 --- /dev/null +++ b/frontend/src/components/dashboard/sidebar/team-switcher.tsx @@ -0,0 +1,212 @@ +"use client" + +import * as React from "react" +import { useRouter } from "next/navigation" +import { ChevronDown, Plus, Command, AudioWaveform } from "lucide-react" +import { useAccounts } from "@/hooks/use-accounts" +import NewTeamForm from "@/components/basejump/new-team-form" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" + +export function TeamSwitcher() { + const router = useRouter() + const { data: accounts } = useAccounts() + const [showNewTeamDialog, setShowNewTeamDialog] = React.useState(false) + + // Prepare personal account and team accounts + const personalAccount = React.useMemo(() => accounts?.find(account => account.personal_account), [accounts]) + const teamAccounts = React.useMemo(() => accounts?.filter(account => !account.personal_account), [accounts]) + + // Create a default list of teams with logos for the UI (will show until real data loads) + const defaultTeams = [ + { + name: personalAccount?.name || "Personal Account", + logo: Command, + plan: "Personal", + account_id: personalAccount?.account_id, + slug: personalAccount?.slug, + personal_account: true + }, + ...(teamAccounts?.map(team => ({ + name: team.name, + logo: AudioWaveform, + plan: "Team", + account_id: team.account_id, + slug: team.slug, + personal_account: false + })) || []) + ] + + // Use the first team or first entry in defaultTeams as activeTeam + const [activeTeam, setActiveTeam] = React.useState(defaultTeams[0]) + + // Update active team when accounts load + React.useEffect(() => { + if (accounts?.length) { + const currentTeam = accounts.find(account => account.account_id === activeTeam.account_id) + if (currentTeam) { + setActiveTeam({ + name: currentTeam.name, + logo: currentTeam.personal_account ? Command : AudioWaveform, + plan: currentTeam.personal_account ? "Personal" : "Team", + account_id: currentTeam.account_id, + slug: currentTeam.slug, + personal_account: currentTeam.personal_account + }) + } else { + // If current team not found, set first available account as active + const firstAccount = accounts[0] + setActiveTeam({ + name: firstAccount.name, + logo: firstAccount.personal_account ? Command : AudioWaveform, + plan: firstAccount.personal_account ? "Personal" : "Team", + account_id: firstAccount.account_id, + slug: firstAccount.slug, + personal_account: firstAccount.personal_account + }) + } + } + }, [accounts, activeTeam.account_id]) + + // Handle team selection + const handleTeamSelect = (team) => { + setActiveTeam(team) + + // Navigate to the appropriate dashboard + if (team.personal_account) { + router.push('/dashboard') + } else { + router.push(`/dashboard/${team.slug}`) + } + } + + if (!activeTeam) { + return null + } + + return ( + + + + + + +
+ +
+ {activeTeam.name} + +
+
+ + {personalAccount && ( + <> + + Personal Account + + handleTeamSelect({ + name: personalAccount.name, + logo: Command, + plan: "Personal", + account_id: personalAccount.account_id, + slug: personalAccount.slug, + personal_account: true + })} + className="gap-2 p-2" + > +
+ +
+ {personalAccount.name} + ⌘1 +
+ + )} + + {teamAccounts?.length > 0 && ( + <> + + Teams + + {teamAccounts.map((team, index) => ( + handleTeamSelect({ + name: team.name, + logo: AudioWaveform, + plan: "Team", + account_id: team.account_id, + slug: team.slug, + personal_account: false + })} + className="gap-2 p-2" + > +
+ +
+ {team.name} + ⌘{index + 2} +
+ ))} + + )} + + + + { + setShowNewTeamDialog(true) + }} + > +
+ +
+
Add team
+
+
+
+
+
+
+ + + + Create a new team + + Create a team to collaborate with others. + + + + +
+ ) +}