Update UI and translations in billing component

The pricing-table.tsx and plan-picker.tsx components under billing have been updated to improve UI spacing, layout, and text translations. The revisions allow for better localization through the use of the useTranslation hook from react-i18next. Layout changes include adjustment in spacing and removal of Sparkles icon. Certain product details are refactored to use translation keys for easier language support.
This commit is contained in:
giancarlo
2024-04-22 13:52:40 +08:00
parent 7020e21193
commit 0796aaeb81
2 changed files with 44 additions and 39 deletions

View File

@@ -265,16 +265,38 @@ export function PlanPicker(
'flex flex-col justify-center space-y-2' 'flex flex-col justify-center space-y-2'
} }
> >
<span className="font-semibold"> <div className={'flex items-center space-x-2.5'}>
<Trans <span className="font-semibold">
i18nKey={`billing:products.${product.id}.name`} <Trans
defaults={product.name} i18nKey={`billing:plans.${product.id}.name`}
/> defaults={product.name}
</span> />
</span>
<If
condition={
plan.trialDays && props.canStartTrial
}
>
<div>
<Badge
className={'px-1 py-0.5 text-xs'}
variant={'success'}
>
<Trans
i18nKey={`billing:trialPeriod`}
values={{
period: plan.trialDays,
}}
/>
</Badge>
</div>
</If>
</div>
<span className={'text-muted-foreground'}> <span className={'text-muted-foreground'}>
<Trans <Trans
i18nKey={`billing:products.${product.id}.description`} i18nKey={`billing:plans.${product.id}.description`}
defaults={product.description} defaults={product.description}
/> />
</span> </span>
@@ -285,23 +307,6 @@ export function PlanPicker(
'flex flex-col space-y-2 lg:flex-row lg:items-center lg:space-x-4 lg:space-y-0 lg:text-right' 'flex flex-col space-y-2 lg:flex-row lg:items-center lg:space-x-4 lg:space-y-0 lg:text-right'
} }
> >
<If
condition={
plan.trialDays && props.canStartTrial
}
>
<div>
<Badge variant={'success'}>
<Trans
i18nKey={`billing:trialPeriod`}
values={{
period: plan.trialDays,
}}
/>
</Badge>
</div>
</If>
<div> <div>
<Price key={plan.id}> <Price key={plan.id}>
<span> <span>
@@ -416,7 +421,7 @@ function PlanDetails({
<Heading level={5}> <Heading level={5}>
<b> <b>
<Trans <Trans
i18nKey={`billing:products.${selectedProduct.id}.name`} i18nKey={`billing:plans.${selectedProduct.id}.name`}
defaults={selectedProduct.name} defaults={selectedProduct.name}
/> />
</b>{' '} </b>{' '}
@@ -428,7 +433,7 @@ function PlanDetails({
<p> <p>
<span className={'text-muted-foreground'}> <span className={'text-muted-foreground'}>
<Trans <Trans
i18nKey={`billing:products.${selectedProduct.id}.description`} i18nKey={`billing:plans.${selectedProduct.id}.description`}
defaults={selectedProduct.description} defaults={selectedProduct.description}
/> />
</span> </span>
@@ -464,7 +469,7 @@ function PlanDetails({
<CheckCircle className={'h-4 text-green-500'} /> <CheckCircle className={'h-4 text-green-500'} />
<span className={'text-secondary-foreground'}> <span className={'text-secondary-foreground'}>
<Trans i18nKey={`billing:features.${item}`} defaults={item} /> <Trans i18nKey={item} defaults={item} />
</span> </span>
</div> </div>
); );

View File

@@ -4,7 +4,8 @@ import { useState } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { ArrowRight, CheckCircle, Circle, Sparkles } from 'lucide-react'; import { ArrowRight, CheckCircle, Circle } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { z } from 'zod'; import { z } from 'zod';
import { import {
@@ -167,7 +168,7 @@ function PricingItem(
> >
<div className={'flex flex-col space-y-6'}> <div className={'flex flex-col space-y-6'}>
<div className={'flex flex-col space-y-4'}> <div className={'flex flex-col space-y-4'}>
<div className={'flex items-center space-x-4'}> <div className={'flex items-center space-x-6'}>
<b <b
className={ className={
'text-current-foreground font-heading font-semibold uppercase' 'text-current-foreground font-heading font-semibold uppercase'
@@ -181,10 +182,6 @@ function PricingItem(
<If condition={props.product.badge}> <If condition={props.product.badge}>
<Badge variant={highlighted ? 'default' : 'outline'}> <Badge variant={highlighted ? 'default' : 'outline'}>
<If condition={highlighted}>
<Sparkles className={'h-3'} />
</If>
<span> <span>
<Trans <Trans
i18nKey={props.product.badge} i18nKey={props.product.badge}
@@ -195,7 +192,7 @@ function PricingItem(
</If> </If>
</div> </div>
<span className={cn(`text-muted-foreground h-8 text-base`)}> <span className={cn(`text-muted-foreground h-10 text-base`)}>
<Trans <Trans
i18nKey={props.product.description} i18nKey={props.product.description}
defaults={props.product.description} defaults={props.product.description}
@@ -203,6 +200,8 @@ function PricingItem(
</span> </span>
</div> </div>
<Separator />
<div className={'flex flex-col space-y-1'}> <div className={'flex flex-col space-y-1'}>
<Price> <Price>
{formatCurrency(props.product.currency, props.primaryLineItem.cost)} {formatCurrency(props.product.currency, props.primaryLineItem.cost)}
@@ -311,10 +310,7 @@ function FeaturesList(
{props.features.map((feature) => { {props.features.map((feature) => {
return ( return (
<ListItem key={feature}> <ListItem key={feature}>
<Trans <Trans i18nKey={feature} defaults={feature} />
i18nKey={`common:plans.features.${feature}`}
defaults={feature}
/>
</ListItem> </ListItem>
); );
})} })}
@@ -426,6 +422,8 @@ function DefaultCheckoutButton(
? '?redirectToCheckout=true' ? '?redirectToCheckout=true'
: ''; : '';
const { t } = useTranslation('billing');
const planId = props.plan.id; const planId = props.plan.id;
const signUpPath = props.paths.signUp; const signUpPath = props.paths.signUp;
const subscriptionPath = props.paths.subscription; const subscriptionPath = props.paths.subscription;
@@ -449,7 +447,9 @@ function DefaultCheckoutButton(
i18nKey={label} i18nKey={label}
defaults={label} defaults={label}
values={{ values={{
plan: props.product.name, plan: t(props.product.name, {
defaultValue: props.product.name,
}),
}} }}
/> />
</span> </span>