Revert "Unify workspace dropdowns; Update layouts (#458)"

This reverts commit 4bc8448a1d.
This commit is contained in:
gbuomprisco
2026-03-11 14:47:47 +08:00
parent 4bc8448a1d
commit 4912e402a3
530 changed files with 11182 additions and 14382 deletions

View File

@@ -17,19 +17,19 @@ export function BillingPortalCard() {
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey="billing.billingPortalCardTitle" />
<Trans i18nKey="billing:billingPortalCardTitle" />
</CardTitle>
<CardDescription>
<Trans i18nKey="billing.billingPortalCardDescription" />
<Trans i18nKey="billing:billingPortalCardDescription" />
</CardDescription>
</CardHeader>
<CardContent className={'space-y-2'}>
<div>
<Button type="submit" data-test={'manage-billing-redirect-button'}>
<Button data-test={'manage-billing-redirect-button'}>
<span>
<Trans i18nKey="billing.billingPortalCardButton" />
<Trans i18nKey="billing:billingPortalCardButton" />
</span>
<ArrowUpRight className={'h-4'} />

View File

@@ -41,7 +41,7 @@ export function BillingSessionStatus({
<Heading level={3}>
<span className={'mr-4 font-semibold'}>
<Trans i18nKey={'billing.checkoutSuccessTitle'} />
<Trans i18nKey={'billing:checkoutSuccessTitle'} />
</span>
🎉
</Heading>
@@ -49,26 +49,22 @@ export function BillingSessionStatus({
<div className={'text-muted-foreground flex flex-col space-y-4'}>
<p>
<Trans
i18nKey={'billing.checkoutSuccessDescription'}
i18nKey={'billing:checkoutSuccessDescription'}
values={{ customerEmail }}
/>
</p>
</div>
<div>
<Button
nativeButton={false}
data-test={'checkout-success-back-link'}
render={
<Link href={redirectPath}>
<span>
<Trans i18nKey={'billing.checkoutSuccessBackButton'} />
</span>
<Button data-test={'checkout-success-back-link'} asChild>
<Link href={redirectPath}>
<span>
<Trans i18nKey={'billing:checkoutSuccessBackButton'} />
</span>
<ChevronRight className={'h-4'} />
</Link>
}
/>
<ChevronRight className={'h-4'} />
</Link>
</Button>
</div>
</div>
</section>

View File

@@ -44,11 +44,11 @@ export function CurrentLifetimeOrderCard({
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey="billing.planCardTitle" />
<Trans i18nKey="billing:planCardTitle" />
</CardTitle>
<CardDescription>
<Trans i18nKey="billing.planCardDescription" />
<Trans i18nKey="billing:planCardDescription" />
</CardDescription>
</CardHeader>
@@ -70,7 +70,7 @@ export function CurrentLifetimeOrderCard({
<div>
<div className="flex flex-col gap-y-1">
<span className="font-semibold">
<Trans i18nKey="billing.detailsLabel" />
<Trans i18nKey="billing:detailsLabel" />
</span>
<LineItemDetails

View File

@@ -21,7 +21,7 @@ export function CurrentPlanAlert(
status: Enums<'subscription_status'>;
}>,
) {
const prefix = 'billing.status';
const prefix = 'billing:status';
const text = `${prefix}.${props.status}.description`;
const title = `${prefix}.${props.status}.heading`;

View File

@@ -23,7 +23,7 @@ export function CurrentPlanBadge(
status: Status;
}>,
) {
const text = `billing.status.${props.status}.badge`;
const text = `billing:status.${props.status}.badge`;
const variant = statusBadgeMap[props.status];
return (

View File

@@ -48,11 +48,11 @@ export function CurrentSubscriptionCard({
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey="billing.planCardTitle" />
<Trans i18nKey="billing:planCardTitle" />
</CardTitle>
<CardDescription>
<Trans i18nKey="billing.planCardDescription" />
<Trans i18nKey="billing:planCardDescription" />
</CardDescription>
</CardHeader>
@@ -94,7 +94,7 @@ export function CurrentSubscriptionCard({
<div className="flex flex-col gap-y-1 border-y border-dashed py-4">
<span className="font-semibold">
<Trans i18nKey="billing.detailsLabel" />
<Trans i18nKey="billing:detailsLabel" />
</span>
<LineItemDetails
@@ -110,12 +110,12 @@ export function CurrentSubscriptionCard({
<InfoIcon className={'h-4 w-4'} />
<AlertTitle>
<Trans i18nKey="billing.trialAlertTitle" />
<Trans i18nKey="billing:trialAlertTitle" />
</AlertTitle>
<AlertDescription>
<Trans
i18nKey="billing.trialAlertDescription"
i18nKey="billing:trialAlertDescription"
values={{
date: formatDate(
subscription.trial_ends_at ?? '',
@@ -134,12 +134,12 @@ export function CurrentSubscriptionCard({
<MessageCircleWarning className={'h-4 w-4'} />
<AlertTitle>
<Trans i18nKey="billing.subscriptionCancelled" />
<Trans i18nKey="billing:subscriptionCancelled" />
</AlertTitle>
<AlertDescription>
<Trans
i18nKey="billing.cancelSubscriptionDate"
i18nKey="billing:cancelSubscriptionDate"
values={{
date: formatDate(
subscription.period_ends_at ?? '',

View File

@@ -1,8 +1,8 @@
'use client';
import { PlusSquare } from 'lucide-react';
import { useLocale, useTranslations } from 'next-intl';
import * as z from 'zod';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import type { LineItemSchema } from '@kit/billing';
import { formatCurrency } from '@kit/shared/utils';
@@ -14,14 +14,14 @@ const className = 'flex text-secondary-foreground items-center text-sm';
export function LineItemDetails(
props: React.PropsWithChildren<{
lineItems: z.output<typeof LineItemSchema>[];
lineItems: z.infer<typeof LineItemSchema>[];
currency: string;
selectedInterval?: string | undefined;
alwaysDisplayMonthlyPrice?: boolean;
}>,
) {
const t = useTranslations('billing');
const locale = useLocale();
const { t, i18n } = useTranslation();
const locale = i18n.language;
const currencyCode = props?.currency.toLowerCase();
const shouldDisplayMonthlyPrice =
@@ -32,16 +32,16 @@ export function LineItemDetails(
return '';
}
const i18nKey = `units.${unit}` as never;
const i18nKey = `billing:units.${unit}`;
if (!t.has(i18nKey)) {
if (!i18n.exists(i18nKey)) {
return unit;
}
return t(i18nKey, {
count,
defaultValue: unit,
} as never);
});
};
const getDisplayCost = (cost: number, hasTiers: boolean) => {
@@ -82,7 +82,7 @@ export function LineItemDetails(
<span>
<Trans
i18nKey={'billing.setupFee'}
i18nKey={'billing:setupFee'}
values={{
setupFee: formatCurrency({
currencyCode,
@@ -111,18 +111,18 @@ export function LineItemDetails(
<PlusSquare className={'w-3'} />
<span>
<Trans i18nKey={'billing.basePlan'} />
<Trans i18nKey={'billing:basePlan'} />
</span>
</span>
<span>
<If
condition={props.selectedInterval}
fallback={<Trans i18nKey={'billing.lifetime'} />}
fallback={<Trans i18nKey={'billing:lifetime'} />}
>
(
<Trans
i18nKey={`billing.billingInterval.${props.selectedInterval}`}
i18nKey={`billing:billingInterval.${props.selectedInterval}`}
/>
)
</If>
@@ -149,7 +149,7 @@ export function LineItemDetails(
<span className={'flex gap-x-2 text-sm'}>
<span>
<Trans
i18nKey={'billing.perUnit'}
i18nKey={'billing:perUnit'}
values={{
unit: getUnitLabel(unit, 1),
}}
@@ -172,10 +172,10 @@ export function LineItemDetails(
<span>
<If
condition={Boolean(unit) && !isDefaultSeatUnit}
fallback={<Trans i18nKey={'billing.perTeamMember'} />}
fallback={<Trans i18nKey={'billing:perTeamMember'} />}
>
<Trans
i18nKey={'billing.perUnitShort'}
i18nKey={'billing:perUnitShort'}
values={{
unit: getUnitLabel(unit, 1),
}}
@@ -215,7 +215,7 @@ export function LineItemDetails(
<span className={'flex space-x-1'}>
<span>
<Trans
i18nKey={'billing.perUnit'}
i18nKey={'billing:perUnit'}
values={{
unit: getUnitLabel(unit, 1),
}}
@@ -268,11 +268,11 @@ function Tiers({
unit,
}: {
currency: string;
item: z.infer<typeof LineItemSchema>;
unit?: string;
item: z.output<typeof LineItemSchema>;
}) {
const t = useTranslations('billing');
const locale = useLocale();
const { t, i18n } = useTranslation();
const locale = i18n.language;
// Helper to safely convert tier values to numbers for pluralization
// Falls back to plural form (2) for 'unlimited' values
@@ -285,13 +285,10 @@ function Tiers({
const getUnitLabel = (count: number) => {
if (!unit) return '';
return t(
`units.${unit}` as never,
{
count,
defaultValue: unit,
} as never,
);
return t(`billing:units.${unit}`, {
count,
defaultValue: unit,
});
};
const tiers = item.tiers?.map((tier, index) => {
@@ -330,7 +327,7 @@ function Tiers({
<If condition={tiersLength > 1}>
<span>
<Trans
i18nKey={'billing.andAbove'}
i18nKey={'billing:andAbove'}
values={{
unit: getUnitLabel(getSafeCount(previousTierFrom) - 1),
previousTier: getSafeCount(previousTierFrom) - 1,
@@ -341,7 +338,7 @@ function Tiers({
<If condition={tiersLength === 1}>
<span>
<Trans
i18nKey={'billing.forEveryUnit'}
i18nKey={'billing:forEveryUnit'}
values={{
unit: getUnitLabel(1),
}}
@@ -353,7 +350,7 @@ function Tiers({
<If condition={isIncluded}>
<span>
<Trans
i18nKey={'billing.includedUpTo'}
i18nKey={'billing:includedUpTo'}
values={{
unit: getUnitLabel(getSafeCount(upTo)),
upTo,
@@ -371,7 +368,7 @@ function Tiers({
</span>{' '}
<span>
<Trans
i18nKey={'billing.fromPreviousTierUpTo'}
i18nKey={'billing:fromPreviousTierUpTo'}
values={{
previousTierFrom,
unit: getUnitLabel(1),

View File

@@ -2,15 +2,15 @@
import { useMemo } from 'react';
import { useLocale } from 'next-intl';
import * as z from 'zod';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import type { LineItemSchema } from '@kit/billing';
import { formatCurrency } from '@kit/shared/utils';
import { Trans } from '@kit/ui/trans';
type PlanCostDisplayProps = {
primaryLineItem: z.output<typeof LineItemSchema>;
primaryLineItem: z.infer<typeof LineItemSchema>;
currencyCode: string;
interval?: string;
alwaysDisplayMonthlyPrice?: boolean;
@@ -30,7 +30,7 @@ export function PlanCostDisplay({
alwaysDisplayMonthlyPrice = true,
className,
}: PlanCostDisplayProps) {
const locale = useLocale();
const { i18n } = useTranslation();
const { shouldDisplayTier, lowestTier, tierTranslationKey, displayCost } =
useMemo(() => {
@@ -62,8 +62,8 @@ export function PlanCostDisplay({
isMultiTier,
lowestTier,
tierTranslationKey: isMultiTier
? 'billing.startingAtPriceUnit'
: 'billing.priceUnit',
? 'billing:startingAtPriceUnit'
: 'billing:priceUnit',
displayCost: cost,
};
}, [primaryLineItem, interval, alwaysDisplayMonthlyPrice]);
@@ -72,7 +72,7 @@ export function PlanCostDisplay({
const formattedCost = formatCurrency({
currencyCode: currencyCode.toLowerCase(),
value: lowestTier?.cost ?? 0,
locale: locale,
locale: i18n.language,
});
return (
@@ -91,7 +91,7 @@ export function PlanCostDisplay({
const formattedCost = formatCurrency({
currencyCode: currencyCode.toLowerCase(),
value: displayCost,
locale: locale,
locale: i18n.language,
});
return <span className={className}>{formattedCost}</span>;

View File

@@ -4,9 +4,9 @@ import { useMemo } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { ArrowRight, CheckCircle } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useForm, useWatch } from 'react-hook-form';
import * as z from 'zod';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import {
BillingConfig,
@@ -25,6 +25,7 @@ import {
FormMessage,
} from '@kit/ui/form';
import { If } from '@kit/ui/if';
import { Label } from '@kit/ui/label';
import {
RadioGroup,
RadioGroupItem,
@@ -49,7 +50,7 @@ export function PlanPicker(
};
}>,
) {
const t = useTranslations('billing');
const { t } = useTranslation(`billing`);
const intervals = useMemo(
() => getPlanIntervals(props.config),
@@ -136,7 +137,7 @@ export function PlanPicker(
render={({ field }) => {
return (
<FormItem className={'flex flex-col gap-4'}>
<FormControl>
<FormControl id={'plan-picker-id'}>
<RadioGroup name={field.name} value={field.value}>
<div className={'flex space-x-1'}>
{intervals.map((interval) => {
@@ -146,23 +147,6 @@ export function PlanPicker(
<label
htmlFor={interval}
key={interval}
onClick={() => {
form.setValue('interval', interval, {
shouldValidate: true,
});
if (selectedProduct) {
const plan = selectedProduct.plans.find(
(item) => item.interval === interval,
);
form.setValue('planId', plan?.id ?? '', {
shouldValidate: true,
shouldDirty: true,
shouldTouch: true,
});
}
}}
className={cn(
'focus-within:border-primary flex items-center gap-x-2.5 rounded-md px-2.5 py-2 transition-colors',
{
@@ -174,6 +158,27 @@ export function PlanPicker(
<RadioGroupItem
id={interval}
value={interval}
onClick={() => {
form.setValue('interval', interval, {
shouldValidate: true,
});
if (selectedProduct) {
const plan = selectedProduct.plans.find(
(item) => item.interval === interval,
);
form.setValue(
'planId',
plan?.id ?? '',
{
shouldValidate: true,
shouldDirty: true,
shouldTouch: true,
},
);
}
}}
/>
<span
@@ -182,7 +187,7 @@ export function PlanPicker(
})}
>
<Trans
i18nKey={`billing.billingInterval.${interval}`}
i18nKey={`billing:billingInterval.${interval}`}
/>
</span>
</label>
@@ -239,28 +244,15 @@ export function PlanPicker(
<RadioGroupItemLabel
selected={selected}
key={primaryLineItem.id}
htmlFor={primaryLineItem.id}
className="rounded-md !border-transparent"
onClick={() => {
if (selected) {
return;
}
form.setValue('planId', planId, {
shouldValidate: true,
});
form.setValue('productId', product.id, {
shouldValidate: true,
});
}}
>
<div
className={
'flex w-full flex-col content-center gap-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0'
}
>
<div
<Label
htmlFor={plan.id}
className={
'flex flex-col justify-center space-y-2.5'
}
@@ -271,11 +263,24 @@ export function PlanPicker(
key={plan.id + selected}
id={plan.id}
value={plan.id}
onClick={() => {
if (selected) {
return;
}
form.setValue('planId', planId, {
shouldValidate: true,
});
form.setValue('productId', product.id, {
shouldValidate: true,
});
}}
/>
<span className="font-semibold">
<Trans
i18nKey={`billing.plans.${product.id}.name`}
i18nKey={`billing:plans.${product.id}.name`}
defaults={product.name}
/>
</span>
@@ -291,7 +296,7 @@ export function PlanPicker(
variant={'success'}
>
<Trans
i18nKey={`billing.trialPeriod`}
i18nKey={`billing:trialPeriod`}
values={{
period: plan.trialDays,
}}
@@ -303,11 +308,11 @@ export function PlanPicker(
<span className={'text-muted-foreground'}>
<Trans
i18nKey={`billing.plans.${product.id}.description`}
i18nKey={`billing:plans.${product.id}.description`}
defaults={product.description}
/>
</span>
</div>
</Label>
<div
className={
@@ -331,10 +336,10 @@ export function PlanPicker(
plan.paymentType === 'recurring'
}
fallback={
<Trans i18nKey={`billing.lifetime`} />
<Trans i18nKey={`billing:lifetime`} />
}
>
<Trans i18nKey={`billing.perMonth`} />
<Trans i18nKey={`billing:perMonth`} />
</If>
</span>
</div>
@@ -362,7 +367,6 @@ export function PlanPicker(
<div>
<Button
type="submit"
data-test="checkout-submit-button"
disabled={props.pending ?? !form.formState.isValid}
>
@@ -404,7 +408,7 @@ function PlanDetails({
selectedInterval: string;
selectedPlan: {
lineItems: z.output<typeof LineItemSchema>[];
lineItems: z.infer<typeof LineItemSchema>[];
paymentType: string;
};
}) {

View File

@@ -5,8 +5,8 @@ import { useState } from 'react';
import Link from 'next/link';
import { ArrowRight, CheckCircle } from 'lucide-react';
import { useTranslations } from 'next-intl';
import * as z from 'zod';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import {
BillingConfig,
@@ -122,14 +122,14 @@ function PricingItem(
selectable: boolean;
primaryLineItem: z.output<typeof LineItemSchema> | undefined;
primaryLineItem: z.infer<typeof LineItemSchema> | undefined;
redirectToCheckout?: boolean;
alwaysDisplayMonthlyPrice?: boolean;
plan: {
id: string;
lineItems: z.output<typeof LineItemSchema>[];
lineItems: z.infer<typeof LineItemSchema>[];
interval?: Interval;
name?: string;
href?: string;
@@ -154,19 +154,19 @@ function PricingItem(
};
}>,
) {
const t = useTranslations();
const { t, i18n } = useTranslation();
const highlighted = props.product.highlighted ?? false;
const lineItem = props.primaryLineItem!;
const isCustom = props.plan.custom ?? false;
const i18nKey = `billing.units.${lineItem.unit}` as never;
const i18nKey = `billing:units.${lineItem.unit}`;
const unitLabel = lineItem?.unit
? t.has(i18nKey)
? i18n.exists(i18nKey)
? t(i18nKey, {
count: 1,
defaultValue: lineItem.unit,
} as never)
})
: lineItem.unit
: '';
@@ -260,10 +260,10 @@ function PricingItem(
<span>
<If
condition={props.plan.interval}
fallback={<Trans i18nKey={'billing.lifetime'} />}
fallback={<Trans i18nKey={'billing:lifetime'} />}
>
{(interval) => (
<Trans i18nKey={`billing.billingInterval.${interval}`} />
<Trans i18nKey={`billing:billingInterval.${interval}`} />
)}
</If>
</span>
@@ -279,10 +279,10 @@ function PricingItem(
<If condition={lineItem?.type === 'per_seat'}>
<If
condition={Boolean(lineItem?.unit) && !isDefaultSeatUnit}
fallback={<Trans i18nKey={'billing.perTeamMember'} />}
fallback={<Trans i18nKey={'billing:perTeamMember'} />}
>
<Trans
i18nKey={'billing.perUnitShort'}
i18nKey={'billing:perUnitShort'}
values={{
unit: unitLabel,
}}
@@ -294,7 +294,7 @@ function PricingItem(
condition={lineItem?.type !== 'per_seat' && lineItem?.unit}
>
<Trans
i18nKey={'billing.perUnit'}
i18nKey={'billing:perUnit'}
values={{
unit: lineItem?.unit,
}}
@@ -343,7 +343,7 @@ function PricingItem(
<div className={'flex flex-col space-y-2'}>
<h6 className={'text-sm font-semibold'}>
<Trans i18nKey={'billing.detailsLabel'} />
<Trans i18nKey={'billing:detailsLabel'} />
</h6>
<LineItemDetails
@@ -402,7 +402,7 @@ function Price({
<span className={'text-muted-foreground text-sm leading-loose'}>
<span>/</span>
<Trans i18nKey={'billing.perMonth'} />
<Trans i18nKey={'billing:perMonth'} />
</span>
</If>
</div>
@@ -446,41 +446,41 @@ function PlanIntervalSwitcher(
return (
<div
className={
'hover:border-border border-border/50 flex gap-x-0 rounded-full border'
'hover:border-border flex gap-x-1 rounded-full border border-transparent transition-colors'
}
>
{props.intervals.map((plan, index) => {
const selected = plan === props.interval;
const className = cn(
'animate-in fade-in rounded-full transition-all focus:!ring-0',
'animate-in fade-in rounded-full !outline-hidden transition-all focus:!ring-0',
{
'border-r-transparent': index === 0,
['hover:text-primary text-muted-foreground']: !selected,
['cursor-default']: selected,
['cursor-default font-semibold']: selected,
['hover:bg-initial']: !selected,
},
);
return (
<Button
size={'sm'}
key={plan}
variant={selected ? 'secondary' : 'custom'}
size={'sm'}
variant={selected ? 'secondary' : 'ghost'}
className={className}
onClick={() => props.setInterval(plan)}
>
<span className={'flex items-center'}>
<CheckCircle
className={cn(
'animate-in fade-in zoom-in-50 mr-1 size-3 duration-200',
{
hidden: !selected,
},
)}
className={cn('animate-in fade-in zoom-in-95 h-3', {
hidden: !selected,
'slide-in-from-left-4': index === 0,
'slide-in-from-right-4': index === props.intervals.length - 1,
})}
/>
<span className={'text-xs capitalize'}>
<Trans i18nKey={`billing.billingInterval.${plan}`} />
<span className={'capitalize'}>
<Trans i18nKey={`common:billingInterval.${plan}`} />
</span>
</span>
</Button>
@@ -509,7 +509,7 @@ function DefaultCheckoutButton(
highlighted?: boolean;
}>,
) {
const t = useTranslations('billing');
const { t } = useTranslation('billing');
const signUpPath = props.paths.signUp;
@@ -522,7 +522,7 @@ function DefaultCheckoutButton(
const linkHref =
props.plan.href ?? `${signUpPath}?${searchParams.toString()}`;
const label = props.plan.buttonLabel ?? 'common.getStartedWithPlan';
const label = props.plan.buttonLabel ?? 'common:getStartedWithPlan';
return (
<Link className={'w-full'} href={linkHref}>
@@ -536,9 +536,9 @@ function DefaultCheckoutButton(
i18nKey={label}
defaults={label}
values={{
plan: t.has(props.product.name as never)
? t(props.product.name as never)
: props.product.name,
plan: t(props.product.name, {
defaultValue: props.product.name,
}),
}}
/>
</span>

View File

@@ -1,6 +1,6 @@
import 'server-only';
import * as z from 'zod';
import { z } from 'zod';
import {
type BillingProviderSchema,
@@ -20,7 +20,7 @@ export function createBillingEventHandlerFactoryService(
// Create a registry for billing webhook handlers
const billingWebhookHandlerRegistry = createRegistry<
BillingWebhookHandlerService,
z.output<typeof BillingProviderSchema>
z.infer<typeof BillingProviderSchema>
>();
// Register the Stripe webhook handler

View File

@@ -1,6 +1,6 @@
import 'server-only';
import * as z from 'zod';
import { z } from 'zod';
import {
type BillingProviderSchema,
@@ -11,7 +11,7 @@ import { createRegistry } from '@kit/shared/registry';
// Create a registry for billing strategy providers
export const billingStrategyRegistry = createRegistry<
BillingStrategyProviderService,
z.output<typeof BillingProviderSchema>
z.infer<typeof BillingProviderSchema>
>();
// Register the Stripe billing strategy

View File

@@ -1,4 +1,4 @@
import * as z from 'zod';
import { z } from 'zod';
import type { BillingProviderSchema } from '@kit/billing';
import {
@@ -14,7 +14,7 @@ import {
import { billingStrategyRegistry } from './billing-gateway-registry';
export function createBillingGatewayService(
provider: z.output<typeof BillingProviderSchema>,
provider: z.infer<typeof BillingProviderSchema>,
) {
return new BillingGatewayService(provider);
}
@@ -30,7 +30,7 @@ export function createBillingGatewayService(
*/
class BillingGatewayService {
constructor(
private readonly provider: z.output<typeof BillingProviderSchema>,
private readonly provider: z.infer<typeof BillingProviderSchema>,
) {}
/**
@@ -40,7 +40,7 @@ class BillingGatewayService {
*
*/
async createCheckoutSession(
params: z.output<typeof CreateBillingCheckoutSchema>,
params: z.infer<typeof CreateBillingCheckoutSchema>,
) {
const strategy = await this.getStrategy();
const payload = CreateBillingCheckoutSchema.parse(params);
@@ -54,7 +54,7 @@ class BillingGatewayService {
* @param {RetrieveCheckoutSessionSchema} params - The parameters to retrieve the checkout session.
*/
async retrieveCheckoutSession(
params: z.output<typeof RetrieveCheckoutSessionSchema>,
params: z.infer<typeof RetrieveCheckoutSessionSchema>,
) {
const strategy = await this.getStrategy();
const payload = RetrieveCheckoutSessionSchema.parse(params);
@@ -68,7 +68,7 @@ class BillingGatewayService {
* @param {CreateBillingPortalSessionSchema} params - The parameters to create the billing portal session.
*/
async createBillingPortalSession(
params: z.output<typeof CreateBillingPortalSessionSchema>,
params: z.infer<typeof CreateBillingPortalSessionSchema>,
) {
const strategy = await this.getStrategy();
const payload = CreateBillingPortalSessionSchema.parse(params);
@@ -82,7 +82,7 @@ class BillingGatewayService {
* @param {CancelSubscriptionParamsSchema} params - The parameters for cancelling the subscription.
*/
async cancelSubscription(
params: z.output<typeof CancelSubscriptionParamsSchema>,
params: z.infer<typeof CancelSubscriptionParamsSchema>,
) {
const strategy = await this.getStrategy();
const payload = CancelSubscriptionParamsSchema.parse(params);
@@ -95,7 +95,7 @@ class BillingGatewayService {
* @description This is used to report the usage of the billing to the provider.
* @param params
*/
async reportUsage(params: z.output<typeof ReportBillingUsageSchema>) {
async reportUsage(params: z.infer<typeof ReportBillingUsageSchema>) {
const strategy = await this.getStrategy();
const payload = ReportBillingUsageSchema.parse(params);
@@ -107,7 +107,7 @@ class BillingGatewayService {
* @description Queries the usage of the metered billing.
* @param params
*/
async queryUsage(params: z.output<typeof QueryBillingUsageSchema>) {
async queryUsage(params: z.infer<typeof QueryBillingUsageSchema>) {
const strategy = await this.getStrategy();
const payload = QueryBillingUsageSchema.parse(params);
@@ -129,7 +129,7 @@ class BillingGatewayService {
* @param params
*/
async updateSubscriptionItem(
params: z.output<typeof UpdateSubscriptionParamsSchema>,
params: z.infer<typeof UpdateSubscriptionParamsSchema>,
) {
const strategy = await this.getStrategy();
const payload = UpdateSubscriptionParamsSchema.parse(params);

View File

@@ -1,6 +1,6 @@
import 'server-only';
import * as z from 'zod';
import { z } from 'zod';
import {
BillingConfig,
@@ -24,7 +24,7 @@ export async function resolveProductPlan(
currency: string,
): Promise<{
product: ProductSchema;
plan: z.output<typeof PlanSchema>;
plan: z.infer<typeof PlanSchema>;
}> {
// we can't always guarantee that the plan will be present in the local config
// so we need to fallback to fetching the plan details from the billing provider