From 3bde1d61ff342ad6d00bf4fabb5a5345f8c53be1 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 20 Jul 2026 00:42:48 +0000 Subject: [PATCH] feat(cart, checkout, bestellbestaetigung): show total savings in the order summary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Du sparst -X,XX €" line under Zwischensumme, summing (compareAtPrice - price) × qty across items with a discount — only shown when > 0, same conditional-render convention as the rest of the sale-pricing UI (badge/strikethrough already gated on discountPercent() !== null). --- .../components/BestellbestaetigungContent.tsx | 13 ++++++++++++- app/cart/components/CartContent.tsx | 12 ++++++++++++ app/checkout/components/CheckoutContent.tsx | 14 +++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/app/bestellbestaetigung/components/BestellbestaetigungContent.tsx b/app/bestellbestaetigung/components/BestellbestaetigungContent.tsx index 2df58e8..31a076a 100644 --- a/app/bestellbestaetigung/components/BestellbestaetigungContent.tsx +++ b/app/bestellbestaetigung/components/BestellbestaetigungContent.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import Image from "next/image"; import type { CartItem } from "../../lib/cart"; import { useProducts } from "../../lib/products"; -import { formatPrice, formatDate } from "../../lib/format"; +import { formatPrice, formatDate, discountPercent } from "../../lib/format"; import { Reveal } from "../../components/Reveal"; import { CheckoutSteps } from "../../components/CheckoutSteps"; import { ORDER_KEY, type OrderSnapshot } from "../../lib/order"; @@ -96,6 +96,10 @@ export function BestellbestaetigungContent() { .filter((row): row is { entry: CartItem; product: NonNullable<(typeof row)["product"]> } => Boolean(row.product)); const subtotal = items.reduce((sum, { entry, product }) => sum + entry.qty * product.price, 0); + const totalSavings = items.reduce((sum, { entry, product }) => { + const discount = discountPercent(product.price, product.compareAtPrice); + return discount !== null ? sum + entry.qty * (product.compareAtPrice! - product.price) : sum; + }, 0); const total = subtotal + order.shippingCost; return ( @@ -194,6 +198,13 @@ export function BestellbestaetigungContent() { {formatPrice(subtotal)} + {totalSavings > 0 && ( +
+ Du sparst + + -{formatPrice(totalSavings)} +
+ )}
Versand diff --git a/app/cart/components/CartContent.tsx b/app/cart/components/CartContent.tsx index 2be813b..5aedc35 100644 --- a/app/cart/components/CartContent.tsx +++ b/app/cart/components/CartContent.tsx @@ -40,6 +40,10 @@ export function CartContent({ .filter((row): row is { entry: typeof cart[number]; product: NonNullable<(typeof row)["product"]> } => Boolean(row.product)); const subtotal = items.reduce((sum, { entry, product }) => sum + entry.qty * product.price, 0); + const totalSavings = items.reduce((sum, { entry, product }) => { + const discount = discountPercent(product.price, product.compareAtPrice); + return discount !== null ? sum + entry.qty * (product.compareAtPrice! - product.price) : sum; + }, 0); const shipping = items.length === 0 || (freeShippingThreshold !== null && subtotal >= freeShippingThreshold) ? 0 @@ -187,6 +191,14 @@ export function CartContent({ {formatPrice(subtotal)}
+ {totalSavings > 0 && ( +
+ Du sparst + + -{formatPrice(totalSavings)} +
+ )} +
diff --git a/app/checkout/components/CheckoutContent.tsx b/app/checkout/components/CheckoutContent.tsx index be665ec..db3b401 100644 --- a/app/checkout/components/CheckoutContent.tsx +++ b/app/checkout/components/CheckoutContent.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import Image from "next/image"; import { useCart, clearCart } from "../../lib/cart"; import { useProducts } from "../../lib/products"; -import { formatPrice } from "../../lib/format"; +import { formatPrice, discountPercent } from "../../lib/format"; import { Reveal } from "../../components/Reveal"; import { VersandModal } from "../../components/VersandModal"; import { CheckoutSteps } from "../../components/CheckoutSteps"; @@ -50,6 +50,10 @@ export function CheckoutContent({ .filter((row): row is { entry: typeof cart[number]; product: NonNullable<(typeof row)["product"]> } => Boolean(row.product)); const subtotal = items.reduce((sum, { entry, product }) => sum + entry.qty * product.price, 0); + const totalSavings = items.reduce((sum, { entry, product }) => { + const discount = discountPercent(product.price, product.compareAtPrice); + return discount !== null ? sum + entry.qty * (product.compareAtPrice! - product.price) : sum; + }, 0); const selectedShipping = shippingMethods.find((m) => m.id === shippingMethodId) ?? null; const freeShipping = selectedShipping?.freeShippingThreshold !== null && @@ -343,6 +347,14 @@ export function CheckoutContent({ {formatPrice(subtotal)}
+ {totalSavings > 0 && ( +
+ Du sparst + + -{formatPrice(totalSavings)} +
+ )} +