"use client"; import { useState, useEffect } from "react"; import { useRouter, usePathname } from "next/navigation"; import { MessageSquare, PlusCircle, Trash2, ServerIcon, Settings, Sparkles, ChevronsUpDown, Copy, Pencil, Github, Key } from "lucide-react"; import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuBadge, useSidebar } from "@/components/ui/sidebar"; import { Separator } from "@/components/ui/separator"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; import Image from "next/image"; import { MCPServerManager } from "./mcp-server-manager"; import { ApiKeyManager } from "./api-key-manager"; import { ThemeToggle } from "./theme-toggle"; import { getUserId, updateUserId } from "@/lib/user-id"; import { useChats } from "@/lib/hooks/use-chats"; import { cn } from "@/lib/utils"; import Link from "next/link"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useMCP } from "@/lib/context/mcp-context"; import { Skeleton } from "@/components/ui/skeleton"; import { AnimatePresence, motion } from "motion/react"; export function ChatSidebar() { const router = useRouter(); const pathname = usePathname(); const [userId, setUserId] = useState(''); const [mcpSettingsOpen, setMcpSettingsOpen] = useState(false); const [apiKeySettingsOpen, setApiKeySettingsOpen] = useState(false); const { state } = useSidebar(); const isCollapsed = state === "collapsed"; const [editUserIdOpen, setEditUserIdOpen] = useState(false); const [newUserId, setNewUserId] = useState(''); // Get MCP server data from context const { mcpServers, setMcpServers, selectedMcpServers, setSelectedMcpServers } = useMCP(); // Initialize userId useEffect(() => { setUserId(getUserId()); }, []); // Use TanStack Query to fetch chats const { chats, isLoading, deleteChat, refreshChats } = useChats(userId); // Start a new chat const handleNewChat = () => { router.push('/'); }; // Delete a chat const handleDeleteChat = async (chatId: string, e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); deleteChat(chatId); // If we're currently on the deleted chat's page, navigate to home if (pathname === `/chat/${chatId}`) { router.push('/'); } }; // Get active MCP servers status const activeServersCount = selectedMcpServers.length; // Handle user ID update const handleUpdateUserId = () => { if (!newUserId.trim()) { toast.error("User ID cannot be empty"); return; } updateUserId(newUserId.trim()); setUserId(newUserId.trim()); setEditUserIdOpen(false); toast.success("User ID updated successfully"); // Refresh the page to reload chats with new user ID window.location.reload(); }; // Show loading state if user ID is not yet initialized if (!userId) { return null; // Or a loading spinner } // Create chat loading skeletons const renderChatSkeletons = () => { return Array(3).fill(0).map((_, index) => (
{!isCollapsed && ( <> )}
)); }; return (
Scira Logo
{!isCollapsed && (
MCP
)}
Chats {isLoading ? ( renderChatSkeletons() ) : chats.length === 0 ? (
{isCollapsed ? (
) : (
No conversations yet
)}
) : ( {chats.map((chat) => (
{!isCollapsed && ( {chat.title.length > 18 ? `${chat.title.slice(0, 18)}...` : chat.title} )}
{!isCollapsed && ( )}
))}
)}
MCP Servers setMcpSettingsOpen(true)} className={cn( "w-full flex items-center gap-2 transition-all", "hover:bg-secondary/50 active:bg-secondary/70" )} tooltip={isCollapsed ? "MCP Servers" : undefined} > 0 ? "text-primary" : "text-muted-foreground" )} /> {!isCollapsed && ( MCP Servers )} {activeServersCount > 0 && !isCollapsed ? ( {activeServersCount} ) : activeServersCount > 0 && isCollapsed ? ( {activeServersCount} ) : null}
{isCollapsed ? ( ) : ( )}
{userId.substring(0, 2).toUpperCase()}
User ID {userId}
{ e.preventDefault(); navigator.clipboard.writeText(userId); toast.success("User ID copied to clipboard"); }}> Copy User ID { e.preventDefault(); setEditUserIdOpen(true); }}> Edit User ID { e.preventDefault(); setMcpSettingsOpen(true); }}> MCP Settings { e.preventDefault(); setApiKeySettingsOpen(true); }}> API Keys { e.preventDefault(); window.open("https://git.new/s-mcp", "_blank"); }}> GitHub e.preventDefault()}>
Theme
{ setEditUserIdOpen(open); if (open) { setNewUserId(userId); } }}> Edit User ID Update your user ID for chat synchronization. This will affect which chats are visible to you.
setNewUserId(e.target.value)} placeholder="Enter your user ID" />
); }