import type { Metadata } from 'next' import Link from 'next/link' import { db } from '@/lib/db' import { requireUser } from '@/lib/auth/current' import { loadDashboard } from '@/lib/dashboard/load' import { de } from '@/lib/i18n/de' import { StampMark, classificationEdgeStyle } from '@/components/StampMark' import { clearRecentAction } from './actions' import type { RecentEntry } from '@/lib/recent/service' export const metadata: Metadata = { title: de.dashboard.heading } export const dynamic = 'force-dynamic' /** * Die Übersicht: vier Fragen, die man morgens hat. * * Woran arbeite ich, was ist fällig, wo hat jemand geschrieben, was hat sich * getan. Jede Liste läuft durch dieselbe Sichtbarkeitsprüfung wie die * Fallliste - das ist der Ort, an dem eine unachtsame Abfrage am ehesten eine * Akte verrät, die man nicht sehen darf. */ export default async function DashboardPage() { const user = await requireUser() const [daten, levels] = await Promise.all([ loadDashboard(user.permissions), db.clearanceLevelConfig.findMany({ orderBy: { level: 'asc' } }), ]) const levelName = new Map(levels.map((l) => [l.level, l.name])) const heute = new Date() return (

{de.dashboard.heading}

{de.dashboard.access}

{de.dashboard.opened}

{daten.geoeffnet.length > 0 ? (
) : null}
{daten.geoeffnet.length === 0 ? ( ) : (
    {daten.geoeffnet.map((eintrag) => (
  • ))}
)}
{(akte) => } {(akte) => ( )}

{de.dashboard.unread}

{daten.ungelesen.length === 0 ? (

{de.dashboard.unreadEmpty}

) : (
    {daten.ungelesen.map((eintrag) => (
  • {eintrag.label} {de.dashboard.unreadCount(eintrag.count)}
  • ))}
)}
{(akte) => }

{de.dashboard.recent}

{daten.zuletzt.length === 0 ? (

{de.dashboard.recentEmpty}

) : (
    {daten.zuletzt.map((akte) => (
  • ))}
)}
) } /** * Ein leerer Zustand ohne Satz. * * „Noch nichts geöffnet" zu schreiben erklärt nichts, was das leere Feld nicht * schon zeigt, und nimmt Platz weg, sobald etwas darin steht. Ein ruhiger * Rahmen mit einem Strich sagt dasselbe und verschwindet von selbst, wenn die * Liste sich füllt. */ function EmptyMark() { return (
) } type Fall = { id: string caseNumber: string title: string status: string classification: number updatedAt: Date dueAt?: Date | null } function Block({ titel, leer, eintraege, children, }: { titel: string leer: string eintraege: Fall[] children: (akte: Fall) => React.ReactNode }) { return (

{titel}

{eintraege.length === 0 ? (

{leer}

) : ( )}
) } /** * Eine Zeile der Sprungliste. Sie kann eine Akte, eine Person oder ein * Dokument sein - deshalb steht die Art nicht dabei, sondern nur das, woran * man sie erkennt: Aktenzeichen, Name oder Dokumentnummer. * * Eine Akte und ein Dokument tragen eine **Kennung**, eine Person nicht: ihr * Name ist der Titel. Stünde er in der Kennungsspalte, stünde er in Mono, wäre * abgeschnitten, und der Dienstgrad rutschte dorthin, wo sonst der Titel * steht - untereinander ergäbe das keine Spalte mehr. * * Ohne Vorabruf, anders als die übrigen Listen: die Seiten dahinter merken * sich, dass sie geöffnet wurden. Der Vorabruf wird zwar serverseitig erkannt * und zählt nicht mit, aber ausgerechnet diese Liste sollte sich nicht selbst * am Leben halten können, wenn diese Erkennung einmal nicht greift. */ function Sprung({ eintrag, levelName, }: { eintrag: RecentEntry levelName: Map }) { return ( {eintrag.targetType === 'PERSONNEL' ? ( <> {/* Kein Aktenzeichen, aber auch keine Leerstelle: dort steht, was es ist. Eine leere Spalte lässt die Zeile wie einen Fehler aussehen. */} {de.personnel.one} {eintrag.secondary ? `[${eintrag.secondary}]` : ''} {eintrag.label} ) : ( <> {eintrag.label} {eintrag.secondary} )} ) } function Akte({ akte, levelName, zusatz, dringend, }: { akte: Fall levelName: Map zusatz?: string dringend?: boolean }) { return ( {akte.caseNumber} {akte.title} {zusatz} ) }