diff --git a/apps/web/src/pages/api/stripe/create_checkout_session.ts b/apps/web/src/pages/api/stripe/create_checkout_session.ts index 8f8b9104..f8325b12 100644 --- a/apps/web/src/pages/api/stripe/create_checkout_session.ts +++ b/apps/web/src/pages/api/stripe/create_checkout_session.ts @@ -3,6 +3,7 @@ import { env } from "next-runtime-env"; import { z } from "zod"; import { createNextApiContext } from "@kan/api/trpc"; +import * as subscriptionRepo from "@kan/db/repository/subscription.repo"; import * as workspaceRepo from "@kan/db/repository/workspace.repo"; import { createStripeClient } from "@kan/stripe"; @@ -40,17 +41,22 @@ export default async function handler( const body = req.body as CheckoutSessionRequest; const { successUrl, cancelUrl, slug, workspacePublicId } = body; - if (!successUrl || !cancelUrl || !slug || !workspacePublicId) { + if (!successUrl || !cancelUrl || !workspacePublicId) { return res.status(400).json({ error: "Missing required fields" }); } - const slugResult = workspaceSlugSchema.safeParse(slug); + if (slug) { + const slugResult = workspaceSlugSchema.safeParse(slug); - if (!slugResult.success) { - return new Response(JSON.stringify({ error: "Invalid workspace slug" }), { - status: 400, - headers: { "Content-Type": "application/json" }, - }); + if (!slugResult.success) { + return new Response( + JSON.stringify({ error: "Invalid workspace slug" }), + { + status: 400, + headers: { "Content-Type": "application/json" }, + }, + ); + } } const workspace = await workspaceRepo.getAllByUserId(db, user.id); @@ -66,6 +72,20 @@ export default async function handler( }); } + const subscription = await subscriptionRepo.create(db, { + plan: "pro", + referenceId: workspacePublicId, + userId: user.id, + stripeCustomerId: user.stripeCustomerId ?? "", + status: "incomplete", + }); + + const subscriptionId = subscription?.id; + + if (!subscriptionId) { + return res.status(500).json({ error: "Error creating subscription" }); + } + const session = await stripe.checkout.sessions.create({ mode: "subscription", line_items: [ @@ -76,10 +96,13 @@ export default async function handler( ], success_url: `${env("NEXT_PUBLIC_BASE_URL")}${successUrl}`, cancel_url: `${env("NEXT_PUBLIC_BASE_URL")}${cancelUrl}`, + client_reference_id: workspacePublicId, customer: user.stripeCustomerId ?? undefined, metadata: { - workspaceSlug: slug, + ...(slug && { workspaceSlug: slug }), workspacePublicId, + userId: user.id, + subscriptionId, }, }); diff --git a/apps/web/src/views/settings/components/UpgradeToProConfirmation.tsx b/apps/web/src/views/settings/components/UpgradeToProConfirmation.tsx index b25a3980..1eb05833 100644 --- a/apps/web/src/views/settings/components/UpgradeToProConfirmation.tsx +++ b/apps/web/src/views/settings/components/UpgradeToProConfirmation.tsx @@ -1,14 +1,11 @@ import { t } from "@lingui/core/macro"; import { HiBolt, HiCheckBadge } from "react-icons/hi2"; -import { authClient } from "@kan/auth/client"; - import Button from "~/components/Button"; import { useModal } from "~/providers/modal"; import { usePopup } from "~/providers/popup"; export function UpgradeToProConfirmation({ - userId, workspacePublicId, }: { userId: string; @@ -18,25 +15,28 @@ export function UpgradeToProConfirmation({ const { showPopup } = usePopup(); const handleUpgrade = async () => { - const { data, error } = await authClient.subscription.upgrade({ - plan: "pro", - referenceId: workspacePublicId, - metadata: { - userId, - workspacePublicId, - ...(entityId && { workspaceSlug: entityId }), - }, - successUrl: "/settings", - cancelUrl: "/settings", - returnUrl: "/settings", - disableRedirect: true, - }); + try { + const response = await fetch("/api/stripe/create_checkout_session", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + ...(entityId && { workspaceSlug: entityId }), + workspacePublicId: workspacePublicId, + cancelUrl: "/settings", + successUrl: "/settings", + }), + }); - if (data?.url) { - window.location.href = data.url; - } + const { url } = (await response.json()) as { url: string }; + + if (url) { + window.location.href = url; + } + } catch (error) { + console.error("Error creating checkout session:", error); - if (error) { showPopup({ header: t`Error upgrading subscription`, message: t`Please try again later, or contact customer support.`, diff --git a/packages/db/src/repository/subscription.repo.ts b/packages/db/src/repository/subscription.repo.ts index a763f048..07394d17 100644 --- a/packages/db/src/repository/subscription.repo.ts +++ b/packages/db/src/repository/subscription.repo.ts @@ -75,3 +75,17 @@ export const getByReferenceId = async (db: dbClient, referenceId: string) => { where: eq(subscription.referenceId, referenceId), }); }; + +export const create = async ( + db: dbClient, + data: { + plan: string; + referenceId: string; + userId: string; + stripeCustomerId: string; + status: string; + }, +) => { + const [result] = await db.insert(subscription).values(data).returning(); + return result; +};