'use client'; import Link from 'next/link'; import { usePathname, useRouter } from 'next/navigation'; import { LayoutDashboard, Users, MessageSquare, Target, Zap, UserPlus, Store, Wrench, BarChart3, Settings, Shield, ChevronLeft, ChevronRight, LogOut, Building2, Bell, Search, Menu, X, Loader2, Sparkles, ListChecks, } from 'lucide-react'; import { useState, useEffect, useRef } from 'react'; import { AuthProvider, useAuth } from '@/lib/hooks/useAuth'; import { RealtimeProvider, useRealtimeContext } from '@/components/realtime/RealtimeProvider'; import { cn } from '@/lib/utils'; const setupNavItems = [ { href: '/setup', label: 'Setup', icon: ListChecks }, ]; const navItems = [ { href: '/dashboard', label: 'Dashboard', icon: LayoutDashboard }, { href: '/control-center', label: 'Control Center', icon: Sparkles }, { href: '/contacts', label: 'Contacts', icon: Users }, { href: '/conversations', label: 'Conversations', icon: MessageSquare }, { href: '/opportunities', label: 'Opportunities', icon: Target }, { href: '/automations', label: 'Automations', icon: Zap }, { href: '/leads', label: 'Get Leads', icon: UserPlus }, { href: '/marketplace', label: 'Marketplace', icon: Store }, { href: '/tools', label: 'Tools', icon: Wrench }, { href: '/reporting', label: 'Reporting', icon: BarChart3 }, ]; const bottomNavItems = [ { href: '/settings', label: 'Settings', icon: Settings }, { href: '/admin', label: 'Admin', icon: Shield, adminOnly: true }, ]; // Tooltip component for collapsed sidebar function Tooltip({ children, content, show }: { children: React.ReactNode; content: string; show: boolean }) { if (!show) return <>{children}; return (
{children}
{content}
); } // Search Modal Component function SearchModal({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) { const [searchQuery, setSearchQuery] = useState(''); const inputRef = useRef(null); useEffect(() => { if (isOpen && inputRef.current) { inputRef.current.focus(); } }, [isOpen]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); if (!isOpen) return; onClose(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [isOpen, onClose]); if (!isOpen) return null; const searchCategories = [ { label: 'Contacts', icon: Users, shortcut: 'C' }, { label: 'Conversations', icon: MessageSquare, shortcut: 'V' }, { label: 'Opportunities', icon: Target, shortcut: 'O' }, { label: 'Settings', icon: Settings, shortcut: 'S' }, ]; return (
); } // Helper function to get user initials function getUserInitials(user: { firstName?: string; lastName?: string; email?: string } | null): string { if (!user) return 'U'; const first = user.firstName?.[0]?.toUpperCase() || ''; const last = user.lastName?.[0]?.toUpperCase() || ''; if (first && last) return `${first}${last}`; if (first) return first; if (user.email) return user.email[0].toUpperCase(); return 'U'; } // Helper function to get user role display function getUserRoleDisplay(user: { role?: string; brokerage?: string } | null): string { if (!user) return 'User'; if (user.brokerage) return user.brokerage; switch (user.role?.toLowerCase()) { case 'admin': return 'Administrator'; case 'agent': return 'Real Estate Agent'; case 'broker': return 'Broker'; case 'manager': return 'Team Manager'; default: return user.role || 'User'; } } function NavLink({ item, collapsed, isActive }: { item: typeof navItems[0]; collapsed: boolean; isActive: boolean }) { const Icon = item.icon; const linkContent = ( {!collapsed && ( {item.label} )} ); return ( {linkContent} ); } function SidebarContent({ collapsed, setCollapsed, onMobileClose }: { collapsed: boolean; setCollapsed: (v: boolean) => void; onMobileClose?: () => void; }) { const pathname = usePathname(); const router = useRouter(); const { user, logout } = useAuth(); const { isConnected } = useRealtimeContext(); const [isLoggingOut, setIsLoggingOut] = useState(false); const handleLogout = async () => { setIsLoggingOut(true); try { await logout(); router.push('/login'); } finally { setIsLoggingOut(false); } }; // Check if user is admin const isAdmin = user?.role?.toLowerCase() === 'admin'; // Filter bottom nav items based on user role const filteredBottomNavItems = bottomNavItems.filter( (item) => !item.adminOnly || isAdmin ); return (
{/* Logo */}
CRESync Real Estate CRM
{onMobileClose && ( )}
{/* Connection Status */}
{isConnected ? ( <> Connected ) : ( <> Connecting... )}
{/* Setup Section */}
Setup
{/* Main Navigation */}
Main Menu
{/* System Section */}
System
{/* User Section */}
{/* User Menu */}
{getUserInitials(user)}

{user?.firstName} {user?.lastName}

{user?.email}

{/* Logout button when collapsed */} {collapsed && (
)}
{/* Expand Button (when collapsed) */} {collapsed && (
)}
); } function AppLayoutContent({ children }: { children: React.ReactNode }) { const pathname = usePathname(); const [collapsed, setCollapsed] = useState(false); const [mobileOpen, setMobileOpen] = useState(false); const [searchOpen, setSearchOpen] = useState(false); const { user, loading } = useAuth(); // Placeholder notification count const notificationCount = 3; // Handle Cmd/Ctrl+K for search useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setSearchOpen((prev) => !prev); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, []); if (loading) { return (

Loading...

); } const currentPage = [...setupNavItems, ...navItems, ...bottomNavItems].find((item) => pathname === item.href)?.label || 'CRESync'; return (
{/* Search Modal */} setSearchOpen(false)} /> {/* Desktop Sidebar */} {/* Mobile Sidebar Overlay */} {mobileOpen && (
setMobileOpen(false)} aria-hidden="true" />
)} {/* Main Content Area */}
{/* Mobile Header */}
CRESync
{/* Main Content */}
{/* Top Bar (Desktop) */}
{/* Page Content */}
{children}
{/* Skip to main content link for accessibility */} Skip to main content
); } export default function AppLayout({ children }: { children: React.ReactNode }) { return ( {children} ); }