super-fit-web-app / src / server / routers / stripe.ts
stripe.ts
Raw
import { z } from "zod";
import { procedure, router } from "../trpc";
import { db } from "@/db/PrismaClient";
import { TRPCError } from '@trpc/server';
import Stripe from 'stripe'
import { getSession } from "@/utils/planetscale/session";

const stripe = new Stripe(process.env.STRIPE_SECRET_TEST_KEY, {
  apiVersion: '2022-11-15'
})

export const stripeRouter = router({
  checkoutSession: procedure
  .mutation(async ({ ctx }) => {
    try{
      const {req, res} = ctx;
      const sessionData = await getSession(req, res);

      if (!sessionData.session_valid) {
        throw new TRPCError({
          code: 'UNAUTHORIZED',
          message: 'User is not signed in.'
        })
      }

      const checkoutSession = await stripe.checkout.sessions.create({
        mode: 'subscription',
        customer: sessionData.user.stripeCustomerId!,
        line_items: [
          {
            price: 'price_1Ne8jiIJijgwhzBsDhsFA7VS', //hard set for testing purposes
            quantity: 1,
          }
        ],
        success_url: `http://${process.env.VERCEL_URL}/?session_id={CHECKOUT_SESSION_ID}`,
        cancel_url: `http://${process.env.VERCEL_URL}/?cancelledPayment=true`,
        subscription_data: {
          metadata: {
            payingUserId: sessionData.user.userId ?? '',
            "SuperFit-auth": req.cookies['SuperFit-session-token'] ?? ''
          }
        }
      })

      if (!checkoutSession.url) {
        throw new TRPCError({
          code: 'INTERNAL_SERVER_ERROR',
          message: 'Stripe Error: Could not create checkout session'
        })
      }

      return checkoutSession.url;
    } catch (error) {
      console.log(error)
      if (error instanceof TRPCError) throw error;
      throw new TRPCError({
        code: 'INTERNAL_SERVER_ERROR',
        message: (error as Error).message,
        cause: error
      });
    }
  }),

  portal: procedure
  .mutation(async ({ ctx }) => {
    try {
      const {req, res} = ctx;
      const sessionData = await getSession(req, res);

      if (!sessionData.session_valid) {
        throw new TRPCError({
          code: 'UNAUTHORIZED',
          message: 'User is not signed in.'
        })
      }

      const session = await stripe.billingPortal.sessions.create({
        customer: sessionData.user.stripeCustomerId!,
        return_url: `http://${process.env.VERCEL_URL}/account/dashboard`
      })

      return {
        url: session.url
      }
    } catch (error) {
      console.log(error)
      if (error instanceof TRPCError) throw error;
      throw new TRPCError({
        code: 'INTERNAL_SERVER_ERROR',
        message: (error as Error).message,
        cause: error
      });
    }
  }),
  getSubscriptionData: procedure
  .input(z.object({
    stripeCustomerId: z.string(),
    session_valid: z.boolean()
  }))
  .query(async ({ ctx, input }) => {
    const { stripeCustomerId, session_valid } = input;

    if (!session_valid) {
      throw new TRPCError({
        code: 'UNAUTHORIZED',
        message: 'User is not signed in.'
      })
    }

    const subscriptionData = await stripe.subscriptions.list({
      customer: stripeCustomerId
    })

    const plans = [];

    for (const subscription of subscriptionData.data) {
      const planDetails = await stripe.products.retrieve(subscription.items.data[0].price.product as string);
      console.log(planDetails)

      const dataToPush = {
        id: planDetails.id,
        name: planDetails.name,
        description: planDetails.description != null ? planDetails.description : `${planDetails.name} plan`,
        // Add any other plan details you need here
      }

      plans.push(dataToPush);
    }

    console.log(plans)

    return {
      subscriptions: subscriptionData.data,
      plans: plans
    }
  }),

  cancelSubscription: procedure
  .input(z.object({
    subscriptionId: z.string()
  }))
  .query(async ({ input, ctx }) => {
    const { subscriptionId } = input;

    const data = await stripe.subscriptions.cancel(subscriptionId)

    const response = {
      endDate: data.cancel_at,
    }

    return response
  })
})