Update UI, improve E2E tests and modify trial period configuration

The code changes incorporate UI updates for better usability and user experience. E2E test scripts(in `user-billing.spec.ts` and `team-billing.spec.ts`) were also updated for improved efficiency and accuracy, primarily replacing 'Active' status check with 'Trial'. Changes have been made in the trialDays configuration, with the term 'trialPeriod' now replaced by 'trialDays' across different components. Notably, a new error handling case is included in `lemon-squeezy-billing-strategy.service.ts` for failed subscription cancellation attempts.
This commit is contained in:
giancarlo
2024-04-15 01:18:27 +08:00
parent 26f1371283
commit 4e305bf8c9
14 changed files with 69 additions and 86 deletions

View File

@@ -81,7 +81,7 @@ export const PlanSchema = z
.min(1),
interval: BillingIntervalSchema.optional(),
lineItems: z.array(LineItemSchema),
trialPeriod: z
trialDays: z
.number({
description:
'Number of days for the trial period. Leave empty for no trial.',

View File

@@ -6,7 +6,6 @@ export const CreateBillingCheckoutSchema = z.object({
returnUrl: z.string().url(),
accountId: z.string().uuid(),
plan: PlanSchema,
trialDays: z.number().optional(),
customerId: z.string().optional(),
customerEmail: z.string().email().optional(),
enableDiscountField: z.boolean().optional(),

View File

@@ -1,7 +1,3 @@
'use client';
import Link from 'next/link';
import { Check, ChevronRight } from 'lucide-react';
import { Button } from '@kit/ui/button';
@@ -12,33 +8,13 @@ import { Trans } from '@kit/ui/trans';
* Retrieves the session status for a Stripe checkout session.
* Since we should only arrive here for a successful checkout, we only check
* for the `paid` status.
*
* @param {Stripe.Checkout.Session['status']} status - The status of the Stripe checkout session.
* @param {string} customerEmail - The email address of the customer associated with the session.
*
* @returns {ReactElement} - The component to render based on the session status.
*/
**/
export function BillingSessionStatus({
customerEmail,
redirectPath,
onRedirect,
}: React.PropsWithChildren<{
customerEmail: string;
redirectPath: string;
}>) {
return (
<SuccessSessionStatus
redirectPath={redirectPath}
customerEmail={customerEmail}
/>
);
}
function SuccessSessionStatus({
customerEmail,
redirectPath,
}: React.PropsWithChildren<{
customerEmail: string;
redirectPath: string;
onRedirect: () => void;
}>) {
return (
<section
@@ -78,15 +54,15 @@ function SuccessSessionStatus({
</p>
</div>
<Link data-test={'checkout-success-back-link'} href={redirectPath}>
<Button>
<form data-test={'checkout-success-back-link'}>
<Button formAction={onRedirect}>
<span>
<Trans i18nKey={'billing:checkoutSuccessBackButton'} />
</span>
<ChevronRight className={'h-4'} />
</Button>
</Link>
</form>
</div>
</section>
);

View File

@@ -288,7 +288,7 @@ export function PlanPicker(
>
<If
condition={
plan.trialPeriod && props.canStartTrial
plan.trialDays && props.canStartTrial
}
>
<div>
@@ -296,7 +296,7 @@ export function PlanPicker(
<Trans
i18nKey={`billing:trialPeriod`}
values={{
period: plan.trialPeriod,
period: plan.trialDays,
}}
/>
</Badge>
@@ -356,7 +356,7 @@ export function PlanPicker(
) : (
<>
<If
condition={selectedPlan?.trialPeriod && props.canStartTrial}
condition={selectedPlan?.trialDays && props.canStartTrial}
fallback={t(`proceedToPayment`)}
>
<span>{t(`startTrial`)}</span>

View File

@@ -119,7 +119,7 @@ export class LemonSqueezyBillingStrategyService
'Failed to cancel subscription',
);
throw error;
throw new Error('Failed to cancel subscription');
}
logger.info(ctx, 'Subscription cancelled successfully');

View File

@@ -33,7 +33,7 @@ export async function createStripeCheckout(
| Stripe.Checkout.SessionCreateParams.SubscriptionData
| undefined = isSubscription
? {
trial_period_days: params.trialDays,
trial_period_days: params.plan.trialDays,
metadata: {
accountId: params.accountId,
},

View File

@@ -191,7 +191,12 @@ export function AccountSelector({
data-test={'account-selector-team'}
data-name={account.label}
data-slug={account.value}
className={'group flex space-x-2'}
className={cn(
'group flex justify-between transition-colors',
{
['bg-muted']: value === account.value,
},
)}
key={account.value}
value={account.value ?? ''}
onSelect={(currentValue) => {
@@ -203,23 +208,28 @@ export function AccountSelector({
}
}}
>
<Avatar
className={cn('h-6 w-6 border border-transparent', {
['border-border']: value === account.value,
['group-hover:border-border ']:
value !== account.value,
})}
>
<AvatarImage src={account.image ?? undefined} />
<div className={'flex items-center'}>
<Avatar
className={cn(
'mr-2 h-6 w-6 border border-transparent',
{
['border-border']: value === account.value,
['group-hover:border-border ']:
value !== account.value,
},
)}
>
<AvatarImage src={account.image ?? undefined} />
<AvatarFallback>
{account.label ? account.label[0] : ''}
</AvatarFallback>
</Avatar>
<AvatarFallback>
{account.label ? account.label[0] : ''}
</AvatarFallback>
</Avatar>
<span className={'mr-2 max-w-[165px] truncate'}>
{account.label}
</span>
<span className={'mr-2 max-w-[165px] truncate'}>
{account.label}
</span>
</div>
<Icon item={account.value ?? ''} />
</CommandItem>

View File

@@ -7,6 +7,7 @@ import { Ellipsis } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Database } from '@kit/supabase/database';
import { Badge } from '@kit/ui/badge';
import { Button } from '@kit/ui/button';
import { DataTable } from '@kit/ui/data-table';
import {
@@ -121,13 +122,7 @@ function useGetColumns(
<span>{displayName}</span>
<If condition={isSelf}>
<span
className={
'bg-muted rounded-md px-2.5 py-1 text-xs font-medium'
}
>
{t('youLabel')}
</span>
<Badge variant={'outline'}>{t('youLabel')}</Badge>
</If>
</span>
);