Update billing system to support single and recurring payments

This update modifies the billing system to properly handle both single and recurring payment plans. Logic is introduced to determine whether the selected plan is recurring or a one-time payment and adjust the interface accordingly. The naming of some components and variables has been changed to more accurately reflect their purpose. Additionally, a
This commit is contained in:
giancarlo
2024-04-01 20:58:26 +08:00
parent 6b72206b00
commit 84a4b45bcd
22 changed files with 291 additions and 119 deletions

View File

@@ -25,7 +25,10 @@ export function PersonalAccountCheckoutForm(props: {
}) {
const [pending, startTransition] = useTransition();
const [error, setError] = useState(false);
const [checkoutToken, setCheckoutToken] = useState<string>();
const [checkoutToken, setCheckoutToken] = useState<string | undefined>(
undefined,
);
// only allow trial if the user is not already a customer
const canStartTrial = !props.customerId;
@@ -36,6 +39,7 @@ export function PersonalAccountCheckoutForm(props: {
<EmbeddedCheckout
checkoutToken={checkoutToken}
provider={billingConfig.provider}
onClose={() => setCheckoutToken(undefined)}
/>
);
}

View File

@@ -2,7 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
import {
BillingPortalCard,
CurrentPlanCard,
CurrentSubscriptionCard,
} from '@kit/billing-gateway/components';
import { Database } from '@kit/supabase/database';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
@@ -51,9 +51,9 @@ async function PersonalAccountBillingPage() {
<If condition={subscription}>
{(subscription) => (
<div
className={'mx-auto flex w-full max-w-2xl flex-col space-y-4'}
className={'mx-auto flex w-full max-w-2xl flex-col space-y-6'}
>
<CurrentPlanCard
<CurrentSubscriptionCard
subscription={subscription}
config={billingConfig}
/>

View File

@@ -24,7 +24,10 @@ export function TeamAccountCheckoutForm(params: {
}) {
const routeParams = useParams();
const [pending, startTransition] = useTransition();
const [checkoutToken, setCheckoutToken] = useState<string | null>(null);
const [checkoutToken, setCheckoutToken] = useState<string | undefined>(
undefined,
);
// If the checkout token is set, render the embedded checkout component
if (checkoutToken) {
@@ -32,6 +35,7 @@ export function TeamAccountCheckoutForm(params: {
<EmbeddedCheckout
checkoutToken={checkoutToken}
provider={billingConfig.provider}
onClose={() => setCheckoutToken(undefined)}
/>
);
}

View File

@@ -1,6 +1,6 @@
import {
BillingPortalCard,
CurrentPlanCard,
CurrentSubscriptionCard,
} from '@kit/billing-gateway/components';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
@@ -53,7 +53,7 @@ async function TeamAccountBillingPage({ params }: Params) {
</If>
<div>
<div className={'flex flex-col space-y-2'}>
<div className={'flex flex-col space-y-6'}>
<If
condition={subscription}
fallback={
@@ -66,7 +66,10 @@ async function TeamAccountBillingPage({ params }: Params) {
}
>
{(data) => (
<CurrentPlanCard subscription={data} config={billingConfig} />
<CurrentSubscriptionCard
subscription={data}
config={billingConfig}
/>
)}
</If>

View File

@@ -114,7 +114,7 @@ async function TeamAccountMembersPage({ params }: Params) {
<PageBody>
<div
className={'mx-auto flex w-full max-w-3xl flex-col space-y-4 pb-32'}
className={'mx-auto flex w-full max-w-3xl flex-col space-y-6 pb-32'}
>
<Card>
<CardHeader className={'flex flex-row justify-between'}>

View File

@@ -7,6 +7,29 @@ const provider = BillingProviderSchema.parse(
export default createBillingSchema({
provider,
products: [
{
id: 'lifetime',
name: 'Lifetime',
description: 'The perfect plan for a lifetime',
currency: 'USD',
features: ['Feature 1', 'Feature 2', 'Feature 3'],
plans: [
{
name: 'Lifetime',
id: 'lifetime',
paymentType: 'one-time',
lineItems: [
{
id: 'price_1P0jgcI1i3VnbZTqXVXaZkMP',
name: 'Base',
description: 'Base plan',
cost: 999.99,
type: 'base',
},
],
},
],
},
{
id: 'starter',
name: 'Starter',

View File

@@ -20,12 +20,13 @@
"cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your organization owner.",
"manageTeamPlan": "Manage your Team Plan",
"manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.",
"flatSubscription": "Flat Subscription",
"basePlan": "Base Plan",
"billingInterval": {
"label": "Choose your billing interval",
"month": "Billed monthly",
"year": "Billed yearly"
},
"lifetime": "Lifetime",
"trialPeriod": "{{period}} day trial",
"perPeriod": "per {{period}}",
"processing": "Processing...",
@@ -85,6 +86,21 @@
"badge": "Paused",
"heading": "Your subscription is paused",
"description": "Your subscription is paused. You can resume it at any time."
},
"succeeded": {
"badge": "Succeeded",
"heading": "Your payment was successful",
"description": "Your payment was successful. Thank you for subscribing!"
},
"pending": {
"badge": "Pending",
"heading": "Your payment is pending",
"description": "Your payment is pending. Please bear with us."
},
"failed": {
"badge": "Failed",
"heading": "Your payment failed",
"description": "Your payment failed. Please update your payment method."
}
}
}