51 lines
1.5 KiB
React
51 lines
1.5 KiB
React
|
|
import { NavLink, Outlet } from 'react-router-dom'
|
||
|
|
import { useSession } from '../context/SessionContext.jsx'
|
||
|
|
import { useCapabilities } from '../hooks/useCapabilities.js'
|
||
|
|
import { getNavViews } from '../registry/viewRegistry.js'
|
||
|
|
import { LoadingState } from '../components/LoadingState.jsx'
|
||
|
|
|
||
|
|
export function AppLayout() {
|
||
|
|
const { me, context, signOut, loading } = useSession()
|
||
|
|
const { capabilities } = useCapabilities()
|
||
|
|
const navViews = getNavViews(capabilities)
|
||
|
|
|
||
|
|
if (loading) {
|
||
|
|
return (
|
||
|
|
<main className="shell">
|
||
|
|
<LoadingState message="Session wird geladen …" />
|
||
|
|
</main>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="app-layout">
|
||
|
|
<header className="app-header">
|
||
|
|
<div className="app-header-brand">
|
||
|
|
<strong>Kairo</strong>
|
||
|
|
{context?.tenant?.name && <span className="muted"> · {context.tenant.name}</span>}
|
||
|
|
</div>
|
||
|
|
<nav className="app-nav">
|
||
|
|
{navViews.map((view) => (
|
||
|
|
<NavLink
|
||
|
|
key={view.key}
|
||
|
|
to={view.path}
|
||
|
|
className={({ isActive }) => (isActive ? 'nav-link active' : 'nav-link')}
|
||
|
|
>
|
||
|
|
{view.title}
|
||
|
|
</NavLink>
|
||
|
|
))}
|
||
|
|
</nav>
|
||
|
|
<div className="app-header-user">
|
||
|
|
<span className="user-label">{me?.display_name}</span>
|
||
|
|
<button type="button" className="secondary" onClick={signOut}>
|
||
|
|
Abmelden
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</header>
|
||
|
|
<main className="shell workspace-shell">
|
||
|
|
<Outlet />
|
||
|
|
</main>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|