//api/stripe
import { auth, currentUser } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";
import { prismadb } from "@/lib/prismadb";
import { stripe } from "@/lib/stripe";
import { absoluteUrl } from "@/lib/utils";
const billingUrl = absoluteUrl("/billing");
export async function GET() {
try {
const { userId } = auth();
const user = await currentUser();
if (!userId || !user) {
return new NextResponse("Unauthorized", { status: 401 });
}
const userSubscription = await prismadb.userSubscription.findUnique({
where: {
userId,
},
});
if (userSubscription && userSubscription.stripeCustomerId) {
const stripeSession = await stripe.billingPortal.sessions.create({
customer: userSubscription.stripeCustomerId,
return_url: billingUrl,
});
return new NextResponse(JSON.stringify({ url: stripeSession.url }));
}
const stripeSession = await stripe.checkout.sessions.create({
success_url: billingUrl,
cancel_url: billingUrl,
payment_method_types: ["card", "Paypal"],
mode: "subscription",
billing_address_collection: "auto",
customer_email: user.emailAddresses[0].emailAddress,
line_items: [
{
price_data: {
currency: "USD",
product_data: {
name: "Plume Pro",
description: "Gain Full Access",
},
unit_amount: 7999,
recurring: {
interval: "month",
},
},
quantity: 1,
},
{
price_data: {
currency: "USD",
product_data: {
name: "Plume Plus",
description: "Gain Full Access",
},
unit_amount: 3999,
recurring: {
interval: "month",
},
},
quantity: 1,
},
],
metadata: {
userId,
},
});
return new NextResponse(JSON.stringify({ url: stripeSession.url }));
} catch (error) {
console.log("[STRIPE_GET]", error);
return new NextResponse("Internal Error", { status: 500 });
}
}
"use client";
import { usePlanModal } from "@/hooks/use-plan-modal";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "../ui/dialog";
import { Separator } from "../ui/separator";
import { Button } from "../ui/button";
import { useToast } from "../ui/use-toast";
import axios from "axios";
import { useState } from "react";
export const PlanModal = () => {
const planModal = usePlanModal();
const { toast } = useToast();
const [loading, setLoading] = useState(false);
const onSubscribe = async () => {
try {
setLoading(true);
const response = await axios.get("/api/stripe");
window.location.href = response.data.url;
} catch (error) {
toast({
variant: "destructive",
description: "Oops! Something went wrong.",
});
} finally {
setLoading(false);
}
};
return (
<Dialog open={planModal.isOpen} onOpenChange={planModal.onClose}>
<DialogContent>
<DialogHeader className="space-y-4">
<DialogTitle className="text-center">Upgrade your Plan</DialogTitle>
<DialogDescription className="text-center space-y-2">
Choose a plan that meets your needs.
</DialogDescription>
</DialogHeader>
<Separator />
<div className="flex items-center justify-between">
<p className="text-2xl font-plus font-medium">
$39
<span className="text-sm font-normal">.99</span>
</p>
<Button size="md" onClick={onSubscribe}>
Subscribe
</Button>
</div>
</DialogContent>
</Dialog>
);
};
I'm developing an application using Next.js and Stripe, with multiple subscription plans for users to choose from. I'm facing a challenge in setting up the plans and checkout flow efficiently. Should I store all the plans in a single API folder or create separate API files for each tier? The current implementation sums up the prices of the two tiers, resulting in a total checkout amount of $119.98. Any advice on better structuring the subscription plans in the API would be greatly appreciated.