Honor Products.noShippingCost across cart, checkout, and product pages
- api/checkout/route.ts: authoritative shipping charge is 0 whenever every cart line opts out via noShippingCost, regardless of the free-shipping threshold. - Cart/checkout order summaries: the whole "Versand" line (cost, free- shipping note, delivery time) is hidden entirely rather than showing "Kostenlos" — that's a different state from hitting the threshold. - ProductSpotlight/Pricing/TodoKartenHero: "zzgl. Versand" and delivery- time hints drop for an exempted product's own page. - /versand + its shared modal: one clarifying sentence that digital products are exempt. - Widerrufsformular link: opens inline in a new tab (no forced download), arrow icon changed from a download glyph to a plain right arrow to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ import Image from "next/image";
|
||||
import { useCart, removeFromCart, setQuantity } from "../../lib/cart";
|
||||
import { useProducts } from "../../lib/products";
|
||||
import { useDiscount, applyDiscount, clearDiscount } from "../../lib/discount";
|
||||
import { computeSubtotal, computeCartTotals, effectivePrice, effectiveTaxRate } from "../../lib/cartTotals";
|
||||
import { computeSubtotal, computeCartTotals, effectivePrice, effectiveTaxRate, cartHasShippableItem } from "../../lib/cartTotals";
|
||||
import { computeTaxBreakdown } from "@einfach-produktiv/invoicing";
|
||||
import { formatPrice, discountPercent } from "../../lib/format";
|
||||
import { Reveal } from "../../components/Reveal";
|
||||
@@ -77,7 +77,7 @@ export function CartContent({
|
||||
|
||||
const subtotal = computeSubtotal(items);
|
||||
const shipping =
|
||||
items.length === 0 || (freeShippingThreshold !== null && subtotal >= freeShippingThreshold)
|
||||
items.length === 0 || !cartHasShippableItem(items) || (freeShippingThreshold !== null && subtotal >= freeShippingThreshold)
|
||||
? 0
|
||||
: shippingCost;
|
||||
const { totalSavings, discountAmount, total } = computeCartTotals(items, shipping, discount);
|
||||
@@ -392,31 +392,40 @@ export function CartContent({
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-0.5 w-full">
|
||||
<div className="flex items-center w-full">
|
||||
<span className="flex items-center gap-1.5 text-body-sm text-text-primary">
|
||||
Versand
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setVersandOpen(true)}
|
||||
className="text-text-muted hover:text-brand transition-colors"
|
||||
aria-label="Alle Informationen zu Versandkosten und Lieferzeiten"
|
||||
>
|
||||
<span aria-hidden>ⓘ</span>
|
||||
</button>
|
||||
</span>
|
||||
<span className="flex-1" />
|
||||
<span className="text-body-sm text-text-primary">
|
||||
{shipping === 0 ? "Kostenlos" : formatPrice(shipping)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-label text-text-muted">
|
||||
{shipping === 0 && freeShippingThreshold !== null
|
||||
? `ab ${formatPrice(freeShippingThreshold)} innerhalb Deutschlands`
|
||||
: "innerhalb Deutschlands"}
|
||||
</p>
|
||||
<p className="text-label text-text-muted">
|
||||
Lieferzeit {shippingSettings.totalDays.min}–{shippingSettings.totalDays.max} Werktage
|
||||
</p>
|
||||
{/* Hidden entirely (not just "Kostenlos") when nothing in
|
||||
the cart actually triggers shipping at all — that's a
|
||||
different state from hitting the free-shipping
|
||||
threshold, which is still a real promotional message
|
||||
worth showing. */}
|
||||
{cartHasShippableItem(items) && (
|
||||
<>
|
||||
<div className="flex items-center w-full">
|
||||
<span className="flex items-center gap-1.5 text-body-sm text-text-primary">
|
||||
Versand
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setVersandOpen(true)}
|
||||
className="text-text-muted hover:text-brand transition-colors"
|
||||
aria-label="Alle Informationen zu Versandkosten und Lieferzeiten"
|
||||
>
|
||||
<span aria-hidden>ⓘ</span>
|
||||
</button>
|
||||
</span>
|
||||
<span className="flex-1" />
|
||||
<span className="text-body-sm text-text-primary">
|
||||
{shipping === 0 ? "Kostenlos" : formatPrice(shipping)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-label text-text-muted">
|
||||
{shipping === 0 && freeShippingThreshold !== null
|
||||
? `ab ${formatPrice(freeShippingThreshold)} innerhalb Deutschlands`
|
||||
: "innerhalb Deutschlands"}
|
||||
</p>
|
||||
<p className="text-label text-text-muted">
|
||||
Lieferzeit {shippingSettings.totalDays.min}–{shippingSettings.totalDays.max} Werktage
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="h-px bg-border w-full" />
|
||||
|
||||
Reference in New Issue
Block a user