Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung.
80 lines
2.7 KiB
TypeScript
80 lines
2.7 KiB
TypeScript
import Link from 'next/link'
|
|
import { signOut } from '@/auth'
|
|
import { requireUser } from '@/lib/auth/current'
|
|
import { de } from '@/lib/i18n/de'
|
|
import { PaletteTrigger } from '@/components/palette/PaletteTrigger'
|
|
import { NavLinks } from '@/components/NavLinks'
|
|
import { ProfileMenu } from '@/components/ProfileMenu'
|
|
import { Avatar } from '@/components/Avatar'
|
|
import { SearchBar } from '@/components/SearchBar'
|
|
import { Vitals } from '@/components/Vitals'
|
|
import { hasAdminAccess } from './admin/sections'
|
|
|
|
/**
|
|
* Das Rahmenwerk der angemeldeten Anwendung.
|
|
*
|
|
* Die Kopfzeile trägt links die Bereiche der Arbeit - Übersicht, Fallakten,
|
|
* Personalakten, Verwaltung - und rechts alles, was den Nutzer selbst
|
|
* betrifft: Suchbalken und Profilbild. Thema, Benachrichtigungen und Abmelden
|
|
* standen früher zwischen den Aktenbereichen und nahmen dort den Platz weg,
|
|
* den die Arbeit braucht; sie sitzen jetzt hinter dem Profilbild.
|
|
*/
|
|
export default async function AppLayout({ children }: { children: React.ReactNode }) {
|
|
const user = await requireUser()
|
|
|
|
async function abmelden() {
|
|
'use server'
|
|
await signOut({ redirectTo: '/anmelden' })
|
|
}
|
|
|
|
const darfPersonal =
|
|
user.permissions.isAdmin || user.permissions.permissions.has('personnel.read')
|
|
|
|
return (
|
|
<div className="min-h-dvh">
|
|
{/* Strg+K. Winzig; die Palette selbst wird erst beim Öffnen geholt. */}
|
|
<PaletteTrigger />
|
|
<Vitals />
|
|
<header className="border-b border-line">
|
|
<div className="mx-auto flex max-w-5xl flex-wrap items-center gap-x-5 gap-y-3 px-6 py-3">
|
|
<Link href="/uebersicht" className="font-condensed text-text no-underline">
|
|
{de.app.shortName}
|
|
</Link>
|
|
|
|
<NavLinks
|
|
links={[
|
|
{ href: '/uebersicht', label: de.nav.dashboard },
|
|
{ href: '/faelle', label: de.nav.cases },
|
|
...(darfPersonal
|
|
? [{ href: '/personalakten', label: de.nav.personnel }]
|
|
: []),
|
|
{ href: '/abteilungen', label: de.nav.departments },
|
|
...(hasAdminAccess(user.permissions)
|
|
? [{ href: '/admin', label: de.nav.admin }]
|
|
: []),
|
|
]}
|
|
/>
|
|
|
|
<div className="ml-auto flex items-center gap-3">
|
|
<SearchBar />
|
|
<ProfileMenu
|
|
displayName={user.displayName}
|
|
username={user.username}
|
|
signOutAction={abmelden}
|
|
avatar={
|
|
<Avatar
|
|
userId={user.id}
|
|
avatarHash={user.avatarHash}
|
|
displayName={user.displayName}
|
|
/>
|
|
}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div id="inhalt">{children}</div>
|
|
</div>
|
|
)
|
|
}
|