'use client'; import { useState } from 'react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { LayoutDashboard, Users, Bookmark, Anchor, Ship, Building2, Receipt, FileText, FolderOpen, Mail, Bell, Settings, Shield, Home, ChevronLeft, ChevronRight, Menu, ChevronDown, ChevronUp, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { useUIStore } from '@/stores/ui-store'; import { Button } from '@/components/ui/button'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Badge } from '@/components/ui/badge'; import { Separator } from '@/components/ui/separator'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import type { UserPortRole } from '@/lib/db/schema/users'; import type { Role } from '@/lib/db/schema/users'; interface SidebarProps { portRoles: (UserPortRole & { port: { id: string; slug: string; name: string }; role: Role })[]; isSuperAdmin?: boolean; user?: { name: string; email: string }; } interface NavItem { href: string; label: string; icon: React.ElementType; exact?: boolean; } interface NavSection { title: string; items: NavItem[]; adminRequired?: boolean; /** When true, only render if the user has marina-side access. */ marinaRequired?: boolean; /** When true, only render if the user has residential-side access. */ residentialRequired?: boolean; } function buildNavSections(portSlug: string | undefined): NavSection[] { const base = portSlug ? `/${portSlug}` : ''; return [ { title: 'Main', marinaRequired: true, items: [ { href: `${base}/dashboard`, label: 'Dashboard', icon: LayoutDashboard }, { href: `${base}/clients`, label: 'Clients', icon: Users }, { href: `${base}/yachts`, label: 'Yachts', icon: Ship }, { href: `${base}/companies`, label: 'Companies', icon: Building2 }, { href: `${base}/interests`, label: 'Interests', icon: Bookmark }, { href: `${base}/berths`, label: 'Berths', icon: Anchor }, ], }, { title: 'Residential', residentialRequired: true, items: [ { href: `${base}/residential/clients`, label: 'Residential Clients', icon: Home, }, { href: `${base}/residential/interests`, label: 'Residential Interests', icon: Bookmark, }, ], }, { title: 'Documents', marinaRequired: true, items: [ { href: `${base}/documents`, label: 'Documents', icon: FileText }, { href: `${base}/documents/files`, label: 'Files', icon: FolderOpen }, ], }, { title: 'Financial', marinaRequired: true, items: [ { href: `${base}/expenses`, label: 'Expenses', icon: Receipt }, { href: `${base}/invoices`, label: 'Invoices', icon: FileText }, ], }, { title: 'Communication', marinaRequired: true, items: [ { href: `${base}/email`, label: 'Email', icon: Mail }, { href: `${base}/reminders`, label: 'Reminders', icon: Bell }, ], }, { title: 'Admin', adminRequired: true, items: [ { href: `${base}/settings`, label: 'Settings', icon: Settings }, { href: `${base}/admin`, label: 'Administration', icon: Shield }, ], }, ]; } function NavItemLink({ item, collapsed, active, }: { item: NavItem; collapsed: boolean; active: boolean; }) { const content = ( {active && !collapsed && ( )} {!collapsed && {item.label}} ); if (collapsed) { return ( {content} {item.label} ); } return content; } function SidebarContent({ collapsed, portSlug, portRoles, hasAdminAccess, hasMarinaAccess, hasResidentialAccess, user, }: { collapsed: boolean; portSlug: string | undefined; portRoles: SidebarProps['portRoles']; hasAdminAccess: boolean; hasMarinaAccess: boolean; hasResidentialAccess: boolean; user?: SidebarProps['user']; }) { const pathname = usePathname(); const [adminExpanded, setAdminExpanded] = useState(true); const sections = buildNavSections(portSlug); function isActive(href: string, exact?: boolean): boolean { if (exact) return pathname === href; return pathname.startsWith(href); } return ( {/* Logo area */} PN {!collapsed && ( Port Nimara Marina CRM )} {/* Nav */} {sections.map((section) => { if (section.adminRequired && !hasAdminAccess) return null; if (section.marinaRequired && !hasMarinaAccess) return null; if (section.residentialRequired && !hasResidentialAccess) return null; return ( {!collapsed && ( {section.title} {section.adminRequired && ( setAdminExpanded((v) => !v)} className="text-[#71768a] hover:text-[#cdcfd6] transition-colors" > {adminExpanded ? ( ) : ( )} )} )} {(!section.adminRequired || adminExpanded || collapsed) && ( {section.items.map((item) => ( ))} )} ); })} {/* User footer */} {collapsed ? ( U User Profile ) : ( {(user?.name ?? 'U').slice(0, 1).toUpperCase()} {user?.name ?? 'User'} {portRoles[0]?.role?.name ?? 'Staff'} )} ); } export function Sidebar({ portRoles, isSuperAdmin = false, user }: SidebarProps) { const sidebarCollapsed = useUIStore((s) => s.sidebarCollapsed); const toggleSidebar = useUIStore((s) => s.toggleSidebar); const currentPortSlug = useUIStore((s) => s.currentPortSlug); // Super admins see every section regardless of role rows. const hasAdminAccess = isSuperAdmin || portRoles.some( (pr) => pr.role?.permissions?.admin?.manage_users || pr.role?.permissions?.admin?.manage_settings, ); const hasMarinaAccess = isSuperAdmin || portRoles.some((pr) => pr.role?.permissions?.clients?.view); const hasResidentialAccess = isSuperAdmin || portRoles.some((pr) => pr.residentialAccess || pr.role?.permissions?.residential_clients?.view); return ( <> {/* Desktop sidebar */} {/* Mobile drawer */} Open navigation > ); }
Port Nimara
Marina CRM
{user?.name ?? 'User'}