fix: clean up 'app-sidebar.tsx' export issues
Refactor SidebarContent and add fallback for undefined member names. Co-authored-by: Moheeb Zara <1184415+virgilvox@users.noreply.github.com>
This commit is contained in:
+30
-42
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { usePathname, useRouter } from 'next/navigation'
|
import { usePathname } from 'next/navigation'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { signOut } from '@/lib/auth-actions'
|
import { signOut } from '@/lib/auth-actions'
|
||||||
@@ -11,16 +11,16 @@ import {
|
|||||||
MessageSquare, Users, CreditCard, BookUser, Download, LogOut,
|
MessageSquare, Users, CreditCard, BookUser, Download, LogOut,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
|
|
||||||
function NavLink({
|
interface NavLinkProps {
|
||||||
href, label, icon: Icon, badge, active, onClick,
|
|
||||||
}: {
|
|
||||||
href: string
|
href: string
|
||||||
label: string
|
label: string
|
||||||
icon: React.ElementType
|
icon: React.ElementType
|
||||||
badge?: number
|
badge?: number
|
||||||
active: boolean
|
active: boolean
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
}) {
|
}
|
||||||
|
|
||||||
|
function NavLink({ href, label, icon: Icon, badge, active, onClick }: NavLinkProps) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={href}
|
href={href}
|
||||||
@@ -45,15 +45,6 @@ function NavLink({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom nav items for mobile
|
|
||||||
const MOBILE_NAV = [
|
|
||||||
{ label: 'Home', href: '/dashboard', icon: LayoutDashboard },
|
|
||||||
{ label: 'Tasks', href: '/tasks', icon: ListChecks },
|
|
||||||
{ label: 'Comms', href: '/comms', icon: MessageSquare },
|
|
||||||
{ label: 'Members', href: '/members', icon: Users },
|
|
||||||
{ label: 'More', href: null, icon: Menu },
|
|
||||||
]
|
|
||||||
|
|
||||||
interface AppSidebarProps {
|
interface AppSidebarProps {
|
||||||
member: SpaceMember & { spaces: Space }
|
member: SpaceMember & { spaces: Space }
|
||||||
taskBadge?: number
|
taskBadge?: number
|
||||||
@@ -63,21 +54,20 @@ interface AppSidebarProps {
|
|||||||
|
|
||||||
export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge = 0 }: AppSidebarProps) {
|
export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge = 0 }: AppSidebarProps) {
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const router = useRouter()
|
|
||||||
const space = member.spaces
|
const space = member.spaces
|
||||||
const initials = member.display_name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2)
|
const initials = (member.display_name || 'U').split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2)
|
||||||
const isAdmin = member.role === 'admin' || member.role === 'board'
|
const isAdmin = member.role === 'admin' || member.role === 'board'
|
||||||
const [drawerOpen, setDrawerOpen] = useState(false)
|
const [drawerOpen, setDrawerOpen] = useState(false)
|
||||||
|
|
||||||
function isActive(href: string) {
|
const isActive = (href: string) => pathname === href || pathname.startsWith(href + '/')
|
||||||
return pathname === href || pathname.startsWith(href + '/')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSignOut() {
|
const handleSignOut = async () => {
|
||||||
await signOut()
|
await signOut()
|
||||||
}
|
}
|
||||||
|
|
||||||
const SidebarContent = ({ onNav }: { onNav?: () => void }) => (
|
const closeDrawer = () => setDrawerOpen(false)
|
||||||
|
|
||||||
|
const renderNav = (onNav?: () => void) => (
|
||||||
<>
|
<>
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="px-5 py-5 border-b border-[var(--sidebar-border)]">
|
<div className="px-5 py-5 border-b border-[var(--sidebar-border)]">
|
||||||
@@ -94,26 +84,26 @@ export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge
|
|||||||
<div className="px-3 mb-1">
|
<div className="px-3 mb-1">
|
||||||
<p className="text-[10px] uppercase tracking-widest text-[var(--sidebar-foreground)]/30 px-2 py-1 font-mono">Workspace</p>
|
<p className="text-[10px] uppercase tracking-widest text-[var(--sidebar-foreground)]/30 px-2 py-1 font-mono">Workspace</p>
|
||||||
</div>
|
</div>
|
||||||
<NavLink href="/dashboard" label="Dashboard" icon={LayoutDashboard} active={isActive('/dashboard')} onClick={onNav} />
|
<NavLink href="/dashboard" label="Dashboard" icon={LayoutDashboard} active={isActive('/dashboard')} onClick={onNav} />
|
||||||
<NavLink href="/tasks" label="Tasks & Chores" icon={ListChecks} active={isActive('/tasks')} badge={taskBadge} onClick={onNav} />
|
<NavLink href="/tasks" label="Tasks & Chores" icon={ListChecks} active={isActive('/tasks')} badge={taskBadge} onClick={onNav} />
|
||||||
<NavLink href="/projects" label="Projects" icon={FolderKanban} active={isActive('/projects')} onClick={onNav} />
|
<NavLink href="/projects" label="Projects" icon={FolderKanban} active={isActive('/projects')} onClick={onNav} />
|
||||||
<NavLink href="/ops" label="Ops & Facilities" icon={Settings2} active={isActive('/ops')} onClick={onNav} />
|
<NavLink href="/ops" label="Ops & Facilities" icon={Settings2} active={isActive('/ops')} onClick={onNav} />
|
||||||
<NavLink href="/comms" label="Comms" icon={MessageSquare} active={isActive('/comms')} badge={commsBadge} onClick={onNav} />
|
<NavLink href="/comms" label="Comms" icon={MessageSquare} active={isActive('/comms')} badge={commsBadge} onClick={onNav} />
|
||||||
|
|
||||||
<div className="px-3 mt-4 mb-1">
|
<div className="px-3 mt-4 mb-1">
|
||||||
<p className="text-[10px] uppercase tracking-widest text-[var(--sidebar-foreground)]/30 px-2 py-1 font-mono">People</p>
|
<p className="text-[10px] uppercase tracking-widest text-[var(--sidebar-foreground)]/30 px-2 py-1 font-mono">People</p>
|
||||||
</div>
|
</div>
|
||||||
<NavLink href="/members" label="Members" icon={Users} active={isActive('/members')} onClick={onNav} />
|
<NavLink href="/members" label="Members" icon={Users} active={isActive('/members')} onClick={onNav} />
|
||||||
<NavLink href="/payments" label="Payments" icon={CreditCard} active={isActive('/payments')} badge={paymentBadge} onClick={onNav} />
|
<NavLink href="/payments" label="Payments" icon={CreditCard} active={isActive('/payments')} badge={paymentBadge} onClick={onNav} />
|
||||||
<NavLink href="/contacts" label="Contacts" icon={BookUser} active={isActive('/contacts')} onClick={onNav} />
|
<NavLink href="/contacts" label="Contacts" icon={BookUser} active={isActive('/contacts')} onClick={onNav} />
|
||||||
|
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<>
|
<>
|
||||||
<div className="px-3 mt-4 mb-1">
|
<div className="px-3 mt-4 mb-1">
|
||||||
<p className="text-[10px] uppercase tracking-widest text-[var(--sidebar-foreground)]/30 px-2 py-1 font-mono">Admin</p>
|
<p className="text-[10px] uppercase tracking-widest text-[var(--sidebar-foreground)]/30 px-2 py-1 font-mono">Admin</p>
|
||||||
</div>
|
</div>
|
||||||
<NavLink href="/import" label="Import / Sync" icon={Download} active={isActive('/import')} onClick={onNav} />
|
<NavLink href="/import" label="Import / Sync" icon={Download} active={isActive('/import')} onClick={onNav} />
|
||||||
<NavLink href="/settings" label="Settings" icon={Settings2} active={isActive('/settings')} onClick={onNav} />
|
<NavLink href="/settings" label="Settings" icon={Settings2} active={isActive('/settings')} onClick={onNav} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
@@ -139,13 +129,13 @@ export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* ── Desktop sidebar ─────────────────────────────────── */}
|
{/* Desktop sidebar */}
|
||||||
<aside className="hidden md:flex w-[230px] shrink-0 bg-[var(--sidebar)] flex-col h-screen sticky top-0 border-r border-[var(--sidebar-border)]">
|
<aside className="hidden md:flex w-[230px] shrink-0 bg-[var(--sidebar)] flex-col h-screen sticky top-0 border-r border-[var(--sidebar-border)]">
|
||||||
<SidebarContent />
|
{renderNav()}
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
{/* ── Mobile: top bar ──────────────────────────────────── */}
|
{/* Mobile: top bar */}
|
||||||
<div className="md:hidden fixed top-0 left-0 right-0 z-40 bg-[var(--sidebar)] border-b border-[var(--sidebar-border)] flex items-center justify-between px-4 py-3">
|
<div className="md:hidden fixed top-0 left-0 right-0 z-40 bg-[var(--sidebar)] border-b border-[var(--sidebar-border)] flex items-center justify-between px-4 h-[52px]">
|
||||||
<Link href="/dashboard" className="flex items-center gap-2">
|
<Link href="/dashboard" className="flex items-center gap-2">
|
||||||
<div className="w-7 h-7 rounded bg-[var(--sidebar-primary)] flex items-center justify-center">
|
<div className="w-7 h-7 rounded bg-[var(--sidebar-primary)] flex items-center justify-center">
|
||||||
<span className="text-white font-mono text-[10px] font-bold">hs</span>
|
<span className="text-white font-mono text-[10px] font-bold">hs</span>
|
||||||
@@ -161,21 +151,19 @@ export function AppSidebar({ member, taskBadge = 0, commsBadge = 0, paymentBadge
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Mobile: full drawer ──────────────────────────────── */}
|
{/* Mobile: drawer overlay */}
|
||||||
{drawerOpen && (
|
{drawerOpen && (
|
||||||
<div className="md:hidden fixed inset-0 z-50 flex">
|
<div className="md:hidden fixed inset-0 z-50 flex">
|
||||||
{/* Backdrop */}
|
<div className="absolute inset-0 bg-black/50" onClick={closeDrawer} />
|
||||||
<div className="absolute inset-0 bg-black/50" onClick={() => setDrawerOpen(false)} />
|
|
||||||
{/* Drawer */}
|
|
||||||
<div className="relative w-[280px] bg-[var(--sidebar)] flex flex-col h-full shadow-xl">
|
<div className="relative w-[280px] bg-[var(--sidebar)] flex flex-col h-full shadow-xl">
|
||||||
<div className="flex items-center justify-between px-4 py-3 border-b border-[var(--sidebar-border)]">
|
<div className="flex items-center justify-between px-4 h-[52px] border-b border-[var(--sidebar-border)]">
|
||||||
<span className="text-[var(--sidebar-foreground)] text-sm font-mono font-bold">Menu</span>
|
<span className="text-[var(--sidebar-foreground)] text-sm font-mono font-bold">Menu</span>
|
||||||
<button onClick={() => setDrawerOpen(false)} className="text-[var(--sidebar-foreground)]/50 hover:text-[var(--sidebar-foreground)]">
|
<button onClick={closeDrawer} className="text-[var(--sidebar-foreground)]/50 hover:text-[var(--sidebar-foreground)]">
|
||||||
<X className="w-5 h-5" />
|
<X className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
<SidebarContent onNav={() => setDrawerOpen(false)} />
|
{renderNav(closeDrawer)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user