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}
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}