From ebfbd2ef6d8ab8ce4f3970b66fb61aa75928858b Mon Sep 17 00:00:00 2001
From: Nick Szaunig
Date: Sun, 23 Aug 2026 21:03:59 +0200
Subject: [PATCH] =?UTF-8?q?feat(frontend):=20Leerer-Zustand-Komponente=20f?=
=?UTF-8?q?=C3=BCr=20alle=20Listenseiten?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Neue gemeinsame EmptyState-Komponente (Icon in Kreis, Titel, Beschreibung,
gestrichelter Rahmen) und Einbindung auf allen 9 Listenseiten mit Tabellen
(Völker, Bienenstände, Königinnen, Aufgaben, Honigchargen, Benutzer,
Inventar, Produkte, Lager mit Behältern und Artikeln).
Bug behoben: Bei leerem Datensatz wurde bisher nur eine Tabelle mit
Kopfzeile und keinerlei Inhalt oder Erklärung angezeigt – wirkte wie ein
Ladefehler statt eines normalen "noch keine Daten"-Zustands. Besonders
für neurodivergente Nutzer wichtig, da Unklarheit über den Systemzustand
("ist das kaputt oder einfach leer?") unnötige kognitive Last erzeugt.
---
.../src/app/(app)/apiaries/page.tsx | 11 ++++++++-
.../src/app/(app)/colonies/page.tsx | 11 ++++++++-
.../src/app/(app)/equipment/page.tsx | 11 ++++++++-
.../src/app/(app)/honey-batches/page.tsx | 11 ++++++++-
.../src/app/(app)/products/page.tsx | 11 ++++++++-
.../src/app/(app)/queens/page.tsx | 11 ++++++++-
.../src/app/(app)/settings/users/page.tsx | 7 +++++-
.../src/app/(app)/storage/page.tsx | 23 ++++++++++++++++---
ApiCore-Frontend/src/app/(app)/tasks/page.tsx | 15 +++++++++++-
.../src/components/empty-state.tsx | 21 +++++++++++++++++
10 files changed, 121 insertions(+), 11 deletions(-)
create mode 100644 ApiCore-Frontend/src/components/empty-state.tsx
diff --git a/ApiCore-Frontend/src/app/(app)/apiaries/page.tsx b/ApiCore-Frontend/src/app/(app)/apiaries/page.tsx
index 0dad296..4caad0f 100644
--- a/ApiCore-Frontend/src/app/(app)/apiaries/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/apiaries/page.tsx
@@ -10,6 +10,7 @@ import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Select,
SelectContent,
@@ -77,7 +78,15 @@ export default function ApiariesPage() {
) : null}
- {apiaries ? (
+ {apiaries && apiaries.length === 0 ? (
+
+ ) : null}
+
+ {apiaries && apiaries.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/colonies/page.tsx b/ApiCore-Frontend/src/app/(app)/colonies/page.tsx
index 9923246..40f34c4 100644
--- a/ApiCore-Frontend/src/app/(app)/colonies/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/colonies/page.tsx
@@ -11,6 +11,7 @@ import { statusTone } from "@/lib/status-tone";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Select,
SelectContent,
@@ -94,7 +95,15 @@ export default function ColoniesPage() {
) : null}
- {colonies ? (
+ {colonies && colonies.length === 0 ? (
+
+ ) : null}
+
+ {colonies && colonies.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/equipment/page.tsx b/ApiCore-Frontend/src/app/(app)/equipment/page.tsx
index e8f1839..d3cab4f 100644
--- a/ApiCore-Frontend/src/app/(app)/equipment/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/equipment/page.tsx
@@ -8,6 +8,7 @@ import { statusTone } from "@/lib/status-tone";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Table,
TableBody,
@@ -44,7 +45,15 @@ export default function EquipmentPage() {
) : null}
- {equipmentList ? (
+ {equipmentList && equipmentList.length === 0 ? (
+
+ ) : null}
+
+ {equipmentList && equipmentList.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/honey-batches/page.tsx b/ApiCore-Frontend/src/app/(app)/honey-batches/page.tsx
index e5b38bf..d799f15 100644
--- a/ApiCore-Frontend/src/app/(app)/honey-batches/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/honey-batches/page.tsx
@@ -11,6 +11,7 @@ import { statusTone } from "@/lib/status-tone";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Select,
SelectContent,
@@ -95,7 +96,15 @@ export default function HoneyBatchesPage() {
) : null}
- {honeyBatches ? (
+ {honeyBatches && honeyBatches.length === 0 ? (
+
+ ) : null}
+
+ {honeyBatches && honeyBatches.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/products/page.tsx b/ApiCore-Frontend/src/app/(app)/products/page.tsx
index cf0f917..62d41de 100644
--- a/ApiCore-Frontend/src/app/(app)/products/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/products/page.tsx
@@ -7,6 +7,7 @@ import { fetchProducts } from "@/lib/products/api";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Table,
TableBody,
@@ -42,7 +43,15 @@ export default function ProductsPage() {
) : null}
- {products ? (
+ {products && products.length === 0 ? (
+
+ ) : null}
+
+ {products && products.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/queens/page.tsx b/ApiCore-Frontend/src/app/(app)/queens/page.tsx
index 22917d3..895d5cd 100644
--- a/ApiCore-Frontend/src/app/(app)/queens/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/queens/page.tsx
@@ -9,6 +9,7 @@ import { QueenStatus } from "@/lib/queens/types";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Select,
SelectContent,
@@ -82,7 +83,15 @@ export default function QueensPage() {
) : null}
- {queens ? (
+ {queens && queens.length === 0 ? (
+
+ ) : null}
+
+ {queens && queens.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/settings/users/page.tsx b/ApiCore-Frontend/src/app/(app)/settings/users/page.tsx
index aa4a011..63f0e19 100644
--- a/ApiCore-Frontend/src/app/(app)/settings/users/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/settings/users/page.tsx
@@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { ConfirmDialog } from "@/components/confirm-dialog";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Table,
TableBody,
@@ -62,7 +63,11 @@ export default function UsersPage() {
) : null}
- {users ? (
+ {users && users.length === 0 ? (
+
+ ) : null}
+
+ {users && users.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/storage/page.tsx b/ApiCore-Frontend/src/app/(app)/storage/page.tsx
index 64b050d..8299e70 100644
--- a/ApiCore-Frontend/src/app/(app)/storage/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/storage/page.tsx
@@ -1,10 +1,11 @@
"use client";
-import { Warehouse } from "lucide-react";
+import { Package, Warehouse } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchStockItems, fetchStorageContainers } from "@/lib/storage/api";
import { QrCodeDialog } from "@/components/qr-code-dialog";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import { Badge } from "@/components/ui/badge";
import {
Table,
@@ -40,7 +41,15 @@ export default function StoragePage() {
/>
Lagerbehälter
{containersLoading ? Lädt…
: null}
- {containers ? (
+ {containers && containers.length === 0 ? (
+
+ ) : null}
+
+ {containers && containers.length > 0 ? (
@@ -78,7 +87,15 @@ export default function StoragePage() {
{itemsLoading ? Lädt…
: null}
- {stockItems ? (
+ {stockItems && stockItems.length === 0 ? (
+
+ ) : null}
+
+ {stockItems && stockItems.length > 0 ? (
diff --git a/ApiCore-Frontend/src/app/(app)/tasks/page.tsx b/ApiCore-Frontend/src/app/(app)/tasks/page.tsx
index 5de93bf..459f12e 100644
--- a/ApiCore-Frontend/src/app/(app)/tasks/page.tsx
+++ b/ApiCore-Frontend/src/app/(app)/tasks/page.tsx
@@ -9,6 +9,7 @@ import { TaskPriority, TaskStatus } from "@/lib/tasks/types";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { PageHeader } from "@/components/page-header";
+import { EmptyState } from "@/components/empty-state";
import {
Select,
SelectContent,
@@ -122,7 +123,19 @@ export default function TasksPage() {
) : null}
- {tasks ? (
+ {tasks && visibleTasks.length === 0 ? (
+
+ ) : null}
+
+ {tasks && visibleTasks.length > 0 ? (
diff --git a/ApiCore-Frontend/src/components/empty-state.tsx b/ApiCore-Frontend/src/components/empty-state.tsx
new file mode 100644
index 0000000..faae328
--- /dev/null
+++ b/ApiCore-Frontend/src/components/empty-state.tsx
@@ -0,0 +1,21 @@
+import { LucideIcon } from "lucide-react";
+
+interface EmptyStateProps {
+ icon: LucideIcon;
+ title: string;
+ description?: string;
+}
+
+export function EmptyState({ icon: Icon, title, description }: EmptyStateProps) {
+ return (
+
+
+
+
+
+
{title}
+ {description ?
{description}
: null}
+
+
+ );
+}