From d64c620f698d203fdd8df1d8aae0800a9e0fa06d Mon Sep 17 00:00:00 2001 From: giancarlo Date: Fri, 5 Apr 2024 11:49:09 +0800 Subject: [PATCH] Refine billing schema and enhance visuals of PricingTable Removed redundant validation for 'lifetime' subscription plans in billing schema. Extensively updated the UI, layout and visuals of PricingTable component to offer a more user-friendly and aesthetically pleasing interface, improving overall user experience. --- .../billing/core/src/create-billing-schema.ts | 17 +- .../gateway/src/components/pricing-table.tsx | 166 +++++++++++------- 2 files changed, 105 insertions(+), 78 deletions(-) diff --git a/packages/billing/core/src/create-billing-schema.ts b/packages/billing/core/src/create-billing-schema.ts index d455f6d5a..65744a349 100644 --- a/packages/billing/core/src/create-billing-schema.ts +++ b/packages/billing/core/src/create-billing-schema.ts @@ -104,21 +104,6 @@ export const PlanSchema = z path: ['lineItems'], }, ) - .refine( - (data) => { - if (data.paymentType === 'one-time') { - const meteredItems = data.lineItems.filter( - (item) => item.type === 'metered', - ); - - return meteredItems.length === 0; - } - }, - { - message: 'One-time plans must not have metered line items', - path: ['paymentType', 'lineItems'], - }, - ) .refine( (data) => { if (data.paymentType === 'one-time') { @@ -126,6 +111,8 @@ export const PlanSchema = z return baseItems.length === 0; } + + return true; }, { message: 'One-time plans must not have non-base line items', diff --git a/packages/billing/gateway/src/components/pricing-table.tsx b/packages/billing/gateway/src/components/pricing-table.tsx index e0c7e8fe3..b2727d55b 100644 --- a/packages/billing/gateway/src/components/pricing-table.tsx +++ b/packages/billing/gateway/src/components/pricing-table.tsx @@ -4,10 +4,11 @@ import { useState } from 'react'; import Link from 'next/link'; -import { CheckCircle, Sparkles } from 'lucide-react'; +import { ArrowRight, CheckCircle, Sparkles } from 'lucide-react'; import { BillingConfig, getBaseLineItem, getPlanIntervals } from '@kit/billing'; import { formatCurrency } from '@kit/shared/utils'; +import { Badge } from '@kit/ui/badge'; import { Button } from '@kit/ui/button'; import { Heading } from '@kit/ui/heading'; import { If } from '@kit/ui/if'; @@ -49,25 +50,36 @@ export function PricingTable({
- {config.products.map((product) => { - const plan = product.plans.find((plan) => plan.interval === interval); + {config.products.map((product, index) => { + const isFirst = index === 0; + const isLast = index === config.products.length - 1; + + const plan = product.plans.find((plan) => { + if (plan.paymentType === 'recurring') { + return plan.interval === interval; + } + + return plan; + }); if (!plan) { - console.warn(`No plan found for ${product.name}`); - - return; + return null; } const basePlan = getBaseLineItem(config, plan.id); return ( -
-
- - {props.product.name} - +
+
+
+ + {props.product.name} + - -
+ + + + + + + + + + +
+ + + + +
+ +
+ + {formatCurrency(props.product.currency, props.baseLineItem.cost)} + + + + - - - + / - {props.product.badge} -
+ + } + > + {(interval) => ( + + )} + + +
- - {props.product.description} - -
- -
- - {formatCurrency(props.product.currency, props.baseLineItem.cost)} - - - - - / - {props.plan.interval} - - -
- -
- +
+ +
@@ -227,7 +264,7 @@ function Price({ children }: React.PropsWithChildren) { > {children} @@ -238,12 +275,12 @@ function Price({ children }: React.PropsWithChildren) { function ListItem({ children }: React.PropsWithChildren) { return ( -
  • +
  • - +
    - {children} + {children}
  • ); } @@ -312,15 +349,18 @@ function DefaultCheckoutButton( const label = props.plan.label ?? 'common:getStarted'; return ( -
    - - - -
    +
    + + + + ); }