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