'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 (
);
}
// 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 (
setSearchQuery(e.target.value)}
aria-label="Search input"
/>
Esc
Quick Search
Tab to navigate
Enter to select
);
}
// 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 (
);
}
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 */}
{/* 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}
);
}