mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 00:03:33 +10:00
feat: stripe handlers and fetchers
This commit is contained in:
23
packages/lib/stripe/fetchers/checkout-session.ts
Normal file
23
packages/lib/stripe/fetchers/checkout-session.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { CheckoutSessionRequest, CheckoutSessionResponse } from "../handlers/checkout-session"
|
||||
|
||||
export type FetchCheckoutSessionOptions = CheckoutSessionRequest['body']
|
||||
|
||||
export const fetchCheckoutSession = async ({
|
||||
id,
|
||||
priceId
|
||||
}: FetchCheckoutSessionOptions) => {
|
||||
const response = await fetch('/api/stripe/checkout-session', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
priceId
|
||||
})
|
||||
});
|
||||
|
||||
const json: CheckoutSessionResponse = await response.json();
|
||||
|
||||
return json;
|
||||
}
|
||||
14
packages/lib/stripe/fetchers/get-subscription.ts
Normal file
14
packages/lib/stripe/fetchers/get-subscription.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { GetSubscriptionResponse } from "../handlers/get-subscription";
|
||||
|
||||
export const fetchSubscription = async () => {
|
||||
const response = await fetch("/api/stripe/subscription", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const json: GetSubscriptionResponse = await response.json();
|
||||
|
||||
return json;
|
||||
};
|
||||
19
packages/lib/stripe/fetchers/portal-session.ts
Normal file
19
packages/lib/stripe/fetchers/portal-session.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { PortalSessionRequest, PortalSessionResponse } from "../handlers/portal-session";
|
||||
|
||||
export type FetchPortalSessionOptions = PortalSessionRequest["body"];
|
||||
|
||||
export const fetchPortalSession = async ({ id }: FetchPortalSessionOptions) => {
|
||||
const response = await fetch("/api/stripe/portal-session", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
}),
|
||||
});
|
||||
|
||||
const json: PortalSessionResponse = await response.json();
|
||||
|
||||
return json;
|
||||
};
|
||||
91
packages/lib/stripe/handlers/checkout-session.ts
Normal file
91
packages/lib/stripe/handlers/checkout-session.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import prisma from "@documenso/prisma";
|
||||
import { stripe } from "../index";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
export type CheckoutSessionRequest = {
|
||||
body: {
|
||||
id: string;
|
||||
priceId: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type CheckoutSessionResponse =
|
||||
| {
|
||||
success: false;
|
||||
message: string;
|
||||
}
|
||||
| {
|
||||
success: true;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const checkoutSessionHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (!process.env.NEXT_PUBLIC_ALLOW_SUBSCRIPTIONS) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "Subscriptions are not enabled",
|
||||
});
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({
|
||||
success: false,
|
||||
message: "Method not allowed",
|
||||
});
|
||||
}
|
||||
|
||||
const token = await getToken({
|
||||
req,
|
||||
});
|
||||
|
||||
if (!token || !token.email) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: "Unauthorized",
|
||||
});
|
||||
}
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: token.email,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: "No user found",
|
||||
});
|
||||
}
|
||||
|
||||
const { id, priceId } = req.body;
|
||||
|
||||
if (typeof id !== "string" || typeof priceId !== "string") {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "No id or priceId found in request",
|
||||
});
|
||||
}
|
||||
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
customer: id,
|
||||
client_reference_id: String(user.id),
|
||||
payment_method_types: ["card"],
|
||||
line_items: [
|
||||
{
|
||||
price: priceId,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
mode: "subscription",
|
||||
allow_promotion_codes: true,
|
||||
success_url: `${process.env.NEXT_PUBLIC_BASE_URL}/settings/billing?success=true`,
|
||||
cancel_url: `${process.env.NEXT_PUBLIC_BASE_URL}/settings/billing?canceled=true`,
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
url: session.url,
|
||||
});
|
||||
};
|
||||
63
packages/lib/stripe/handlers/get-subscription.ts
Normal file
63
packages/lib/stripe/handlers/get-subscription.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import prisma from "@documenso/prisma";
|
||||
import { Subscription } from "@prisma/client";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
export type GetSubscriptionRequest = never;
|
||||
|
||||
export type GetSubscriptionResponse =
|
||||
| {
|
||||
success: false;
|
||||
message: string;
|
||||
}
|
||||
| {
|
||||
success: true;
|
||||
subscription: Subscription;
|
||||
};
|
||||
|
||||
export const getSubscriptionHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (!process.env.NEXT_PUBLIC_ALLOW_SUBSCRIPTIONS) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "Subscriptions are not enabled",
|
||||
});
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({
|
||||
success: false,
|
||||
message: "Method not allowed",
|
||||
});
|
||||
}
|
||||
|
||||
const token = await getToken({
|
||||
req,
|
||||
});
|
||||
|
||||
if (!token || !token.email) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: "Unauthorized",
|
||||
});
|
||||
}
|
||||
|
||||
const subscription = await prisma.subscription.findFirst({
|
||||
where: {
|
||||
User: {
|
||||
email: token.email,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!subscription) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: "No subscription found",
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
subscription,
|
||||
});
|
||||
};
|
||||
@ -1 +1,53 @@
|
||||
export
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { stripe } from "../index";
|
||||
|
||||
export type PortalSessionRequest = {
|
||||
body: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type PortalSessionResponse =
|
||||
| {
|
||||
success: false;
|
||||
message: string;
|
||||
}
|
||||
| {
|
||||
success: true;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const portalSessionHandler = async (req: NextApiRequest, res: NextApiResponse<PortalSessionResponse>) => {
|
||||
if (!process.env.NEXT_PUBLIC_ALLOW_SUBSCRIPTIONS) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "Subscriptions are not enabled",
|
||||
});
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({
|
||||
success: false,
|
||||
message: "Method not allowed",
|
||||
});
|
||||
}
|
||||
|
||||
const { id } = req.body;
|
||||
|
||||
if (typeof id !== "string") {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "No id found in request",
|
||||
});
|
||||
}
|
||||
|
||||
const session = await stripe.billingPortal.sessions.create({
|
||||
customer: id,
|
||||
return_url: `${process.env.NEXT_PUBLIC_BASE_URL}/settings/billing`,
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
url: session.url,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user