From c3dc5961702f1d980645f00d183a9f815967680e Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Thu, 1 Oct 2026 18:37:37 +0200 Subject: [PATCH] feat(ui): honey batch page with one main action, traceability errors, confirmed removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DetailHeader: "Abfüllung anlegen" as the main action, PDF export in "Mehr", state as icon + word, retry and way back on load errors. - Traceability says what it shows and offers a retry on errors instead of "Lädt…" forever. - Removing a container allocation asks first and says what changes. Co-Authored-By: Claude Opus 5.5 (1M context) --- ...honey-batch-container-allocations-card.tsx | 22 ++-- .../src/app/(app)/honey-batches/[id]/page.tsx | 103 ++++++++++-------- 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/honey-batch-container-allocations-card.tsx b/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/honey-batch-container-allocations-card.tsx index bb79261..ee458a6 100644 --- a/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/honey-batch-container-allocations-card.tsx +++ b/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/honey-batch-container-allocations-card.tsx @@ -1,7 +1,6 @@ "use client"; import { FormEvent, useState } from "react"; -import { Trash2 } from "lucide-react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { @@ -15,6 +14,7 @@ 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 { ConfirmDialog } from "@/components/confirm-dialog"; import { Boxes } from "lucide-react"; import { Select, @@ -132,16 +132,16 @@ export function HoneyBatchContainerAllocationsCard({ honeyBatch }: { honeyBatch:

{allocation.amount} kg

- + removeMutation.mutate(allocation.storageContainerId)} + /> ))} diff --git a/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/page.tsx b/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/page.tsx index 15bc12f..d982347 100644 --- a/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/page.tsx +++ b/ApiCore-Frontend/src/app/(app)/honey-batches/[id]/page.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { useParams } from "next/navigation"; -import { Droplet, FlaskConical } from "lucide-react"; +import { Droplet, FileText, FlaskConical } from "lucide-react"; import { useMutation, useQuery } from "@tanstack/react-query"; import { toast } from "sonner"; import { fetchHoneyBatch, fetchHoneyBatchTraceability } from "@/lib/honey-batches/api"; @@ -11,9 +11,11 @@ import { exportHoneyBatchTraceabilityPdf } from "@/lib/export/api"; import { QrCodeDialog } from "@/components/qr-code-dialog"; import { DocumentUploadCard } from "@/components/document-upload-card"; import { EmptyState } from "@/components/empty-state"; +import { ErrorState, LoadingState } from "@/components/query-state"; +import { DetailHeader, DetailQueryFallback, DetailStatus } from "@/components/detail-header"; +import { errorMessage } from "@/lib/forms/error-message"; import { HoneyBatchStorageCard } from "./honey-batch-storage-card"; import { HoneyBatchContainerAllocationsCard } from "./honey-batch-container-allocations-card"; -import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { AddMeasurementDialog } from "./add-measurement-dialog"; @@ -21,50 +23,68 @@ import { EditMeasurementDialog } from "./edit-measurement-dialog"; import { ExtractionEditDialog } from "./extraction-edit-dialog"; import { HoneyBatchEditDialog } from "./honey-batch-edit-dialog"; +const BACK = { backHref: "/honey-batches", backLabel: "Alle Honigchargen" }; + export default function HoneyBatchDetailPage() { const params = useParams<{ id: string }>(); - const { data: honeyBatch, isLoading, isError } = useQuery({ + const honeyBatchQuery = useQuery({ queryKey: ["honey-batches", params.id], queryFn: () => fetchHoneyBatch(params.id), }); - const { data: traceability } = useQuery({ + const honeyBatch = honeyBatchQuery.data; + const traceabilityQuery = useQuery({ queryKey: ["honey-batches", params.id, "traceability"], queryFn: () => fetchHoneyBatchTraceability(params.id), }); + const traceability = traceabilityQuery.data; const exportPdfMutation = useMutation({ mutationFn: () => exportHoneyBatchTraceabilityPdf(params.id), - onError: () => toast.error("PDF-Bericht konnte nicht exportiert werden"), + onError: (error) => + toast.error(errorMessage(error, "PDF-Bericht konnte nicht exportiert werden")), }); - if (isLoading) { - return

Lädt…

; - } - if (isError || !honeyBatch) { - return ( -

- Honigcharge konnte nicht geladen werden. -

- ); + if (honeyBatchQuery.isLoading || honeyBatchQuery.isError || !honeyBatch) { + return ; } return (
+ + } + primaryAction={ + + } + moreActions={[ + { + label: "Rückverfolgung als PDF", + icon: FileText, + onSelect: () => exportPdfMutation.mutate(), + disabled: exportPdfMutation.isPending, + }, + ]} + {...BACK} + />
- -
- - - - {honeyBatch.batchNumber} -
-
- {HONEY_BATCH_STATUS_LABELS[honeyBatch.status]} + + Angaben +
@@ -75,15 +95,6 @@ export default function HoneyBatchDetailPage() { {honeyBatch.waterContent !== null ? (

Wassergehalt: {honeyBatch.waterContent}%

) : null} - @@ -133,17 +144,19 @@ export default function HoneyBatchDetailPage() { Rückverfolgbarkeit - - {!traceability ?

Lädt…

: null} +

+ Woher der Honig dieser Charge stammt: Schleuderung, Ernten und Völker. +

+ {traceabilityQuery.isLoading ? : null} + {traceabilityQuery.isError ? ( + void traceabilityQuery.refetch()} + isRetrying={traceabilityQuery.isFetching} + /> + ) : null} {traceability ? ( <>
@@ -162,7 +175,7 @@ export default function HoneyBatchDetailPage() {

Ernte am {new Date(harvest.date).toLocaleDateString("de-DE")}