"use client"; import { useCallback, useEffect, useState } from "react"; import type { ReactNode } from "react"; import { ExternalLink, MailCheck, Save, Send, ShieldCheck } from "lucide-react"; import { useToast } from "@/components/common/ToastProvider"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { api } from "@/lib/api"; import type { PublicLinksSettings, SettingsSource, SmtpSettings, SmtpSettingsPayload, SmtpTestResponse, } from "@/types/system-settings"; type SettingsTab = "smtp" | "public-links"; const sourceLabels: Record = { database: "Admin-Konfiguration", environment: "Umgebung", missing: "Nicht konfiguriert", }; function getErrorMessage(error: unknown, fallback: string) { if (typeof error === "object" && error !== null && "response" in error) { const response = (error as { response?: { data?: { detail?: string; message?: string } } }).response; return response?.data?.detail ?? response?.data?.message ?? fallback; } return fallback; } function emptySmtpSettings(): SmtpSettings { return { host: "", port: 587, username: "", password_is_set: false, from_email: "", from_name: "Funktechnik Schubert", use_tls: true, enabled: false, source: "missing", }; } export default function SettingsPage() { const { showToast } = useToast(); const [activeTab, setActiveTab] = useState("smtp"); const [smtp, setSmtp] = useState(emptySmtpSettings()); const [newPassword, setNewPassword] = useState(""); const [testRecipient, setTestRecipient] = useState(""); const [publicLinks, setPublicLinks] = useState({ repair_status_base_url: "", source: "missing", }); const [loading, setLoading] = useState(true); const [savingSmtp, setSavingSmtp] = useState(false); const [sendingTest, setSendingTest] = useState(false); const [savingPublicLinks, setSavingPublicLinks] = useState(false); const [error, setError] = useState(""); const loadSettings = useCallback(async () => { setError(""); setLoading(true); try { const [smtpResponse, publicLinksResponse] = await Promise.all([ api.get("/system-settings/smtp"), api.get("/system-settings/public-links"), ]); setSmtp(smtpResponse.data); setPublicLinks(publicLinksResponse.data); } catch (err) { setError(getErrorMessage(err, "Einstellungen konnten nicht geladen werden.")); } finally { setLoading(false); } }, []); useEffect(() => { queueMicrotask(() => { void loadSettings(); }); }, [loadSettings]); async function saveSmtp() { setSavingSmtp(true); try { const payload: SmtpSettingsPayload = { host: smtp.host, port: smtp.port, username: smtp.username, from_email: smtp.from_email, from_name: smtp.from_name, use_tls: smtp.use_tls, enabled: smtp.enabled, }; if (newPassword) { payload.password = newPassword; } const response = await api.put("/system-settings/smtp", payload); setSmtp(response.data); setNewPassword(""); showToast({ type: "success", title: "SMTP-Konfiguration gespeichert" }); } catch (err) { showToast({ type: "error", title: "SMTP konnte nicht gespeichert werden", description: getErrorMessage(err, "Bitte prüfe die Eingaben."), }); } finally { setSavingSmtp(false); } } async function sendTestMail() { setSendingTest(true); try { const response = await api.post("/system-settings/smtp/test", { recipient: testRecipient, }); showToast({ type: response.data.success ? "success" : "error", title: response.data.success ? "Testmail versendet" : "Testmail fehlgeschlagen", description: response.data.message, }); } catch (err) { showToast({ type: "error", title: "Testmail fehlgeschlagen", description: getErrorMessage(err, "Die Testmail konnte nicht versendet werden."), }); } finally { setSendingTest(false); } } async function savePublicLinks() { setSavingPublicLinks(true); try { const response = await api.put("/system-settings/public-links", { repair_status_base_url: publicLinks.repair_status_base_url, }); setPublicLinks(response.data); showToast({ type: "success", title: "Öffentliche Links gespeichert" }); } catch (err) { showToast({ type: "error", title: "Öffentliche Links konnten nicht gespeichert werden", description: getErrorMessage(err, "Bitte prüfe die Basis-URL."), }); } finally { setSavingPublicLinks(false); } } if (loading) { return
Einstellungen werden geladen...
; } if (error) { return
{error}
; } return (

Einstellungen

SMTP-Versand und öffentliche Statuslinks verwalten

setActiveTab("smtp")}> SMTP setActiveTab("public-links")}> Öffentliche Links
{activeTab === "smtp" ? (

SMTP

Quelle: {sourceLabels[smtp.source]} {smtp.password_is_set ? " · Passwort ist gesetzt" : ""}

setSmtp((current) => ({ ...current, host: event.target.value }))} /> setSmtp((current) => ({ ...current, port: Number(event.target.value) || 587 }))} /> setSmtp((current) => ({ ...current, username: event.target.value }))} /> setNewPassword(event.target.value)} /> setSmtp((current) => ({ ...current, from_email: event.target.value }))} /> setSmtp((current) => ({ ...current, from_name: event.target.value }))} />
Für Apple Mail/iCloud: smtp.mail.me.com, Port 587, TLS/STARTTLS aktiv, Benutzername vollständige Mailadresse, Passwort = app-spezifisches Passwort.

Testmail senden

setTestRecipient(event.target.value)} />
) : (

Öffentliche Links

Quelle: {sourceLabels[publicLinks.source]}

setPublicLinks((current) => ({ ...current, repair_status_base_url: event.target.value }))} />

Statusmails erzeugen weiterhin sichere Einmal-Token in Hermes. Die Basis-URL bestimmt nur, auf welche öffentliche Website-Route der Link zeigt.

)}
); } function TabButton({ active, onClick, children, }: { active: boolean; onClick: () => void; children: ReactNode; }) { return ( ); } function Field({ label, children }: { label: string; children: ReactNode }) { return ( ); }