Refactor billing schema for increased flexibility

The billing schema has been revamped to allow more flexible billing setups, supporting multiple line items per plan. Changes extend to related app and UI components for a seamless experience. As a result, the previously used 'line-items-mapper.ts' is no longer needed and has been removed.
This commit is contained in:
giancarlo
2024-03-30 00:59:06 +08:00
parent 163eff6583
commit f93af31009
18 changed files with 1120 additions and 1213 deletions

View File

@@ -1,5 +1,18 @@
# SITE
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_PRODUCT_NAME=Makerkit
NEXT_PUBLIC_SITE_TITLE="Makerkit - The easiest way to build and manage your SaaS"
NEXT_PUBLIC_SITE_DESCRIPTION="Makerkit is the easiest way to build and manage your SaaS. It provides you with the tools you need to build your SaaS, without the hassle of building it from scratch."
NEXT_PUBLIC_DEFAULT_THEME_MODE=light
NEXT_PUBLIC_THEME_COLOR="#ffffff"
NEXT_PUBLIC_THEME_COLOR_DARK="#0a0a0a"
# AUTH
NEXT_PUBLIC_AUTH_PASSWORD=true
NEXT_PUBLIC_AUTH_MAGIC_LINK=false
# BILLING
NEXT_PUBLIC_BILLING_PROVIDER=stripe
# SUPABASE
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321

View File

@@ -1 +1,4 @@
## DO NOT ADD VARS HERE UNLESS THEY ARE PUBLIC
## DO NOT ADD VARS HERE UNLESS THEY ARE PUBLIC (eg. prefixed with NEXT_PUBLIC_)
NEXT_PUBLIC_PRODUCT_NAME=Makerkit
NEXT_PUBLIC_BILLING_PROVIDER=stripe

View File

@@ -62,7 +62,11 @@ export async function createTeamAccountCheckoutSession(params: {
throw new Error('Product not found');
}
const { lineItems, trialDays } = getLineItemsFromPlanId(product, planId);
const plan = product?.plans.find((plan) => plan.id === planId);
if (!plan) {
throw new Error('Plan not found');
}
// find the customer ID for the account if it exists
// (eg. if the account has been billed before)
@@ -75,12 +79,10 @@ export async function createTeamAccountCheckoutSession(params: {
// call the payment gateway to create the checkout session
const { checkoutToken } = await service.createCheckoutSession({
accountId,
lineItems,
plan,
returnUrl,
customerEmail,
customerId,
trialDays,
paymentType: product.paymentType,
});
// return the checkout token to the client

View File

@@ -2,11 +2,6 @@ import { z } from 'zod';
const production = process.env.NODE_ENV === 'production';
enum Themes {
Light = 'light',
Dark = 'dark',
}
const AppConfigSchema = z.object({
name: z
.string({
@@ -29,7 +24,7 @@ const AppConfigSchema = z.object({
description: `This is the default locale of your SaaS.`,
})
.default('en'),
theme: z.nativeEnum(Themes),
theme: z.enum(['light', 'dark', 'system']),
production: z.boolean(),
themeColor: z.string(),
themeColorDark: z.string(),
@@ -37,14 +32,14 @@ const AppConfigSchema = z.object({
const appConfig = AppConfigSchema.parse({
name: process.env.NEXT_PUBLIC_PRODUCT_NAME,
title: 'Awesomely - Your SaaS Title',
description: 'Your SaaS Description',
title: process.env.NEXT_PUBLIC_SITE_TITLE,
description: process.env.NEXT_PUBLIC_SITE_DESCRIPTION,
url: process.env.NEXT_PUBLIC_SITE_URL,
locale: process.env.NEXT_PUBLIC_DEFAULT_LOCALE,
theme: Themes.Light,
theme: process.env.NEXT_PUBLIC_DEFAULT_THEME_MODE,
themeColor: process.env.NEXT_PUBLIC_THEME_COLOR,
themeColorDark: process.env.NEXT_PUBLIC_THEME_COLOR_DARK,
production,
themeColor: '#ffffff',
themeColorDark: '#0a0a0a',
});
export default appConfig;

View File

@@ -20,8 +20,8 @@ const authConfig = AuthConfigSchema.parse({
// NB: Enable the providers below in the Supabase Console
// in your production project
providers: {
password: true,
magicLink: false,
password: process.env.NEXT_PUBLIC_AUTH_PASSWORD === 'true',
magicLink: process.env.NEXT_PUBLIC_AUTH_MAGIC_LINK === 'true',
oAuth: ['google'],
},
} satisfies z.infer<typeof AuthConfigSchema>);

View File

@@ -1,7 +1,11 @@
import { createBillingSchema } from '@kit/billing';
import { BillingProviderSchema, createBillingSchema } from '@kit/billing';
const provider = BillingProviderSchema.parse(
process.env.NEXT_PUBLIC_BILLING_PROVIDER,
);
export default createBillingSchema({
provider: 'stripe',
provider,
products: [
{
id: 'starter',
@@ -9,23 +13,37 @@ export default createBillingSchema({
description: 'The perfect plan to get started',
currency: 'USD',
badge: `Value`,
paymentType: 'recurring',
plans: [
{
name: 'Starter Monthly',
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe',
price: 9.99,
recurring: {
interval: 'month',
},
id: 'starter-monthly',
trialPeriod: 7,
paymentType: 'recurring',
interval: 'month',
lineItems: [
{
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe',
name: 'Base',
description: 'Base plan',
cost: 9.99,
type: 'base',
},
],
},
{
name: 'Starter Yearly',
id: 'starter-yearly',
price: 99.99,
recurring: {
interval: 'year',
},
paymentType: 'recurring',
interval: 'year',
lineItems: [
{
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe1',
name: 'Base',
description: 'Base plan',
cost: 99.99,
type: 'base',
},
],
},
],
features: ['Feature 1', 'Feature 2', 'Feature 3'],
@@ -37,23 +55,36 @@ export default createBillingSchema({
highlighted: true,
description: 'The perfect plan for professionals',
currency: 'USD',
paymentType: 'recurring',
plans: [
{
name: 'Pro Monthly',
id: 'pro-monthly',
price: 19.99,
recurring: {
interval: 'month',
},
paymentType: 'recurring',
interval: 'month',
lineItems: [
{
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe2',
name: 'Base',
description: 'Base plan',
cost: 19.99,
type: 'base',
},
],
},
{
name: 'Pro Yearly',
id: 'pro-yearly',
price: 199.99,
recurring: {
interval: 'year',
},
paymentType: 'recurring',
interval: 'year',
lineItems: [
{
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe3',
name: 'Base',
description: 'Base plan',
cost: 199.99,
type: 'base',
},
],
},
],
features: [
@@ -69,23 +100,36 @@ export default createBillingSchema({
name: 'Enterprise',
description: 'The perfect plan for enterprises',
currency: 'USD',
paymentType: 'recurring',
plans: [
{
name: 'Enterprise Monthly',
id: 'enterprise-monthly',
price: 99.99,
recurring: {
interval: 'month',
},
paymentType: 'recurring',
interval: 'month',
lineItems: [
{
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe4',
name: 'Base',
description: 'Base plan',
cost: 29.99,
type: 'base',
},
],
},
{
name: 'Enterprise Yearly',
id: 'enterprise-yearly',
price: 999.99,
recurring: {
interval: 'year',
},
paymentType: 'recurring',
interval: 'year',
lineItems: [
{
id: 'price_1NNwYHI1i3VnbZTqI2UzaHIe5',
name: 'Base',
description: 'Base plan',
cost: 299.99,
type: 'base',
},
],
},
],
features: [