feat: Chargen- und Erntebilder einzeln pro Kachel pflegbar

Die Chargenseite (/charge/[code]) zeigt zwei Bildkacheln: links Ernte und
Jahr, rechts den Standort. Gefuellt wurden sie aus einer Bilder-LISTE, in
der allein die Reihenfolge entschied, welches Bild wohin kommt.

Damit liess sich das zweite Bild nicht allein setzen. Wer nur ein Foto vom
Standort pflegen wollte, bekam es auf Position 0 — also in die linke
Kachel, wo Ernte und Jahr stehen sollten. Welche Kachel ein Bild fuellt,
war im Formular ausserdem nirgends erkennbar.

Jetzt zwei benannte Slots statt einer Liste, im Chargen- wie im
Ernten-Formular:

  Bild 1 — linke Kachel auf der Chargenseite
  Bild 2 — rechte Kachel auf der Chargenseite (Standort)

Jeder Slot hat eine eigene Vorschau, einen eigenen Auswahl- und einen
eigenen Entfernen-Knopf. Beide tragen denselben Feldnamen "images" und
werden in dieser Reihenfolge uebermittelt.

Dafuer brauchte es einen positionserhaltenden Parser: strArray() trimmt
und filtert leere Werte heraus, wodurch ein leerer erster Slot
verschwunden und der zweite nach vorn gerutscht waere — genau der Fehler,
der behoben werden sollte. Neu ist strArraySlots(), das leere Slots als ""
stehen laesst und nur am Ende stehende entfernt (ein leeres Feld ergibt
weiterhin [] statt ["", ""]).

Die Konsumenten mussten entsprechend von "??" auf "||" wechseln: ein im
Admin geleerter Slot kommt als leerer String an, nicht als undefined. Mit
"??" haette dieser leere String als gueltiger Wert gegolten und das
Erntebild darunter verdeckt (charge/[code], ernten, ernten/[year]/[type]).

strArray/strArraySlots sind nach lib/form-fields.ts gewandert und werden
aus _shared.ts re-exportiert — saemtliche bestehenden Importe bleiben
unveraendert. Grund: _shared.ts zieht ueber lib/prisma.ts einen
Datenbank-Adapter nach und liess sich ohne DATABASE_URL nicht testen. Als
reine Funktionen ohne Datenbankbezug sind die beiden jetzt direkt
pruefbar, passend zur bereits dokumentierten Teststrategie des Projekts.

Sieben neue Tests decken den Kernfall ab (leerer erster Slot bleibt
offen), mit Gegenprobe, dass strArray denselben Fall weiterhin
zusammenrutschen laesst.

Produktbilder bleiben bewusst bei der bisherigen Liste: dort ist die
Bilderzahl offen und die Reihenfolge traegt keine Kachel-Bedeutung.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5 committed 2026-09-15 21:10:12 +02:00
1 parent 979d39e677
commit ff365c3cb1
12 files changed
+182 -27

No files matched your search

+6 -2
View File
@@ -44,9 +44,13 @@ export default async function BatchPage(props: PageProps<"/charge/[code]">) {
// das entsprechende Erntebild zurueck. Bewusst NICHT alles-oder-nichts:
// wer nur ein Chargenfoto pflegt, soll nicht das zweite (Standort-)Bild
// verlieren, nur weil die Charge kein zweites eigenes Foto hat.
// "||" statt "??": ein im Admin geleerter Slot kommt als leerer String
// an, nicht als undefined (siehe imageSlots() in
// admin/actions/harvests-batches.ts). Mit "??" wuerde dieser leere String
// als gueltiger Wert durchgehen und das Erntebild darunter verdecken.
const displayImages = [
batch.images[0] ?? batch.harvest.images[0] ?? null,
batch.images[1] ?? batch.harvest.images[1] ?? null,
batch.images[0] || batch.harvest.images[0] || null,
batch.images[1] || batch.harvest.images[1] || null,
];
return (