feat: öffentliche Herkunftsseiten für Honigchargen + Kunden-QR-Code

Neuer unauthentifizierter Endpunkt GET /api/v1/public/batches/:lot
(Abschnitt 27 der Lastenheft) liefert kontrolliert freigegebene
Rückverfolgbarkeitsdaten einer Abfüllcharge – Produkt, Erntemonat,
Bienenstand-Namen, Schleuderdatum, Wassergehalt – ohne interne IDs,
Adressen oder Koordinaten preiszugeben. Die neue Seite /herkunft/{lot}
liegt außerhalb der (app)-Route-Group und damit ohne Login/Sidebar,
gedacht als Ziel eines QR-Codes auf dem Honigglas. Der bestehende
QR-Dienst kennt jetzt den Entity-Typ "bottling-batches" und verlinkt
intern auf diese neue öffentliche Seite; ein entsprechender
QR-Code-Button samt Klartext-Link steht ab sofort auf der
Abfüllungs-Detailseite bereit.
This commit is contained in:
Nick Szaunig committed 2026-08-25 01:35:47 +02:00
1 parent 711536f299
commit d56550c0e5
13 files changed
+538 -48

No files matched your search

@@ -1,10 +1,12 @@
"use client";
import Link from "next/link";
import { useParams } from "next/navigation";
import { Package } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { fetchBottlingBatch } from "@/lib/bottling/api";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { QrCodeDialog } from "@/components/qr-code-dialog";
export default function BottlingBatchDetailPage() {
const params = useParams<{ id: string }>();
@@ -27,14 +29,21 @@ export default function BottlingBatchDetailPage() {
return (
<main className="flex flex-col gap-4 p-4 sm:p-6">
<Card className="max-w-lg">
<CardHeader className="flex flex-row items-center gap-2.5">
<span
className="flex size-8 items-center justify-center rounded-lg text-white shadow-[var(--shadow-soft)]"
style={{ background: "var(--gradient-honey)" }}
>
<Package className="size-4" />
</span>
<CardTitle className="font-mono">Abfüllung {bottlingBatch.lotNumber}</CardTitle>
<CardHeader className="flex flex-row items-center justify-between gap-2.5">
<div className="flex items-center gap-2.5">
<span
className="flex size-8 items-center justify-center rounded-lg text-white shadow-[var(--shadow-soft)]"
style={{ background: "var(--gradient-honey)" }}
>
<Package className="size-4" />
</span>
<CardTitle className="font-mono">Abfüllung {bottlingBatch.lotNumber}</CardTitle>
</div>
<QrCodeDialog
entityType="bottling-batches"
id={bottlingBatch.id}
label="QR-Code für Etikett"
/>
</CardHeader>
<CardContent className="flex flex-col gap-2 text-sm">
<p>Honigcharge: {bottlingBatch.honeyBatch.batchNumber}</p>
@@ -48,6 +57,16 @@ export default function BottlingBatchDetailPage() {
Mindesthaltbar bis:{" "}
{new Date(bottlingBatch.bestBeforeDate).toLocaleDateString("de-DE")}
</p>
<p>
Öffentliche Herkunftsseite:{" "}
<Link
className="underline"
href={`/herkunft/${encodeURIComponent(bottlingBatch.lotNumber)}`}
target="_blank"
>
/herkunft/{bottlingBatch.lotNumber}
</Link>
</p>
</CardContent>
</Card>
</main>