import Link from "next/link"; import { notFound, redirect } from "next/navigation"; import { ArrowLeft } from "lucide-react"; import { aktuelleSitzung } from "@/lib/auth"; import { darfPersonSehen } from "@/lib/authz"; import { fuerOrganisation } from "@/lib/db"; import { alsDatum, personAnrede } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { FristAnzeige, NichtsGefunden } from "@/components/stammdaten/anzeige"; import { DIENSTGRAD_TEXT } from "@/lib/stammdaten/texte"; export const metadata = { title: "Mitglied" }; /** * Mitgliedsdetail. * * Die Zugriffsprüfung läuft über darfPersonSehen(): die eigenen Daten darf * jeder sehen, fremde nur mit dem Recht person.lesen. Adressen und * Geburtsdatum sind personenbezogene Daten — sie stehen deshalb hinter * derselben Schranke wie alles andere. */ export default async function MitgliedSeite({ params }: { params: Promise<{ id: string }> }) { const sitzung = await aktuelleSitzung(); if (!sitzung) redirect("/anmelden"); const { id } = await params; if (!darfPersonSehen(sitzung, id)) redirect("/mitglieder"); const person = await fuerOrganisation(sitzung.organisationId, (db) => db.person.findUnique({ where: { id }, select: { id: true, vorname: true, nachname: true, mitgliedsnummer: true, dienstgrad: true, abteilung: true, email: true, telefon: true, mobil: true, strasse: true, plz: true, ort: true, geburtsdatum: true, eintrittsdatum: true, austrittsdatum: true, aktiv: true, // Seit Phase 10 hängt die Anmeldung am Konto, nicht an der Akte. Ob // ein Mitglied überhaupt eines hat, ist die nützlichere Auskunft als // ein Zeitstempel: ohne Konto kommt es nicht in FLORIAN hinein. mitgliedschaft: { select: { art: true, benutzer: { select: { email: true, letzteAnmeldung: true, aktiv: true }, }, }, }, rollen: { include: { rolle: true } }, qualifikationen: { where: { geloeschtAm: null }, include: { typ: true }, orderBy: [{ gueltigBis: "asc" }, { erworbenAm: "desc" }], }, ausweisTokens: { where: { geloeschtAm: null, aktiv: true }, select: { id: true, typ: true, bezeichnung: true, letzteNutzung: true }, }, }, }), ); if (!person) notFound(); /* * eslint-disable-next-line react/jsx-key -- Fehlalarm: Diese JSX-Elemente * sind nicht die Kinder einer Liste, sondern die zweiten Glieder von * Wertepaaren. Gerendert werden sie unten in einer map, deren Wrapper den * key traegt (`
Kein Terminal-Zugang hinterlegt.
) : (