From 6d7a77c8dd061497f44786d1301f54be5fb8f30e Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Sat, 19 Sep 2026 07:59:15 +0200 Subject: [PATCH] feat: Liefergebiet im Admin-Bereich umschaltbar (Deutschland / EU) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Admin-Bereich → Inhalte → Firmendaten → "Liefergebiet". Auswahl zwischen "Nur Deutschland" und "Europäische Union". Der Wert steuert drei Stellen gleichzeitig, damit sie nicht auseinanderlaufen koennen: 1. Checkout-Formular: bei "EU" eine Laenderauswahl mit den 27 Mitgliedstaaten, bei "Nur Deutschland" stattdessen ein Satz, der das Gebiet benennt — bevor jemand die Adresse eintippt und erst beim Abschicken erfaehrt, dass daraus nichts wird. Eine Auswahl mit einem einzigen Eintrag waere eine Attrappe. 2. api/checkout/route.ts: verbindliche Pruefung. Die Auswahl im Formular ist Bequemlichkeit, kein Schutz — der Endpunkt nimmt JSON entgegen und laesst sich ohne Formular aufrufen. Ohne diese Pruefung entstuende eine Bestellung mit einer Lieferadresse, fuer die weder Versandweg noch Umsatzsteuerpflicht geklaert sind, und bezahlt waere sie dann auch schon. Abgewiesen wird mit einer Meldung, die sagt, was stattdessen geht (Adresse im Gebiet oder Abholung). 3. Seite "Versand und Zahlung": eigener Abschnitt "Liefergebiet" mit dem passenden Satz. Eigener Abschnitt statt Nebensatz, weil die Frage vor dem Warenkorb entscheidet, ob ein Kauf ueberhaupt zustande kommt. Die Vorgabe ist "Nur Deutschland", und zwar an jeder Stelle einzeln: ein fehlender oder unsinniger Wert, eine nicht durchgereichte Prop — im Zweifel liefert der Shop in WENIGER Laender, nie in mehr. "EU" heisst die 27 Mitgliedstaaten, nicht Europa im geografischen Sinn. Schweiz, Norwegen und das Vereinigte Koenigreich sind Zollausland; dorthin zu liefern braucht mehr als einen Haken im Admin-Bereich. Technisch dazugekommen: - lib/shipping-region.ts, reine Logik ohne Datenbankzugriff (wie shipping-calc.ts), 11 Tests. - content-registry.ts kennt jetzt den Feldtyp "select" mit "options" — ein Freitextfeld waere hier falsch: ein Tippfehler im Liefergebiet wuerde stillschweigend auf den Vorgabewert zurueckfallen, und niemand saehe, dass die Umstellung nicht gegriffen hat. - Laendernamen ueber Intl.DisplayNames statt 27 Namen je Sprache im Woerterbuch: eine eigene Liste waere ab dem naechsten Beitritt falsch. - 3 weitere Tests in der Checkout-Route (Abweisung, EU-Mitglied durch, Drittland trotzdem abgewiesen). tsc: 0 Fehler. vitest: 350/350 gruen (zuvor 336). eslint: 0 Warnungen. "next build" laeuft durch. Co-Authored-By: Claude Opus 5 (1M context) --- src/app/admin/inhalte/page.tsx | 25 ++++++++ src/app/api/checkout/route.test.ts | 38 ++++++++++++- src/app/api/checkout/route.ts | 23 +++++++- src/app/checkout/checkout-form.tsx | 57 ++++++++++++++++++- src/app/checkout/page.tsx | 10 +++- src/app/versand-zahlung/page.tsx | 17 +++++- src/i18n/dictionaries/de.ts | 5 ++ src/i18n/dictionaries/en.ts | 5 ++ src/i18n/dictionary-type.ts | 7 +++ src/lib/content-registry.ts | 29 ++++++++++ src/lib/shipping-region.test.ts | 91 ++++++++++++++++++++++++++++++ src/lib/shipping-region.ts | 64 +++++++++++++++++++++ src/lib/shipping.ts | 19 +++++++ 13 files changed, 383 insertions(+), 7 deletions(-) create mode 100644 src/lib/shipping-region.test.ts create mode 100644 src/lib/shipping-region.ts diff --git a/src/app/admin/inhalte/page.tsx b/src/app/admin/inhalte/page.tsx index 37cead2..c81257b 100644 --- a/src/app/admin/inhalte/page.tsx +++ b/src/app/admin/inhalte/page.tsx @@ -12,6 +12,9 @@ import type { Locale } from "@/i18n/config"; const ROWS_BY_TYPE: Record = { text: 1, textarea: 3, + // Auswahlfelder rendern ein + {(def.options ?? []).map((option) => ( + + ))} + + + ); + } return (