import React, { useState, useCallback, useMemo } from 'react'; import { Link, useLocation, useNavigate, Location } from 'react-router-dom'; import { cn } from '../../lib/utils'; import Logo from '../ui/Logo'; import { Button } from '../ui/Button'; import Typography from '../ui/Typography'; import { FiChevronLeft, FiChevronRight, FiSend, FiRefreshCw, FiMessageSquare, FiPlus, FiUserPlus, FiTool, } from 'react-icons/fi'; import { HiChatBubbleBottomCenterText, HiServerStack, HiPuzzlePiece, HiCog6Tooth, HiQuestionMarkCircle, HiLink, HiMagnifyingGlass, HiUserCircle, HiHeart, } from 'react-icons/hi2'; import { IconType } from 'react-icons'; import { toast } from 'sonner'; import { useHCS10 } from '../../contexts/HCS10Context'; import { SessionCreationModal } from '../chat/SessionCreationModal'; import AgentItem from './AgentItem'; import ConnectionRequestItem from './ConnectionRequestItem'; import NavItem from './NavItem'; interface ConnectionRequest { id: string; requesting_account_id: string; sequence_number: number; memo?: string; operator_id?: string; } interface NavigationState { [key: string]: boolean; } interface SidebarProps { className?: string; } interface NavSubItem { id: string; path: string; label: string; icon: IconType; description?: string; gradient?: string; } interface NavItemType { id: string; path: string; label: string; icon: IconType; description?: string; gradient?: string; iconBg?: string; subItems?: NavSubItem[]; } const primaryNavItems: NavItemType[] = [ { id: 'discover', path: '/discover', label: 'Discover', icon: HiMagnifyingGlass, description: 'Find new agents', gradient: 'from-[#ff9b50] to-[#ff6b6b]', iconBg: 'from-[#ff9b50] to-[#ff6b6b]', }, { id: 'connections', path: '/connections', label: 'Connections', icon: HiLink, description: 'Manage connections', gradient: 'from-[#4facfe] to-[#00f2fe]', iconBg: 'from-[#4facfe] to-[#00f2fe]', }, { id: 'mcp', path: '/mcp', label: 'MCP Servers', icon: HiServerStack, description: 'Manage MCP connections', gradient: 'from-[#5eef81] to-[#48df7b]', iconBg: 'from-[#5eef81] to-[#48df7b]', }, { id: 'plugins', path: '/plugins', label: 'Plugins', icon: HiPuzzlePiece, description: 'Extend functionality', gradient: 'from-[#7eb9ff] to-[#5599fe]', iconBg: 'from-[#7eb9ff] to-[#5599fe]', }, { id: 'tools', path: '/tools', label: 'Tools', icon: FiTool, description: 'Development tools', gradient: 'from-[#ff9b50] to-[#ff6b6b]', iconBg: 'from-[#ff9b50] to-[#ff6b6b]', }, { id: 'hcs10', path: '/hcs10-profile', label: 'My Profile', icon: HiUserCircle, description: 'Manage your profile', gradient: 'from-[#6b73c1] to-[#5054a1]', iconBg: 'from-[#6b73c1] to-[#5054a1]', }, ]; const secondaryNavItems: NavItemType[] = [ { id: 'settings', path: '/settings', label: 'Settings', icon: HiCog6Tooth, description: 'Configure your workspace', gradient: 'from-gray-500 to-gray-600', iconBg: 'from-gray-500 to-gray-600', }, { id: 'help', path: '/help', label: 'Help & Docs', icon: HiQuestionMarkCircle, description: 'Get support', gradient: 'from-blue-500 to-indigo-600', iconBg: 'from-blue-500 to-indigo-600', }, { id: 'acknowledgements', path: '/acknowledgements', label: 'Acknowledgements', icon: HiHeart, description: 'Credits & licenses', gradient: 'from-pink-500 to-rose-600', iconBg: 'from-pink-500 to-rose-600', }, { id: 'telegram', path: 'https://t.me/hashgraphonline', label: 'Telegram', icon: FiSend, description: 'Join our community', gradient: 'from-cyan-500 to-blue-600', iconBg: 'from-cyan-500 to-blue-600', }, ]; const SidebarContent: React.FC = React.memo( ({ className, location }) => { const navigate = useNavigate(); const { agents, connectionRequests, isLoadingAgents, activeTopicId, refreshConnections, onSelectAgent, onAcceptRequest, onRejectRequest, } = useHCS10(); const [isCollapsed, setIsCollapsed] = React.useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const [actionLoading, setActionLoading] = useState>( {} ); const [expandedSections, setExpandedSections] = useState( {} ); const [isSessionCreationModalOpen, setIsSessionCreationModalOpen] = useState(false); const isActive = (path: string) => { if (path === '/') { return location.pathname === '/'; } return location.pathname.startsWith(path); }; const handleRefresh = useCallback(async () => { if (isRefreshing) return; setIsRefreshing(true); try { await refreshConnections(); } catch { } setTimeout(() => setIsRefreshing(false), 1500); }, [isRefreshing, refreshConnections]); const activeAgents = useMemo(() => { return agents.filter((agent) => agent.type === 'active'); }, [agents]); const runAction = useCallback( async (actionId: string, actionFn: () => Promise) => { setActionLoading((prev) => ({ ...prev, [actionId]: true })); try { await actionFn(); } catch { } finally { setActionLoading((prev) => ({ ...prev, [actionId]: false })); } }, [] ); const handleAccept = useCallback( (request: ConnectionRequest) => runAction( `accept_${request.sequence_number}`, async () => { if (onAcceptRequest) { await onAcceptRequest(request); } } ), [runAction, onAcceptRequest] ); const handleReject = useCallback( (request: ConnectionRequest) => runAction( `reject_${request.sequence_number}`, async () => { if (onRejectRequest) { await onRejectRequest(request); } } ), [runAction, onRejectRequest] ); const toggleNavSection = useCallback((sectionId: string) => { setExpandedSections((prev) => ({ ...prev, [sectionId]: !prev[sectionId], })); }, []); const isActiveAgent = useCallback( (agentId: string) => activeTopicId === agentId, [activeTopicId] ); const handleStartPersonalChat = useCallback(() => { setIsSessionCreationModalOpen(true); }, []); const handleSessionCreated = useCallback( async () => { try { navigate('/chat'); toast.success('New session created successfully!'); } catch { } setIsSessionCreationModalOpen(false); }, [navigate] ); const formatTimestamp = useCallback( (timestamp: Date | number | undefined) => { if (!timestamp) return ''; const date = typeof timestamp === 'number' ? new Date(timestamp) : timestamp; const now = new Date(); const diff = now.getTime() - date.getTime(); if (diff < 60000) return 'Just now'; if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`; if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`; return date.toLocaleDateString(); }, [] ); return ( ); } ); const Sidebar: React.FC = React.memo((props) => { const location = useLocation(); return ; }); export default Sidebar;