193 lines
5.8 KiB
TypeScript
193 lines
5.8 KiB
TypeScript
import { useEffect, useState } from "react";
|
||
import { useNavigate } from "react-router-dom";
|
||
import { apiGet } from "../lib/api";
|
||
import type { DashboardOverview } from "../lib/types";
|
||
|
||
interface AdminStats {
|
||
totalSamples: number;
|
||
openSamples: number;
|
||
completedToday: number;
|
||
nextSampleNumber: number;
|
||
}
|
||
|
||
export default function AdminDashboardPage() {
|
||
const navigate = useNavigate();
|
||
const [stats, setStats] = useState<AdminStats | null>(null);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
async function loadStats() {
|
||
try {
|
||
const dashboard = await apiGet<DashboardOverview>("/dashboard");
|
||
setStats({
|
||
totalSamples: dashboard.nextSampleNumber - 1,
|
||
openSamples: dashboard.openSamples,
|
||
completedToday: dashboard.completedToday,
|
||
nextSampleNumber: dashboard.nextSampleNumber,
|
||
});
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
void loadStats();
|
||
}, []);
|
||
|
||
const adminModules = [
|
||
{
|
||
title: "Landwirte",
|
||
description: "Verwaltung der Landwirte und Betriebe",
|
||
icon: "👨🌾",
|
||
route: "/admin/landwirte",
|
||
color: "#4a7c59",
|
||
},
|
||
{
|
||
title: "Benutzer",
|
||
description: "Benutzerverwaltung und Berechtigungen",
|
||
icon: "👥",
|
||
route: "/admin/benutzer",
|
||
color: "#5b7ba8",
|
||
},
|
||
{
|
||
title: "Medikamente",
|
||
description: "Verwaltung der Medikamentenkataloge",
|
||
icon: "💊",
|
||
route: "/admin/medikamente",
|
||
color: "#8b5a7c",
|
||
},
|
||
{
|
||
title: "Erreger",
|
||
description: "Verwaltung der Erreger und Kürzel",
|
||
icon: "🦠",
|
||
route: "/admin/erreger",
|
||
color: "#7c5a5a",
|
||
},
|
||
{
|
||
title: "Antibiogramm",
|
||
description: "Verwaltung der Antibiotika-Kataloge",
|
||
icon: "📊",
|
||
route: "/admin/antibiogramm",
|
||
color: "#5a7c7c",
|
||
},
|
||
{
|
||
title: "Berichtsvorlage",
|
||
description: "Gestaltung der PDF-Berichtsvorlagen",
|
||
icon: "📄",
|
||
route: "/report-template",
|
||
color: "#7c7c5a",
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div className="page-stack">
|
||
{/* Header Bereich */}
|
||
<section className="hero-card admin-hero">
|
||
<div>
|
||
<p className="eyebrow">Administration</p>
|
||
<h3>Administrator Dashboard</h3>
|
||
<p className="muted-text">
|
||
Verwalten Sie Landwirte, Benutzer, Medikamente, Erreger und Systemeinstellungen.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Statistik-Karten */}
|
||
<section className="metrics-grid admin-metrics">
|
||
<article className="metric-card metric-card--primary">
|
||
<span className="metric-card__label">Nächste Probennummer</span>
|
||
<strong className="metric-card__value--large">
|
||
{loading ? "..." : stats?.nextSampleNumber}
|
||
</strong>
|
||
</article>
|
||
<article className="metric-card">
|
||
<span className="metric-card__label">Offene Proben</span>
|
||
<strong>{loading ? "..." : stats?.openSamples}</strong>
|
||
</article>
|
||
<article className="metric-card">
|
||
<span className="metric-card__label">Heute abgeschlossen</span>
|
||
<strong>{loading ? "..." : stats?.completedToday}</strong>
|
||
</article>
|
||
<article className="metric-card">
|
||
<span className="metric-card__label">Gesamtproben</span>
|
||
<strong>{loading ? "..." : stats?.totalSamples}</strong>
|
||
</article>
|
||
</section>
|
||
|
||
{/* Admin Module Grid */}
|
||
<section className="admin-modules-section">
|
||
<div className="section-card__header">
|
||
<div>
|
||
<p className="eyebrow">Verwaltung</p>
|
||
<h3>Verwaltungsmodule</h3>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="admin-modules-grid">
|
||
{adminModules.map((module) => (
|
||
<button
|
||
key={module.route}
|
||
type="button"
|
||
className="admin-module-card"
|
||
onClick={() => navigate(module.route)}
|
||
style={{ "--module-color": module.color } as React.CSSProperties}
|
||
>
|
||
<span className="admin-module-card__icon">{module.icon}</span>
|
||
<div className="admin-module-card__content">
|
||
<strong>{module.title}</strong>
|
||
<span className="muted-text">{module.description}</span>
|
||
</div>
|
||
<span className="admin-module-card__arrow">→</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
{/* Schnellzugriffe */}
|
||
<section className="quick-actions-section">
|
||
<div className="section-card">
|
||
<div className="section-card__header">
|
||
<div>
|
||
<p className="eyebrow">Schnellzugriff</p>
|
||
<h3>Häufige Aktionen</h3>
|
||
</div>
|
||
</div>
|
||
<div className="quick-actions-grid">
|
||
<button
|
||
type="button"
|
||
className="quick-action-button"
|
||
onClick={() => navigate("/samples/new")}
|
||
>
|
||
<span>➕</span>
|
||
<span>Neue Probe anlegen</span>
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="quick-action-button"
|
||
onClick={() => navigate("/search/probe")}
|
||
>
|
||
<span>🔍</span>
|
||
<span>Probe suchen</span>
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="quick-action-button"
|
||
onClick={() => navigate("/portal")}
|
||
>
|
||
<span>📧</span>
|
||
<span>Portal & Berichte</span>
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="quick-action-button"
|
||
onClick={() => navigate("/search/landwirt")}
|
||
>
|
||
<span>👤</span>
|
||
<span>Landwirt suchen</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
);
|
||
}
|