import { type FormEvent, useState } from "react";
import { useRouter } from "next/navigation";
import { checkout, type Cart, type Order } from "@/lib/checkout";
import { GuestToggle } from "./guest-toggle";
import { ReceiptEmailField } from "./receipt-email-field";
import { SubmitButton } from "./submit-button";
type Props = {
cart: Cart;
onComplete?: (order: Order) => void;
};
type SubmitState = "idle" | "building" | "complete";
function receiptEmail(cart: Cart) {
return cart.customer?.email ?? "";
}
export function GuestCheckout({ cart, onComplete }: Props) {
const router = useRouter();
const [asGuest, setAsGuest] = useState(true);
const [state, setState] = useState<SubmitState>("idle");
const [error, setError] = useState("");
async function createSession() {
if (asGuest) {
return checkout.createGuestSession(cart);
}
return checkout.createAccountSession(cart);
}
async function submit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
setState("building");
setError("");
try {
const session = await createSession();
const order = await checkout.confirm(session.id);
onComplete?.(order);
router.push(`/checkout/confirm/${order.id}`);
} catch (cause) {
setError(checkout.messageFor(cause));
setState("idle");
}
}
return (
<form onSubmit={submit}>
<GuestToggle
value={asGuest}
onChange={setAsGuest}
disabled={state === "building"}
/>
<ReceiptEmailField
defaultValue={receiptEmail(cart)}
disabled={state === "building"}
/>
{error ? <CheckoutError>{error}</CheckoutError> : null}
<SubmitButton disabled={state === "building"}>
{state === "building" ? "Creating checkout..." : "Checkout"}
</SubmitButton>
</form>
);
}
A cropped implementation file for the guest checkout feature. Palette writes imports, state, session creation, submission, error handling, and the checkout form from top to bottom.