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} +
+
+ ); +}