✨ first version
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user