This commit is contained in:
Karol Wypchlo 2021-03-04 14:40:28 +01:00
parent 2d17ad0663
commit 1a1ec57772
2 changed files with 21 additions and 20 deletions

View File

@ -3,12 +3,20 @@ import Stripe from "stripe";
import { StatusCodes } from "http-status-codes"; import { StatusCodes } from "http-status-codes";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const isFreeTier = (tier) => tier === 1;
const isPaidTier = (tier) => !isFreeTier(tier);
const getStripeCustomer = (user) => { const getStripeCustomer = async (user, authorization) => {
if (user.stripeCustomerId) { if (user.stripeCustomerId) {
return stripe.customers.retrieve(user.stripeCustomerId); return stripe.customers.retrieve(user.stripeCustomerId);
} }
return stripe.customers.create({ email: user.email });
const customer = stripe.customers.create();
// update user instance and include the customer id once created
await got.put(`http://accounts:3000/user`, { headers: { authorization }, json: { stripeCustomerId: customer.id } });
return customer;
}; };
export default async (req, res) => { export default async (req, res) => {
@ -22,31 +30,23 @@ export default async (req, res) => {
return res.status(StatusCodes.BAD_REQUEST).json({ error: { message: "Missing 'price' attribute" } }); return res.status(StatusCodes.BAD_REQUEST).json({ error: { message: "Missing 'price' attribute" } });
} }
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [customer_email] - lets you prefill the email input in the form
// For full details see https://stripe.com/docs/api/checkout/sessions/create
try { try {
const authorization = req.headers.authorization; // authorization header from request const authorization = req.headers.authorization; // authorization header from request
const { stripeCustomerId, ...user } = await got("http://accounts:3000/user", { headers: { authorization } }).json(); const user = await got("http://accounts:3000/user", { headers: { authorization } }).json();
// const customer = await getStripeCustomer(user);
// if (!user.stripeCustomerId) { if (isPaidTier(user.tier)) {
// await got.put(`http://accounts:3000/user`, { const message = `Customer can have only one active subscription at a time, use Stripe Customer Portal to manage active subscription`;
// headers: { authorization },
// json: { stripeCustomerId: customer.id },
// });
// }
return res.status(StatusCodes.BAD_REQUEST).json({ error: { message } });
}
const customer = await getStripeCustomer(user, authorization);
const session = await stripe.checkout.sessions.create({ const session = await stripe.checkout.sessions.create({
mode: "subscription", mode: "subscription",
payment_method_types: ["card"], payment_method_types: ["card"],
line_items: [{ price, quantity: 1 }], line_items: [{ price, quantity: 1 }],
[stripeCustomerId ? "customer" : "customer_email"]: stripeCustomerId ? stripeCustomerId : user.email, customer: customer.id,
client_reference_id: user.sub, client_reference_id: user.sub,
// ?session_id={CHECKOUT_SESSION_ID} means the redirect will have the session ID set as a query param
success_url: `${process.env.SKYNET_DASHBOARD_URL}/payments?session_id={CHECKOUT_SESSION_ID}`, success_url: `${process.env.SKYNET_DASHBOARD_URL}/payments?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.SKYNET_DASHBOARD_URL}/payments`, cancel_url: `${process.env.SKYNET_DASHBOARD_URL}/payments`,
}); });

View File

@ -41,6 +41,8 @@ const plans = [
const fetcher = (url) => fetch(url).then((r) => r.json()); const fetcher = (url) => fetch(url).then((r) => r.json());
const apiPrefix = process.env.NODE_ENV === "development" ? "/api/stubs" : ""; const apiPrefix = process.env.NODE_ENV === "development" ? "/api/stubs" : "";
const isFreeTier = (tier) => tier === 1;
const isPaidTier = (tier) => !isFreeTier(tier);
const ActiveBadge = () => { const ActiveBadge = () => {
return ( return (
@ -54,7 +56,6 @@ export default function Payments() {
const { data: user } = useSWR(`${apiPrefix}/user`, fetcher); const { data: user } = useSWR(`${apiPrefix}/user`, fetcher);
const [selectedPlan, setSelectedPlan] = useState(plans[0]); const [selectedPlan, setSelectedPlan] = useState(plans[0]);
const activePlan = plans.find((plan) => user?.tier === plan?.tier); const activePlan = plans.find((plan) => user?.tier === plan?.tier);
const isFreePlan = (plan) => plan?.tier === 1;
const handleSubscribe = async () => { const handleSubscribe = async () => {
try { try {
const price = selectedPlan.stripe; const price = selectedPlan.stripe;
@ -82,7 +83,7 @@ export default function Payments() {
<div className="px-4 py-5 sm:p-6"> <div className="px-4 py-5 sm:p-6">
<dt className="text-sm font-medium text-gray-500 truncate">Subscription status</dt> <dt className="text-sm font-medium text-gray-500 truncate">Subscription status</dt>
<dd className="mt-1 text-3xl font-semibold text-gray-900 capitalize"> <dd className="mt-1 text-3xl font-semibold text-gray-900 capitalize">
{isFreePlan(activePlan) ? "—" : user?.subscriptionStatus} {isFreeTier(activePlan?.tier) ? "—" : user?.subscriptionStatus}
</dd> </dd>
</div> </div>
{user?.subscriptionCancelAtPeriodEnd && ( {user?.subscriptionCancelAtPeriodEnd && (