'use client'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { api, errMsg } from '@/lib/api'; import { useSession } from '@/lib/session'; import { Alert, Empty } from '@/components/ui'; interface Sys { jobs: Record; oldestPendingJob: string | null; backup?: { configured: boolean; lastRunAt?: string | null; ok?: boolean; ageHours?: number | null; stale?: boolean; error?: string | null; sizeBytes?: number | null; targets?: { name: string; ok: boolean }[]; lastRestoreTestAt?: string | null; restoreOk?: boolean | null; restoreStale?: boolean } } export default function Dashboard() { const { me, can } = useSession(); const [mine, setMine] = useState<{ contracts: { status: string; cancelEffectiveAt: string | null }[]; resources: { state: string; stale: boolean }[]; orders: { status: string }[] } | null>(null); const [licenses, setLicenses] = useState<{ active: number; expiring: number; unassigned: number } | null>(null); const [customers, setCustomers] = useState(null); const [sys, setSys] = useState(null); const [err, setErr] = useState(''); useEffect(() => { if (me?.kind === 'customer') { Promise.all([api('GET', '/contracts'), api('GET', '/resources'), api('GET', '/orders')]).then(([contracts, resources, orders]) => setMine({ contracts, resources, orders })).catch((e) => setErr(errMsg(e))); return; } if (!me || me.kind !== 'staff') return; if (can('customers.read')) api('GET', '/admin/customers').then((l) => setCustomers(l.length)).catch((e) => setErr(errMsg(e))); if (can('jobs.read')) api('GET', '/admin/system').then(setSys).catch((e) => setErr(errMsg(e))); if (can('licenses.read')) api<{ active: number; expiring: number; unassigned: number }>('GET', '/admin/licenses/summary').then(setLicenses).catch(() => undefined); }, [me, can]); if (!me) return null; const failed = sys ? (sys.jobs.failed ?? 0) + (sys.jobs.needs_review ?? 0) : 0; return (<>

Hallo {me.user.name.split(' ')[0]}

{err && {err}} {me.kind === 'customer' ? (<> {me.organizations.map((o) => (

{o.name}

Kundennummer {o.customerNumber}

Organisation ansehen
))} {mine && mine.contracts.length === 0 && mine.resources.length === 0 && mine.orders.length === 0 &&
Sobald Produkte, Verträge, Rechnungen oder Tickets für Ihre Organisation vorhanden sind, erscheinen sie hier.
} {mine && (mine.contracts.length > 0 || mine.resources.length > 0 || mine.orders.length > 0) &&
{mine.contracts.filter((c) => c.status === 'active').length}

Aktive Verträge

{mine.contracts.some((c) => c.cancelEffectiveAt) &&

Gekündigter Vertrag vorhanden

}Verträge ansehen
{mine.resources.length}

Ressourcen und Lizenzen

{mine.resources.some((r) => r.stale) &&

Stand teilweise veraltet

}Ressourcen ansehen
{mine.orders.filter((o) => ['pending_approval', 'provisioning', 'failed'].includes(o.status)).length > 0 &&
{mine.orders.filter((o) => ['pending_approval', 'provisioning', 'failed'].includes(o.status)).length}

Bestellungen in Bearbeitung

Bestellungen ansehen
}
} ) : (<>
{customers !== null &&
{customers}

Kunden

Kunden verwalten
} {licenses &&
{licenses.active}

Aktive Lizenzen

{licenses.expiring > 0 &&

{licenses.expiring} laufen in 30 Tagen ab

}{licenses.unassigned > 0 &&

{licenses.unassigned} ohne Kunde

}Lizenzen verwalten
} {sys &&
{sys.jobs.scheduled ?? 0}

Wartende Aufträge

} {sys?.backup &&

Backup

Details und Einstellungen

{!sys.backup.configured ? <>

Nicht eingerichtet.

Kein Backup : <>

{sys.backup.stale ? {sys.backup.ok ? 'Veraltet' : 'Fehlgeschlagen'} : Aktuell}

Letzter Lauf: {sys.backup.lastRunAt ? new Date(sys.backup.lastRunAt).toLocaleString('de-DE', { dateStyle: 'medium', timeStyle: 'short' }) : '–'}{sys.backup.sizeBytes ? ` · ${(sys.backup.sizeBytes / 1024).toFixed(0)} KB` : ''}
Ziele: {sys.backup.targets?.length ? sys.backup.targets.map((t) => `${t.ok ? '✓' : '✕'} ${t.name}`).join(', ') : '–'}
Wiederherstellungstest: {sys.backup.lastRestoreTestAt ? `${sys.backup.restoreOk ? '✓' : '✕'} ${new Date(sys.backup.lastRestoreTestAt).toLocaleDateString('de-DE')}` : 'noch nie'}{sys.backup.restoreStale ? ' (überfällig)' : ''}

{sys.backup.error &&

{sys.backup.error}

}}
} {sys &&
{failed}

Aufträge mit Fehlern / Prüfbedarf

{failed > 0 && Prüfen}
}
)} ); }