Add real order persistence, customer accounts, and cart sync

Checkout now persists orders server-side (Payload orders collection,
re-priced from live product data, discount codes redeemed exactly once)
instead of writing a client-only sessionStorage snapshot. Buying requires
an account (registration inline in checkout, no separate step) — accounts
get order history with delivery status, profile/address editing, password
change, and a cart that syncs across devices while logged in.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Marco
2026-07-22 06:45:42 +00:00
parent 516945fc8c
commit 7f37f111e8
27 changed files with 1697 additions and 89 deletions
+38
View File
@@ -0,0 +1,38 @@
"use client";
import { useEffect, useRef } from "react";
import { useCart } from "../lib/cart";
// Mirrors the local cart to the server whenever it changes, so a logged-in
// customer's cart follows them across devices (see Customers.ts's `cart`
// field). Renders nothing — mounted once in the root layout. Debounced
// (not fired on every keystroke-equivalent quantity bump) and silently a
// no-op when logged out — POST /api/account/cart 401s in that case, which
// this component doesn't need to distinguish from success; there's simply
// nothing to keep in sync yet.
export function CartSync() {
const cart = useCart();
const isFirstRender = useRef(true);
useEffect(() => {
// Skip the mount-time fire — this would otherwise POST on every page
// load even when nothing actually changed.
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
const timeout = setTimeout(() => {
fetch("/api/account/cart", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cart }),
}).catch(() => {
// Best-effort — a failed sync just means the next cart change (or
// the next login-time merge) tries again.
});
}, 800);
return () => clearTimeout(timeout);
}, [cart]);
return null;
}