feat: billing portal

This commit is contained in:
Henry
2025-01-03 15:12:31 +00:00
parent 67e714b8b0
commit 3ee0c0039c
14 changed files with 2383 additions and 693 deletions

View File

@@ -0,0 +1,73 @@
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { Stripe } from "stripe";
import * as userRepo from "@kan/db/repository/user.repo";
import { createNextClient } from "@kan/supabase/clients";
const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
if (!stripeSecretKey) {
throw new Error("STRIPE_SECRET_KEY is not defined");
}
const stripe = new Stripe(stripeSecretKey, {
apiVersion: "2024-12-18.acacia",
});
export default async function handler(req: NextRequest) {
if (req.method !== "POST") {
return new Response(JSON.stringify({ error: "Method not allowed" }), {
status: 405,
headers: { "Content-Type": "application/json" },
});
}
try {
const response = NextResponse.next();
const db = createNextClient(req, response);
const { data } = await db.auth.getUser();
if (!data.user) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 403,
headers: { "Content-Type": "application/json" },
});
}
const user = await userRepo.getById(db, data.user.id);
if (!user?.stripeCustomerId) {
return new Response(
JSON.stringify({ error: "No billing account found" }),
{
status: 404,
headers: { "Content-Type": "application/json" },
},
);
}
const session = await stripe.billingPortal.sessions.create({
customer: user.stripeCustomerId,
return_url: `${process.env.WEBSITE_URL}/settings`,
});
return new Response(JSON.stringify({ url: session.url }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error("Error:", error);
return new Response(
JSON.stringify({ error: "Error creating portal session" }),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}
}
export const runtime = "edge";
export const preferredRegion = "lhr1";
export const dynamic = "force-dynamic";