diff --git a/app/checkout/components/CheckoutContent.tsx b/app/checkout/components/CheckoutContent.tsx new file mode 100644 index 0000000..5603f34 --- /dev/null +++ b/app/checkout/components/CheckoutContent.tsx @@ -0,0 +1,380 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; +import Image from "next/image"; +import { useCart } from "../../lib/cart"; +import { useProducts } from "../../lib/products"; +import { formatPrice } from "../../lib/format"; +import { SHIPPING_COST, FREE_SHIPPING_THRESHOLD } from "../../lib/shipping"; +import { Reveal } from "../../components/Reveal"; + +const EXPRESS_SHIPPING_COST = 4.9; + +const steps = [ + { label: "Warenkorb", state: "done" as const }, + { label: "Adresse", state: "active" as const }, + { label: "Zahlung", state: "upcoming" as const }, + { label: "Abschluss", state: "upcoming" as const }, +]; + +function StepCircle({ state, number }: { state: "done" | "active" | "upcoming"; number: number }) { + if (state === "done") { + return ( +
+ +
+ ); + } + if (state === "active") { + return ( +
+ {number} +
+ ); + } + return ( +
+ {number} +
+ ); +} + +function FormField({ + label, + ...props +}: { label: string } & React.InputHTMLAttributes) { + return ( + + ); +} + +export function CheckoutContent() { + const cart = useCart(); + const products = useProducts(); + const [shippingMethod, setShippingMethod] = useState<"standard" | "express">("standard"); + const [paymentMethod, setPaymentMethod] = useState<"card" | "paypal" | "bank">("card"); + + const productsLoading = products.length === 0 && cart.length > 0; + const items = cart + .map((entry) => ({ entry, product: products.find((p) => p.id === entry.id) })) + .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 freeShipping = subtotal >= FREE_SHIPPING_THRESHOLD; + const shipping = items.length === 0 || freeShipping + ? 0 + : shippingMethod === "express" + ? EXPRESS_SHIPPING_COST + : SHIPPING_COST; + const total = subtotal + shipping; + + if (!productsLoading && items.length === 0) { + return ( + +

+ Checkout +

+

+ Dein Warenkorb ist leer — es gibt noch nichts zum Abschließen. +

+ + Zum Shop + +
+ ); + } + + return ( + <> + {/* Header — breadcrumb, stepper, title */} + +

+ Startseite + + Warenkorb + + Checkout +

+ +
+ {steps.map((step, i) => ( +
+
+
+ + + {step.label} + +
+
+ {i < steps.length - 1 &&
} +
+ ))} +
+ +
+

+ Checkout +

+

Fast geschafft! Nur noch ein paar Angaben.

+
+ + +
+ {/* Form column */} +
+ {/* 1. Rechnungsadresse */} + +

+ 1. Rechnungsadresse +

+
+ + +
+ + +
+ + +
+ + +
+ + {/* 2. Versandart */} + +

+ 2. Versandart +

+ {( + [ + { id: "standard", label: "Standardversand (2–4 Werktage)", price: SHIPPING_COST }, + { id: "express", label: "Expressversand (1–2 Werktage)", price: EXPRESS_SHIPPING_COST }, + ] as const + ).map((option) => ( + + ))} +
+ + {/* 3. Zahlungsart */} + +

+ 3. Zahlungsart +

+ + + + + + + + + Jetzt kaufen (zahlungspflichtig) + + +
+ + Sichere SSL-Verschlüsselung +
+
+
+ + {/* Sidebar */} + +
+

+ Deine Bestellung +

+ + {items.map(({ entry, product }) => ( +
+
+ {product.name} +
+
+

{product.name}

+

{entry.qty} × {formatPrice(product.price)}

+
+

{formatPrice(entry.qty * product.price)}

+
+ ))} + +
+ +
+ Zwischensumme + + {formatPrice(subtotal)} +
+ +
+
+ Versand + + + {shipping === 0 ? "Kostenlos" : formatPrice(shipping)} + +
+

innerhalb Deutschlands

+
+ +
+ +
+
+ + Gesamtsumme + + + {formatPrice(total)} +
+

inkl. MwSt.

+
+
+ +
+ {[ + { icon: "/icon-lock.svg", title: "Sichere Zahlung", desc: "Deine Daten sind bei uns sicher und geschützt." }, + { icon: "/icon-trust-return.png", title: "14 Tage Rückgaberecht", desc: "Nicht zufrieden? Sende deine Bestellung innerhalb von 14 Tagen zurück." }, + { icon: "/icon-trust-leaf.png", title: "Nachhaltig verpackt", desc: "Wir achten auf umweltfreundliche Materialien und plastikfreien Versand." }, + ].map((b) => ( +
+ +
+

{b.title}

+

{b.desc}

+
+
+ ))} +
+ + {/* Newsletter hint — divider under the TEXT, not the icon, per + this page's own Figma spec (different from /cart's version, + which puts the divider under the icon — the two aren't meant + to be identical, see project notes on this pattern). */} +
+ +
+

+ Nach deiner Bestellung bekommst du regelmäßig Impulse & Tipps per E-Mail. +

+

+ Für mehr Klarheit, Fokus und Struktur – jede Woche. +

+
+
+
+
+
+
+ +
+ + ); +} diff --git a/app/checkout/page.tsx b/app/checkout/page.tsx new file mode 100644 index 0000000..acff019 --- /dev/null +++ b/app/checkout/page.tsx @@ -0,0 +1,26 @@ +import type { Metadata } from "next"; +import { CheckoutContent } from "./components/CheckoutContent"; +import { TrustRow } from "../components/TrustRow"; +import { Footer } from "../components/Footer"; + +// robots: noindex — transactional page, same reasoning as /cart. +export const metadata: Metadata = { + title: "Checkout", + description: "Schließe deine Bestellung bei einfach produktiv ab.", + robots: { + index: false, + follow: true, + }, +}; + +export default function CheckoutPage() { + return ( + <> +
+ + +
+