Files
promo_steakhouse/src/components/app-sidebar.tsx
T
lukas c65842ff5c
CI / test (push) Successful in 5m5s
CI / build (push) Successful in 4m6s
CI / deploy (push) Successful in 44s
✨ first version
2026-08-28 08:00:21 +02:00

129 lines
4.0 KiB
TypeScript

import { useEffect, useRef, useState } from 'react'
import { Link, useRouter } from '@tanstack/react-router'
import { authClient } from '#/lib/auth-client'
type StaffUser = { name: string; role?: string | null }
type SectionLink = { label: string; hash: string }
type Props = {
staffUser?: StaffUser | null
sectionLinks?: SectionLink[]
}
function MenuIcon() {
return (
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" aria-hidden="true">
<path d="M4 6h16M4 12h16M4 18h16" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
</svg>
)
}
export function AppSidebar({ staffUser, sectionLinks }: Props) {
const router = useRouter()
const [isOpen, setIsOpen] = useState(false)
const navRef = useRef<HTMLElement>(null)
useEffect(() => {
if (!isOpen) return
function handleOutsideClick(event: MouseEvent) {
if (navRef.current && !navRef.current.contains(event.target as Node)) {
setIsOpen(false)
}
}
function handleKeyDown(event: KeyboardEvent) {
if (event.key === 'Escape') setIsOpen(false)
}
document.addEventListener('mousedown', handleOutsideClick)
document.addEventListener('keydown', handleKeyDown)
return () => {
document.removeEventListener('mousedown', handleOutsideClick)
document.removeEventListener('keydown', handleKeyDown)
}
}, [isOpen])
async function handleLogout() {
await authClient.signOut()
await router.navigate({ to: '/staff/login' })
await router.invalidate()
}
return (
<nav className="app-sidebar" aria-label="Hauptnavigation" ref={navRef}>
<div className="app-sidebar-bar">
<Link className="wordmark app-sidebar-brand" to="/" onClick={() => setIsOpen(false)}>
Steakhaus <span>bei Mirko</span>
</Link>
<button
type="button"
className="app-sidebar-toggle"
aria-label={isOpen ? 'Menü schließen' : 'Menü öffnen'}
aria-expanded={isOpen}
onClick={() => setIsOpen((open) => !open)}
>
<MenuIcon />
</button>
</div>
<div className={isOpen ? 'app-sidebar-panel is-open' : 'app-sidebar-panel'} onClick={() => setIsOpen(false)}>
<ul className="app-sidebar-nav">
{sectionLinks && sectionLinks.length > 0 && (
<>
{sectionLinks.map((section) => (
<li key={section.hash}>
<Link to="/" hash={section.hash}>
{section.label}
</Link>
</li>
))}
<li className="app-sidebar-divider" role="separator" />
</>
)}
{staffUser && (
<li>
<Link to="/staff" activeOptions={{ exact: true }} activeProps={{ className: 'is-active' }}>
Reservierungen
</Link>
</li>
)}
{staffUser?.role === 'admin' && (
<li>
<Link to="/staff/team" activeProps={{ className: 'is-active' }}>
Mitarbeiter
</Link>
</li>
)}
{staffUser && <li className="app-sidebar-divider" role="separator" />}
<li>
<Link to="/" activeOptions={{ exact: true }} activeProps={{ className: 'is-active' }}>
Startseite
</Link>
</li>
<li>
<Link to="/impressum" activeProps={{ className: 'is-active' }}>
Impressum
</Link>
</li>
</ul>
<div className="app-sidebar-footer">
{staffUser ? (
<>
<span className="app-sidebar-user">Angemeldet als {staffUser.name}</span>
<button type="button" className="btn btn-secondary" onClick={handleLogout}>
Abmelden
</button>
</>
) : (
<Link className="btn btn-secondary" to="/staff/login">
Mitarbeiter-Login
</Link>
)}
</div>
</div>
</nav>
)
}