Add password reset, order confirmation email with editable templates, and fix missing account entry points

Password reset uses Payload's built-in forgot/reset-password flow,
customized to link to this app instead of the Payload admin. Order
confirmation email and the password-reset email's wording both come from
a new Payload email-templates collection, editable without a deploy and
previewable via Live Preview at /email-preview/[type] (same mechanism as
Posts/LegalPages/Testimonials, sample data instead of a real document).

Also: order numbers get a random suffix (prevents guessing, motivated by
a considered-and-deferred guest order-lookup feature); the discount code
field only shows in the cart when a code is actually active (codes now
apply via a ?code= link instead of manual entry); and three navigation
gaps found while testing — no reachable login link with an empty cart, no
logout link anywhere, no way back from profile to order history.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Marco
2026-07-22 08:14:08 +00:00
parent adca6e0f64
commit f0df359db4
26 changed files with 865 additions and 81 deletions
@@ -4,8 +4,9 @@ import Link from "next/link";
import { Reveal } from "../../../components/Reveal";
import { Footer } from "../../../components/Footer";
import { formatPrice, formatDate } from "../../../lib/format";
import { getSessionCustomer, getCustomerOrderDetail, ORDER_STATUS_LABEL, customerOrderAction } from "../../../lib/customerAuth";
import { getSessionCustomer, getCustomerOrderDetail, customerOrderAction } from "../../../lib/customerAuth";
import { OrderActionButton } from "./components/OrderActionButton";
import { OrderStatusBadge } from "../../components/OrderStatusBadge";
export const metadata: Metadata = {
title: "Bestelldetails",
@@ -45,7 +46,7 @@ export default async function KontoBestellungDetailPage({ params }: { params: Pr
</div>
<div className="flex flex-col gap-1">
<p className="text-label text-text-muted">Status</p>
<p className="text-body-sm text-text-primary">{ORDER_STATUS_LABEL[order.status] ?? order.status}</p>
<OrderStatusBadge status={order.status} />
</div>
<div className="flex flex-col gap-1">
<p className="text-label text-text-muted">Zahlungsart</p>
+5 -2
View File
@@ -4,7 +4,9 @@ import Link from "next/link";
import { Reveal } from "../../components/Reveal";
import { Footer } from "../../components/Footer";
import { formatPrice, formatDate } from "../../lib/format";
import { getSessionCustomer, getCustomerOrders, ORDER_STATUS_LABEL } from "../../lib/customerAuth";
import { getSessionCustomer, getCustomerOrders } from "../../lib/customerAuth";
import { OrderStatusBadge } from "../components/OrderStatusBadge";
import { LogoutButton } from "../components/LogoutButton";
// robots: noindex — account area, same reasoning as /checkout.
export const metadata: Metadata = {
@@ -57,7 +59,7 @@ export default async function KontoBestellungenPage() {
</div>
<div className="flex flex-col gap-1">
<p className="text-label text-text-muted">Status</p>
<p className="text-body-sm text-text-primary">{ORDER_STATUS_LABEL[order.status] ?? order.status}</p>
<OrderStatusBadge status={order.status} />
</div>
<div className="flex flex-col gap-1 ml-auto">
<p className="text-label text-text-muted">Gesamtbetrag</p>
@@ -75,6 +77,7 @@ export default async function KontoBestellungenPage() {
<Link href="/shop" className="underline text-body-sm text-text-primary hover:text-brand transition-colors">
Weiter einkaufen
</Link>
<LogoutButton />
</div>
</Reveal>
</main>