120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
import { env } from "~/env.mjs";
|
|
import { getOrCreateStripeCustomerIdForUser } from "~/server/stripe-webhook-handlers";
|
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
|
import { z } from "zod";
|
|
|
|
export const stripeRouter = createTRPCRouter({
|
|
createCheckoutSession: protectedProcedure
|
|
.input(
|
|
z.object({ billedAnnually: z.boolean(), recordModalOpen: z.boolean() })
|
|
)
|
|
.mutation(
|
|
async ({ ctx: { prisma, stripe, session, req, posthog }, input }) => {
|
|
if (
|
|
!stripe ||
|
|
!env.STRIPE_ANNUAL_PRICE_ID ||
|
|
!env.STRIPE_MONTHLY_PRICE_ID
|
|
) {
|
|
throw new Error("Stripe env variables not set");
|
|
}
|
|
|
|
const customerId = await getOrCreateStripeCustomerIdForUser({
|
|
prisma,
|
|
stripe,
|
|
userId: session.user?.id,
|
|
});
|
|
|
|
if (!customerId) {
|
|
throw new Error("Could not create customer");
|
|
}
|
|
|
|
const baseUrl =
|
|
env.NODE_ENV === "development"
|
|
? `http://${req.headers.host ?? "localhost:3000"}`
|
|
: `https://${req.headers.host ?? env.NEXTAUTH_URL}`;
|
|
|
|
const checkoutSession = await stripe.checkout.sessions.create({
|
|
customer: customerId,
|
|
client_reference_id: session.user?.id,
|
|
payment_method_types: ["card"],
|
|
allow_promotion_codes: true,
|
|
mode: "subscription",
|
|
line_items: [
|
|
{
|
|
price: input.billedAnnually
|
|
? env.STRIPE_ANNUAL_PRICE_ID
|
|
: env.STRIPE_MONTHLY_PRICE_ID,
|
|
quantity: 1,
|
|
},
|
|
],
|
|
success_url: input.recordModalOpen
|
|
? `${baseUrl}/videos?checkoutCanceled=false&close=true`
|
|
: `${baseUrl}/videos?checkoutCanceled=false&close=false`,
|
|
cancel_url: `${baseUrl}/videos?checkoutCanceled=true`,
|
|
subscription_data: {
|
|
metadata: {
|
|
userId: session.user?.id,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!checkoutSession) {
|
|
throw new Error("Could not create checkout session");
|
|
}
|
|
|
|
posthog?.capture({
|
|
distinctId: session.user.id,
|
|
event: "visiting checkout page",
|
|
properties: {
|
|
billingCycle: input.billedAnnually ? "annual" : "monthly",
|
|
},
|
|
});
|
|
void posthog?.shutdownAsync();
|
|
|
|
return { checkoutUrl: checkoutSession.url };
|
|
}
|
|
),
|
|
createBillingPortalSession: protectedProcedure.mutation(
|
|
async ({ ctx: { stripe, session, prisma, req, posthog } }) => {
|
|
if (!stripe) {
|
|
throw new Error("Stripe env variables not set");
|
|
}
|
|
|
|
const customerId = await getOrCreateStripeCustomerIdForUser({
|
|
prisma,
|
|
stripe,
|
|
userId: session.user?.id,
|
|
});
|
|
|
|
if (!customerId) {
|
|
throw new Error("Could not create customer");
|
|
}
|
|
|
|
const baseUrl =
|
|
env.NODE_ENV === "development"
|
|
? `http://${req.headers.host ?? "localhost:3000"}`
|
|
: `https://${req.headers.host ?? env.NEXTAUTH_URL}`;
|
|
|
|
const stripeBillingPortalSession =
|
|
await stripe.billingPortal.sessions.create({
|
|
customer: customerId,
|
|
return_url: `${baseUrl}/videos`,
|
|
});
|
|
|
|
if (!stripeBillingPortalSession) {
|
|
throw new Error("Could not create billing portal session");
|
|
}
|
|
|
|
posthog?.capture({
|
|
distinctId: session.user.id,
|
|
event: "visiting billing portal page",
|
|
properties: {
|
|
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
|
},
|
|
});
|
|
void posthog?.shutdownAsync();
|
|
|
|
return { billingPortalUrl: stripeBillingPortalSession.url };
|
|
}
|
|
),
|
|
});
|