"use server"; import { revalidatePath } from "next/cache"; import { getServerSession } from "@/lib/auth/guards"; import { prisma } from "@/lib/db"; import { stripe, createStripeCheckout, createStripePortal, isStripeConfigured, } from "@/lib/billing/stripe"; import { createPaypalSubscription, cancelPaypalSubscription, isPaypalConfigured, } from "@/lib/billing/paypal"; import { paypalPlanId, type BillingInterval } from "@/lib/billing/catalog"; import { getActiveSubscription } from "@/lib/billing/subscription"; import type { PlanKey } from "@/lib/billing/plans"; type ActionResult = { ok: true; url?: string } | { ok: false; error: string }; function errMsg(e: unknown): string { return e instanceof Error ? e.message : "Something went wrong"; } export async function startStripeCheckoutAction( plan: PlanKey, interval: BillingInterval ): Promise { const session = await getServerSession(); if (!session) return { ok: false, error: "Please sign in." }; if (!isStripeConfigured()) return { ok: false, error: "Card payments aren't configured yet." }; const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { id: true, email: true, name: true, stripeCustomerId: true }, }); if (!user) return { ok: false, error: "Account not found." }; try { const url = await createStripeCheckout({ user, plan, interval, subjectId: user.id, subjectType: "user", }); return { ok: true, url }; } catch (e) { return { ok: false, error: errMsg(e) }; } } export async function startPaypalCheckoutAction(plan: PlanKey): Promise { const session = await getServerSession(); if (!session) return { ok: false, error: "Please sign in." }; if (!isPaypalConfigured()) return { ok: false, error: "PayPal isn't configured yet." }; const planId = paypalPlanId(plan); if (!planId) return { ok: false, error: "PayPal plan isn't configured for this tier." }; try { const { approveUrl } = await createPaypalSubscription({ planId, custom: { subjectId: session.user.id, subjectType: "user", plan }, }); return { ok: true, url: approveUrl }; } catch (e) { return { ok: false, error: errMsg(e) }; } } export async function openStripePortalAction(): Promise { const session = await getServerSession(); if (!session) return { ok: false, error: "Please sign in." }; const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { stripeCustomerId: true }, }); if (!user?.stripeCustomerId) return { ok: false, error: "No billing account yet." }; try { const url = await createStripePortal(user.stripeCustomerId); return { ok: true, url }; } catch (e) { return { ok: false, error: errMsg(e) }; } } export async function cancelSubscriptionAction(): Promise { const session = await getServerSession(); if (!session) return { ok: false, error: "Please sign in." }; const sub = await getActiveSubscription(session.user.id); if (!sub) return { ok: false, error: "No active subscription." }; try { if (sub.provider === "paypal" && sub.paypalSubscriptionId) { await cancelPaypalSubscription(sub.paypalSubscriptionId); await prisma.subscription.update({ where: { id: sub.id }, data: { status: "canceled", cancelAtPeriodEnd: true }, }); } else if (sub.provider === "stripe" && sub.stripeSubscriptionId) { await stripe().subscriptions.update(sub.stripeSubscriptionId, { cancel_at_period_end: true }); await prisma.subscription.update({ where: { id: sub.id }, data: { cancelAtPeriodEnd: true }, }); } revalidatePath("/billing"); return { ok: true }; } catch (e) { return { ok: false, error: errMsg(e) }; } }