Skip to main content
Glama
TenantLayout.tsx6.68 kB
import React, { useState } from 'react'; import { NavLink, useNavigate } from 'react-router-dom'; import { useAuth } from '@/context/AuthContext'; import { LayoutDashboard, Book, MessageSquare, Settings, Users, BarChart, MonitorSmartphone, ChevronDown, Menu, X, LogOut } from 'lucide-react'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { getInitials } from '@/lib/utils'; interface TenantLayoutProps { children: React.ReactNode; } const TenantLayout: React.FC<TenantLayoutProps> = ({ children }) => { const { user, logout } = useAuth(); const navigate = useNavigate(); const [isOpen, setIsOpen] = useState(false); const handleLogout = () => { logout(); navigate('/login'); }; const navItems = [ { name: 'Dashboard', path: '/dashboard', icon: <LayoutDashboard className="w-5 h-5" /> }, { name: 'Knowledge Base', path: '/knowledge-base', icon: <Book className="w-5 h-5" /> }, { name: 'Chat History', path: '/chat-history', icon: <MessageSquare className="w-5 h-5" /> }, { name: 'Live Chat Test', path: '/live-chat', icon: <MessageSquare className="w-5 h-5" /> }, { name: 'Widget', path: '/widget', icon: <MonitorSmartphone className="w-5 h-5" /> }, { name: 'Clients', path: '/clients', icon: <Users className="w-5 h-5" /> }, { name: 'Analytics', path: '/analytics', icon: <BarChart className="w-5 h-5" /> }, { name: 'Settings', path: '/settings', icon: <Settings className="w-5 h-5" /> }, ]; return ( <div className="flex h-screen bg-gray-50"> {/* Sidebar - desktop */} <aside className="hidden md:flex flex-col w-64 bg-white border-r border-gray-200"> <div className="p-6"> <div className="flex items-center space-x-2"> <div className="bg-primary text-white p-2 rounded-md"> <MessageSquare className="h-6 w-6" /> </div> <span className="text-xl font-bold">MCP Chat</span> </div> </div> <nav className="flex-1 px-4 py-2 space-y-1"> {navItems.map((item) => ( <NavLink key={item.path} to={item.path} className={({ isActive }) => `flex items-center px-4 py-3 text-sm rounded-md transition-colors ${ isActive ? "bg-primary/10 text-primary font-medium" : "text-gray-700 hover:bg-gray-100" }` } > {item.icon} <span className="ml-3">{item.name}</span> </NavLink> ))} </nav> <div className="p-4 border-t border-gray-200"> <div className="flex items-center space-x-3"> <Avatar> <AvatarImage src={user?.avatar} alt={user?.name} /> <AvatarFallback>{user ? getInitials(user.name) : 'U'}</AvatarFallback> </Avatar> <div className="flex-1 min-w-0"> <p className="text-sm font-medium text-gray-900 truncate">{user?.name}</p> <p className="text-xs text-gray-500 truncate">{user?.email}</p> </div> <button onClick={handleLogout} className="text-gray-500 hover:text-gray-700" aria-label="Logout" > <LogOut className="w-5 h-5" /> </button> </div> </div> </aside> {/* Mobile header */} <div className="md:hidden fixed top-0 left-0 right-0 bg-white border-b border-gray-200 z-10"> <div className="flex items-center justify-between px-4 py-3"> <div className="flex items-center space-x-2"> <div className="bg-primary text-white p-1.5 rounded-md"> <MessageSquare className="h-5 w-5" /> </div> <span className="text-lg font-bold">MCP Chat</span> </div> <button onClick={() => setIsOpen(!isOpen)} className="text-gray-500 hover:text-gray-700 focus:outline-none" > {isOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />} </button> </div> </div> {/* Mobile sidebar */} {isOpen && ( <div className="md:hidden fixed inset-0 z-20 bg-gray-800 bg-opacity-50"> <div className="absolute top-0 right-0 bottom-0 w-64 bg-white"> <div className="flex justify-end p-4"> <button onClick={() => setIsOpen(false)} className="text-gray-500 hover:text-gray-700 focus:outline-none" > <X className="h-6 w-6" /> </button> </div> <nav className="px-4 py-2 space-y-1"> {navItems.map((item) => ( <NavLink key={item.path} to={item.path} className={({ isActive }) => `flex items-center px-4 py-3 text-sm rounded-md transition-colors ${ isActive ? "bg-primary/10 text-primary font-medium" : "text-gray-700 hover:bg-gray-100" }` } onClick={() => setIsOpen(false)} > {item.icon} <span className="ml-3">{item.name}</span> </NavLink> ))} </nav> <div className="absolute bottom-0 left-0 right-0 p-4 border-t border-gray-200"> <div className="flex items-center space-x-3"> <Avatar> <AvatarImage src={user?.avatar} alt={user?.name} /> <AvatarFallback>{user ? getInitials(user.name) : 'U'}</AvatarFallback> </Avatar> <div className="flex-1 min-w-0"> <p className="text-sm font-medium text-gray-900 truncate">{user?.name}</p> <p className="text-xs text-gray-500 truncate">{user?.email}</p> </div> <button onClick={handleLogout} className="text-gray-500 hover:text-gray-700" aria-label="Logout" > <LogOut className="w-5 h-5" /> </button> </div> </div> </div> </div> )} {/* Main content */} <main className="flex-1 overflow-auto"> <div className="pt-16 md:pt-0 px-4 md:px-8 py-6 max-w-7xl mx-auto"> {children} </div> </main> </div> ); }; export default TenantLayout;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ChiragPatankar/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server