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:
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user