"use client"; import { Suspense, useEffect, useMemo, useState } from "react"; import { useSearchParams } from "next/navigation"; import { signIn, signOut, useSession } from "next-auth/react"; type AccountStatus = { readyToProcessPayments: boolean; onboardingComplete: boolean; requirementsStatus?: string; }; function ConnectDashboardClient() { const [displayName, setDisplayName] = useState( process.env.NEXT_PUBLIC_STORE_DEFAULT_NAME || "" ); const [contactEmail, setContactEmail] = useState(""); const [accountId, setAccountId] = useState(""); const [storeSlug, setStoreSlug] = useState("storeshifted"); const [status, setStatus] = useState(null); const [loading, setLoading] = useState(false); const [message, setMessage] = useState(""); const [productName, setProductName] = useState(""); const [productDescription, setProductDescription] = useState(""); const [productPrice, setProductPrice] = useState("4999"); const [currency, setCurrency] = useState("usd"); const searchParams = useSearchParams(); const { data: session, status: sessionStatus } = useSession(); const isAuthenticated = sessionStatus === "authenticated"; useEffect(() => { const stored = window.localStorage.getItem("connectAccountId"); if (stored) setAccountId(stored); const storedSlug = window.localStorage.getItem("connectStoreSlug"); if (storedSlug) setStoreSlug(storedSlug); }, []); useEffect(() => { const fromQuery = searchParams.get("accountId"); if (fromQuery) setAccountId(fromQuery); }, [searchParams]); useEffect(() => { async function loadStore() { if (!isAuthenticated) return; try { const res = await fetch("/api/store/me"); const data = await res.json(); if (res.ok && data.slug) { setStoreSlug(data.slug); if (data.stripeAccountId) setAccountId(data.stripeAccountId); } } catch { // ignore } } loadStore(); }, [session]); useEffect(() => { if (accountId) { window.localStorage.setItem("connectAccountId", accountId); } }, [accountId]); useEffect(() => { if (storeSlug) { window.localStorage.setItem("connectStoreSlug", storeSlug); } }, [storeSlug]); const storefrontUrl = useMemo(() => { if (!storeSlug) return ""; return `/storefront/${storeSlug}`; }, [storeSlug]); async function createAccount() { if (!isAuthenticated) { setMessage("Please sign in first."); return; } setMessage(""); setLoading(true); try { const res = await fetch("/api/connect/account/create", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ displayName, contactEmail, slug: storeSlug }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to create account"); setAccountId(data.accountId); setMessage("Connected account created."); } catch (err: any) { setMessage(err.message || "Failed to create account."); } finally { setLoading(false); } } async function refreshStatus() { if (!accountId) return; setMessage(""); setLoading(true); try { const res = await fetch(`/api/connect/account/status?accountId=${accountId}`); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to fetch status"); setStatus(data); } catch (err: any) { setMessage(err.message || "Failed to fetch status."); } finally { setLoading(false); } } async function startOnboarding() { if (!accountId) return; setMessage(""); setLoading(true); try { const res = await fetch("/api/connect/account/link", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to create account link"); window.location.href = data.url; } catch (err: any) { setMessage(err.message || "Failed to start onboarding."); } finally { setLoading(false); } } async function createProduct() { if (!accountId) return; setMessage(""); setLoading(true); try { const res = await fetch("/api/connect/products/create", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId, name: productName, description: productDescription, priceInCents: Number(productPrice), currency, }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to create product"); setMessage(`Product created: ${data.productId}`); } catch (err: any) { setMessage(err.message || "Failed to create product."); } finally { setLoading(false); } } async function createSubscription() { if (!accountId) return; setMessage(""); setLoading(true); try { const res = await fetch("/api/connect/subscription/create", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to create subscription"); window.location.href = data.url; } catch (err: any) { setMessage(err.message || "Failed to create subscription."); } finally { setLoading(false); } } async function openBillingPortal() { if (!accountId) return; setMessage(""); setLoading(true); try { const res = await fetch("/api/connect/subscription/portal", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to create portal session"); window.location.href = data.url; } catch (err: any) { setMessage(err.message || "Failed to open billing portal."); } finally { setLoading(false); } } return (

Stripe Connect Demo

This demo onboards connected accounts, creates products on their account, and provides a storefront for customers to purchase.

Account Access

{isAuthenticated ? (
Signed in as {session!.user.email}
) : (
Sign in to create an account.
)}

Create Connected Account

setDisplayName(e.target.value)} placeholder="Display name" /> setContactEmail(e.target.value)} placeholder="Contact email" /> setStoreSlug(e.target.value)} placeholder="Store slug (e.g. storeshifted)" />
{accountId ? (
Connected account: {accountId}
) : null}

Onboard to Collect Payments

{status ? (
Ready to process payments: {String(status.readyToProcessPayments)}
Onboarding complete: {String(status.onboardingComplete)}
Requirements status: {status.requirementsStatus || "unknown"}
) : null}

Create Product on Connected Account

setProductName(e.target.value)} placeholder="Product name" /> setProductDescription(e.target.value)} placeholder="Description" /> setProductPrice(e.target.value)} placeholder="Price in cents" /> setCurrency(e.target.value)} placeholder="Currency (usd)" />

Storefront

This demo uses the connected account ID in the URL. Replace this with your own identifier in production.

Subscription (Platform Billing)

Creates a hosted subscription checkout session and a billing portal for the connected account.

{message ?
{message}
: null}
); } export default function ConnectDashboardPage() { return ( ); }