import { FormEvent, useEffect, useMemo, useState } from "react"; import { apiDelete, apiGet, apiPatch, apiPost, pdfUrl } from "../lib/api"; import type { PortalSnapshot, UserRole } from "../lib/types"; function formatDate(value: string | null) { if (!value) { return "-"; } return new Intl.DateTimeFormat("de-DE", { dateStyle: "medium", timeStyle: "short", }).format(new Date(value)); } export default function PortalPage() { const [snapshot, setSnapshot] = useState(null); const [selectedFarmer, setSelectedFarmer] = useState(""); const [farmerQuery, setFarmerQuery] = useState(""); const [cowQuery, setCowQuery] = useState(""); const [sampleNumberQuery, setSampleNumberQuery] = useState(""); const [dateQuery, setDateQuery] = useState(""); const [selectedReports, setSelectedReports] = useState([]); const [message, setMessage] = useState(null); const [userForm, setUserForm] = useState({ code: "", displayName: "", email: "", portalLogin: "", password: "", role: "APP" as UserRole, }); const [passwordDrafts, setPasswordDrafts] = useState>({}); async function loadSnapshot() { const params = new URLSearchParams(); if (selectedFarmer) { params.set("farmerBusinessKey", selectedFarmer); } if (farmerQuery) { params.set("farmerQuery", farmerQuery); } if (cowQuery) { params.set("cowQuery", cowQuery); } if (sampleNumberQuery) { params.set("sampleNumber", sampleNumberQuery); } if (dateQuery) { params.set("date", dateQuery); } const response = await apiGet(`/portal/snapshot?${params.toString()}`); setSnapshot(response); setSelectedReports(response.reportCandidates.map((candidate) => candidate.sampleId)); } useEffect(() => { void loadSnapshot(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const reportCount = useMemo(() => selectedReports.length, [selectedReports]); function toggleReport(sampleId: string) { setSelectedReports((current) => current.includes(sampleId) ? current.filter((entry) => entry !== sampleId) : [...current, sampleId], ); } async function handleSearch(event?: FormEvent) { event?.preventDefault(); try { setMessage(null); await loadSnapshot(); } catch (loadError) { setMessage((loadError as Error).message); } } async function handleDispatchReports() { try { const response = await apiPost<{ mailDeliveryActive: boolean }>("/portal/reports/send", { sampleIds: selectedReports, }); setMessage( response.mailDeliveryActive ? "Berichte wurden versendet." : "Berichte wurden als versendet markiert. Fuer echten Mailversand fehlt noch SMTP-Konfiguration.", ); await loadSnapshot(); } catch (dispatchError) { setMessage((dispatchError as Error).message); } } async function handleCreateUser(event: FormEvent) { event.preventDefault(); try { await apiPost("/portal/users", { ...userForm, active: true, }); setUserForm({ code: "", displayName: "", email: "", portalLogin: "", password: "", role: "APP", }); setMessage("Benutzer gespeichert."); await loadSnapshot(); } catch (userError) { setMessage((userError as Error).message); } } async function handleDeleteUser(userId: string) { try { await apiDelete(`/portal/users/${userId}`); setMessage("Benutzer geloescht."); await loadSnapshot(); } catch (deleteError) { setMessage((deleteError as Error).message); } } async function handlePasswordChange(userId: string) { try { await apiPost(`/portal/users/${userId}/password`, { password: passwordDrafts[userId], }); setPasswordDrafts((current) => ({ ...current, [userId]: "" })); setMessage("Passwort aktualisiert."); } catch (passwordError) { setMessage((passwordError as Error).message); } } async function handleToggleBlocked(sampleId: string, blocked: boolean) { try { await apiPatch(`/portal/reports/${sampleId}/block`, { blocked }); await loadSnapshot(); } catch (blockError) { setMessage((blockError as Error).message); } } if (!snapshot) { return
Portal wird geladen ...
; } return (

MUH-Portal

Benutzer, Berichtversand und Schnellsuche

Das Portal kombiniert Verwaltungsfunktionen mit dem Versandstatus aller abgeschlossenen Proben.

{message ? (
{message}
) : null}

Bericht-Versand

Versandbereite Proben

{reportCount} markiert
{snapshot.reportCandidates.map((candidate) => ( ))}

Benutzerverwaltung

{snapshot.users.map((user) => ( ))}
Kuerzel Name E-Mail Login Rolle Passwort
{user.code} {user.displayName} {user.email ?? "-"} {user.portalLogin ?? "-"} {user.role} setPasswordDrafts((current) => ({ ...current, [user.id]: event.target.value })) } placeholder="Neues Passwort" />

Suchergebnis

Gefundene Milchproben

{snapshot.samples.map((sample) => ( ))}
Probe Anlage Landwirt Kuh Typ Interne Bemerkung PDF Versand
{sample.sampleNumber} {formatDate(sample.createdAt)} {sample.farmerName} {sample.cowNumber}{sample.cowName ? ` / ${sample.cowName}` : ""} {sample.sampleKindLabel === "DRY_OFF" ? "Trockensteller" : "Milchprobe"} {sample.internalNote ?? "-"} {sample.completed ? ( PDF ) : ( - )}
{sample.reportSent ? "versendet" : "offen"} {sample.completed ? ( ) : null}
); }