diff --git a/.changeset/good-ads-greet.md b/.changeset/good-ads-greet.md new file mode 100644 index 00000000000..06dfb32119a --- /dev/null +++ b/.changeset/good-ads-greet.md @@ -0,0 +1,5 @@ +--- +'@clerk/ui': minor +--- + +Add support for rendering per-seat costs in checkout diff --git a/.changeset/khaki-hairs-punch.md b/.changeset/khaki-hairs-punch.md new file mode 100644 index 00000000000..7b4e9fe5ebc --- /dev/null +++ b/.changeset/khaki-hairs-punch.md @@ -0,0 +1,8 @@ +--- +'@clerk/localizations': minor +'@clerk/clerk-js': minor +'@clerk/shared': minor +'@clerk/ui': minor +--- + +Add support for total due per period to checkout diff --git a/packages/clerk-js/src/utils/billing.ts b/packages/clerk-js/src/utils/billing.ts index 77b28782197..e994843361f 100644 --- a/packages/clerk-js/src/utils/billing.ts +++ b/packages/clerk-js/src/utils/billing.ts @@ -77,6 +77,9 @@ export const billingTotalsFromJSON = ; + totalDuePerPeriod: LocalizationValue; perMonth: LocalizationValue; }; }; diff --git a/packages/ui/src/components/Checkout/CheckoutForm.tsx b/packages/ui/src/components/Checkout/CheckoutForm.tsx index 2a6dc9c4122..f5933e69465 100644 --- a/packages/ui/src/components/Checkout/CheckoutForm.tsx +++ b/packages/ui/src/components/Checkout/CheckoutForm.tsx @@ -48,10 +48,34 @@ export const CheckoutForm = withCardStateProvider(() => { : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion plan.annualMonthlyFee!; - const descriptionElements = []; + const seatPerUnitTotal = totals.perUnitTotals?.find(({ name }) => name === 'seats'); + const seatPerUnitTotalTiers = seatPerUnitTotal?.tiers ?? []; + const firstSeatTotalTier = seatPerUnitTotalTiers[0]; + const secondSeatTotalTier = seatPerUnitTotalTiers[1]; + const paidSeatTotalTier = + firstSeatTotalTier?.feePerBlock.amount && + firstSeatTotalTier.feePerBlock.amount > 0 && + seatPerUnitTotalTiers.length === 1 + ? firstSeatTotalTier + : secondSeatTotalTier?.feePerBlock.amount && secondSeatTotalTier.feePerBlock.amount > 0 + ? secondSeatTotalTier + : undefined; + + const descriptionElements: Array> = []; if (planPeriod === 'annual') { descriptionElements.push(localizationKeys('billing.billedAnnually')); } + if ( + seatPerUnitTotalTiers.length > 1 && + firstSeatTotalTier?.feePerBlock.amount === 0 && + firstSeatTotalTier.quantity !== null + ) { + descriptionElements.push( + localizationKeys('billing.pricingTable.seatCost.includedSeats', { + includedSeats: firstSeatTotalTier.quantity, + }), + ); + } const seatUnitPrice = getSeatUnitPrice(plan); if (seatUnitPrice && seatUnitPrice.tiers.length === 1 && seatUnitPrice.tiers[0].feePerBlock.amount === 0) { descriptionElements.push( @@ -91,6 +115,16 @@ export const CheckoutForm = withCardStateProvider(() => { suffix={localizationKeys('billing.checkout.perMonth')} /> + {paidSeatTotalTier && paidSeatTotalTier.quantity !== null && ( + + + + + )} { )} - {!!freeTrialEndsAt && !!plan.freeTrialDays && totals.totalDueAfterFreeTrial && ( + {!!freeTrialEndsAt && !!plan.freeTrialDays && totals.totalDueAfterFreeTrial ? ( { text={`${totals.totalDueAfterFreeTrial.currencySymbol}${totals.totalDueAfterFreeTrial.amountFormatted}`} /> + ) : ( + + + + )} diff --git a/packages/ui/src/elements/LineItems.tsx b/packages/ui/src/elements/LineItems.tsx index ab5173392ba..c6e35f6938f 100644 --- a/packages/ui/src/elements/LineItems.tsx +++ b/packages/ui/src/elements/LineItems.tsx @@ -112,7 +112,6 @@ const Title = React.forwardRef(({ title, descr ({ display: 'inline-flex', - alignItems: 'center', gap: t.space.$1, })} >