Something went wrong. Try again.
a tool for shared writing and social publishing
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970"use server";
import { getIdentityData } from "./getIdentityData";import { getStripe } from "stripe/client";import { supabaseServerClient } from "supabase/serverClient";import { getPriceId } from "stripe/products";import { Ok, Err, type Result } from "src/result";
export async function createCheckoutSession( cadence: "month" | "year", returnUrl?: string, coupon?: string,): Promise<Result<{ url: string }, string>> { const identity = await getIdentityData(); if (!identity) { return Err("Not authenticated"); }
const priceId = await getPriceId(cadence); if (!priceId) { return Err("No Stripe price found. Run the sync script first."); }
// Check for existing Stripe customer let customerId: string | undefined; const { data: existingSub } = await supabaseServerClient .from("user_subscriptions") .select("stripe_customer_id") .eq("identity_id", identity.id) .single();
if (existingSub?.stripe_customer_id) { customerId = existingSub.stripe_customer_id; }
const appUrl = process.env.NEXT_PUBLIC_APP_URL || "https://leaflet.pub";
const successUrl = new URL("/api/checkout/success", appUrl); successUrl.searchParams.set("session_id", "{CHECKOUT_SESSION_ID}"); if (returnUrl) { successUrl.searchParams.set("return", returnUrl); }
// Stripe requires an absolute URL; returnUrl is a relative path like "/home". const cancelUrl = returnUrl ? new URL(returnUrl, appUrl).toString() : appUrl;
const session = await getStripe().checkout.sessions.create({ mode: "subscription", line_items: [{ price: priceId, quantity: 1 }], client_reference_id: identity.id, ...(customerId ? { customer: customerId } : { customer_email: identity.email || undefined }), subscription_data: { metadata: { identity_id: identity.id } }, // Stripe rejects discounts and allow_promotion_codes together: a // preset coupon takes the discount slot, otherwise let users enter a code. ...(coupon ? { discounts: [{ coupon }] } : { allow_promotion_codes: true }), success_url: successUrl.toString(), cancel_url: cancelUrl, });
if (!session.url) { return Err("Failed to create checkout session"); }
return Ok({ url: session.url });}