mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +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