Consolidate Kreditkarte/PayPal into one "Online-Zahlung" checkout option
Both already route through the same Stripe PaymentIntent (automatic_payment_methods: enabled — Stripe's own recommended Payment Element pattern, letting Stripe itself decide which eligible method to show). Pre-selecting one of two identical-behind-the-scenes rows before the payment step was redundant friction, not a real choice. Collapses them into one option with a hint text explaining the actual instrument is picked on the next screen; Überweisung is unaffected. Also refines paymentMethodTitle from a neutral "Online-Zahlung" placeholder (snapshotted at order-creation time, before the customer has picked an instrument) to the real one Stripe reports, once payment confirms — carried through to both the stored order and the sessionStorage snapshot shown on /bestellbestaetigung. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { forwardRef, useEffect, useRef, useState } from "react";
|
||||
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -22,6 +22,7 @@ import { normalizeVatId, isValidVatId } from "../../lib/vatId";
|
||||
import { computeExemptTotals, destinationCountry, isExemptionEligibleCountry } from "../../lib/vatExemption";
|
||||
import { validateEmailFormat } from "../../lib/email";
|
||||
import type { ShippingMethod, ShippingCountry, PaymentMethod, TrustBadge, ShippingSettings } from "../../lib/payload";
|
||||
import { groupPaymentMethodsForCheckout } from "../../lib/payload";
|
||||
import type { CustomerProfile } from "../../lib/customerAuth";
|
||||
|
||||
// Native HTML5 pattern validation (instant, no round-trip) mirroring the
|
||||
@@ -141,7 +142,12 @@ export function CheckoutContent({
|
||||
// validateZip() call site.
|
||||
const plzDigitsMap: Record<string, number> = Object.fromEntries(shippingCountries.map((c) => [c.name, c.plzDigits]));
|
||||
const [shippingMethodId, setShippingMethodId] = useState<number | null>(shippingMethods[0]?.id ?? null);
|
||||
const [paymentMethodId, setPaymentMethodId] = useState<number | null>(paymentMethods[0]?.id ?? null);
|
||||
// Kreditkarte/PayPal collapse into one "Online-Zahlung" option here —
|
||||
// see groupPaymentMethodsForCheckout's own comment for why. The
|
||||
// resulting id is still a real payment-methods row id, so everything
|
||||
// downstream (submission, sessionStorage draft restore) is unaffected.
|
||||
const paymentOptions = useMemo(() => groupPaymentMethodsForCheckout(paymentMethods), [paymentMethods]);
|
||||
const [paymentMethodId, setPaymentMethodId] = useState<number | null>(paymentOptions[0]?.id ?? null);
|
||||
const [versandOpen, setVersandOpen] = useState(false);
|
||||
const [purchaseError, setPurchaseError] = useState<string | null>(null);
|
||||
const [purchasing, setPurchasing] = useState(false);
|
||||
@@ -1219,23 +1225,26 @@ export function CheckoutContent({
|
||||
3. Zahlungsart
|
||||
</p>
|
||||
|
||||
{paymentMethods.map((method) => (
|
||||
<label key={method.id} className="flex items-center gap-3 w-full cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="payment"
|
||||
checked={paymentMethodId === method.id}
|
||||
onChange={() => setPaymentMethodId(method.id)}
|
||||
className="size-5 shrink-0 accent-brand"
|
||||
/>
|
||||
<span className="flex-1 text-body-sm text-text-primary">{method.title}</span>
|
||||
<span className="flex items-center gap-2 shrink-0">
|
||||
{method.icons.map((icon, i) => (
|
||||
<div key={i} className="relative h-5 w-8 shrink-0">
|
||||
<Image src={icon} alt="" fill sizes="32px" className="object-contain" />
|
||||
</div>
|
||||
))}
|
||||
{paymentOptions.map((method) => (
|
||||
<label key={method.id} className="flex flex-col gap-1 w-full cursor-pointer">
|
||||
<span className="flex items-center gap-3 w-full">
|
||||
<input
|
||||
type="radio"
|
||||
name="payment"
|
||||
checked={paymentMethodId === method.id}
|
||||
onChange={() => setPaymentMethodId(method.id)}
|
||||
className="size-5 shrink-0 accent-brand"
|
||||
/>
|
||||
<span className="flex-1 text-body-sm text-text-primary">{method.title}</span>
|
||||
<span className="flex items-center gap-2 shrink-0">
|
||||
{method.icons.map((icon, i) => (
|
||||
<div key={i} className="relative h-5 w-8 shrink-0">
|
||||
<Image src={icon} alt="" fill sizes="32px" className="object-contain" />
|
||||
</div>
|
||||
))}
|
||||
</span>
|
||||
</span>
|
||||
{method.hint && <span className="pl-8 text-label text-text-muted">{method.hint}</span>}
|
||||
</label>
|
||||
))}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user