"use client"; import { useEffect, useState } from "react"; type Product = { id: string; name: string; description?: string | null; unitAmount?: number | null; currency?: string | null; stripePriceId?: string | null; }; export default function StorefrontPage({ params }: { params: { accountId: string } }) { const { accountId: slug } = params; const [products, setProducts] = useState([]); const [loading, setLoading] = useState(false); const [message, setMessage] = useState(""); const [accountId, setAccountId] = useState(""); useEffect(() => { if (slug) { window.localStorage.setItem("connectStoreSlug", slug); } async function load() { setLoading(true); 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 res = await fetch(`/api/storefront/products?slug=${slug}`); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to load products"); const normalized = data.products?.map((p: any) => ({ id: p.stripeProductId ?? p.id, name: p.name, description: p.description, unitAmount: p.unitAmount ?? p.default_price?.unit_amount ?? null, currency: p.currency ?? p.default_price?.currency ?? null, stripePriceId: p.stripePriceId ?? p.default_price?.id ?? null, })) || []; setProducts(normalized); } catch (err: any) { setMessage(err.message || "Failed to load products."); } finally { setLoading(false); } } load(); }, [slug]); async function buyNow(product: Product) { if (!product.unitAmount || !product.currency || !accountId) { setMessage("Product is missing a price."); return; } setLoading(true); setMessage(""); try { const res = await fetch("/api/connect/checkout", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId, name: product.name, description: product.description, unitAmount: product.unitAmount, currency: product.currency, quantity: 1, }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to start checkout"); window.location.href = data.url; } catch (err: any) { setMessage(err.message || "Checkout failed."); } finally { setLoading(false); } } async function addToCart(product: Product) { if (!product.unitAmount || !product.currency || !product.stripePriceId) { setMessage("Product is missing a price."); return; } setLoading(true); setMessage(""); try { const res = await fetch("/api/cart/add", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ slug, productId: product.id, priceId: product.stripePriceId, name: product.name, unitAmount: product.unitAmount, currency: product.currency, quantity: 1, }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to add to cart"); setMessage("Added to cart."); } catch (err: any) { setMessage(err.message || "Failed to add to cart."); } finally { setLoading(false); } } return (

Storefront

Store: {slug} (mapped to a connected account)

{message ?
{message}
: null}
{products.map((product) => (

{product.name}

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

{product.unitAmount ? `${(product.unitAmount / 100).toFixed(2)} ${product.currency?.toUpperCase() || "USD"}` : "No price"}
Pay with card View cart
))} {!products.length && !loading ? (
No products yet.
) : null}
); }