Add stripe portal session helper to link to payment methods (#1576)

This commit is contained in:
Luke Vella 2025-02-24 17:58:28 +00:00 committed by GitHub
parent b1f52041ef
commit e9df0c3dd3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 87 additions and 82 deletions

View file

@ -0,0 +1,82 @@
import { stripe } from "@rallly/billing";
import { prisma } from "@rallly/database";
import { absoluteUrl } from "@rallly/utils/absolute-url";
import * as Sentry from "@sentry/nextjs";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { auth } from "@/next-auth";
export function createStripePortalSessionHandler(path: string = "") {
return async function (request: NextRequest) {
const sessionId = request.nextUrl.searchParams.get("session_id");
const returnPath =
request.nextUrl.searchParams.get("return_path") ?? "/settings/billing";
let customerId: string | undefined;
if (sessionId) {
try {
const session = await stripe.checkout.sessions.retrieve(sessionId);
if (typeof session.customer !== "string") {
Sentry.captureException(new Error("Invalid customer ID in session"));
return NextResponse.json(
{ error: "Invalid customer ID in session" },
{ status: 400 },
);
}
customerId = session.customer;
} catch (error) {
Sentry.captureException(error);
return NextResponse.json(
{ error: "Failed to retrieve session" },
{ status: 500 },
);
}
} else {
const userSession = await auth();
if (!userSession?.user || userSession.user.email === null) {
const url = new URL("/login", request.url);
url.searchParams.set("redirectTo", request.nextUrl.pathname);
return NextResponse.redirect(url, 302);
}
try {
const user = await prisma.user.findUnique({
where: {
id: userSession.user.id,
},
select: {
customerId: true,
},
});
customerId = user?.customerId ?? undefined;
} catch (error) {
Sentry.captureException(error);
return NextResponse.json(
{ error: "Failed to retrieve user" },
{ status: 500 },
);
}
}
if (!customerId) {
return NextResponse.json({
error: "No customer ID found",
});
}
try {
const portalSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: returnPath ? absoluteUrl(returnPath) : undefined,
});
return NextResponse.redirect(portalSession.url + path);
} catch (error) {
Sentry.captureException(error);
return NextResponse.json(
{ error: "Failed to create portal session" },
{ status: 500 },
);
}
};
}

View file

@ -0,0 +1,3 @@
import { createStripePortalSessionHandler } from "../helpers/create-portal-session";
export const GET = createStripePortalSessionHandler("/payment-methods");

View file

@ -1,83 +1,3 @@
import { stripe } from "@rallly/billing";
import { prisma } from "@rallly/database";
import { absoluteUrl } from "@rallly/utils/absolute-url";
import * as Sentry from "@sentry/nextjs";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { createStripePortalSessionHandler } from "./helpers/create-portal-session";
import { auth } from "@/next-auth";
export async function GET(request: NextRequest) {
const sessionId = request.nextUrl.searchParams.get("session_id");
const returnPath = request.nextUrl.searchParams.get("return_path");
let customerId: string | undefined;
if (sessionId) {
try {
const session = await stripe.checkout.sessions.retrieve(sessionId);
if (typeof session.customer !== "string") {
Sentry.captureException(new Error("Invalid customer ID in session"));
return NextResponse.json(
{ error: "Invalid customer ID in session" },
{ status: 400 },
);
}
customerId = session.customer;
} catch (error) {
Sentry.captureException(error);
return NextResponse.json(
{ error: "Failed to retrieve session" },
{ status: 500 },
);
}
} else {
const userSession = await auth();
if (!userSession?.user || userSession.user.email === null) {
Sentry.captureException(new Error("User not logged in"));
return NextResponse.json(
{ error: "User not logged in" },
{ status: 400 },
);
}
try {
const user = await prisma.user.findUnique({
where: {
id: userSession.user.id,
},
select: {
customerId: true,
},
});
customerId = user?.customerId ?? undefined;
} catch (error) {
Sentry.captureException(error);
return NextResponse.json(
{ error: "Failed to retrieve user" },
{ status: 500 },
);
}
}
if (!customerId) {
Sentry.captureException(new Error("Session has no customer ID"));
return NextResponse.json(
{ error: "Session has no customer ID" },
{ status: 400 },
);
}
try {
const portalSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: returnPath ? absoluteUrl(returnPath) : undefined,
});
return NextResponse.redirect(portalSession.url);
} catch (error) {
Sentry.captureException(error);
return NextResponse.json(
{ error: "Failed to create portal session" },
{ status: 500 },
);
}
}
export const GET = createStripePortalSessionHandler();