From 34d2072e3446affff0f23f6e458ef63e3029235e Mon Sep 17 00:00:00 2001
From: Dylan Staley <88163+dstaley@users.noreply.github.com>
Date: Mon, 3 Aug 2026 13:25:27 -0500
Subject: [PATCH 1/3] feat(clerk-js,localizations,shared,ui): Add support for
rendering discounts on subscription items
---
.changeset/green-dolphins-discount.md | 8 ++
.../src/core/resources/BillingSubscription.ts | 4 +
.../src/utils/__tests__/billing.test.ts | 84 +++++++++++++++++++
packages/clerk-js/src/utils/billing.ts | 34 ++++++++
packages/localizations/src/ar-SA.ts | 5 ++
packages/localizations/src/be-BY.ts | 5 ++
packages/localizations/src/bg-BG.ts | 5 ++
packages/localizations/src/bn-IN.ts | 5 ++
packages/localizations/src/ca-ES.ts | 5 ++
packages/localizations/src/cs-CZ.ts | 5 ++
packages/localizations/src/da-DK.ts | 5 ++
packages/localizations/src/de-DE.ts | 5 ++
packages/localizations/src/el-GR.ts | 5 ++
packages/localizations/src/en-GB.ts | 5 ++
packages/localizations/src/en-US.ts | 5 ++
packages/localizations/src/es-CR.ts | 5 ++
packages/localizations/src/es-ES.ts | 5 ++
packages/localizations/src/es-MX.ts | 5 ++
packages/localizations/src/es-UY.ts | 5 ++
packages/localizations/src/fa-IR.ts | 5 ++
packages/localizations/src/fi-FI.ts | 5 ++
packages/localizations/src/fr-FR.ts | 5 ++
packages/localizations/src/he-IL.ts | 5 ++
packages/localizations/src/hi-IN.ts | 5 ++
packages/localizations/src/hr-HR.ts | 5 ++
packages/localizations/src/hu-HU.ts | 5 ++
packages/localizations/src/id-ID.ts | 5 ++
packages/localizations/src/is-IS.ts | 5 ++
packages/localizations/src/it-IT.ts | 5 ++
packages/localizations/src/ja-JP.ts | 5 ++
packages/localizations/src/kk-KZ.ts | 5 ++
packages/localizations/src/ko-KR.ts | 5 ++
packages/localizations/src/mn-MN.ts | 5 ++
packages/localizations/src/ms-MY.ts | 5 ++
packages/localizations/src/nb-NO.ts | 5 ++
packages/localizations/src/nl-BE.ts | 5 ++
packages/localizations/src/nl-NL.ts | 5 ++
packages/localizations/src/pl-PL.ts | 5 ++
packages/localizations/src/pt-BR.ts | 5 ++
packages/localizations/src/pt-PT.ts | 5 ++
packages/localizations/src/ro-RO.ts | 5 ++
packages/localizations/src/ru-RU.ts | 5 ++
packages/localizations/src/sk-SK.ts | 5 ++
packages/localizations/src/sr-RS.ts | 5 ++
packages/localizations/src/sv-SE.ts | 5 ++
packages/localizations/src/ta-IN.ts | 5 ++
packages/localizations/src/te-IN.ts | 5 ++
packages/localizations/src/th-TH.ts | 5 ++
packages/localizations/src/tr-TR.ts | 5 ++
packages/localizations/src/uk-UA.ts | 5 ++
packages/localizations/src/vi-VN.ts | 5 ++
packages/localizations/src/zh-CN.ts | 5 ++
packages/localizations/src/zh-TW.ts | 5 ++
packages/shared/src/types/billing.ts | 47 +++++++++++
packages/shared/src/types/json.ts | 35 ++++++++
packages/shared/src/types/localization.ts | 5 ++
.../Subscriptions/SubscriptionsList.tsx | 64 ++++++++++++++
57 files changed, 526 insertions(+)
create mode 100644 .changeset/green-dolphins-discount.md
diff --git a/.changeset/green-dolphins-discount.md b/.changeset/green-dolphins-discount.md
new file mode 100644
index 00000000000..10c44232cdc
--- /dev/null
+++ b/.changeset/green-dolphins-discount.md
@@ -0,0 +1,8 @@
+---
+'@clerk/clerk-js': patch
+'@clerk/localizations': patch
+'@clerk/shared': patch
+'@clerk/ui': patch
+---
+
+Show applied discounts in the subscription overview.
diff --git a/packages/clerk-js/src/core/resources/BillingSubscription.ts b/packages/clerk-js/src/core/resources/BillingSubscription.ts
index 3ba88bfe442..9e15cb6b639 100644
--- a/packages/clerk-js/src/core/resources/BillingSubscription.ts
+++ b/packages/clerk-js/src/core/resources/BillingSubscription.ts
@@ -1,5 +1,6 @@
import type {
BillingCredits,
+ BillingDiscountRedemption,
BillingMoneyAmount,
BillingSubscriptionItemJSON,
BillingSubscriptionItemNextPayment,
@@ -18,6 +19,7 @@ import { unixEpochToDate } from '@/utils/date';
import {
billingCreditsFromJSON,
+ billingDiscountRedemptionFromJSON,
billingMoneyAmountFromJSON,
billingPerUnitTotalTierFromJSON,
billingSubscriptionItemNextPaymentFromJSON,
@@ -85,6 +87,7 @@ export class BillingSubscriptionItem extends BaseResource implements BillingSubs
};
seats?: BillingSubscriptionItemSeats;
credits?: BillingCredits;
+ appliedDiscount?: BillingDiscountRedemption;
nextPayment?: BillingSubscriptionItemNextPayment | null;
isFreeTrial!: boolean;
@@ -122,6 +125,7 @@ export class BillingSubscriptionItem extends BaseResource implements BillingSubs
: undefined;
this.credits = data.credits ? billingCreditsFromJSON(data.credits) : undefined;
+ this.appliedDiscount = data.applied_discount ? billingDiscountRedemptionFromJSON(data.applied_discount) : undefined;
this.nextPayment =
data.next_payment === undefined
? undefined
diff --git a/packages/clerk-js/src/utils/__tests__/billing.test.ts b/packages/clerk-js/src/utils/__tests__/billing.test.ts
index 702c7a0cc2e..727ca360ca5 100644
--- a/packages/clerk-js/src/utils/__tests__/billing.test.ts
+++ b/packages/clerk-js/src/utils/__tests__/billing.test.ts
@@ -8,6 +8,7 @@ import type {
import { describe, expect, it } from 'vitest';
import {
+ billingDiscountRedemptionFromJSON,
billingPaymentTotalsFromJSON,
billingSubscriptionItemNextPaymentFromJSON,
billingSubscriptionNextPaymentFromJSON,
@@ -40,6 +41,15 @@ const nextPaymentTotalsJSON = (): BillingTotalsJSON => ({
cycle_days_total: 30,
cycle_passed_percent: 50,
},
+ discount: {
+ amount: moneyJSON(1000),
+ discount_id: 'discount_123',
+ name: 'Welcome',
+ effect: 'percentage',
+ percent_off: 20,
+ promo_code: 'WELCOME20',
+ cycles_remaining: 2,
+ },
total: moneyJSON(500),
},
total_due_after_free_trial: null,
@@ -109,6 +119,14 @@ describe('billingPaymentTotalsFromJSON', () => {
cycle_days_total: 30,
cycle_passed_percent: 3,
},
+ discount: {
+ amount: moneyJSON(100),
+ discount_id: 'discount_123',
+ name: 'Fixed discount',
+ effect: 'fixed_amount',
+ amount_off: moneyJSON(100),
+ cycles_remaining: null,
+ },
total: moneyJSON(16),
},
};
@@ -117,6 +135,14 @@ describe('billingPaymentTotalsFromJSON', () => {
expect(totals.discounts?.proration?.amount.amount).toBe(16);
expect(totals.discounts?.proration?.cycleDaysPassed).toBe(1);
+ expect(totals.discounts?.discount).toMatchObject({
+ amount: { amount: 100 },
+ discountId: 'discount_123',
+ name: 'Fixed discount',
+ effect: 'fixed_amount',
+ amountOff: { amount: 100, amountFormatted: '1.00', currency: 'USD', currencySymbol: '$' },
+ cyclesRemaining: null,
+ });
expect(totals.discounts?.total.amount).toBe(16);
});
@@ -209,6 +235,15 @@ describe('billingSubscriptionNextPaymentFromJSON', () => {
cycleDaysTotal: 30,
cyclePassedPercent: 50,
},
+ discount: {
+ amount: { amount: 1000 },
+ discountId: 'discount_123',
+ name: 'Welcome',
+ effect: 'percentage',
+ percentOff: 20,
+ promoCode: 'WELCOME20',
+ cyclesRemaining: 2,
+ },
total: { amount: 500 },
},
perUnitTotals: [{ name: 'seats', blockSize: 1 }],
@@ -223,6 +258,55 @@ describe('billingSubscriptionNextPaymentFromJSON', () => {
});
});
+describe('billingDiscountRedemptionFromJSON', () => {
+ it('maps an applied subscription item discount', () => {
+ const discount = billingDiscountRedemptionFromJSON({
+ object: 'commerce_discount_redemption',
+ id: 'redemption_123',
+ subscription_item_id: 'sub_item_123',
+ discount_id: 'discount_123',
+ name: 'Welcome',
+ source: 'promo_code',
+ promo_code: 'WELCOME20',
+ effect: 'fixed_amount',
+ amount_off: moneyJSON(500),
+ amount: moneyJSON(400),
+ cycles_remaining: 2,
+ cycles_applied: 1,
+ status: 'active',
+ redeemed_at: 1_609_459_200_000,
+ redeemed_by: 'user_123',
+ });
+
+ expect(discount).toMatchObject({
+ id: 'redemption_123',
+ subscriptionItemId: 'sub_item_123',
+ discountId: 'discount_123',
+ name: 'Welcome',
+ source: 'promo_code',
+ promoCode: 'WELCOME20',
+ effect: 'fixed_amount',
+ amountOff: {
+ amount: 500,
+ amountFormatted: '5.00',
+ currency: 'USD',
+ currencySymbol: '$',
+ },
+ amount: {
+ amount: 400,
+ amountFormatted: '4.00',
+ currency: 'USD',
+ currencySymbol: '$',
+ },
+ cyclesRemaining: 2,
+ cyclesApplied: 1,
+ status: 'active',
+ redeemedAt: new Date('2021-01-01T00:00:00.000Z'),
+ redeemedBy: 'user_123',
+ });
+ });
+});
+
describe('billingSubscriptionItemNextPaymentFromJSON', () => {
it('maps amount, date, and per_unit_totals', () => {
const data: BillingSubscriptionItemNextPaymentJSON = {
diff --git a/packages/clerk-js/src/utils/billing.ts b/packages/clerk-js/src/utils/billing.ts
index 796141c2751..40303e7d825 100644
--- a/packages/clerk-js/src/utils/billing.ts
+++ b/packages/clerk-js/src/utils/billing.ts
@@ -1,8 +1,12 @@
import type {
+ BillingAppliedDiscount,
+ BillingAppliedDiscountJSON,
BillingCheckoutTotals,
BillingCheckoutTotalsJSON,
BillingCredits,
BillingCreditsJSON,
+ BillingDiscountRedemption,
+ BillingDiscountRedemptionJSON,
BillingDiscounts,
BillingDiscountsJSON,
BillingMoneyAmount,
@@ -105,10 +109,40 @@ const billingDiscountsFromJSON = (data: BillingDiscountsJSON): BillingDiscounts
cyclePassedPercent: data.proration.cycle_passed_percent,
}
: null,
+ discount: data.discount ? billingAppliedDiscountFromJSON(data.discount) : undefined,
total: billingMoneyAmountFromJSON(data.total),
};
};
+const billingAppliedDiscountFromJSON = (data: BillingAppliedDiscountJSON): BillingAppliedDiscount => ({
+ amount: billingMoneyAmountFromJSON(data.amount),
+ discountId: data.discount_id,
+ name: data.name,
+ effect: data.effect,
+ percentOff: data.percent_off,
+ amountOff: data.amount_off ? billingMoneyAmountFromJSON(data.amount_off) : undefined,
+ promoCode: data.promo_code,
+ cyclesRemaining: data.cycles_remaining,
+});
+
+export const billingDiscountRedemptionFromJSON = (data: BillingDiscountRedemptionJSON): BillingDiscountRedemption => ({
+ id: data.id,
+ subscriptionItemId: data.subscription_item_id,
+ discountId: data.discount_id,
+ name: data.name,
+ source: data.source,
+ promoCode: data.promo_code,
+ effect: data.effect,
+ percentOff: data.percent_off,
+ amountOff: data.amount_off ? billingMoneyAmountFromJSON(data.amount_off) : undefined,
+ amount: data.amount ? billingMoneyAmountFromJSON(data.amount) : undefined,
+ cyclesRemaining: data.cycles_remaining,
+ cyclesApplied: data.cycles_applied,
+ status: data.status,
+ redeemedAt: unixEpochToDate(data.redeemed_at),
+ redeemedBy: data.redeemed_by,
+});
+
const billingPeriodTotalsFromJSON = (data: BillingPeriodTotalsJSON): BillingPeriodTotals => {
return {
subtotal: billingMoneyAmountFromJSON(data.subtotal),
diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts
index 412c5ad3367..596a5584f6f 100644
--- a/packages/localizations/src/ar-SA.ts
+++ b/packages/localizations/src/ar-SA.ts
@@ -126,6 +126,9 @@ export const arSA: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const arSA: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const arSA: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts
index 6171efa76f1..dc084c9cb5c 100644
--- a/packages/localizations/src/be-BY.ts
+++ b/packages/localizations/src/be-BY.ts
@@ -126,6 +126,9 @@ export const beBY: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const beBY: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const beBY: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts
index 5c24af73f66..e745c6c0113 100644
--- a/packages/localizations/src/bg-BG.ts
+++ b/packages/localizations/src/bg-BG.ts
@@ -127,6 +127,9 @@ export const bgBG: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -138,6 +141,7 @@ export const bgBG: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -216,6 +220,7 @@ export const bgBG: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts
index dd477c1dacd..246d73cdabc 100644
--- a/packages/localizations/src/bn-IN.ts
+++ b/packages/localizations/src/bn-IN.ts
@@ -132,6 +132,9 @@ export const bnIN: LocalizationResource = {
credit: 'ক্রেডিট',
creditRemainder: 'আপনার বর্তমান সাবস্ক্রিপশনের অবশিষ্ট সময়ের জন্য ক্রেডিট।',
defaultFreePlanActive: 'আপনি বর্তমানে বিনামূল্যের প্ল্যানে আছেন',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'বিনামূল্যে',
getStarted: 'শুরু করুন',
highlightedPlanBadge: 'জনপ্রিয়',
@@ -143,6 +146,7 @@ export const bnIN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'মাসিক',
+ months: undefined,
pastDue: 'বকেয়া',
pay: '{{amount}} পরিশোধ করুন',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const bnIN: LocalizationResource = {
year: 'বছর',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts
index c7a12dcd007..b072019fa84 100644
--- a/packages/localizations/src/ca-ES.ts
+++ b/packages/localizations/src/ca-ES.ts
@@ -133,6 +133,9 @@ export const caES: LocalizationResource = {
credit: 'Crèdit',
creditRemainder: 'Crèdit pel temps restant de la teva subscripció actual.',
defaultFreePlanActive: 'Estàs al pla gratuït',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratuït',
getStarted: 'Comença',
highlightedPlanBadge: 'Popular',
@@ -144,6 +147,7 @@ export const caES: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensual',
+ months: undefined,
pastDue: 'Pagament pendent',
pay: 'Paga {{amount}}',
payerCreditRemainder: undefined,
@@ -222,6 +226,7 @@ export const caES: LocalizationResource = {
year: 'Any',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts
index 794f8c5b0a8..515881fbf28 100644
--- a/packages/localizations/src/cs-CZ.ts
+++ b/packages/localizations/src/cs-CZ.ts
@@ -130,6 +130,9 @@ export const csCZ: LocalizationResource = {
credit: 'Kredit',
creditRemainder: 'Kredit za zbytek vašeho současného předplatného.',
defaultFreePlanActive: 'Aktuálně používáte bezplatný plán',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Zdarma',
getStarted: 'Začít',
highlightedPlanBadge: 'Populární',
@@ -141,6 +144,7 @@ export const csCZ: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Měsíčně',
+ months: undefined,
pastDue: 'Po splatnosti',
pay: 'Zaplatit {{amount}}',
payerCreditRemainder: undefined,
@@ -219,6 +223,7 @@ export const csCZ: LocalizationResource = {
year: 'Rok',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts
index 7726dd8f310..bf4b56f20c5 100644
--- a/packages/localizations/src/da-DK.ts
+++ b/packages/localizations/src/da-DK.ts
@@ -126,6 +126,9 @@ export const daDK: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const daDK: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const daDK: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts
index 2d615e35ee0..d296dd770e6 100644
--- a/packages/localizations/src/de-DE.ts
+++ b/packages/localizations/src/de-DE.ts
@@ -132,6 +132,9 @@ export const deDE: LocalizationResource = {
credit: 'Guthaben',
creditRemainder: 'Verbleibendes Guthaben für den restlichen Abrechnungszeitraum.',
defaultFreePlanActive: 'Sie nutzen aktuell den kostenlosen Plan.',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Kostenlos',
getStarted: 'Jetzt starten',
highlightedPlanBadge: 'Beliebt',
@@ -143,6 +146,7 @@ export const deDE: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Monatlich',
+ months: undefined,
pastDue: 'Überfällig',
pay: '{{amount}} bezahlen',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const deDE: LocalizationResource = {
year: 'Jahr',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts
index b0f43aabb26..a3ab5b1daaf 100644
--- a/packages/localizations/src/el-GR.ts
+++ b/packages/localizations/src/el-GR.ts
@@ -126,6 +126,9 @@ export const elGR: LocalizationResource = {
credit: 'Πίστωση',
creditRemainder: 'Υπόλοιπο πίστωσης',
defaultFreePlanActive: 'Το προεπιλεγμένο δωρεάν πλάνο είναι ενεργό',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Δωρεάν',
getStarted: 'Ξεκινήστε',
highlightedPlanBadge: 'Δημοφιλές',
@@ -137,6 +140,7 @@ export const elGR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Μηνιαία',
+ months: undefined,
pastDue: 'Ληξιπρόθεσμο',
pay: 'Πληρωμή',
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const elGR: LocalizationResource = {
year: 'έτος',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts
index 6c1415128ad..bd379c1eacc 100644
--- a/packages/localizations/src/en-GB.ts
+++ b/packages/localizations/src/en-GB.ts
@@ -126,6 +126,9 @@ export const enGB: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const enGB: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const enGB: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts
index 4c4e33bcd4c..86d4c3ab782 100644
--- a/packages/localizations/src/en-US.ts
+++ b/packages/localizations/src/en-US.ts
@@ -121,6 +121,9 @@ export const enUS: LocalizationResource = {
credit: 'Credit',
creditRemainder: 'Credit for the remainder of your current subscription.',
defaultFreePlanActive: "You're currently on the Free plan",
+ discountAmount: '({{amount}} off)',
+ discountCyclesRemaining: '{{cycles}} {{period}} remaining',
+ discountDuration: '({{amount}} off first {{cycles}} {{period}})',
free: 'Free',
getStarted: 'Get started',
highlightedPlanBadge: 'Popular',
@@ -132,6 +135,7 @@ export const enUS: LocalizationResource = {
monthAbbreviation: 'mo',
monthPerUnit: 'Month per {{unitName}}',
monthly: 'Monthly',
+ months: 'Months',
pastDue: 'Past due',
pay: 'Pay {{amount}}',
payerCreditRemainder: 'Credit from account balance.',
@@ -210,6 +214,7 @@ export const enUS: LocalizationResource = {
year: 'Year',
yearAbbreviation: 'yr',
yearPerUnit: 'Year per {{unitName}}',
+ years: 'Years',
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts
index 051c1c8e592..fe7b4477816 100644
--- a/packages/localizations/src/es-CR.ts
+++ b/packages/localizations/src/es-CR.ts
@@ -126,6 +126,9 @@ export const esCR: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratis',
getStarted: 'Empezar',
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const esCR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const esCR: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts
index a28358daa7e..5e70ef929cd 100644
--- a/packages/localizations/src/es-ES.ts
+++ b/packages/localizations/src/es-ES.ts
@@ -132,6 +132,9 @@ export const esES: LocalizationResource = {
credit: 'Crédito',
creditRemainder: 'Crédito por el tiempo restante de tu suscripción actual.',
defaultFreePlanActive: 'Actualmente estás en el plan gratuito',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratis',
getStarted: 'Empezar',
highlightedPlanBadge: 'Popular',
@@ -143,6 +146,7 @@ export const esES: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensual',
+ months: undefined,
pastDue: 'Pago pendiente',
pay: 'Pagar {{amount}}',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const esES: LocalizationResource = {
year: 'Año',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts
index 43d21afac61..130e9fae55e 100644
--- a/packages/localizations/src/es-MX.ts
+++ b/packages/localizations/src/es-MX.ts
@@ -127,6 +127,9 @@ export const esMX: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratis',
getStarted: 'Empezar',
highlightedPlanBadge: undefined,
@@ -138,6 +141,7 @@ export const esMX: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -216,6 +220,7 @@ export const esMX: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts
index 59cf112290f..7a3fc1447e6 100644
--- a/packages/localizations/src/es-UY.ts
+++ b/packages/localizations/src/es-UY.ts
@@ -126,6 +126,9 @@ export const esUY: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const esUY: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const esUY: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts
index 8b90baf9f22..18620d3648f 100644
--- a/packages/localizations/src/fa-IR.ts
+++ b/packages/localizations/src/fa-IR.ts
@@ -131,6 +131,9 @@ export const faIR: LocalizationResource = {
credit: 'اعتبار',
creditRemainder: 'اعتبار برای باقیمانده اشتراک فعلی شما.',
defaultFreePlanActive: 'شما در حال حاضر در طرح رایگان هستید',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'رایگان',
getStarted: 'شروع کنید',
highlightedPlanBadge: 'محبوب',
@@ -142,6 +145,7 @@ export const faIR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'ماهانه',
+ months: undefined,
pastDue: 'سررسید گذشته',
pay: 'پرداخت {{amount}}',
payerCreditRemainder: undefined,
@@ -220,6 +224,7 @@ export const faIR: LocalizationResource = {
year: 'سال',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts
index c7ee3488ae9..65802a743c7 100644
--- a/packages/localizations/src/fi-FI.ts
+++ b/packages/localizations/src/fi-FI.ts
@@ -132,6 +132,9 @@ export const fiFI: LocalizationResource = {
credit: 'Hyvitys',
creditRemainder: 'Hyvitys nykyisen tilauksesi jäljellä olevalta ajalta.',
defaultFreePlanActive: 'Olet tällä hetkellä ilmaisella tilauksella.',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Ilmainen',
getStarted: 'Aloita',
highlightedPlanBadge: 'Suosittu',
@@ -143,6 +146,7 @@ export const fiFI: LocalizationResource = {
monthAbbreviation: 'kk',
monthPerUnit: 'Kuukausi per {{unitName}}',
monthly: 'Kuukausittain',
+ months: undefined,
pastDue: 'Erääntynyt',
pay: 'Maksa {{amount}}',
payerCreditRemainder: 'Hyvitys tilin saldosta.',
@@ -221,6 +225,7 @@ export const fiFI: LocalizationResource = {
year: 'Vuosi',
yearAbbreviation: 'v',
yearPerUnit: 'Vuosi per {{unitName}}',
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts
index aa019e5fa48..1d60760ae9b 100644
--- a/packages/localizations/src/fr-FR.ts
+++ b/packages/localizations/src/fr-FR.ts
@@ -134,6 +134,9 @@ export const frFR: LocalizationResource = {
credit: 'Crédit',
creditRemainder: 'Crédit restant',
defaultFreePlanActive: 'Vous êtes actuellement sur le plan gratuit',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratuit',
getStarted: 'Commencer',
highlightedPlanBadge: 'Populaire',
@@ -145,6 +148,7 @@ export const frFR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensuel',
+ months: undefined,
pastDue: 'En retard',
pay: 'Payer {{amount}}',
payerCreditRemainder: undefined,
@@ -223,6 +227,7 @@ export const frFR: LocalizationResource = {
year: 'An',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts
index a95959d3aab..59a888b6cbc 100644
--- a/packages/localizations/src/he-IL.ts
+++ b/packages/localizations/src/he-IL.ts
@@ -126,6 +126,9 @@ export const heIL: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const heIL: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const heIL: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts
index 3331c95b3a3..f98367ebfe2 100644
--- a/packages/localizations/src/hi-IN.ts
+++ b/packages/localizations/src/hi-IN.ts
@@ -132,6 +132,9 @@ export const hiIN: LocalizationResource = {
credit: 'क्रेडिट',
creditRemainder: 'आपकी मौजूदा सदस्यता की शेष अवधि के लिए क्रेडिट।',
defaultFreePlanActive: 'आप वर्तमान में निःशुल्क योजना पर हैं',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'मुफ्त',
getStarted: 'शुरू करें',
highlightedPlanBadge: 'लोकप्रिय',
@@ -143,6 +146,7 @@ export const hiIN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'मासिक',
+ months: undefined,
pastDue: 'बकाया',
pay: '{{amount}} भुगतान करें',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const hiIN: LocalizationResource = {
year: 'वर्ष',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts
index 3cd2486c91a..07769ee5155 100644
--- a/packages/localizations/src/hr-HR.ts
+++ b/packages/localizations/src/hr-HR.ts
@@ -133,6 +133,9 @@ export const hrHR: LocalizationResource = {
credit: 'Kredit',
creditRemainder: 'Kredit za preostalo razdoblje vaše trenutne pretplate.',
defaultFreePlanActive: 'Trenutno ste na besplatnom planu',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Besplatno',
getStarted: 'Započnite',
highlightedPlanBadge: 'Popularno',
@@ -144,6 +147,7 @@ export const hrHR: LocalizationResource = {
monthAbbreviation: 'mj',
monthPerUnit: 'Mjesec po {{unitName}}',
monthly: 'Mjesečno',
+ months: undefined,
pastDue: 'Dospjelo',
pay: 'Plati {{amount}}',
payerCreditRemainder: 'Kredit sa stanja računa.',
@@ -222,6 +226,7 @@ export const hrHR: LocalizationResource = {
year: 'Godina',
yearAbbreviation: 'god',
yearPerUnit: 'Godina po {{unitName}}',
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts
index ecbc5857b1c..9567f27be83 100644
--- a/packages/localizations/src/hu-HU.ts
+++ b/packages/localizations/src/hu-HU.ts
@@ -133,6 +133,9 @@ export const huHU: LocalizationResource = {
credit: 'Jóváírás',
creditRemainder: 'Jóváírás a jelenlegi előfizetésed hátralévő idejére.',
defaultFreePlanActive: 'Jelenleg az Ingyenes csomagot használod',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Ingyenes',
getStarted: 'Kezdés',
highlightedPlanBadge: 'Népszerű',
@@ -144,6 +147,7 @@ export const huHU: LocalizationResource = {
monthAbbreviation: 'hó',
monthPerUnit: 'Hónap / {{unitName}}',
monthly: 'Havi',
+ months: undefined,
pastDue: 'Lejárt',
pay: '{{amount}} fizetése',
payerCreditRemainder: 'Jóváírás a fiók egyenlegből.',
@@ -222,6 +226,7 @@ export const huHU: LocalizationResource = {
year: 'Év',
yearAbbreviation: 'év',
yearPerUnit: 'Év / {{unitName}}',
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts
index 890a5432be7..7f2ccfcf54f 100644
--- a/packages/localizations/src/id-ID.ts
+++ b/packages/localizations/src/id-ID.ts
@@ -126,6 +126,9 @@ export const idID: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const idID: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const idID: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts
index bbea10b5afd..05bfdadb026 100644
--- a/packages/localizations/src/is-IS.ts
+++ b/packages/localizations/src/is-IS.ts
@@ -132,6 +132,9 @@ export const isIS: LocalizationResource = {
credit: 'Inneign',
creditRemainder: 'Inneign fyrir eftirstöðvar núverandi áskriftar.',
defaultFreePlanActive: 'Þú ert á ókeypis áskrift',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Ókeypis',
getStarted: 'Byrja',
highlightedPlanBadge: 'Vinsælt',
@@ -143,6 +146,7 @@ export const isIS: LocalizationResource = {
monthAbbreviation: 'mán.',
monthPerUnit: 'Mánuður á {{unitName}}',
monthly: 'Mánaðarlega',
+ months: undefined,
pastDue: 'Gjaldfallið',
pay: 'Greiða {{amount}}',
payerCreditRemainder: 'Inneign frá reikningsstöðu.',
@@ -221,6 +225,7 @@ export const isIS: LocalizationResource = {
year: 'Ár',
yearAbbreviation: 'ár',
yearPerUnit: 'Ár á {{unitName}}',
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts
index 0919d7813ef..f605a2ce8df 100644
--- a/packages/localizations/src/it-IT.ts
+++ b/packages/localizations/src/it-IT.ts
@@ -132,6 +132,9 @@ export const itIT: LocalizationResource = {
credit: 'Credito',
creditRemainder: 'Credito per il resto del tuo abbonamento attuale.',
defaultFreePlanActive: 'Attualmente sei sul piano Gratuito',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratuito',
getStarted: 'Inizia',
highlightedPlanBadge: 'Popolare',
@@ -143,6 +146,7 @@ export const itIT: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensile',
+ months: undefined,
pastDue: 'Scaduto',
pay: 'Paga {{amount}}',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const itIT: LocalizationResource = {
year: 'Anno',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts
index 79b739b0e20..34f10d76d06 100644
--- a/packages/localizations/src/ja-JP.ts
+++ b/packages/localizations/src/ja-JP.ts
@@ -133,6 +133,9 @@ export const jaJP: LocalizationResource = {
credit: 'クレジット',
creditRemainder: '現在のサブスクリプションの残り期間に対するクレジット。',
defaultFreePlanActive: '現在は無料プランをご利用中です',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: '無料',
getStarted: 'はじめる',
highlightedPlanBadge: '人気',
@@ -144,6 +147,7 @@ export const jaJP: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: '月払い',
+ months: undefined,
pastDue: '支払い遅延',
pay: '{{amount}}を支払う',
payerCreditRemainder: 'アカウント残高からのクレジット。',
@@ -222,6 +226,7 @@ export const jaJP: LocalizationResource = {
year: '年',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts
index 5739bb8e83f..a7a835090e7 100644
--- a/packages/localizations/src/kk-KZ.ts
+++ b/packages/localizations/src/kk-KZ.ts
@@ -126,6 +126,9 @@ export const kkKZ: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Тегін',
getStarted: 'Бастау',
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const kkKZ: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const kkKZ: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts
index 4070b2a7d16..a7c5739f8ee 100644
--- a/packages/localizations/src/ko-KR.ts
+++ b/packages/localizations/src/ko-KR.ts
@@ -130,6 +130,9 @@ export const koKR: LocalizationResource = {
credit: '크레딧',
creditRemainder: '현재 구독 남은 기간에 대한 크레딧',
defaultFreePlanActive: '현재 무료 플랜을 사용 중이에요',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: '무료',
getStarted: '시작하기',
highlightedPlanBadge: '인기',
@@ -141,6 +144,7 @@ export const koKR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: '월간',
+ months: undefined,
pastDue: '연체',
pay: '{{amount}} 결제',
payerCreditRemainder: undefined,
@@ -219,6 +223,7 @@ export const koKR: LocalizationResource = {
year: '년',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts
index 66ad147f594..3719a4c6625 100644
--- a/packages/localizations/src/mn-MN.ts
+++ b/packages/localizations/src/mn-MN.ts
@@ -126,6 +126,9 @@ export const mnMN: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const mnMN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const mnMN: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts
index 28f3b8fa362..319765d7d5b 100644
--- a/packages/localizations/src/ms-MY.ts
+++ b/packages/localizations/src/ms-MY.ts
@@ -134,6 +134,9 @@ export const msMY: LocalizationResource = {
credit: 'Kredit',
creditRemainder: 'Kredit untuk baki langganan semasa anda.',
defaultFreePlanActive: 'Anda kini menggunakan pelan Percuma',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Percuma',
getStarted: 'Mulakan',
highlightedPlanBadge: 'Popular',
@@ -145,6 +148,7 @@ export const msMY: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Bulanan',
+ months: undefined,
pastDue: 'Tertunggak',
pay: 'Bayar {{amount}}',
payerCreditRemainder: undefined,
@@ -223,6 +227,7 @@ export const msMY: LocalizationResource = {
year: 'Tahun',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts
index 634d14772cf..665c9f8f746 100644
--- a/packages/localizations/src/nb-NO.ts
+++ b/packages/localizations/src/nb-NO.ts
@@ -133,6 +133,9 @@ export const nbNO: LocalizationResource = {
credit: 'Kreditt',
creditRemainder: 'Kreditt for gjenstående del av ditt nåværende abonnement.',
defaultFreePlanActive: 'Du er på gratis-planen',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratis',
getStarted: 'Kom i gang',
highlightedPlanBadge: 'Populær',
@@ -144,6 +147,7 @@ export const nbNO: LocalizationResource = {
monthAbbreviation: 'mnd',
monthPerUnit: 'Måned per {{unitName}}',
monthly: 'Månedlig',
+ months: undefined,
pastDue: 'Forfalt',
pay: 'Betal {{amount}}',
payerCreditRemainder: 'Kreditt fra kontosaldo.',
@@ -222,6 +226,7 @@ export const nbNO: LocalizationResource = {
year: 'År',
yearAbbreviation: 'år',
yearPerUnit: 'År per {{unitName}}',
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts
index 7584091ffb9..ff7e9b30a40 100644
--- a/packages/localizations/src/nl-BE.ts
+++ b/packages/localizations/src/nl-BE.ts
@@ -126,6 +126,9 @@ export const nlBE: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const nlBE: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const nlBE: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts
index 3bc6bff7ac1..135300b7d98 100644
--- a/packages/localizations/src/nl-NL.ts
+++ b/packages/localizations/src/nl-NL.ts
@@ -126,6 +126,9 @@ export const nlNL: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const nlNL: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const nlNL: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts
index be54a14ff4e..55a39875928 100644
--- a/packages/localizations/src/pl-PL.ts
+++ b/packages/localizations/src/pl-PL.ts
@@ -126,6 +126,9 @@ export const plPL: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const plPL: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const plPL: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts
index 42e0c5b08f7..1690a10bdb3 100644
--- a/packages/localizations/src/pt-BR.ts
+++ b/packages/localizations/src/pt-BR.ts
@@ -132,6 +132,9 @@ export const ptBR: LocalizationResource = {
credit: 'Crédito',
creditRemainder: 'Crédito para o restante da sua assinatura atual.',
defaultFreePlanActive: 'Você está atualmente no plano Gratuito',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratuito',
getStarted: 'Começar',
highlightedPlanBadge: 'Popular',
@@ -143,6 +146,7 @@ export const ptBR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensal',
+ months: undefined,
pastDue: 'Atrasado',
pay: 'Pagar {{amount}}',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const ptBR: LocalizationResource = {
year: 'Ano',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts
index d136f7b6fca..71a1fe6f066 100644
--- a/packages/localizations/src/pt-PT.ts
+++ b/packages/localizations/src/pt-PT.ts
@@ -134,6 +134,9 @@ export const ptPT: LocalizationResource = {
credit: 'Crédito',
creditRemainder: 'Crédito relativo ao período restante da sua subscrição atual.',
defaultFreePlanActive: 'Está atualmente no plano Gratuito',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratuito',
getStarted: 'Começar',
highlightedPlanBadge: 'Popular',
@@ -145,6 +148,7 @@ export const ptPT: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensal',
+ months: undefined,
pastDue: 'Em atraso',
pay: 'Pagar {{amount}}',
payerCreditRemainder: undefined,
@@ -223,6 +227,7 @@ export const ptPT: LocalizationResource = {
year: 'Ano',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts
index ffb22de2fc2..f66fb24d412 100644
--- a/packages/localizations/src/ro-RO.ts
+++ b/packages/localizations/src/ro-RO.ts
@@ -132,6 +132,9 @@ export const roRO: LocalizationResource = {
credit: 'Credit',
creditRemainder: 'Credit pentru restul abonamentului curent.',
defaultFreePlanActive: 'În prezent ești pe planul Gratuit',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Gratuit',
getStarted: 'Începe',
highlightedPlanBadge: 'Popular',
@@ -143,6 +146,7 @@ export const roRO: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Lunar',
+ months: undefined,
pastDue: 'Restanță',
pay: 'Plătește {{amount}}',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const roRO: LocalizationResource = {
year: 'An',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts
index a8552a376d7..242bfdfb0fc 100644
--- a/packages/localizations/src/ru-RU.ts
+++ b/packages/localizations/src/ru-RU.ts
@@ -126,6 +126,9 @@ export const ruRU: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const ruRU: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const ruRU: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts
index 386d4b8e6a2..331ef956835 100644
--- a/packages/localizations/src/sk-SK.ts
+++ b/packages/localizations/src/sk-SK.ts
@@ -126,6 +126,9 @@ export const skSK: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Bezplatne',
getStarted: 'Začať',
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const skSK: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const skSK: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts
index 729042ee9f9..1eaff6c0504 100644
--- a/packages/localizations/src/sr-RS.ts
+++ b/packages/localizations/src/sr-RS.ts
@@ -126,6 +126,9 @@ export const srRS: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const srRS: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const srRS: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts
index 12cea3490e5..5696ee4a76b 100644
--- a/packages/localizations/src/sv-SE.ts
+++ b/packages/localizations/src/sv-SE.ts
@@ -126,6 +126,9 @@ export const svSE: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const svSE: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const svSE: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts
index c4c30019d93..72322b38fa3 100644
--- a/packages/localizations/src/ta-IN.ts
+++ b/packages/localizations/src/ta-IN.ts
@@ -134,6 +134,9 @@ export const taIN: LocalizationResource = {
credit: 'கடன்',
creditRemainder: 'உங்கள் தற்போதைய சந்தாவின் மீதமுள்ள காலத்திற்கான கடன்.',
defaultFreePlanActive: 'நீங்கள் தற்போது இலவச திட்டத்தில் உள்ளீர்கள்',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'இலவசம்',
getStarted: 'தொடங்குங்கள்',
highlightedPlanBadge: 'பிரபலமான',
@@ -145,6 +148,7 @@ export const taIN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'மாதந்தோறும்',
+ months: undefined,
pastDue: 'நிலுவை',
pay: '{{amount}} செலுத்து',
payerCreditRemainder: undefined,
@@ -223,6 +227,7 @@ export const taIN: LocalizationResource = {
year: 'ஆண்டு',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts
index 3e523d8d58d..52afc8d930c 100644
--- a/packages/localizations/src/te-IN.ts
+++ b/packages/localizations/src/te-IN.ts
@@ -133,6 +133,9 @@ export const teIN: LocalizationResource = {
credit: 'క్రెడిట్',
creditRemainder: 'మీ ప్రస్తుత సబ్స్క్రిప్షన్ యొక్క మిగిలిన కాలానికి క్రెడిట్.',
defaultFreePlanActive: 'మీరు ప్రస్తుతం ఉచిత ప్లాన్లో ఉన్నారు',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'ఉచితం',
getStarted: 'ప్రారంభించండి',
highlightedPlanBadge: 'ప్రసిద్ధ',
@@ -144,6 +147,7 @@ export const teIN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'నెలవారీ',
+ months: undefined,
pastDue: 'బకాయి',
pay: '{{amount}} చెల్లించు',
payerCreditRemainder: undefined,
@@ -222,6 +226,7 @@ export const teIN: LocalizationResource = {
year: 'సంవత్సరం',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts
index b86fd886f32..612c2ae5651 100644
--- a/packages/localizations/src/th-TH.ts
+++ b/packages/localizations/src/th-TH.ts
@@ -130,6 +130,9 @@ export const thTH: LocalizationResource = {
credit: 'เครดิต',
creditRemainder: 'เครดิตสำหรับส่วนที่เหลือของการสมัครสมาชิกปัจจุบันของคุณ',
defaultFreePlanActive: 'คุณกำลังใช้แผนฟรีอยู่',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'ฟรี',
getStarted: 'เริ่มต้นใช้งาน',
highlightedPlanBadge: 'ยอดนิยม',
@@ -141,6 +144,7 @@ export const thTH: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'รายเดือน',
+ months: undefined,
pastDue: 'เกินกำหนด',
pay: 'ชำระ {{amount}}',
payerCreditRemainder: undefined,
@@ -219,6 +223,7 @@ export const thTH: LocalizationResource = {
year: 'ปี',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts
index 34ae01d2949..0396bedcad3 100644
--- a/packages/localizations/src/tr-TR.ts
+++ b/packages/localizations/src/tr-TR.ts
@@ -126,6 +126,9 @@ export const trTR: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const trTR: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const trTR: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts
index d30dea0a59c..eb102f1969d 100644
--- a/packages/localizations/src/uk-UA.ts
+++ b/packages/localizations/src/uk-UA.ts
@@ -126,6 +126,9 @@ export const ukUA: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const ukUA: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const ukUA: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts
index 266cc6d915e..d9c0fad274d 100644
--- a/packages/localizations/src/vi-VN.ts
+++ b/packages/localizations/src/vi-VN.ts
@@ -132,6 +132,9 @@ export const viVN: LocalizationResource = {
credit: 'Tín dụng',
creditRemainder: 'Tín dụng cho phần còn lại của đăng ký hiện tại.',
defaultFreePlanActive: 'Bạn hiện đang trên gói Miễn phí',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: 'Miễn phí',
getStarted: 'Bắt đầu',
highlightedPlanBadge: 'Phổ biến',
@@ -143,6 +146,7 @@ export const viVN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Hàng tháng',
+ months: undefined,
pastDue: 'Quá hạn',
pay: 'Thanh toán {{amount}}',
payerCreditRemainder: undefined,
@@ -221,6 +225,7 @@ export const viVN: LocalizationResource = {
year: 'Năm',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts
index 56a9b1b385a..9e32d56b1bb 100644
--- a/packages/localizations/src/zh-CN.ts
+++ b/packages/localizations/src/zh-CN.ts
@@ -126,6 +126,9 @@ export const zhCN: LocalizationResource = {
credit: undefined,
creditRemainder: undefined,
defaultFreePlanActive: undefined,
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: undefined,
getStarted: undefined,
highlightedPlanBadge: undefined,
@@ -137,6 +140,7 @@ export const zhCN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
+ months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
@@ -215,6 +219,7 @@ export const zhCN: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts
index 3b8462c96ea..8cbc5c3451a 100644
--- a/packages/localizations/src/zh-TW.ts
+++ b/packages/localizations/src/zh-TW.ts
@@ -129,6 +129,9 @@ export const zhTW: LocalizationResource = {
credit: '餘額',
creditRemainder: '您目前訂閱的剩餘期間的餘額。',
defaultFreePlanActive: '您目前正在免費計劃中',
+ discountAmount: undefined,
+ discountCyclesRemaining: undefined,
+ discountDuration: undefined,
free: '免費',
getStarted: '開始',
highlightedPlanBadge: '熱門',
@@ -140,6 +143,7 @@ export const zhTW: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: '每月',
+ months: undefined,
pastDue: '逾期',
pay: '支付 {{amount}}',
payerCreditRemainder: '來自帳戶餘額的折抵。',
@@ -218,6 +222,7 @@ export const zhTW: LocalizationResource = {
year: '年',
yearAbbreviation: undefined,
yearPerUnit: undefined,
+ years: undefined,
},
configureSSO: {
activate: {
diff --git a/packages/shared/src/types/billing.ts b/packages/shared/src/types/billing.ts
index 73de14061d9..65615681856 100644
--- a/packages/shared/src/types/billing.ts
+++ b/packages/shared/src/types/billing.ts
@@ -845,6 +845,10 @@ export interface BillingSubscriptionItemResource extends ClerkResource {
amount: BillingMoneyAmount;
};
credits?: BillingCredits;
+ /**
+ * The active discount applied to this subscription item.
+ */
+ appliedDiscount?: BillingDiscountRedemption;
/**
* Seat entitlement details for this subscription item. Only set for organization subscription items with
* seat-based billing.
@@ -1025,6 +1029,45 @@ export interface BillingProrationDiscount {
cyclePassedPercent: number;
}
+/**
+ * A catalog discount applied to a checkout or payment.
+ *
+ * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes.
+ */
+export interface BillingAppliedDiscount {
+ amount: BillingMoneyAmount;
+ discountId: string;
+ name: string;
+ effect: 'percentage' | 'fixed_amount';
+ percentOff?: number;
+ amountOff?: BillingMoneyAmount;
+ promoCode?: string;
+ cyclesRemaining: number | null;
+}
+
+/**
+ * A discount redemption applied to a subscription item.
+ *
+ * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes.
+ */
+export interface BillingDiscountRedemption {
+ id: string;
+ subscriptionItemId: string;
+ discountId: string;
+ name: string;
+ source: 'promotion' | 'manual' | 'promo_code';
+ promoCode?: string;
+ effect?: 'percentage' | 'fixed_amount';
+ percentOff?: number;
+ amountOff?: BillingMoneyAmount;
+ amount?: BillingMoneyAmount;
+ cyclesRemaining: number | null;
+ cyclesApplied: number;
+ status?: 'active' | 'exhausted' | 'removed';
+ redeemedAt: Date;
+ redeemedBy: string | null;
+}
+
/**
* Discounts applied to the checkout, such as prorated discounts for mid-cycle seat additions.
*
@@ -1037,6 +1080,10 @@ export interface BillingDiscounts {
* means you are not charged for the portion of the new seat's cycle that has already elapsed.
*/
proration: BillingProrationDiscount | null;
+ /**
+ * The catalog discount applied to the transaction. This field is omitted when no catalog discount applies.
+ */
+ discount?: BillingAppliedDiscount;
/**
* The total of all discounts applied to the checkout.
*/
diff --git a/packages/shared/src/types/json.ts b/packages/shared/src/types/json.ts
index 0a7f57efe6d..8ce3e6fe3d1 100644
--- a/packages/shared/src/types/json.ts
+++ b/packages/shared/src/types/json.ts
@@ -899,6 +899,7 @@ export interface BillingSubscriptionItemJSON extends ClerkResourceJSON {
*/
seats?: BillingSubscriptionItemSeatsJSON;
credits?: BillingCreditsJSON;
+ applied_discount?: BillingDiscountRedemptionJSON;
plan: BillingPlanJSON;
plan_period: BillingSubscriptionPlanPeriod;
price_id: string;
@@ -1012,6 +1013,36 @@ export interface BillingProrationDiscountJSON {
cycle_passed_percent: number;
}
+export interface BillingAppliedDiscountJSON {
+ amount: BillingMoneyAmountJSON;
+ discount_id: string;
+ name: string;
+ effect: 'percentage' | 'fixed_amount';
+ percent_off?: number;
+ amount_off?: BillingMoneyAmountJSON;
+ promo_code?: string;
+ cycles_remaining: number | null;
+}
+
+export interface BillingDiscountRedemptionJSON extends ClerkResourceJSON {
+ object: 'commerce_discount_redemption';
+ id: string;
+ subscription_item_id: string;
+ discount_id: string;
+ name: string;
+ source: 'promotion' | 'manual' | 'promo_code';
+ promo_code?: string;
+ effect?: 'percentage' | 'fixed_amount';
+ percent_off?: number;
+ amount_off?: BillingMoneyAmountJSON;
+ amount?: BillingMoneyAmountJSON;
+ cycles_remaining: number | null;
+ cycles_applied: number;
+ status?: 'active' | 'exhausted' | 'removed';
+ redeemed_at: number;
+ redeemed_by: string | null;
+}
+
/**
* Discounts applied to the checkout, such as prorated discounts for mid-cycle seat additions.
*
@@ -1024,6 +1055,10 @@ export interface BillingDiscountsJSON {
* means you are not charged for the portion of the new seat's cycle that has already elapsed.
*/
proration: BillingProrationDiscountJSON | null;
+ /**
+ * The catalog discount applied to the transaction. This field is omitted when no catalog discount applies.
+ */
+ discount?: BillingAppliedDiscountJSON;
/**
* The total of all discounts applied to the checkout.
*/
diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts
index efb96c465cc..2c073be283c 100644
--- a/packages/shared/src/types/localization.ts
+++ b/packages/shared/src/types/localization.ts
@@ -186,9 +186,11 @@ export type __internal_LocalizationResource = {
membershipRole__guestMember: LocalizationValue;
billing: {
month: LocalizationValue;
+ months: LocalizationValue;
monthAbbreviation: LocalizationValue;
monthPerUnit: LocalizationValue<'unitName'>;
year: LocalizationValue;
+ years: LocalizationValue;
yearAbbreviation: LocalizationValue;
yearPerUnit: LocalizationValue<'unitName'>;
free: LocalizationValue;
@@ -223,6 +225,9 @@ export type __internal_LocalizationResource = {
alwaysFree: LocalizationValue;
accountFunds: LocalizationValue;
defaultFreePlanActive: LocalizationValue;
+ discountAmount: LocalizationValue<'amount'>;
+ discountCyclesRemaining: LocalizationValue<'cycles' | 'period'>;
+ discountDuration: LocalizationValue<'amount' | 'cycles' | 'period'>;
viewFeatures: LocalizationValue;
seeAllFeatures: LocalizationValue;
viewPayment: LocalizationValue;
diff --git a/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx b/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
index bf512a9b447..874012906c3 100644
--- a/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
+++ b/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
@@ -5,6 +5,7 @@ import { useProtect } from '@/ui/common/Gate';
import { FullHeightLoader } from '@/ui/elements/FullHeightLoader';
import { ProfileSection } from '@/ui/elements/Section';
import { common } from '@/ui/styledSystem';
+import { toNegativeAmount } from '@/ui/utils/billing';
import { getSeatLimitAndIncludedSeatsLocalizationKey } from '@/ui/utils/billingPlanSeats';
import { isManageableSubscriptionItem } from '@/ui/utils/billingSubscription';
@@ -246,6 +247,68 @@ function SubscriptionOverviewRow({
);
}
+function SubscriptionDiscountRow({ subscriptionItem }: { subscriptionItem: BillingSubscriptionItemResource }) {
+ const { $, t } = useLocalizations();
+ const appliedDiscount = subscriptionItem.appliedDiscount;
+
+ if (!appliedDiscount || appliedDiscount.status !== 'active') {
+ return null;
+ }
+
+ const totalCycles =
+ appliedDiscount.cyclesRemaining === null ? null : appliedDiscount.cyclesApplied + appliedDiscount.cyclesRemaining;
+ const period = t(
+ subscriptionItem.planPeriod === 'annual' ? localizationKeys('billing.years') : localizationKeys('billing.months'),
+ ).toLocaleLowerCase();
+
+ const discountAmount =
+ appliedDiscount.effect === 'percentage' && appliedDiscount.percentOff !== undefined
+ ? `${appliedDiscount.percentOff}%`
+ : appliedDiscount.amountOff
+ ? $(appliedDiscount.amountOff)
+ : '';
+ const discountTitle = `${appliedDiscount.name} ${t(
+ totalCycles === null
+ ? localizationKeys('billing.discountAmount', { amount: discountAmount })
+ : localizationKeys('billing.discountDuration', {
+ amount: discountAmount,
+ cycles: totalCycles,
+ period,
+ }),
+ )}`;
+
+ return (
+
+ subscriptionItem.status === 'upcoming'
+ ? {
+ background: common.mutedBackground(t),
+ }
+ : {}
+ }
+ >
+ |
+
+ {discountTitle}
+ {appliedDiscount.cyclesRemaining !== null ? (
+
+ ) : null}
+
+ |
+
+ {appliedDiscount.amount ? $(toNegativeAmount(appliedDiscount.amount)) : null}
+ |
+
+ );
+}
+
function SubscriptionItemRow({
subscriptionItem,
length,
@@ -405,6 +468,7 @@ function SubscriptionItemRow({
) : null}
+
);
}
From c9d665965d50704e0912c6ad7011a378bce615a6 Mon Sep 17 00:00:00 2001
From: Mauricio Antunes
Date: Wed, 5 Aug 2026 12:15:28 -0300
Subject: [PATCH 2/3] feat(ui,backend): Show applied discounts on payments and
statements (#9337)
---
.../render-discounts-payment-statement.md | 6 +++
packages/backend/src/util/billing.ts | 14 +++++
.../PaymentAttempts/PaymentAttemptPage.tsx | 20 ++++++-
.../components/Statements/StatementPage.tsx | 12 +++++
packages/ui/src/utils/billing.ts | 52 ++++++++++++++++++-
5 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 .changeset/render-discounts-payment-statement.md
diff --git a/.changeset/render-discounts-payment-statement.md b/.changeset/render-discounts-payment-statement.md
new file mode 100644
index 00000000000..6c09d1d1906
--- /dev/null
+++ b/.changeset/render-discounts-payment-statement.md
@@ -0,0 +1,6 @@
+---
+'@clerk/ui': patch
+'@clerk/backend': patch
+---
+
+Show applied discount on billing payment attempts and statements.
diff --git a/packages/backend/src/util/billing.ts b/packages/backend/src/util/billing.ts
index ab22640d0c4..6a0b5708ad6 100644
--- a/packages/backend/src/util/billing.ts
+++ b/packages/backend/src/util/billing.ts
@@ -1,4 +1,6 @@
import type {
+ BillingAppliedDiscount,
+ BillingAppliedDiscountJSON,
BillingCredits,
BillingCreditsJSON,
BillingDiscounts,
@@ -51,6 +53,17 @@ const billingCreditsFromJSON = (credits: BillingCreditsJSON): BillingCredits =>
total: billingMoneyAmountFromJSON(credits.total),
});
+const billingAppliedDiscountFromJSON = (discount: BillingAppliedDiscountJSON): BillingAppliedDiscount => ({
+ amount: billingMoneyAmountFromJSON(discount.amount),
+ discountId: discount.discount_id,
+ name: discount.name,
+ effect: discount.effect,
+ percentOff: discount.percent_off,
+ amountOff: discount.amount_off ? billingMoneyAmountFromJSON(discount.amount_off) : undefined,
+ promoCode: discount.promo_code,
+ cyclesRemaining: discount.cycles_remaining,
+});
+
const billingDiscountsFromJSON = (discounts: BillingDiscountsJSON): BillingDiscounts => ({
proration: discounts.proration
? {
@@ -60,6 +73,7 @@ const billingDiscountsFromJSON = (discounts: BillingDiscountsJSON): BillingDisco
cyclePassedPercent: discounts.proration.cycle_passed_percent,
}
: null,
+ discount: discounts.discount ? billingAppliedDiscountFromJSON(discounts.discount) : undefined,
total: billingMoneyAmountFromJSON(discounts.total),
});
diff --git a/packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx b/packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx
index 55d57251b3d..d135dc0c005 100644
--- a/packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx
+++ b/packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx
@@ -5,7 +5,7 @@ import { Alert } from '@/ui/elements/Alert';
import { Header } from '@/ui/elements/Header';
import { LineItems } from '@/ui/elements/LineItems';
import { ProfileCard } from '@/ui/elements/ProfileCard';
-import { toNegativeAmount } from '@/ui/utils/billing';
+import { getDiscountDescription, toNegativeAmount } from '@/ui/utils/billing';
import { getPlanSeatLimit, getSeatsPerUnitTotal, summarizeSeatCharges } from '@/ui/utils/billingPlanSeats';
import { formatDate } from '@/ui/utils/formatDate';
import { truncateWithEndVisible } from '@/ui/utils/truncateTextWithEndVisible';
@@ -201,13 +201,14 @@ export const PaymentAttemptPage = () => {
};
function PaymentAttemptBody({ paymentAttempt }: { paymentAttempt: BillingPaymentResource | undefined }) {
- const { $ } = useLocalizations();
+ const { $, t } = useLocalizations();
if (!paymentAttempt) {
return null;
}
const { subscriptionItem } = paymentAttempt;
+ const catalogDiscount = paymentAttempt.totals?.discounts?.discount;
const fee =
subscriptionItem.planPeriod === 'month'
@@ -285,6 +286,21 @@ function PaymentAttemptBody({ paymentAttempt }: { paymentAttempt: BillingPayment
)}
+ {catalogDiscount && catalogDiscount.amount.amount > 0 && (
+
+ {catalogDiscount.promoCode} : null}
+ />
+
+
+ )}
{subscriptionItem.credits &&
subscriptionItem.credits.proration &&
subscriptionItem.credits.proration.amount.amount > 0 && (
diff --git a/packages/ui/src/components/Statements/StatementPage.tsx b/packages/ui/src/components/Statements/StatementPage.tsx
index 7112a58881a..8f1df7f5894 100644
--- a/packages/ui/src/components/Statements/StatementPage.tsx
+++ b/packages/ui/src/components/Statements/StatementPage.tsx
@@ -3,6 +3,7 @@ import { __internal_useStatementQuery } from '@clerk/shared/react/index';
import { Alert } from '@/ui/elements/Alert';
import { Header } from '@/ui/elements/Header';
import { ProfileCard } from '@/ui/elements/ProfileCard';
+import { getDiscountDescription } from '@/ui/utils/billing';
import { formatDate } from '@/ui/utils/formatDate';
import { useSubscriberTypeContext, useSubscriberTypeLocalizationRoot } from '../../contexts/components';
@@ -146,6 +147,17 @@ export const StatementPage = () => {
value={`(${$(item.totals.discounts.proration.amount)})`}
/>
) : null}
+ {item.totals?.discounts?.discount && item.totals.discounts.discount.amount.amount > 0 ? (
+
+ ) : null}
{item.subscriptionItem.credits &&
item.subscriptionItem.credits.proration &&
item.subscriptionItem.credits.proration.amount.amount > 0 ? (
diff --git a/packages/ui/src/utils/billing.ts b/packages/ui/src/utils/billing.ts
index fd528923a96..01766a9551a 100644
--- a/packages/ui/src/utils/billing.ts
+++ b/packages/ui/src/utils/billing.ts
@@ -1,4 +1,54 @@
-import type { BillingMoneyAmount } from '@clerk/shared/types/billing';
+import type { BillingMoneyAmount, BillingSubscriptionPlanPeriod } from '@clerk/shared/types/billing';
+
+import type { useLocalizations } from '../localization';
+import { localizationKeys } from '../localization';
+
+type Discount = {
+ effect?: 'percentage' | 'fixed_amount';
+ percentOff?: number;
+ amountOff?: BillingMoneyAmount;
+};
+
+type Localizations = Pick, '$' | 't'>;
+
+export function getDiscountDescription(
+ discount: Discount,
+ cycles: number | null,
+ planPeriod: BillingSubscriptionPlanPeriod,
+ { $, t }: Localizations,
+) {
+ const amount =
+ discount.effect === 'percentage' && discount.percentOff !== undefined
+ ? `${discount.percentOff}%`
+ : discount.amountOff
+ ? $(discount.amountOff)
+ : '';
+
+ if (cycles === null) {
+ return t(localizationKeys('billing.discountAmount', { amount }));
+ }
+
+ const period = getBillingPeriodLabel(planPeriod, cycles, t);
+ return t(localizationKeys('billing.discountDuration', { amount, cycles, period }));
+}
+
+export function getBillingPeriodLabel(
+ planPeriod: BillingSubscriptionPlanPeriod,
+ cycles: number,
+ t: Localizations['t'],
+) {
+ return t(
+ localizationKeys(
+ planPeriod === 'annual'
+ ? cycles === 1
+ ? 'billing.year'
+ : 'billing.years'
+ : cycles === 1
+ ? 'billing.month'
+ : 'billing.months',
+ ),
+ ).toLocaleLowerCase();
+}
/**
* Given a BillingMoneyAmount, convert positive values to negative. If the amount is already negative, leave it alone.
From 4e89c8c3c411d952be7c75da4e7c3c8c0538e0c8 Mon Sep 17 00:00:00 2001
From: Dylan Staley <88163+dstaley@users.noreply.github.com>
Date: Wed, 5 Aug 2026 15:08:25 -0500
Subject: [PATCH 3/3] feat(clerk-js,localizations,shared,ui): Add support for
promo codes at checkout (#9317)
---
.changeset/brown-guests-roll.md | 8 +
integration/tests/pricing-table.test.ts | 2 +-
packages/clerk-js/bundlewatch.config.json | 4 +-
.../src/core/modules/billing/namespace.ts | 14 ++
.../src/core/resources/BillingCheckout.ts | 42 ++++-
packages/localizations/src/ar-SA.ts | 5 +
packages/localizations/src/be-BY.ts | 5 +
packages/localizations/src/bg-BG.ts | 5 +
packages/localizations/src/bn-IN.ts | 5 +
packages/localizations/src/ca-ES.ts | 5 +
packages/localizations/src/cs-CZ.ts | 5 +
packages/localizations/src/da-DK.ts | 5 +
packages/localizations/src/de-DE.ts | 5 +
packages/localizations/src/el-GR.ts | 5 +
packages/localizations/src/en-GB.ts | 5 +
packages/localizations/src/en-US.ts | 9 +-
packages/localizations/src/es-CR.ts | 5 +
packages/localizations/src/es-ES.ts | 5 +
packages/localizations/src/es-MX.ts | 5 +
packages/localizations/src/es-UY.ts | 5 +
packages/localizations/src/fa-IR.ts | 5 +
packages/localizations/src/fi-FI.ts | 5 +
packages/localizations/src/fr-FR.ts | 5 +
packages/localizations/src/he-IL.ts | 5 +
packages/localizations/src/hi-IN.ts | 5 +
packages/localizations/src/hr-HR.ts | 5 +
packages/localizations/src/hu-HU.ts | 5 +
packages/localizations/src/id-ID.ts | 5 +
packages/localizations/src/is-IS.ts | 5 +
packages/localizations/src/it-IT.ts | 5 +
packages/localizations/src/ja-JP.ts | 5 +
packages/localizations/src/kk-KZ.ts | 5 +
packages/localizations/src/ko-KR.ts | 5 +
packages/localizations/src/mn-MN.ts | 5 +
packages/localizations/src/ms-MY.ts | 5 +
packages/localizations/src/nb-NO.ts | 5 +
packages/localizations/src/nl-BE.ts | 5 +
packages/localizations/src/nl-NL.ts | 5 +
packages/localizations/src/pl-PL.ts | 5 +
packages/localizations/src/pt-BR.ts | 5 +
packages/localizations/src/pt-PT.ts | 5 +
packages/localizations/src/ro-RO.ts | 5 +
packages/localizations/src/ru-RU.ts | 5 +
packages/localizations/src/sk-SK.ts | 5 +
packages/localizations/src/sr-RS.ts | 5 +
packages/localizations/src/sv-SE.ts | 5 +
packages/localizations/src/ta-IN.ts | 5 +
packages/localizations/src/te-IN.ts | 5 +
packages/localizations/src/th-TH.ts | 5 +
packages/localizations/src/tr-TR.ts | 5 +
packages/localizations/src/uk-UA.ts | 5 +
packages/localizations/src/vi-VN.ts | 5 +
packages/localizations/src/zh-CN.ts | 5 +
packages/localizations/src/zh-TW.ts | 5 +
packages/react/src/stateProxy.ts | 1 +
.../react/__tests__/payment-element.test.tsx | 1 +
packages/shared/src/types/billing.ts | 29 +++
packages/shared/src/types/localization.ts | 5 +
.../src/components/Checkout/CheckoutForm.tsx | 170 +++++++++++++++++-
.../Checkout/__tests__/Checkout.test.tsx | 170 ++++++++++++++++++
.../Subscriptions/SubscriptionsList.tsx | 29 +--
.../__tests__/SubscriptionsList.test.tsx | 15 ++
packages/ui/src/elements/LineItems.tsx | 17 +-
63 files changed, 719 insertions(+), 37 deletions(-)
create mode 100644 .changeset/brown-guests-roll.md
diff --git a/.changeset/brown-guests-roll.md b/.changeset/brown-guests-roll.md
new file mode 100644
index 00000000000..c0e1854f831
--- /dev/null
+++ b/.changeset/brown-guests-roll.md
@@ -0,0 +1,8 @@
+---
+'@clerk/localizations': minor
+'@clerk/clerk-js': minor
+'@clerk/shared': minor
+'@clerk/ui': minor
+---
+
+Add support for applying promo codes at checkout
diff --git a/integration/tests/pricing-table.test.ts b/integration/tests/pricing-table.test.ts
index 98b2b0a7e53..e0876409bd8 100644
--- a/integration/tests/pricing-table.test.ts
+++ b/integration/tests/pricing-table.test.ts
@@ -356,7 +356,7 @@ testAgainstRunningApps({})('pricing table @billing', ({ app }) => {
await expect(matchLineItem(u.po.checkout.root, 'Total Due after')).toBeHidden();
await expect(matchLineItem(u.po.checkout.root, 'Total due today', '$999.00')).toBeVisible();
- expect(await countLineItems(u.po.checkout.root)).toBe(3);
+ expect(await countLineItems(u.po.checkout.root)).toBe(4);
await u.po.checkout.root.getByRole('button', { name: /^pay\s\$/i }).waitFor({ state: 'visible' });
await u.po.checkout.clickPayOrSubscribe();
diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json
index a9bf078f735..018bebef844 100644
--- a/packages/clerk-js/bundlewatch.config.json
+++ b/packages/clerk-js/bundlewatch.config.json
@@ -1,8 +1,8 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "549KB" },
- { "path": "./dist/clerk.browser.js", "maxSize": "75KB" },
- { "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
+ { "path": "./dist/clerk.browser.js", "maxSize": "77KB" },
+ { "path": "./dist/clerk.legacy.browser.js", "maxSize": "119KB" },
{ "path": "./dist/clerk.no-rhc.js", "maxSize": "316KB" },
{ "path": "./dist/clerk.native.js", "maxSize": "76KB" },
{ "path": "./dist/vendors*.js", "maxSize": "7KB" },
diff --git a/packages/clerk-js/src/core/modules/billing/namespace.ts b/packages/clerk-js/src/core/modules/billing/namespace.ts
index 99f06cd319c..cb6874463d5 100644
--- a/packages/clerk-js/src/core/modules/billing/namespace.ts
+++ b/packages/clerk-js/src/core/modules/billing/namespace.ts
@@ -21,6 +21,7 @@ import type {
GetPlansParams,
GetStatementsParams,
GetSubscriptionParams,
+ UpdateCheckoutParams,
} from '@clerk/shared/types';
import { convertPageToOffsetSearchParams } from '../../../utils/convertPageToOffsetSearchParams';
@@ -149,6 +150,19 @@ export class Billing implements BillingNamespace {
return new BillingCheckout(json);
};
+ updateCheckout = async (params: UpdateCheckoutParams) => {
+ const { id, orgId, ...rest } = params;
+ const json = (
+ await BaseResource._fetch({
+ path: Billing.path(`/checkouts/${id}`, { orgId }),
+ method: 'PATCH',
+ body: rest as any,
+ })
+ )?.response as unknown as BillingCheckoutJSON;
+
+ return new BillingCheckout(json);
+ };
+
getCreditBalance = async (params: GetCreditBalanceParams): Promise => {
return await BaseResource._fetch({
path: Billing.path('/credits', { orgId: params.orgId }),
diff --git a/packages/clerk-js/src/core/resources/BillingCheckout.ts b/packages/clerk-js/src/core/resources/BillingCheckout.ts
index 19b9d8c5dc0..4e08ae2ef2c 100644
--- a/packages/clerk-js/src/core/resources/BillingCheckout.ts
+++ b/packages/clerk-js/src/core/resources/BillingCheckout.ts
@@ -14,6 +14,7 @@ import type {
CheckoutSignalValue,
ConfirmCheckoutParams,
CreateCheckoutParams,
+ UpdateCheckoutParams,
} from '@clerk/shared/types';
import { computed, endBatch, signal, startBatch } from 'alien-signals';
@@ -117,7 +118,7 @@ export const createSignals = () => {
return { resourceSignal, errorSignal, fetchSignal, computedSignal };
};
-type CheckoutTask = 'start' | 'confirm' | 'finalize';
+type CheckoutTask = 'start' | 'update' | 'confirm' | 'finalize';
export class CheckoutFlow implements CheckoutFlowResourceNonStrict {
private resource = new BillingCheckout(null);
@@ -197,6 +198,24 @@ export class CheckoutFlow implements CheckoutFlowResourceNonStrict {
});
}
+ async update(params: Pick): Promise<{ error: ClerkError | null }> {
+ if (!this.resource.id) {
+ throw new Error('Clerk: `start()` must be called before `update()`');
+ }
+ return this.runAsyncCheckoutTask(
+ 'update',
+ async () => {
+ this.resource = (await BillingCheckout.clerk.billing?.updateCheckout({
+ id: this.resource.id,
+ orgId: this.resource.payer.organizationId || undefined,
+ ...params,
+ })) as BillingCheckout;
+ },
+ undefined,
+ false,
+ );
+ }
+
async finalize(params?: CheckoutFlowFinalizeParams): Promise<{ error: ClerkError | null }> {
const { navigate } = params || {};
return this.runAsyncCheckoutTask('finalize', async () => {
@@ -208,13 +227,23 @@ export class CheckoutFlow implements CheckoutFlowResourceNonStrict {
});
}
- private runAsyncCheckoutTask(operationType: CheckoutTask, task: () => Promise, beforeTask?: () => void) {
+ private runAsyncCheckoutTask(
+ operationType: CheckoutTask,
+ task: () => Promise,
+ beforeTask?: () => void,
+ updateErrorSignal = true,
+ ) {
// Noops during transitive state
if (typeof BillingCheckout.clerk.user === 'undefined') {
console.warn('Clerk: Checkout operations cannot be performed during transitive state');
return { error: null };
}
- return createRunAsyncCheckoutTask(this, this.signals, this.pendingOperations)(operationType, task, beforeTask);
+ return createRunAsyncCheckoutTask(this, this.signals, this.pendingOperations)(
+ operationType,
+ task,
+ beforeTask,
+ updateErrorSignal,
+ );
}
}
@@ -226,8 +255,9 @@ function createRunAsyncCheckoutTask(
operationType: CheckoutTask,
task: () => Promise,
beforeTask?: () => void,
+ updateErrorSignal?: boolean,
) => Promise<{ error: ClerkError | null }> {
- return async (operationType, task, beforeTask?: () => void) => {
+ return async (operationType, task, beforeTask?: () => void, updateErrorSignal = true) => {
if (pendingOperations.get(operationType)) {
// Wait for the existing operation to complete and return its result
// If it fails, all callers should receive the same error
@@ -246,7 +276,9 @@ function createRunAsyncCheckoutTask(
signals.resourceSignal({ resource: resource });
return { error: null };
} catch (err) {
- signals.errorSignal({ error: err });
+ if (updateErrorSignal) {
+ signals.errorSignal({ error: err });
+ }
return { error: err };
} finally {
pendingOperations.delete(operationType);
diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts
index 596a5584f6f..9cd27120c13 100644
--- a/packages/localizations/src/ar-SA.ts
+++ b/packages/localizations/src/ar-SA.ts
@@ -100,8 +100,11 @@ export const arSA: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const arSA: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts
index dc084c9cb5c..431205e47ca 100644
--- a/packages/localizations/src/be-BY.ts
+++ b/packages/localizations/src/be-BY.ts
@@ -100,8 +100,11 @@ export const beBY: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const beBY: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts
index e745c6c0113..9306da5af14 100644
--- a/packages/localizations/src/bg-BG.ts
+++ b/packages/localizations/src/bg-BG.ts
@@ -101,8 +101,11 @@ export const bgBG: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -117,6 +120,8 @@ export const bgBG: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts
index 246d73cdabc..b95016e9eea 100644
--- a/packages/localizations/src/bn-IN.ts
+++ b/packages/localizations/src/bn-IN.ts
@@ -105,8 +105,11 @@ export const bnIN: LocalizationResource = {
cannotSubscribeUnrecoverable:
'আপনি এই প্ল্যানে সাবস্ক্রাইব করতে পারবেন না। আপনার বিদ্যমান সাবস্ক্রিপশন এই প্ল্যানের চেয়ে বেশি ব্যয়বহুল।',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'আপনার পেমেন্ট সফল হয়েছে।',
description__subscriptionSuccessful: 'আপনার নতুন সাবস্ক্রিপশন সম্পূর্ণ প্রস্তুত।',
+ discount: undefined,
downgradeNotice:
'বিলিং চক্রের শেষ পর্যন্ত আপনি আপনার বর্তমান সাবস্ক্রিপশন এবং এর বৈশিষ্ট্যগুলি রাখবেন, তারপরে আপনাকে এই সাবস্ক্রিপশনে স্যুইচ করা হবে।',
emailForm: {
@@ -122,6 +125,8 @@ export const bnIN: LocalizationResource = {
},
pastDueNotice: 'আপনার পূর্ববর্তী সাবস্ক্রিপশন বকেয়া ছিল, কোনো পেমেন্ট ছাড়াই।',
perMonth: 'প্রতি মাসে',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'চেকআউট',
title__paymentSuccessful: 'পেমেন্ট সফল হয়েছে!',
title__subscriptionSuccessful: 'সফল!',
diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts
index b072019fa84..335fd3f6198 100644
--- a/packages/localizations/src/ca-ES.ts
+++ b/packages/localizations/src/ca-ES.ts
@@ -105,8 +105,11 @@ export const caES: LocalizationResource = {
cannotSubscribeUnrecoverable:
"No pots subscriure't a aquest pla. La teva subscripció actual és més cara que aquest pla.",
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: "El teu pagament s'ha realitzat correctament.",
description__subscriptionSuccessful: 'La teva nova subscripció està a punt.',
+ discount: undefined,
downgradeNotice:
'Mantindràs la teva subscripció actual i les seves funcions fins al final del cicle de facturació; després es canviarà a aquesta subscripció.',
emailForm: {
@@ -123,6 +126,8 @@ export const caES: LocalizationResource = {
},
pastDueNotice: 'La teva subscripció anterior tenia un pagament pendent.',
perMonth: 'al mes',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Pagament',
title__paymentSuccessful: 'Pagament realitzat amb èxit!',
title__subscriptionSuccessful: 'Tot a punt!',
diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts
index 515881fbf28..d071a25cee0 100644
--- a/packages/localizations/src/cs-CZ.ts
+++ b/packages/localizations/src/cs-CZ.ts
@@ -103,8 +103,11 @@ export const csCZ: LocalizationResource = {
'Nelze se přihlásit k tomuto plánu s měsíční platbou. Abyste se k němu přihlásili, musíte zvolit roční platbu.',
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Vaše platba byla úspěšná.',
description__subscriptionSuccessful: 'Vaše nové předplatné je nastaveno.',
+ discount: undefined,
downgradeNotice:
'Současné předplatné a jeho funkce si ponecháte do konce fakturačního cyklu, poté budete převedeni na toto předplatné.',
emailForm: {
@@ -120,6 +123,8 @@ export const csCZ: LocalizationResource = {
},
pastDueNotice: 'Vaše předchozí předplatné bylo po splatnosti, bez platby.',
perMonth: 'měsíčně',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Pokladna',
title__paymentSuccessful: 'Platba byla úspěšná!',
title__subscriptionSuccessful: 'Úspěch!',
diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts
index bf4b56f20c5..4b92e5824ad 100644
--- a/packages/localizations/src/da-DK.ts
+++ b/packages/localizations/src/da-DK.ts
@@ -100,8 +100,11 @@ export const daDK: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const daDK: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts
index d296dd770e6..3452a759cf2 100644
--- a/packages/localizations/src/de-DE.ts
+++ b/packages/localizations/src/de-DE.ts
@@ -105,8 +105,11 @@ export const deDE: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Sie können diesen Plan nicht abonnieren. Ihr vorhandenes Abonnement ist teurer als dieser Plan.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Ihre Bezahlung war erfolgreich.',
description__subscriptionSuccessful: 'Ihr Abonnement wurde erfolgreich aktiviert.',
+ discount: undefined,
downgradeNotice:
'Sie behalten Ihr aktuelles Abonnement bis zum Ende des Abrechnungszeitraums. So lange können Sie weiterhin alle Funktionen nutzen, danach werden Sie auf dieses Abonnement umgestellt.',
emailForm: {
@@ -122,6 +125,8 @@ export const deDE: LocalizationResource = {
},
pastDueNotice: 'Ihr vorheriges Abonnement war überfällig, ohne Zahlung.',
perMonth: 'pro Monat',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Bezahlung',
title__paymentSuccessful: 'Zahlung erfolgreich!',
title__subscriptionSuccessful: 'Geschafft!',
diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts
index a3ab5b1daaf..f8eafb4d040 100644
--- a/packages/localizations/src/el-GR.ts
+++ b/packages/localizations/src/el-GR.ts
@@ -100,8 +100,11 @@ export const elGR: LocalizationResource = {
cannotSubscribeMonthly: 'Δεν μπορείτε να εγγραφείτε μηνιαίως σε αυτό το πλάνο',
cannotSubscribeUnrecoverable: 'Δεν μπορείτε να εγγραφείτε σε αυτό το πλάνο αυτήν τη στιγμή',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Η πληρωμή σας ολοκληρώθηκε επιτυχώς',
description__subscriptionSuccessful: 'Η συνδρομή σας ξεκίνησε επιτυχώς',
+ discount: undefined,
downgradeNotice: 'Θα υποβαθμιστείτε στο τέλος της τρέχουσας περιόδου χρέωσης',
emailForm: {
subtitle: 'Εισάγετε τη διεύθυνση email σας για να συνεχίσετε',
@@ -116,6 +119,8 @@ export const elGR: LocalizationResource = {
},
pastDueNotice: 'Η συνδρομή σας είναι ληξιπρόθεσμη. Παρακαλώ ενημερώστε τη μέθοδο πληρωμής σας.',
perMonth: 'ανά μήνα',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Ολοκλήρωση πληρωμής',
title__paymentSuccessful: 'Επιτυχής πληρωμή',
title__subscriptionSuccessful: 'Επιτυχής συνδρομή',
diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts
index bd379c1eacc..28d1b445039 100644
--- a/packages/localizations/src/en-GB.ts
+++ b/packages/localizations/src/en-GB.ts
@@ -100,8 +100,11 @@ export const enGB: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const enGB: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts
index 86d4c3ab782..3c558fba21a 100644
--- a/packages/localizations/src/en-US.ts
+++ b/packages/localizations/src/en-US.ts
@@ -94,8 +94,11 @@ export const enUS: LocalizationResource = {
cannotSubscribeUnrecoverable:
'You cannot subscribe to this plan. Your existing subscription is more expensive than this plan.',
checkout: {
+ addPromoCode: 'Add promo code',
+ applyPromoCode: 'Apply',
description__paymentSuccessful: 'Your payment was successful.',
description__subscriptionSuccessful: 'Your new subscription is all set.',
+ discount: 'Discount',
downgradeNotice:
'You will keep your current subscription and its features until the end of the billing cycle, then you will be switched to this subscription.',
emailForm: {
@@ -111,6 +114,8 @@ export const enUS: LocalizationResource = {
},
pastDueNotice: 'Your previous subscription was past due, with no payment.',
perMonth: 'per month',
+ promoCodePlaceholder: 'Enter promo code',
+ removePromoCode: 'Remove promo code',
title: 'Checkout',
title__paymentSuccessful: 'Payment was successful!',
title__subscriptionSuccessful: 'Success!',
@@ -121,9 +126,9 @@ export const enUS: LocalizationResource = {
credit: 'Credit',
creditRemainder: 'Credit for the remainder of your current subscription.',
defaultFreePlanActive: "You're currently on the Free plan",
- discountAmount: '({{amount}} off)',
+ discountAmount: '{{amount}} off',
discountCyclesRemaining: '{{cycles}} {{period}} remaining',
- discountDuration: '({{amount}} off first {{cycles}} {{period}})',
+ discountDuration: '{{amount}} off first {{cycles}} {{period}}',
free: 'Free',
getStarted: 'Get started',
highlightedPlanBadge: 'Popular',
diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts
index fe7b4477816..529164af2b0 100644
--- a/packages/localizations/src/es-CR.ts
+++ b/packages/localizations/src/es-CR.ts
@@ -100,8 +100,11 @@ export const esCR: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Tu nueva suscripción está lista.',
description__subscriptionSuccessful: 'Tu nueva suscripción está lista.',
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const esCR: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: '¡Pago exitoso!',
title__subscriptionSuccessful: '¡Éxito!',
diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts
index 5e70ef929cd..9278ddc234c 100644
--- a/packages/localizations/src/es-ES.ts
+++ b/packages/localizations/src/es-ES.ts
@@ -104,8 +104,11 @@ export const esES: LocalizationResource = {
'No puedes suscribirte a este plan con pago mensual. Para suscribirte, debes elegir el pago anual.',
cannotSubscribeUnrecoverable: 'No puedes suscribirte a este plan. Tu suscripción actual es más cara que este plan.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Tu pago se ha realizado correctamente.',
description__subscriptionSuccessful: 'Tu nueva suscripción está lista.',
+ discount: undefined,
downgradeNotice:
'Mantendrás tu suscripción actual y sus funciones hasta el final del ciclo de facturación; después se te cambiará a esta suscripción.',
emailForm: {
@@ -122,6 +125,8 @@ export const esES: LocalizationResource = {
},
pastDueNotice: 'Tu suscripción anterior tenía un pago pendiente.',
perMonth: 'al mes',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Pago',
title__paymentSuccessful: '¡Pago realizado con éxito!',
title__subscriptionSuccessful: '¡Todo listo!',
diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts
index 130e9fae55e..5aac172a435 100644
--- a/packages/localizations/src/es-MX.ts
+++ b/packages/localizations/src/es-MX.ts
@@ -101,8 +101,11 @@ export const esMX: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -117,6 +120,8 @@ export const esMX: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: '¡Pago exitoso!',
title__subscriptionSuccessful: '¡Éxito!',
diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts
index 7a3fc1447e6..f6eaf9d3813 100644
--- a/packages/localizations/src/es-UY.ts
+++ b/packages/localizations/src/es-UY.ts
@@ -100,8 +100,11 @@ export const esUY: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const esUY: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts
index 18620d3648f..549f81c35db 100644
--- a/packages/localizations/src/fa-IR.ts
+++ b/packages/localizations/src/fa-IR.ts
@@ -103,8 +103,11 @@ export const faIR: LocalizationResource = {
'شما نمیتوانید با پرداخت ماهانه در این طرح مشترک شوید. برای عضویت در این طرح، باید پرداخت سالانه را انتخاب کنید.',
cannotSubscribeUnrecoverable: 'شما نمیتوانید در این طرح مشترک شوید. اشتراک موجود شما گرانتر از این طرح است.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'پرداخت شما با موفقیت انجام شد.',
description__subscriptionSuccessful: 'اشتراک شما با موفقیت ایجاد شد.',
+ discount: undefined,
downgradeNotice:
'شما اشتراک فعلی و ویژگیهای آن را تا پایان دوره صورتحساب حفظ خواهید کرد، سپس به این اشتراک منتقل خواهید شد.',
emailForm: {
@@ -121,6 +124,8 @@ export const faIR: LocalizationResource = {
},
pastDueNotice: 'اشتراک قبلی شما سررسید گذشته بود، بدون پرداخت.',
perMonth: 'ماهانه',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'تسویه حساب',
title__paymentSuccessful: 'پرداخت موفقیت آمیز بود!',
title__subscriptionSuccessful: 'موفقیت آمیز!',
diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts
index 65802a743c7..c9db40cff10 100644
--- a/packages/localizations/src/fi-FI.ts
+++ b/packages/localizations/src/fi-FI.ts
@@ -105,8 +105,11 @@ export const fiFI: LocalizationResource = {
'Et voi tilata tätä pakettia kuukausimaksulla. Tilataksesi tämän sinun on valittava vuositilaus.',
cannotSubscribeUnrecoverable: 'Et voi tilata tätä pakettia. Nykyinen tilauksesi on kalliimpi kuin tämä paketti.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Maksusi onnistui.',
description__subscriptionSuccessful: 'Uusi tilauksesi on valmis.',
+ discount: undefined,
downgradeNotice:
'Säilytät nykyisen tilauksesi ja sen ominaisuudet laskutuskauden loppuun asti, minkä jälkeen siirryt tähän tilaukseen.',
emailForm: {
@@ -122,6 +125,8 @@ export const fiFI: LocalizationResource = {
},
pastDueNotice: 'Edellinen tilauksesi oli erääntynyt eikä maksua ole suoritettu.',
perMonth: 'kuukaudessa',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Kassa',
title__paymentSuccessful: 'Maksu onnistui!',
title__subscriptionSuccessful: 'Onnistui!',
diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts
index 1d60760ae9b..da88015b5ac 100644
--- a/packages/localizations/src/fr-FR.ts
+++ b/packages/localizations/src/fr-FR.ts
@@ -106,8 +106,11 @@ export const frFR: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Vous ne pouvez pas souscrire à ce plan. Votre abonnement actuel est plus cher que celui-ci.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Votre paiement a été effectué avec succès.',
description__subscriptionSuccessful: 'Votre nouvel abonnement est prêt.',
+ discount: undefined,
downgradeNotice:
"Vous conserverez votre abonnement actuel et ses fonctionnalités jusqu'à la fin du cycle de facturation, puis vous passerez à cet abonnement.",
emailForm: {
@@ -124,6 +127,8 @@ export const frFR: LocalizationResource = {
},
pastDueNotice: 'Votre abonnement précédent était en retard de paiement.',
perMonth: 'par mois',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Paiement',
title__paymentSuccessful: 'Le paiement a réussi !',
title__subscriptionSuccessful: 'Succès !',
diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts
index 59a888b6cbc..6061280e560 100644
--- a/packages/localizations/src/he-IL.ts
+++ b/packages/localizations/src/he-IL.ts
@@ -100,8 +100,11 @@ export const heIL: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const heIL: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts
index f98367ebfe2..731f704f194 100644
--- a/packages/localizations/src/hi-IN.ts
+++ b/packages/localizations/src/hi-IN.ts
@@ -105,8 +105,11 @@ export const hiIN: LocalizationResource = {
'आप मासिक भुगतान करके इस योजना की सदस्यता नहीं ले सकते। इस योजना की सदस्यता लेने के लिए, आपको वार्षिक भुगतान करना चुनना होगा।',
cannotSubscribeUnrecoverable: 'आप इस योजना की सदस्यता नहीं ले सकते। आपकी मौजूदा सदस्यता इस योजना से अधिक महंगी है।',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'आपका भुगतान सफल रहा।',
description__subscriptionSuccessful: 'आपकी नई सदस्यता पूरी तरह तैयार है।',
+ discount: undefined,
downgradeNotice:
'बिलिंग चक्र के अंत तक आप अपनी मौजूदा सदस्यता और उसकी सुविधाएँ रखेंगे, फिर आपको इस सदस्यता पर स्विच कर दिया जाएगा।',
emailForm: {
@@ -122,6 +125,8 @@ export const hiIN: LocalizationResource = {
},
pastDueNotice: 'आपकी पिछली सदस्यता बकाया थी, बिना किसी भुगतान के।',
perMonth: 'प्रति माह',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'चेकआउट',
title__paymentSuccessful: 'भुगतान सफल रहा!',
title__subscriptionSuccessful: 'सफल!',
diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts
index 07769ee5155..51e7055601e 100644
--- a/packages/localizations/src/hr-HR.ts
+++ b/packages/localizations/src/hr-HR.ts
@@ -106,8 +106,11 @@ export const hrHR: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Ne možete se pretplatiti na ovaj plan. Vaša postojeća pretplata je skuplja od ovog plana.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Vaše plaćanje je uspješno.',
description__subscriptionSuccessful: 'Vaša nova pretplata je spremna.',
+ discount: undefined,
downgradeNotice:
'Zadržat ćete svoju trenutnu pretplatu i njezine značajke do kraja obračunskog razdoblja, nakon čega ćete biti prebačeni na ovu pretplatu.',
emailForm: {
@@ -123,6 +126,8 @@ export const hrHR: LocalizationResource = {
},
pastDueNotice: 'Vaša prethodna pretplata je bila dospjela, bez plaćanja.',
perMonth: 'mjesečno',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Naplata',
title__paymentSuccessful: 'Plaćanje je uspjelo!',
title__subscriptionSuccessful: 'Uspjeh!',
diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts
index 9567f27be83..3c81b4651de 100644
--- a/packages/localizations/src/hu-HU.ts
+++ b/packages/localizations/src/hu-HU.ts
@@ -106,8 +106,11 @@ export const huHU: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Nem tudsz előfizetni erre a csomagra. A jelenlegi előfizetésed drágább, mint ez a csomag.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'A fizetés sikeres volt.',
description__subscriptionSuccessful: 'Az új előfizetésed beállítva.',
+ discount: undefined,
downgradeNotice:
'A jelenlegi előfizetésed és funkciói a számlázási ciklus végéig megmaradnak, ezután átváltunk erre az előfizetésre.',
emailForm: {
@@ -123,6 +126,8 @@ export const huHU: LocalizationResource = {
},
pastDueNotice: 'Az előző előfizetésed lejárt, fizetés nélkül.',
perMonth: 'havonta',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Pénztár',
title__paymentSuccessful: 'Sikeres fizetés!',
title__subscriptionSuccessful: 'Sikeres!',
diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts
index 7f2ccfcf54f..4d1348a7e16 100644
--- a/packages/localizations/src/id-ID.ts
+++ b/packages/localizations/src/id-ID.ts
@@ -100,8 +100,11 @@ export const idID: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const idID: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts
index 05bfdadb026..c38e7410f2b 100644
--- a/packages/localizations/src/is-IS.ts
+++ b/packages/localizations/src/is-IS.ts
@@ -105,8 +105,11 @@ export const isIS: LocalizationResource = {
'Þú getur ekki skráð þig í þessa áskrift með mánaðarlegri greiðslu. Til að skrá þig þarftu að velja árlega greiðslu.',
cannotSubscribeUnrecoverable: 'Þú getur ekki skráð þig í þessa áskrift. Núverandi áskrift þín er dýrari en þessi.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Greiðsla þín tókst.',
description__subscriptionSuccessful: 'Nýja áskriftin þín er tilbúin.',
+ discount: undefined,
downgradeNotice:
'Þú heldur núverandi áskrift og eiginleikum hennar til loka greiðslutímabilsins, síðan verður þú flutt yfir í þessa áskrift.',
emailForm: {
@@ -122,6 +125,8 @@ export const isIS: LocalizationResource = {
},
pastDueNotice: 'Fyrri áskrift þín var gjaldfallin, án greiðslu.',
perMonth: 'á mánuði',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Greiðsla',
title__paymentSuccessful: 'Greiðsla tókst!',
title__subscriptionSuccessful: 'Tókst!',
diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts
index f605a2ce8df..126242f8e81 100644
--- a/packages/localizations/src/it-IT.ts
+++ b/packages/localizations/src/it-IT.ts
@@ -104,8 +104,11 @@ export const itIT: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Non puoi abbonarti a questo piano. Il tuo abbonamento esistente è più costoso di questo piano.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Il pagamento è andato a buon fine.',
description__subscriptionSuccessful: 'Il tuo nuovo abbonamento è pronto.',
+ discount: undefined,
downgradeNotice:
'Manterrai il tuo abbonamento attuale e le sue funzionalità fino alla fine del ciclo di fatturazione, quindi passerai a questo abbonamento.',
emailForm: {
@@ -122,6 +125,8 @@ export const itIT: LocalizationResource = {
},
pastDueNotice: 'Il tuo precedente abbonamento era scaduto, senza alcun pagamento.',
perMonth: 'al mese',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Checkout',
title__paymentSuccessful: 'Pagamento riuscito!',
title__subscriptionSuccessful: 'Successo!',
diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts
index 34f10d76d06..db672198c3f 100644
--- a/packages/localizations/src/ja-JP.ts
+++ b/packages/localizations/src/ja-JP.ts
@@ -106,8 +106,11 @@ export const jaJP: LocalizationResource = {
cannotSubscribeUnrecoverable:
'このプランを契約することはできません。現在のサブスクリプションの方がこのプランより高額です。',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: '支払いが完了しました。',
description__subscriptionSuccessful: '新しいサブスクリプションの設定が完了しました。',
+ discount: undefined,
downgradeNotice:
'現在の請求期間が終了するまでは既存のサブスクリプションとその機能を利用でき、その後このサブスクリプションに切り替わります。',
emailForm: {
@@ -123,6 +126,8 @@ export const jaJP: LocalizationResource = {
},
pastDueNotice: '前回のサブスクリプションには未払い分が残っています。',
perMonth: '月あたり',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'チェックアウト',
title__paymentSuccessful: '支払いが完了しました!',
title__subscriptionSuccessful: '成功しました!',
diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts
index a7a835090e7..e7e9b32406d 100644
--- a/packages/localizations/src/kk-KZ.ts
+++ b/packages/localizations/src/kk-KZ.ts
@@ -100,8 +100,11 @@ export const kkKZ: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Сіздің жаңа жазылымыңыз дайын.',
description__subscriptionSuccessful: 'Сіздің жаңа жазылымыңыз дайын.',
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const kkKZ: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: 'Төлем сәтті аяқталды!',
title__subscriptionSuccessful: 'Сәтті!',
diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts
index a7c5739f8ee..fb6314dd941 100644
--- a/packages/localizations/src/ko-KR.ts
+++ b/packages/localizations/src/ko-KR.ts
@@ -104,8 +104,11 @@ export const koKR: LocalizationResource = {
cannotSubscribeMonthly: '이 플랜은 월간 결제가 불가해요. 연간 결제를 선택해 주세요.',
cannotSubscribeUnrecoverable: '이 플랜으로 구독할 수 없어요. 현재 구독이 더 높은 요금제예요.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: '결제가 완료됐어요.',
description__subscriptionSuccessful: '새 구독이 준비됐어요.',
+ discount: undefined,
downgradeNotice: '현재 구독은 결제 주기 종료까지 유지되고, 이후 이 구독으로 전환돼요.',
emailForm: {
subtitle: '결제를 완료하려면 영수증을 받을 이메일 주소를 추가해야 해요.',
@@ -120,6 +123,8 @@ export const koKR: LocalizationResource = {
},
pastDueNotice: '이전 구독이 연체되어 결제가 되지 않았어요.',
perMonth: '월',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: '결제',
title__paymentSuccessful: '결제가 완료됐어요!',
title__subscriptionSuccessful: '성공!',
diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts
index 3719a4c6625..6f5b02c1cfd 100644
--- a/packages/localizations/src/mn-MN.ts
+++ b/packages/localizations/src/mn-MN.ts
@@ -100,8 +100,11 @@ export const mnMN: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const mnMN: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts
index 319765d7d5b..dafaf669dc4 100644
--- a/packages/localizations/src/ms-MY.ts
+++ b/packages/localizations/src/ms-MY.ts
@@ -106,8 +106,11 @@ export const msMY: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Anda tidak boleh melanggan pelan ini. Langganan sedia ada anda lebih mahal daripada pelan ini.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Pembayaran anda berjaya.',
description__subscriptionSuccessful: 'Langganan baharu anda telah sedia.',
+ discount: undefined,
downgradeNotice:
'Anda akan mengekalkan langganan semasa anda dan cirinya sehingga akhir kitaran pengebilan, kemudian anda akan ditukar kepada langganan ini.',
emailForm: {
@@ -124,6 +127,8 @@ export const msMY: LocalizationResource = {
},
pastDueNotice: 'Langganan anda sebelum ini tertunggak, tanpa pembayaran.',
perMonth: 'sebulan',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Pembayaran',
title__paymentSuccessful: 'Pembayaran berjaya!',
title__subscriptionSuccessful: 'Berjaya!',
diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts
index 665c9f8f746..bae7549516c 100644
--- a/packages/localizations/src/nb-NO.ts
+++ b/packages/localizations/src/nb-NO.ts
@@ -106,8 +106,11 @@ export const nbNO: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Du kan ikke abonnere på denne planen. Ditt eksisterende abonnement er dyrere enn denne planen.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Betalingen din var vellykket.',
description__subscriptionSuccessful: 'Ditt nye abonnement er klart.',
+ discount: undefined,
downgradeNotice:
'Du beholder ditt nåværende abonnement og dets funksjoner til slutten av faktureringsperioden, deretter byttes du til dette abonnementet.',
emailForm: {
@@ -123,6 +126,8 @@ export const nbNO: LocalizationResource = {
},
pastDueNotice: 'Ditt forrige abonnement var forfalt, uten betaling.',
perMonth: 'per måned',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Kasse',
title__paymentSuccessful: 'Betalingen var vellykket!',
title__subscriptionSuccessful: 'Fullført!',
diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts
index ff7e9b30a40..5c6b71f19fd 100644
--- a/packages/localizations/src/nl-BE.ts
+++ b/packages/localizations/src/nl-BE.ts
@@ -100,8 +100,11 @@ export const nlBE: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const nlBE: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts
index 135300b7d98..eb730b5c818 100644
--- a/packages/localizations/src/nl-NL.ts
+++ b/packages/localizations/src/nl-NL.ts
@@ -100,8 +100,11 @@ export const nlNL: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const nlNL: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts
index 55a39875928..46b4ae7d912 100644
--- a/packages/localizations/src/pl-PL.ts
+++ b/packages/localizations/src/pl-PL.ts
@@ -100,8 +100,11 @@ export const plPL: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const plPL: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts
index 1690a10bdb3..37c396d3fe8 100644
--- a/packages/localizations/src/pt-BR.ts
+++ b/packages/localizations/src/pt-BR.ts
@@ -104,8 +104,11 @@ export const ptBR: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Você não pode assinar este plano. Sua assinatura existente é mais cara que este plano.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Seu pagamento foi realizado com sucesso.',
description__subscriptionSuccessful: 'Sua nova assinatura está pronta.',
+ discount: undefined,
downgradeNotice:
'Você manterá sua assinatura atual e seus recursos até o final do ciclo de faturamento, após o qual você será transferido para este plano.',
emailForm: {
@@ -122,6 +125,8 @@ export const ptBR: LocalizationResource = {
},
pastDueNotice: 'Sua assinatura anterior estava em atraso, sem pagamento.',
perMonth: 'por mês',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Checkout',
title__paymentSuccessful: 'Pagamento realizado com sucesso!',
title__subscriptionSuccessful: 'Sucesso!',
diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts
index 71a1fe6f066..6c7d7fb0291 100644
--- a/packages/localizations/src/pt-PT.ts
+++ b/packages/localizations/src/pt-PT.ts
@@ -106,8 +106,11 @@ export const ptPT: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Não pode subscrever este plano. A sua subscrição atual é mais dispendiosa do que este plano.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'O seu pagamento foi efetuado com sucesso.',
description__subscriptionSuccessful: 'A sua nova subscrição está pronta.',
+ discount: undefined,
downgradeNotice:
'Manterá a sua subscrição atual e respetivas funcionalidades até ao fim do ciclo de faturação e, depois disso, passará para esta subscrição.',
emailForm: {
@@ -124,6 +127,8 @@ export const ptPT: LocalizationResource = {
},
pastDueNotice: 'A sua subscrição anterior encontrava-se em atraso, sem pagamento.',
perMonth: 'por mês',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Finalizar compra',
title__paymentSuccessful: 'Pagamento efetuado com sucesso!',
title__subscriptionSuccessful: 'Sucesso!',
diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts
index f66fb24d412..f541ec4b043 100644
--- a/packages/localizations/src/ro-RO.ts
+++ b/packages/localizations/src/ro-RO.ts
@@ -105,8 +105,11 @@ export const roRO: LocalizationResource = {
cannotSubscribeUnrecoverable:
'Nu te poți abona la acest plan. Abonamentul tău actual este mai scump decât acest plan.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Plata ta a fost efectuată cu succes.',
description__subscriptionSuccessful: 'Noul tău abonament este configurat.',
+ discount: undefined,
downgradeNotice:
'Vei păstra abonamentul curent și funcțiile sale până la finalul ciclului de facturare, apoi vei fi schimbat la acest abonament.',
emailForm: {
@@ -122,6 +125,8 @@ export const roRO: LocalizationResource = {
},
pastDueNotice: 'Abonamentul anterior era restant, fără plată.',
perMonth: 'pe lună',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Plată',
title__paymentSuccessful: 'Plata a reușit!',
title__subscriptionSuccessful: 'Succes!',
diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts
index 242bfdfb0fc..f289adaa41f 100644
--- a/packages/localizations/src/ru-RU.ts
+++ b/packages/localizations/src/ru-RU.ts
@@ -100,8 +100,11 @@ export const ruRU: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const ruRU: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts
index 331ef956835..a972297b275 100644
--- a/packages/localizations/src/sk-SK.ts
+++ b/packages/localizations/src/sk-SK.ts
@@ -100,8 +100,11 @@ export const skSK: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const skSK: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts
index 1eaff6c0504..eedbe97319e 100644
--- a/packages/localizations/src/sr-RS.ts
+++ b/packages/localizations/src/sr-RS.ts
@@ -100,8 +100,11 @@ export const srRS: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const srRS: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts
index 5696ee4a76b..fa4746e80da 100644
--- a/packages/localizations/src/sv-SE.ts
+++ b/packages/localizations/src/sv-SE.ts
@@ -100,8 +100,11 @@ export const svSE: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const svSE: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts
index 72322b38fa3..821ce49c87b 100644
--- a/packages/localizations/src/ta-IN.ts
+++ b/packages/localizations/src/ta-IN.ts
@@ -107,8 +107,11 @@ export const taIN: LocalizationResource = {
cannotSubscribeUnrecoverable:
'இந்த திட்டத்திற்கு நீங்கள் சந்தா செலுத்த முடியாது. உங்கள் தற்போதைய சந்தா இந்த திட்டத்தை விட விலை அதிகம்.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'உங்கள் கட்டணம் வெற்றிகரமாக முடிந்தது.',
description__subscriptionSuccessful: 'உங்கள் புதிய சந்தா முழுமையாகத் தயாராக உள்ளது.',
+ discount: undefined,
downgradeNotice:
'பில்லிங் சுழற்சியின் முடிவு வரை உங்கள் தற்போதைய சந்தாவையும் அதன் அம்சங்களையும் வைத்திருப்பீர்கள், பின்னர் நீங்கள் இந்த சந்தாவிற்கு மாற்றப்படுவீர்கள்.',
emailForm: {
@@ -124,6 +127,8 @@ export const taIN: LocalizationResource = {
},
pastDueNotice: 'உங்கள் முந்தைய சந்தா நிலுவையில் இருந்தது, கட்டணம் எதுவும் இல்லாமல்.',
perMonth: 'மாதத்திற்கு',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'செக்அவுட்',
title__paymentSuccessful: 'கட்டணம் வெற்றிகரமாக முடிந்தது!',
title__subscriptionSuccessful: 'வெற்றி!',
diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts
index 52afc8d930c..207a330b33b 100644
--- a/packages/localizations/src/te-IN.ts
+++ b/packages/localizations/src/te-IN.ts
@@ -106,8 +106,11 @@ export const teIN: LocalizationResource = {
cannotSubscribeUnrecoverable:
'మీరు ఈ ప్లాన్కు సబ్స్క్రైబ్ చేయలేరు. మీ ప్రస్తుత సబ్స్క్రిప్షన్ ఈ ప్లాన్ కంటే ఖరీదైనది.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'మీ చెల్లింపు విజయవంతమైంది.',
description__subscriptionSuccessful: 'మీ కొత్త సబ్స్క్రిప్షన్ పూర్తిగా సిద్ధంగా ఉంది.',
+ discount: undefined,
downgradeNotice:
'బిల్లింగ్ చక్రం ముగిసే వరకు మీరు మీ ప్రస్తుత సబ్స్క్రిప్షన్ను మరియు దాని ఫీచర్లను ఉంచుకుంటారు, ఆ తర్వాత మీరు ఈ సబ్స్క్రిప్షన్కు మార్చబడతారు.',
emailForm: {
@@ -123,6 +126,8 @@ export const teIN: LocalizationResource = {
},
pastDueNotice: 'మీ మునుపటి సబ్స్క్రిప్షన్ చెల్లింపు లేకుండా బకాయిగా ఉంది.',
perMonth: 'నెలకు',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'చెక్అవుట్',
title__paymentSuccessful: 'చెల్లింపు విజయవంతమైంది!',
title__subscriptionSuccessful: 'విజయం!',
diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts
index 612c2ae5651..8cd8bc93cec 100644
--- a/packages/localizations/src/th-TH.ts
+++ b/packages/localizations/src/th-TH.ts
@@ -103,8 +103,11 @@ export const thTH: LocalizationResource = {
cannotSubscribeMonthly: 'คุณไม่สามารถสมัครแผนนี้โดยการชำระรายเดือน หากต้องการสมัครแผนนี้ คุณต้องเลือกชำระรายปี',
cannotSubscribeUnrecoverable: 'คุณไม่สามารถสมัครแผนนี้ได้ การสมัครสมาชิกปัจจุบันของคุณมีราคาแพงกว่าแผนนี้',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'การชำระเงินของคุณสำเร็จ',
description__subscriptionSuccessful: 'การสมัครสมาชิกใหม่ของคุณพร้อมแล้ว',
+ discount: undefined,
downgradeNotice:
'คุณจะยังคงใช้การสมัครสมาชิกปัจจุบันและฟีเจอร์ของมันจนจบรอบบิล จากนั้นคุณจะถูกเปลี่ยนไปใช้การสมัครสมาชิกนี้',
emailForm: {
@@ -120,6 +123,8 @@ export const thTH: LocalizationResource = {
},
pastDueNotice: 'การสมัครสมาชิกก่อนหน้าของคุณเกินกำหนดและไม่มีการชำระเงิน',
perMonth: 'ต่อเดือน',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'ชำระเงิน',
title__paymentSuccessful: 'ชำระเงินสำเร็จ!',
title__subscriptionSuccessful: 'สำเร็จ!',
diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts
index 0396bedcad3..1d2544e54d6 100644
--- a/packages/localizations/src/tr-TR.ts
+++ b/packages/localizations/src/tr-TR.ts
@@ -100,8 +100,11 @@ export const trTR: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const trTR: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts
index eb102f1969d..1f59d61c211 100644
--- a/packages/localizations/src/uk-UA.ts
+++ b/packages/localizations/src/uk-UA.ts
@@ -100,8 +100,11 @@ export const ukUA: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const ukUA: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts
index d9c0fad274d..ad8368e63ae 100644
--- a/packages/localizations/src/vi-VN.ts
+++ b/packages/localizations/src/vi-VN.ts
@@ -105,8 +105,11 @@ export const viVN: LocalizationResource = {
'Bạn không thể đăng ký gói này bằng cách thanh toán hàng tháng. Để đăng ký gói này, bạn cần chọn thanh toán hàng năm.',
cannotSubscribeUnrecoverable: 'Bạn không thể đăng ký gói này. Gói đăng ký hiện tại của bạn đắt hơn gói này.',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: 'Thanh toán của bạn đã thành công.',
description__subscriptionSuccessful: 'Đăng ký mới của bạn đã được thiết lập.',
+ discount: undefined,
downgradeNotice:
'Bạn sẽ giữ đăng ký hiện tại và các tính năng của nó cho đến cuối chu kỳ thanh toán, sau đó bạn sẽ được chuyển sang đăng ký này.',
emailForm: {
@@ -122,6 +125,8 @@ export const viVN: LocalizationResource = {
},
pastDueNotice: 'Đăng ký trước của bạn đã quá hạn và chưa thanh toán.',
perMonth: 'hàng tháng',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: 'Thanh toán',
title__paymentSuccessful: 'Thanh toán thành công!',
title__subscriptionSuccessful: 'Thành công!',
diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts
index 9e32d56b1bb..ee47c162a81 100644
--- a/packages/localizations/src/zh-CN.ts
+++ b/packages/localizations/src/zh-CN.ts
@@ -100,8 +100,11 @@ export const zhCN: LocalizationResource = {
cannotSubscribeMonthly: undefined,
cannotSubscribeUnrecoverable: undefined,
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: undefined,
description__subscriptionSuccessful: undefined,
+ discount: undefined,
downgradeNotice: undefined,
emailForm: {
subtitle: undefined,
@@ -116,6 +119,8 @@ export const zhCN: LocalizationResource = {
},
pastDueNotice: undefined,
perMonth: undefined,
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: undefined,
title__paymentSuccessful: undefined,
title__subscriptionSuccessful: undefined,
diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts
index 8cbc5c3451a..bdfc40a0d19 100644
--- a/packages/localizations/src/zh-TW.ts
+++ b/packages/localizations/src/zh-TW.ts
@@ -103,8 +103,11 @@ export const zhTW: LocalizationResource = {
cannotSubscribeMonthly: '您無法每月支付訂閱此計劃。要訂閱此計劃,您需要選擇每年支付。',
cannotSubscribeUnrecoverable: '您無法訂閱此計劃。您的現有訂閱比此計劃更昂貴。',
checkout: {
+ addPromoCode: undefined,
+ applyPromoCode: undefined,
description__paymentSuccessful: '您的付款已成功。',
description__subscriptionSuccessful: '您的訂閱已成功設定。',
+ discount: undefined,
downgradeNotice: '您將保留目前的訂閱及其功能直到本計費週期結束,然後您將被切換到此訂閱。',
emailForm: {
subtitle: '在您可以完成購買之前,您必須新增一個電子郵件地址,以便發送收據。',
@@ -119,6 +122,8 @@ export const zhTW: LocalizationResource = {
},
pastDueNotice: '您的上一個訂閱已逾期,未付款。',
perMonth: '每月',
+ promoCodePlaceholder: undefined,
+ removePromoCode: undefined,
title: '結帳',
title__paymentSuccessful: '付款成功!',
title__subscriptionSuccessful: '成功!',
diff --git a/packages/react/src/stateProxy.ts b/packages/react/src/stateProxy.ts
index 47832c63227..3066d4e1583 100644
--- a/packages/react/src/stateProxy.ts
+++ b/packages/react/src/stateProxy.ts
@@ -439,6 +439,7 @@ export class StateProxy implements State {
},
start: this.gateMethod, 'start'>(target, 'start'),
+ update: this.gateMethod, 'update'>(target, 'update'),
confirm: this.gateMethod, 'confirm'>(target, 'confirm'),
finalize: this.gateMethod, 'finalize'>(target, 'finalize'),
},
diff --git a/packages/shared/src/react/__tests__/payment-element.test.tsx b/packages/shared/src/react/__tests__/payment-element.test.tsx
index 4138738d563..82bd939516c 100644
--- a/packages/shared/src/react/__tests__/payment-element.test.tsx
+++ b/packages/shared/src/react/__tests__/payment-element.test.tsx
@@ -143,6 +143,7 @@ describe('PaymentElement Localization', () => {
error: null,
fetchStatus: 'idle' as const,
confirm: vi.fn(),
+ update: vi.fn(),
start: vi.fn(),
clear: vi.fn(),
finalize: vi.fn(),
diff --git a/packages/shared/src/types/billing.ts b/packages/shared/src/types/billing.ts
index 65615681856..5d90e45d24b 100644
--- a/packages/shared/src/types/billing.ts
+++ b/packages/shared/src/types/billing.ts
@@ -85,6 +85,14 @@ export interface BillingNamespace {
*/
startCheckout: (params: CreateCheckoutParams) => Promise;
+ /**
+ * Applies or removes a promo code on an existing Billing checkout for the current user or supplied Organization.
+ * @returns A [`BillingCheckoutResource`](/docs/reference/types/billing-checkout-resource) object.
+ *
+ * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes.
+ */
+ updateCheckout: (params: UpdateCheckoutParams) => Promise;
+
/**
* Gets the credit balance for the current payer.
* @returns A [`BillingCreditBalanceResource`](https://clerk.com/docs/reference/types/billing-credit-balance-resource) object.
@@ -1288,6 +1296,22 @@ export type CreateCheckoutParams = WithOptionalOrgType<{
priceId?: string;
}>;
+/**
+ * The `updateCheckout()` method accepts the following parameters.
+ *
+ * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes.
+ */
+export type UpdateCheckoutParams = WithOptionalOrgType<{
+ /**
+ * The unique identifier for the checkout session.
+ */
+ id: string;
+ /**
+ * The promo code to apply. Use an empty string to remove the applied promo code.
+ */
+ promoCode: string;
+}>;
+
/**
* The `confirm()` method accepts the following parameters. **Only one of `paymentMethodId`, `paymentToken`, or `useTestCard` should be provided.**
*
@@ -1516,6 +1540,11 @@ export interface CheckoutFlowFinalizeParams {
* Common methods available on all checkout flow instances.
*/
interface CheckoutFlowMethods {
+ /**
+ * Updates the current checkout. Use an empty promo code to remove the applied promo code.
+ */
+ update: (params: Pick) => Promise<{ error: ClerkError | null }>;
+
/**
* A function to confirm and finalize the checkout process, usually after payment information has been provided and validated. [Learn more.](#confirm)
*/
diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts
index 2c073be283c..5f2a29de1c2 100644
--- a/packages/shared/src/types/localization.ts
+++ b/packages/shared/src/types/localization.ts
@@ -303,6 +303,11 @@ export type __internal_LocalizationResource = {
};
};
checkout: {
+ addPromoCode: LocalizationValue;
+ applyPromoCode: LocalizationValue;
+ discount: LocalizationValue;
+ promoCodePlaceholder: LocalizationValue;
+ removePromoCode: LocalizationValue;
title: LocalizationValue;
title__paymentSuccessful: LocalizationValue;
title__subscriptionSuccessful: LocalizationValue;
diff --git a/packages/ui/src/components/Checkout/CheckoutForm.tsx b/packages/ui/src/components/Checkout/CheckoutForm.tsx
index 00e23e79ff1..6c6c708383e 100644
--- a/packages/ui/src/components/Checkout/CheckoutForm.tsx
+++ b/packages/ui/src/components/Checkout/CheckoutForm.tsx
@@ -1,3 +1,4 @@
+import { isClerkAPIResponseError } from '@clerk/shared/error';
import { __experimental_useCheckout as useCheckout } from '@clerk/shared/react';
import type { BillingPaymentMethodResource, ConfirmCheckoutParams, RemoveFunctions } from '@clerk/shared/types';
import { useMemo, useState } from 'react';
@@ -10,7 +11,7 @@ import { LineItems } from '@/ui/elements/LineItems';
import { SegmentedControl } from '@/ui/elements/SegmentedControl';
import { Select, SelectButton, SelectOptionList } from '@/ui/elements/Select';
import { Tooltip } from '@/ui/elements/Tooltip';
-import { toNegativeAmount } from '@/ui/utils/billing';
+import { getDiscountDescription, toNegativeAmount } from '@/ui/utils/billing';
import {
getCheckoutSeatUnitTotal,
getIncludedSeatsUnitTotalTier,
@@ -28,12 +29,14 @@ import {
descriptors,
Flex,
Form,
+ Icon,
+ Input,
localizationKeys,
Spinner,
Text,
useLocalizations,
} from '../../customizables';
-import { ChevronUpDown, InformationCircle } from '../../icons';
+import { ChevronUpDown, Close, InformationCircle } from '../../icons';
import type { PropsOfComponent, ThemableCssProp } from '../../styledSystem';
import * as AddPaymentMethod from '../PaymentMethods/AddPaymentMethod';
import { PaymentMethodRow } from '../PaymentMethods/PaymentMethodRow';
@@ -45,6 +48,165 @@ const capitalize = (name: string) => name[0].toUpperCase() + name.slice(1);
const HIDDEN_INPUT_NAME = 'payment_method_id';
+const promoCodeErrorMessage = (error: unknown) => {
+ if (isClerkAPIResponseError(error)) {
+ return error.errors[0]?.longMessage || error.errors[0]?.message;
+ }
+ return error instanceof Error ? error.message : undefined;
+};
+
+const useUpdatePromoCode = () => {
+ const { checkout } = useCheckout();
+ const { t } = useLocalizations();
+ const [error, setError] = useState();
+ const [isLoading, setIsLoading] = useState(false);
+
+ const updatePromoCode = async (value: string) => {
+ setError(undefined);
+ setIsLoading(true);
+ const result = await checkout.update({ promoCode: value });
+ setIsLoading(false);
+
+ if (result.error) {
+ setError(promoCodeErrorMessage(result.error) || t(localizationKeys('unstable__errors.form_param_value_invalid')));
+ return false;
+ }
+
+ return true;
+ };
+
+ return { error, isLoading, setError, updatePromoCode };
+};
+
+const AppliedPromoCodeRow = () => {
+ const { checkout } = useCheckout();
+ const { $, t } = useLocalizations();
+ const { isLoading, updatePromoCode } = useUpdatePromoCode();
+ const discount = checkout.status === 'needs_confirmation' ? checkout.totals.discounts?.discount : undefined;
+ const appliedPromoCode = discount?.promoCode;
+
+ if (!discount || !appliedPromoCode) {
+ return null;
+ }
+
+ return (
+
+ void updatePromoCode('')}
+ sx={{
+ padding: 0,
+ position: 'relative',
+ '&::after': {
+ content: '""',
+ position: 'absolute',
+ inset: '-18px',
+ },
+ }}
+ >
+
+
+ }
+ />
+
+
+ );
+};
+
+const PromoCodeInput = () => {
+ const { checkout } = useCheckout();
+ const { t } = useLocalizations();
+ const [promoCode, setPromoCode] = useState('');
+ const { error, isLoading, setError, updatePromoCode } = useUpdatePromoCode();
+
+ if (checkout.status !== 'needs_confirmation' || checkout.totals.discounts?.discount) {
+ return null;
+ }
+
+ const errorId = 'checkout-promo-code-error';
+
+ return (
+ ({
+ padding: theme.space.$4,
+ borderBottomWidth: theme.borderWidths.$normal,
+ borderBottomStyle: theme.borderStyles.$solid,
+ borderBottomColor: theme.colors.$borderAlpha100,
+ })}
+ >
+ {
+ event.preventDefault();
+ void updatePromoCode(promoCode.trim()).then(success => {
+ if (success) {
+ setPromoCode('');
+ }
+ });
+ }}
+ sx={theme => ({
+ display: 'grid',
+ gridTemplateColumns: 'minmax(0, 1fr) auto',
+ gap: theme.space.$2,
+ })}
+ >
+ {
+ setPromoCode(event.target.value);
+ setError(undefined);
+ }}
+ />
+
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+
+ );
+};
+
export const CheckoutForm = withCardStateProvider(() => {
const { checkout } = useCheckout();
const { $ } = useLocalizations();
@@ -172,6 +334,8 @@ export const CheckoutForm = withCardStateProvider(() => {
)}
+
+
{!!freeTrialEndsAt && !!plan.freeTrialDays && totals.totalDueAfterFreeTrial ? (
{
+
+
{showDowngradeInfo && (
{
});
});
+ describe('promo codes', () => {
+ const money = (amount: number, amountFormatted: string) => ({
+ amount,
+ amountFormatted,
+ currency: 'USD',
+ currencySymbol: '$',
+ });
+
+ const plan = {
+ id: 'plan_promo',
+ name: 'Pro',
+ description: 'Pro plan',
+ features: [],
+ fee: money(12989, '129.89'),
+ annualFee: money(155868, '1,558.68'),
+ annualMonthlyFee: money(12989, '129.89'),
+ slug: 'pro',
+ avatarUrl: '',
+ publiclyVisible: true,
+ isDefault: true,
+ isRecurring: true,
+ hasBaseFee: true,
+ forPayerType: 'user',
+ freeTrialDays: 0,
+ freeTrialEnabled: false,
+ };
+
+ const checkout = {
+ id: 'chk_promo',
+ status: 'needs_confirmation',
+ externalClientSecret: 'cs_test_promo',
+ externalGatewayId: 'gw_test',
+ totals: {
+ subtotal: money(12989, '129.89'),
+ baseFee: money(12989, '129.89'),
+ grandTotal: money(12989, '129.89'),
+ taxTotal: money(0, '0.00'),
+ credit: money(0, '0.00'),
+ pastDue: money(0, '0.00'),
+ totalDueNow: money(12989, '129.89'),
+ totalDuePerPeriod: money(12989, '129.89'),
+ discounts: null,
+ },
+ isImmediatePlanChange: true,
+ planPeriod: 'month',
+ plan,
+ payer: { organizationId: null },
+ paymentMethod: undefined,
+ confirm: vi.fn(),
+ freeTrialEndsAt: null,
+ needsPaymentMethod: false,
+ };
+
+ it('shows an inline error when a promo code cannot be applied', async () => {
+ const { wrapper, fixtures } = await createFixtures(f => {
+ f.withUser({ email_addresses: ['test@clerk.com'] });
+ f.withBilling();
+ });
+
+ fixtures.clerk.user?.getPaymentMethods.mockResolvedValue({ data: [], total_count: 0 });
+ fixtures.clerk.billing.startCheckout.mockResolvedValue(checkout as any);
+ fixtures.clerk.billing.updateCheckout.mockRejectedValue(new Error('Invalid promo code'));
+
+ const { baseElement, getByRole, userEvent } = render(
+ {}}
+ >
+
+ ,
+ { wrapper },
+ );
+
+ const input = await waitFor(() => getByRole('textbox', { name: 'Enter promo code' }));
+ const lineItemsRoot = baseElement.querySelector('.cl-checkoutFormLineItemsRoot');
+ expect(lineItemsRoot?.nextElementSibling).toContainElement(input);
+ await userEvent.type(input, 'INVALID');
+ await userEvent.click(getByRole('button', { name: 'Apply' }));
+
+ await waitFor(() => {
+ expect(fixtures.clerk.billing.updateCheckout).toHaveBeenCalledWith(
+ expect.objectContaining({ id: 'chk_promo', promoCode: 'INVALID' }),
+ );
+ expect(input).toHaveAttribute('aria-invalid', 'true');
+ expect(getByRole('alert')).toHaveTextContent('Invalid promo code');
+ });
+ });
+
+ it('shows and removes an applied promo code with its applied amount and duration', async () => {
+ const { wrapper, fixtures } = await createFixtures(f => {
+ f.withUser({ email_addresses: ['test@clerk.com'] });
+ f.withBilling();
+ });
+
+ const appliedCheckout = {
+ ...checkout,
+ totals: {
+ ...checkout.totals,
+ grandTotal: money(10391, '103.91'),
+ totalDueNow: money(10391, '103.91'),
+ discounts: {
+ proration: {
+ amount: money(500, '5.00'),
+ cycleDaysPassed: 15,
+ cycleDaysTotal: 30,
+ cyclePassedPercent: 50,
+ },
+ discount: {
+ amount: money(2598, '25.98'),
+ amountOff: money(5000, '50.00'),
+ discountId: 'disc_20',
+ name: '20% off first month',
+ effect: 'percentage',
+ percentOff: 20,
+ promoCode: 'WELCOME20',
+ cyclesRemaining: 1,
+ },
+ total: money(2598, '25.98'),
+ },
+ },
+ };
+
+ fixtures.clerk.user?.getPaymentMethods.mockResolvedValue({ data: [], total_count: 0 });
+ fixtures.clerk.billing.startCheckout.mockResolvedValue(checkout as any);
+ fixtures.clerk.billing.updateCheckout
+ .mockResolvedValueOnce(appliedCheckout as any)
+ .mockResolvedValueOnce(checkout as any);
+
+ const { getByRole, getByText, queryByRole, queryByText, userEvent } = render(
+ {}}
+ >
+
+ ,
+ { wrapper },
+ );
+
+ await userEvent.type(await waitFor(() => getByRole('textbox', { name: 'Enter promo code' })), 'WELCOME20');
+ await userEvent.click(getByRole('button', { name: 'Apply' }));
+
+ await waitFor(() => {
+ expect(getByText('WELCOME20')).toBeVisible();
+ expect(getByText('20% off first 1 month')).toBeVisible();
+ expect(getByText('-$25.98')).toBeVisible();
+ expect(queryByText('-$50.00')).toBeNull();
+ expect(getByText('Prorated discount').closest('.cl-lineItemsGroup')?.nextElementSibling).toBe(
+ getByText('WELCOME20').closest('.cl-lineItemsGroup'),
+ );
+ expect(queryByRole('textbox', { name: 'Enter promo code' })).toBeNull();
+ });
+
+ await userEvent.click(getByRole('button', { name: 'Remove promo code' }));
+
+ await waitFor(() => {
+ expect(fixtures.clerk.billing.updateCheckout).toHaveBeenLastCalledWith(
+ expect.objectContaining({ id: 'chk_promo', promoCode: '' }),
+ );
+ expect(queryByText('WELCOME20')).toBeNull();
+ expect(getByRole('textbox', { name: 'Enter promo code' })).toBeVisible();
+ });
+ });
+ });
+
describe('differentiates between new subscriptions and mid-cycle seat additions in checkout totals', () => {
const proPlan = {
id: 'plan_totals',
diff --git a/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx b/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
index 874012906c3..b73a026b625 100644
--- a/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
+++ b/packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
@@ -5,7 +5,7 @@ import { useProtect } from '@/ui/common/Gate';
import { FullHeightLoader } from '@/ui/elements/FullHeightLoader';
import { ProfileSection } from '@/ui/elements/Section';
import { common } from '@/ui/styledSystem';
-import { toNegativeAmount } from '@/ui/utils/billing';
+import { getBillingPeriodLabel, getDiscountDescription, toNegativeAmount } from '@/ui/utils/billing';
import { getSeatLimitAndIncludedSeatsLocalizationKey } from '@/ui/utils/billingPlanSeats';
import { isManageableSubscriptionItem } from '@/ui/utils/billingSubscription';
@@ -257,25 +257,12 @@ function SubscriptionDiscountRow({ subscriptionItem }: { subscriptionItem: Billi
const totalCycles =
appliedDiscount.cyclesRemaining === null ? null : appliedDiscount.cyclesApplied + appliedDiscount.cyclesRemaining;
- const period = t(
- subscriptionItem.planPeriod === 'annual' ? localizationKeys('billing.years') : localizationKeys('billing.months'),
- ).toLocaleLowerCase();
-
- const discountAmount =
- appliedDiscount.effect === 'percentage' && appliedDiscount.percentOff !== undefined
- ? `${appliedDiscount.percentOff}%`
- : appliedDiscount.amountOff
- ? $(appliedDiscount.amountOff)
- : '';
- const discountTitle = `${appliedDiscount.name} ${t(
- totalCycles === null
- ? localizationKeys('billing.discountAmount', { amount: discountAmount })
- : localizationKeys('billing.discountDuration', {
- amount: discountAmount,
- cycles: totalCycles,
- period,
- }),
- )}`;
+ const discountTitle = `${appliedDiscount.name} (${getDiscountDescription(
+ appliedDiscount,
+ totalCycles,
+ subscriptionItem.planPeriod,
+ { $, t },
+ )})`;
return (
) : null}
diff --git a/packages/ui/src/components/Subscriptions/__tests__/SubscriptionsList.test.tsx b/packages/ui/src/components/Subscriptions/__tests__/SubscriptionsList.test.tsx
index 9993b9db8d2..b3a673ca191 100644
--- a/packages/ui/src/components/Subscriptions/__tests__/SubscriptionsList.test.tsx
+++ b/packages/ui/src/components/Subscriptions/__tests__/SubscriptionsList.test.tsx
@@ -303,6 +303,20 @@ describe('SubscriptionsList', () => {
status: 'active' as const,
isFreeTrial: false,
pastDueAt: null,
+ appliedDiscount: {
+ id: 'redemption_active',
+ subscriptionItemId: 'sub_active',
+ discountId: 'discount_active',
+ name: 'Summer sale',
+ source: 'promo_code' as const,
+ effect: 'percentage' as const,
+ percentOff: 20,
+ cyclesRemaining: 2,
+ cyclesApplied: 1,
+ status: 'active' as const,
+ redeemedAt: new Date('2021-01-01'),
+ redeemedBy: null,
+ },
cancel: vi.fn(),
pathRoot: '',
reload: vi.fn(),
@@ -327,6 +341,7 @@ describe('SubscriptionsList', () => {
expect(getByText('Pro Plan')).toBeVisible();
// Active subscription should show the Active badge
expect(queryByText(/^Active$/)).toBeNull();
+ expect(getByText('Summer sale (20% off first 3 months)')).toBeVisible();
});
});
diff --git a/packages/ui/src/elements/LineItems.tsx b/packages/ui/src/elements/LineItems.tsx
index 161a007e387..56a8e933acc 100644
--- a/packages/ui/src/elements/LineItems.tsx
+++ b/packages/ui/src/elements/LineItems.tsx
@@ -108,7 +108,7 @@ const Title = React.forwardRef(({ title, descr
...common.textVariants(t)[textVariant],
})}
>
- {title ? (
+ {title || badge ? (
({
display: 'inline-flex',
@@ -123,7 +123,7 @@ const Title = React.forwardRef(({ title, descr
aria-hidden
/>
) : null}
-
+ {title ? : null}
{badge ? {badge} : null}
) : null}
@@ -169,9 +169,18 @@ interface DescriptionProps {
copyLabel?: string;
prefix?: string | LocalizationKey;
suffix?: string | LocalizationKey;
+ descriptionInnerAlignment?: 'start' | 'center' | 'end';
}
-function Description({ text, prefix, suffix, truncateText = false, copyText = false, copyLabel }: DescriptionProps) {
+function Description({
+ text,
+ prefix,
+ suffix,
+ truncateText = false,
+ copyText = false,
+ copyLabel,
+ descriptionInnerAlignment = 'end',
+}: DescriptionProps) {
const context = React.useContext(GroupContext);
if (!context) {
throw new Error('LineItems.Description must be used within LineItems.Group');
@@ -192,7 +201,7 @@ function Description({ text, prefix, suffix, truncateText = false, copyText = fa
sx={t => ({
display: 'inline-flex',
justifyContent: 'flex-end',
- alignItems: 'end',
+ alignItems: descriptionInnerAlignment,
gap: t.space.$1,
minWidth: '0',
})}