import { Inbox } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import type { ReactNode } from "react";
import { BenachrichtigungFormular } from "@/components/einstellungen/BenachrichtigungFormular";
import { Badge } from "@/components/ui/Badge";
import { Karte } from "@/components/ui/Karte";
import { Leerzustand } from "@/components/ui/Leerzustand";
import { MonoKopieren } from "@/components/ui/MonoKopieren";
import { Seitenkopf } from "@/components/ui/Seitenkopf";
import { Tabelle, TabellenZeile, TabellenZelle } from "@/components/ui/Tabelle";
import { datumZeit } from "@/lib/format";
import { darf } from "@/server/auth/rechte";
import { sitzungErforderlich } from "@/server/auth/sitzungspflicht";
import { einstellungenSeite, type Zeitplan, type ZustellungZeile } from "@/server/queries/einstellungen";
export const metadata: Metadata = { title: "Einstellungen" };
function Info({ titel, children }: { titel: string; children: ReactNode }) {
return (
{titel}
{children}
);
}
function Abschnitt({ titel, id, children }: { titel: string; id: string; children: ReactNode }) {
return (
);
}
function ZeitplanAnzeige({ plan }: { plan: Zeitplan }) {
return (
{plan.beschreibung && {plan.beschreibung}}
{plan.ausdruck}
);
}
const KANAL_TEXT = { EMAIL: "E-Mail", WEBHOOK: "Webhook" } as const;
function Zustellungen({ zeilen }: { zeilen: readonly ZustellungZeile[] }) {
if (zeilen.length === 0) {
return (
}
titel="Noch nichts versendet"
text="Hier erscheinen die letzten Zustellungen samt Ergebnis – auch Testnachrichten."
/>
);
}
return (
{zeilen.map((z) => (
{KANAL_TEXT[z.kanal]}
{z.betreff}
{z.anlaesse === 1 ? "1 Anlass" : `${z.anlaesse} Anlässe`}
{z.versuche > 1 && ` · ${z.versuche}. Versuch`}
{z.ergebnis === "GESENDET" ? (
gesendet
) : (
fehlgeschlagen
{z.fehler && {z.fehler}}
{z.naechsterVersuchAm
? `neuer Versuch ab ${datumZeit(z.naechsterVersuchAm)}`
: "kein weiterer Versuch"}
)}
))}
);
}
/** Einstellungen (#028): lesen duerfen alle, aendern nur `einstellungenVerwalten` (Admin). */
export default async function Einstellungen() {
// Jede Seite prueft selbst; die Huelle ist nur das zweite Netz (CLAUDE.md).
const { benutzer } = await sitzungErforderlich("lesen", "/einstellungen");
const darfAendern = darf(benutzer.rolle, "einstellungenVerwalten");
const seite = await einstellungenSeite();
// Eine Webhook-Adresse traegt oft ein Token im Pfad – Leser sehen nur Schema und Host.
const ansicht = darfAendern
? seite.benachrichtigung
: {
...seite.benachrichtigung,
webhook: { ...seite.benachrichtigung.webhook, url: seite.webhookZiel ?? "" },
};
const { instanz } = seite;
return (
alle 5 Minuten geprüft
Zeitzone Europe/Berlin. Gesetzt über SSHKV_SYNC_CRON und{" "}
SSHKV_MELDUNG_CRON in der Umgebung des Workers.
{/* Platz fuer den Abschnitt „Syslog“ – folgt in einem eigenen Issue. */}
{instanz.version}
{instanz.deploymentKey ? (
<>
{darf(benutzer.rolle, "deploymentKeyVerwalten") && (
Deployment-Key rotieren
)}
>
) : (
noch nicht erzeugt – läuft der Worker?
)}
{instanz.oidc.konfiguriert ? (
instanz.oidc.name
) : (
nicht eingerichtet
)}
{!instanz.notfall.vorhanden ? (
nicht angelegt
) : instanz.notfall.totpEingerichtet ? (
TOTP eingerichtet
) : (
TOTP noch nicht eingerichtet
)}
);
}