Saas Update Subscription

Resuming the subscription

src/components/stripeButton.jsx

jsx
1"use client";
2
3import Button from "@/components/ui/button";
4import { useState } from "react";
5
6export default function StripeButton({ type, plan }) {
7  const [loading, setLoading] = useState(false);
8  const [message, setMessage] = useState("");
9  const [confirmOpen, setConfirmOpen] = useState(false);
10
11  . . .
12
13  async function resume() {
14    setLoading(true);
15
16    const response = await fetch(`/api/stripe/resume`, {
17      method: "POST",
18      headers: {
19        "Content-Type": "application/json",
20      },
21    });
22
23    setLoading(false);
24
25    if (response.ok) {
26      setMessage("Your subscription has been successfully resumed.");
27    } else {
28      setMessage("Something went wrong.");
29    }
30  }
31
32  return (
33    <>
34      {type === "checkout" && (. . .)}
35
36      {type === "cancel" && (. . .)}
37
38      {type === "resume" && (
39        <Button
40          style="primary"
41          loading={loading}
42          className="w-full text-center"
43          onClick={() => resume()}>
44          Resume my subscription
45        </Button>
46      )}
47
48      <p>{message}</p>
49    </>
50  );
51}

src/app/dashboard/settings/page.jsx

jsx
1import { auth } from "@/libs/auth";
2import prisma from "@/libs/db";
3import { redirect } from "next/navigation";
4import StripeButton from "@/components/stripeButton";
5
6export default async function SettingsPage() {
7  const session = await auth();
8
9  return (
10    <div className="flex min-h-[80vh] items-center justify-center bg-gray-100">
11      <div className="w-full max-w-md bg-white p-8 rounded-lg shadow-md">
12        <h1 className="text-2xl font-bold text-center mb-6">User Settings</h1>
13        <form
14          action={async (formData) => {
15            "use server";
16            await prisma.user.update({
17              where: {
18                email: session?.user?.email,
19              },
20              data: {
21                name: formData.get("name"),
22              },
23            });
24
25            redirect("/dashboard/settings");
26          }}
27          className="space-y-6">
28          . . .
29          {session?.user?.subscriptionStatus === "active" && (
30            <StripeButton type={"cancel"} />
31          )}
32          {session?.user?.subscriptionStatus === "cancel_pending" && (
33            <StripeButton type={"resume"} />
34          )}
35        </form>
36      </div>
37    </div>
38  );
39}

Resume my subscription

Updating webhook

javascript
1import Stripe from "stripe";
2import prisma from "@/libs/db";
3import { headers } from "next/headers";
4
5export async function POST(request) {
6  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
7
8  // Get the Stripe signature
9  const headersList = await headers();
10  const signature = headersList.get("stripe-signature");
11
12  // Getting the raw body
13  const body = await request.text();
14
15  // Constructing the event with raw body, signature, and webhook secret
16  const event = stripe.webhooks.constructEvent(
17    body,
18    signature,
19    process.env.STRIPE_WEBHOOK_SECRET
20  );
21
22  switch (event.type) {
23    // Handling subscription creation and updates
24    case "customer.subscription.created":
25    case "customer.subscription.updated": {
26      await prisma.user.update({
27        where: { stripeCustomerId: event.data.object.customer },
28        data: {
29          subscriptionId: event.data.object.id,
30          subscriptionStatus: event.data.object.status,
31          role:
32            event.data.object.status === "active" || "trialing"
33              ? "paid user"
34              : "free user",
35        },
36      });
37
38      if (
39        event.data.object.cancellation_details?.reason ===
40        "cancellation_requested"
41      ) {
42        await prisma.user.update({
43          where: { stripeCustomerId: event.data.object.customer },
44          data: {
45            subscriptionStatus: "cancel_pending",
46          },
47        });
48      }
49      break;
50    }
51
52    case "customer.subscription.deleted": {
53      await prisma.user.update({
54        where: { stripeCustomerId: event.data.object.customer },
55        data: {
56          subscriptionStatus: event.data.object.status,
57          role: "free user",
58        },
59      });
60      break;
61    }
62
63    default:
64      console.warn(`Unhandled event type: ${event.type}`);
65  }
66
67  return new Response("Stripe success", {
68    status: 200,
69  });
70}