"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 (
);
}
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}
);
}