import Link from "next/link"; import { ContentHeader } from "@/components/layout/ContentHeader"; import { AblaufBadge, EinkaufBadge, KeineMeldungBadge, VerkaufBadge } from "@/components/ui/Badges"; import { Callout, ProgressBar } from "@/components/ui/Callout"; import { Card } from "@/components/ui/Card"; import { CopyableCode } from "@/components/ui/CopyableCode"; import { SmallBox } from "@/components/ui/SmallBox"; import { TodoList, type Aufgabe } from "@/components/ui/TodoList"; import { formatDatum, formatEuro } from "@/lib/format"; import { hostsNachAblauf, offeneAufgaben } from "@/server/queries/dashboard"; import { hostsOhneKunde, kennzahlen } from "@/server/queries/hosts"; import { kundenListe, offeneRechnungspunkteProKunde } from "@/server/queries/kunden"; export const metadata = { title: "Dashboard" }; export default async function DashboardSeite() { const heute = new Date(); const [zahlen, ohneKunde, ablaufListe, aufgabenDaten, kunden, rechnungspunkte] = await Promise.all([ kennzahlen(heute), hostsOhneKunde(), hostsNachAblauf(heute), offeneAufgaben(), kundenListe(), offeneRechnungspunkteProKunde(), ]); const aufgaben: Aufgabe[] = [ ...aufgabenDaten.aufgaben.map((aufgabe) => ({ id: aufgabe.id, titel: aufgabe.titel, detail: [ aufgabe.detail, aufgabe.betrag !== null ? `${formatEuro(aufgabe.betrag)} netto` : null, aufgabe.faelligAm ? `fällig am ${formatDatum(aufgabe.faelligAm)}` : null, `Laufzeit ${formatDatum(aufgabe.start)} – ${formatDatum(aufgabe.ende)}`, ] .filter(Boolean) .join(" · "), dringlichkeit: aufgabe.dringlichkeit, badgeText: aufgabe.badgeText, href: aufgabe.href, aktion: aufgabe.aktion, })), ...ohneKunde.slice(0, 5).map((host) => ({ id: `zuweisen-${host.id}`, titel: `${host.hostname} einem Kunden zuweisen`, detail: `Server-ID ${host.serverId ?? "unbekannt"} · seit ${formatDatum(host.erstmalsGesehenAm)} gemeldet`, dringlichkeit: "info" as const, badgeText: "Zuweisen", href: "/hosts/nicht-zugeordnet", })), ]; return ( <>
{ohneKunde.length > 0 ? ( Jetzt zuweisen } > Neu registrierte Hosts erscheinen hier, bis sie einem Kunden zugewiesen sind:{" "} {ohneKunde.map((host) => host.hostname).join(", ")} ) : null}
{/* Auf dem Handy bleiben Host und Ablauf; der Rest käme ohnehin nur per Seitwärtsscrollen ins Bild (#034). */} {ablaufListe.map((host) => ( ))} {ablaufListe.length === 0 ? ( ) : null}
Host Kunde Key Ablauf Proxmox Kundenrechnung
{host.hostname} {host.meldetNicht ? : null} {/* Auf schmalen Bildschirmen steht der Kunde hier mit darunter. */}
{host.kunde ? host.kunde.name : "Nicht zugeordnet"}
{host.kunde ? ( {host.kunde.name} ) : ( Nicht zugeordnet )}
Noch kein Host mit Subscription gemeldet.
{aufgabenDaten.gesamt + ohneKunde.length} } > {aufgabenDaten.gesamt > aufgabenDaten.aufgaben.length ? (

{aufgabenDaten.gesamt - aufgabenDaten.aufgaben.length} weitere Punkte unter{" "} Rechnungen.

) : null}
{kunden.length === 0 ? (

Noch keine Kunden angelegt. Ersten Kunden anlegen

) : ( kunden.map((kunde) => { const punkte = rechnungspunkte.get(kunde.id) ?? { offen: 0, gesamt: 0 }; const erledigt = punkte.gesamt - punkte.offen; const prozent = punkte.gesamt === 0 ? 100 : Math.round((erledigt / punkte.gesamt) * 100); return (
{kunde.name} {erledigt} von {punkte.gesamt} Punkten erledigt
); }) )}