feat(frontend): EmptyState statt Fließtext in verschachtelten Listen

Ersetzt den bisherigen reinen Fließtext ("Noch keine X dokumentiert.")
durch die gemeinsame EmptyState-Komponente (Icon, Titel, Beschreibung)
in allen verschachtelten Listen auf den Volk- und Königin-Detailseiten:
Fütterung, Behandlungen, Varroa, Durchsichten, Historie (Volk und
Königin), Bewertungen und Honigmessungen.

Rundet den bereits umgesetzten EmptyState-Look der Hauptlistenseiten
konsistent auf die Detailseiten-Unterkarten ab.
This commit is contained in:
Nick Szaunig committed 2026-08-24 00:27:04 +02:00
1 parent e889edd6c5
commit c0922387fd
8 files changed
+56 -9

No files matched your search

@@ -1,9 +1,11 @@
"use client";
import Link from "next/link";
import { Utensils } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchColonyFeedings, fetchColonyFeedingsSummary } from "@/lib/feedings/api";
import { Button } from "@/components/ui/button";
import { EmptyState } from "@/components/empty-state";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export function ColonyFeedingsCard({ colonyId }: { colonyId: string }) {
@@ -39,7 +41,11 @@ export function ColonyFeedingsCard({ colonyId }: { colonyId: string }) {
) : null}
{isLoading ? <p className="text-muted-foreground">Lädt…</p> : null}
{!isLoading && (!feedings || feedings.length === 0) ? (
<p className="text-muted-foreground">Noch keine Fütterung dokumentiert.</p>
<EmptyState
icon={Utensils}
title="Noch keine Fütterung"
description="Erfasse die erste Fütterung für dieses Volk."
/>
) : null}
{feedings?.map((feeding) => (
<div key={feeding.id} className="rounded-md border p-3">
@@ -1,7 +1,9 @@
"use client";
import { History } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchColonyHistory } from "@/lib/colonies/api";
import { EmptyState } from "@/components/empty-state";
import {
Card,
CardContent,
@@ -31,7 +33,11 @@ export function ColonyHistoryCard({ colonyId }: { colonyId: string }) {
</CardHeader>
<CardContent className="flex flex-col gap-3 text-sm">
{!hasHistory ? (
<p className="text-muted-foreground">Noch keine Historie vorhanden.</p>
<EmptyState
icon={History}
title="Noch keine Historie"
description="Standortwechsel und Ableger erscheinen hier."
/>
) : null}
{history.apiaryHistory.map((entry) => (
<p key={entry.id}>
@@ -1,9 +1,11 @@
"use client";
import Link from "next/link";
import { ClipboardCheck } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchColonyInspections } from "@/lib/inspections/api";
import { Button } from "@/components/ui/button";
import { EmptyState } from "@/components/empty-state";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export function ColonyInspectionsCard({ colonyId }: { colonyId: string }) {
@@ -27,7 +29,11 @@ export function ColonyInspectionsCard({ colonyId }: { colonyId: string }) {
<CardContent className="flex flex-col gap-3 text-sm">
{isLoading ? <p className="text-muted-foreground">Lädt…</p> : null}
{!isLoading && (!inspections || inspections.length === 0) ? (
<p className="text-muted-foreground">Noch keine Durchsicht dokumentiert.</p>
<EmptyState
icon={ClipboardCheck}
title="Noch keine Durchsicht"
description="Dokumentiere die erste Durchsicht für dieses Volk."
/>
) : null}
{inspections?.map((inspection) => (
<div key={inspection.id} className="rounded-md border p-3">
@@ -1,9 +1,11 @@
"use client";
import Link from "next/link";
import { Syringe } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchColonyTreatments } from "@/lib/treatments/api";
import { Button } from "@/components/ui/button";
import { EmptyState } from "@/components/empty-state";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export function ColonyTreatmentsCard({ colonyId }: { colonyId: string }) {
@@ -27,7 +29,11 @@ export function ColonyTreatmentsCard({ colonyId }: { colonyId: string }) {
<CardContent className="flex flex-col gap-3 text-sm">
{isLoading ? <p className="text-muted-foreground">Lädt…</p> : null}
{!isLoading && (!treatments || treatments.length === 0) ? (
<p className="text-muted-foreground">Noch keine Behandlung dokumentiert.</p>
<EmptyState
icon={Syringe}
title="Noch keine Behandlung"
description="Dokumentiere die erste Behandlung für dieses Volk."
/>
) : null}
{treatments?.map((treatment) => (
<div key={treatment.id} className="rounded-md border p-3">
@@ -1,9 +1,11 @@
"use client";
import Link from "next/link";
import { Bug } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchColonyVarroaMeasurements } from "@/lib/varroa/api";
import { Button } from "@/components/ui/button";
import { EmptyState } from "@/components/empty-state";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
const CHART_WIDTH = 280;
@@ -64,7 +66,11 @@ export function ColonyVarroaCard({ colonyId }: { colonyId: string }) {
<CardContent className="flex flex-col gap-3 text-sm">
{isLoading ? <p className="text-muted-foreground">Lädt…</p> : null}
{!isLoading && (!measurements || measurements.length === 0) ? (
<p className="text-muted-foreground">Noch keine Varroamessung dokumentiert.</p>
<EmptyState
icon={Bug}
title="Noch keine Varroamessung"
description="Erfasse die erste Messung für dieses Volk."
/>
) : null}
<VarroaTrendChart values={values} />
{measurements?.map((measurement) => (
@@ -2,11 +2,12 @@
import Link from "next/link";
import { useParams } from "next/navigation";
import { Droplet } from "lucide-react";
import { Droplet, FlaskConical } from "lucide-react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { fetchHoneyBatch, fetchHoneyBatchTraceability } from "@/lib/honey-batches/api";
import { exportHoneyBatchTraceabilityPdf } from "@/lib/export/api";
import { QrCodeDialog } from "@/components/qr-code-dialog";
import { EmptyState } from "@/components/empty-state";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -78,7 +79,11 @@ export default function HoneyBatchDetailPage() {
</CardHeader>
<CardContent className="flex flex-col gap-3 text-sm">
{honeyBatch.measurements.length === 0 ? (
<p className="text-muted-foreground">Noch keine Messung dokumentiert.</p>
<EmptyState
icon={FlaskConical}
title="Noch keine Messung"
description="Erfasse die erste Wassergehalt-Messung für diese Charge."
/>
) : null}
{honeyBatch.measurements.map((measurement) => (
<div key={measurement.id} className="rounded-md border p-3">
@@ -1,12 +1,14 @@
"use client";
import { FormEvent, useState } from "react";
import { Star } from "lucide-react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { addQueenEvaluation, fetchQueenEvaluations } from "@/lib/queens/api";
import { CreateQueenEvaluationInput } from "@/lib/queens/types";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { EmptyState } from "@/components/empty-state";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Dialog,
@@ -131,7 +133,11 @@ export function QueenEvaluationsCard({ queenId }: { queenId: string }) {
<CardContent className="flex flex-col gap-3 text-sm">
{isLoading ? <p className="text-muted-foreground">Lädt…</p> : null}
{!isLoading && (!evaluations || evaluations.length === 0) ? (
<p className="text-muted-foreground">Noch keine Bewertung dokumentiert.</p>
<EmptyState
icon={Star}
title="Noch keine Bewertung"
description="Erfasse die erste Bewertung für diese Königin."
/>
) : null}
{evaluations?.map((evaluation) => (
<div key={evaluation.id} className="rounded-md border p-3">
@@ -1,7 +1,9 @@
"use client";
import { History } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchQueenHistory } from "@/lib/queens/api";
import { EmptyState } from "@/components/empty-state";
import {
Card,
CardContent,
@@ -26,7 +28,11 @@ export function QueenHistoryCard({ queenId }: { queenId: string }) {
</CardHeader>
<CardContent className="flex flex-col gap-3 text-sm">
{history.length === 0 ? (
<p className="text-muted-foreground">Noch keine Historie vorhanden.</p>
<EmptyState
icon={History}
title="Noch keine Historie"
description="Volkszuordnungen erscheinen hier."
/>
) : null}
{history.map((entry) => (
<p key={entry.id}>