"use client"; import { useEffect, useMemo, useState } from "react"; import { useSearchParams } from "next/navigation"; import { Elements, LinkAuthenticationElement, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js"; import { stripePromise } from "../../../../lib/stripeJs"; type Product = { id: string; name: string; description?: string | null; default_price?: { id: string; unit_amount: number | null; currency: string; } | null; }; function CheckoutForm({ accountId, product }: { accountId: string; product: Product }) { const stripe = useStripe(); const elements = useElements(); const [message, setMessage] = useState(""); const [loading, setLoading] = useState(false); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!stripe || !elements) return; setLoading(true); setMessage(""); const result = await stripe.confirmPayment({ elements, confirmParams: { return_url: `${window.location.origin}/success`, }, }); if (result.error) { setMessage(result.error.message || "Payment failed."); } setLoading(false); } return (

{product.name}

{product.description || "No description provided."}

{product.default_price?.unit_amount ? `${(product.default_price.unit_amount / 100).toFixed(2)} ${product.default_price.currency.toUpperCase()}` : "No price"}
{message ?
{message}
: null}
); } export default function StorefrontPayPage({ params }: { params: { accountId: string } }) { const { accountId: slug } = params; const searchParams = useSearchParams(); const productId = searchParams.get("productId"); const [product, setProduct] = useState(null); const [clientSecret, setClientSecret] = useState(""); const [message, setMessage] = useState(""); const [accountId, setAccountId] = useState(""); const elementsOptions = useMemo(() => { if (!clientSecret) return null; return { clientSecret }; }, [clientSecret]); useEffect(() => { if (!productId) { setMessage("Missing productId in URL."); return; } if (slug) { window.localStorage.setItem("connectStoreSlug", slug); } async function load() { setMessage(""); try { const lookup = await fetch(`/api/connect/account/lookup?slug=${slug}`); const lookupData = await lookup.json(); if (!lookup.ok) throw new Error(lookupData.error || "Store not found"); setAccountId(lookupData.accountId); const prodRes = await fetch( `/api/connect/products/get?accountId=${lookupData.accountId}&productId=${productId}` ); const prodData = await prodRes.json(); if (!prodRes.ok) throw new Error(prodData.error || "Failed to load product"); setProduct(prodData.product); const priceId = prodData.product?.default_price?.id; if (!priceId) throw new Error("Product does not have a default price."); const intentRes = await fetch("/api/connect/payment-intent", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId: lookupData.accountId, priceId }), }); const intentData = await intentRes.json(); if (!intentRes.ok) throw new Error(intentData.error || "Failed to create payment intent"); setClientSecret(intentData.clientSecret); } catch (err: any) { setMessage(err.message || "Failed to initialize checkout."); } } load(); }, [slug, productId]); if (!stripePromise) { return (
Missing `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`.
); } return (

Card Checkout

Store: {slug}

{message ?
{message}
: null} {product && elementsOptions ? ( ) : null}
); }