Move low-stock hint to badge, right-align VAT breakdown, gate cart discount field, split billing/shipping delivery method
- Removed the inline "Nur noch wenige verfügbar" text hint from AddToCartButton/AddToCartInlineButton (was making card heights vary in every grid that renders them — RelatedProducts, ProductSpotlight's CTA row) — now only shown via the same image-overlaid pill badge Ausverkauft/discount already use (position: absolute, doesn't affect layout). Added that badge to RelatedProducts.tsx and todo-cards' Pricing.tsx, which didn't have it before. - RelatedProducts cards now also show "inkl. X% MwSt." (was missing entirely) - VatBreakdown rows are now flex rows with a spacer instead of plain text, so every € amount right-aligns to the same edge regardless of how many digits the rate itself has (was visibly staggered with mixed 7%/19% rates) - Cart's manual discount-code field only renders when Payload actually has at least one active code right now (lib/discountServer.ts's new hasActiveDiscountCode()) — no point showing an open field that could never validate. An already-applied code (e.g. from an older session) still always shows its own result row regardless. - Checkout's "1. Rechnungsadresse" no longer offers a Packstation option — a Packstation isn't a valid billing address for an invoice. Only a plain street address now; Packstation is only offered on the separate, optional "Abweichende Lieferadresse" section, which already had its own address/Packstation toggle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,10 +14,10 @@ export type CheckoutDraft = {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
deliveryMethod: "address" | "packstation";
|
||||
// Rechnungsadresse is always a plain street address now — no
|
||||
// deliveryMethod/packstationNumber/postNumber here, only on the
|
||||
// shipping* override fields below (see CheckoutContent.tsx).
|
||||
street: string;
|
||||
packstationNumber: string;
|
||||
postNumber: string;
|
||||
zip: string;
|
||||
city: string;
|
||||
country: string;
|
||||
|
||||
@@ -44,6 +44,31 @@ async function fetchDiscountCode(code: string): Promise<PayloadDiscountCode | nu
|
||||
return data.docs?.[0] ?? null;
|
||||
}
|
||||
|
||||
// Whether it's worth showing the cart's manual "Rabattcode" input field at
|
||||
// all — no point offering an open text field for a shopper to type into
|
||||
// when there's nothing in Payload that could ever validate. Existence-only
|
||||
// check (active: true), not the fuller validFrom/validUntil/minOrderValue
|
||||
// window validateDiscountCode() does for an actual submitted code — this
|
||||
// just gates whether the field renders, the real validation still happens
|
||||
// at apply time regardless.
|
||||
export async function hasActiveDiscountCode(): Promise<boolean> {
|
||||
const params = new URLSearchParams({
|
||||
"where[tenant.slug][equals]": TENANT_SLUG,
|
||||
"where[active][equals]": "true",
|
||||
limit: "1",
|
||||
});
|
||||
const res = await fetch(`${PAYLOAD_URL}/api/discount-codes?${params}`, {
|
||||
headers: { "x-discount-service-secret": SERVICE_SECRET },
|
||||
next: { revalidate: 60 },
|
||||
});
|
||||
if (!res.ok) {
|
||||
console.error(`hasActiveDiscountCode: Payload returned ${res.status} ${res.statusText}`);
|
||||
return false;
|
||||
}
|
||||
const data: { docs?: unknown[] } = await res.json();
|
||||
return (data.docs?.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
export type DiscountValidation =
|
||||
| { valid: true; doc: PayloadDiscountCode }
|
||||
| { valid: false; reason: string };
|
||||
|
||||
Reference in New Issue
Block a user