Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/green-dolphins-discount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@clerk/clerk-js': patch
'@clerk/localizations': patch
'@clerk/shared': patch
'@clerk/ui': patch
---

Show applied discounts in the subscription overview.
2 changes: 1 addition & 1 deletion packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{ "path": "./dist/clerk.browser.js", "maxSize": "75KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.no-rhc.js", "maxSize": "316KB" },
{ "path": "./dist/clerk.native.js", "maxSize": "74KB" },
{ "path": "./dist/clerk.native.js", "maxSize": "76KB" },
{ "path": "./dist/vendors*.js", "maxSize": "7KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "36KB" },
{ "path": "./dist/base-account-sdk*.js", "maxSize": "207KB" },
Expand Down
4 changes: 4 additions & 0 deletions packages/clerk-js/src/core/resources/BillingSubscription.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {
BillingCredits,
BillingDiscountRedemption,
BillingMoneyAmount,
BillingSubscriptionItemJSON,
BillingSubscriptionItemNextPayment,
Expand All @@ -18,6 +19,7 @@ import { unixEpochToDate } from '@/utils/date';

import {
billingCreditsFromJSON,
billingDiscountRedemptionFromJSON,
billingMoneyAmountFromJSON,
billingPerUnitTotalTierFromJSON,
billingSubscriptionItemNextPaymentFromJSON,
Expand Down Expand Up @@ -85,6 +87,7 @@ export class BillingSubscriptionItem extends BaseResource implements BillingSubs
};
seats?: BillingSubscriptionItemSeats;
credits?: BillingCredits;
appliedDiscount?: BillingDiscountRedemption;
nextPayment?: BillingSubscriptionItemNextPayment | null;
isFreeTrial!: boolean;

Expand Down Expand Up @@ -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
Expand Down
84 changes: 84 additions & 0 deletions packages/clerk-js/src/utils/__tests__/billing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
import { describe, expect, it } from 'vitest';

import {
billingDiscountRedemptionFromJSON,
billingPaymentTotalsFromJSON,
billingSubscriptionItemNextPaymentFromJSON,
billingSubscriptionNextPaymentFromJSON,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
},
};
Expand All @@ -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);
});

Expand Down Expand Up @@ -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 }],
Expand All @@ -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 = {
Expand Down
34 changes: 34 additions & 0 deletions packages/clerk-js/src/utils/billing.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type {
BillingAppliedDiscount,
BillingAppliedDiscountJSON,
BillingCheckoutTotals,
BillingCheckoutTotalsJSON,
BillingCredits,
BillingCreditsJSON,
BillingDiscountRedemption,
BillingDiscountRedemptionJSON,
BillingDiscounts,
BillingDiscountsJSON,
BillingMoneyAmount,
Expand Down Expand Up @@ -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),
Expand Down
5 changes: 5 additions & 0 deletions packages/localizations/src/ar-SA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -137,6 +140,7 @@ export const arSA: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
Expand Down Expand Up @@ -215,6 +219,7 @@ export const arSA: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
years: undefined,
},
configureSSO: {
activate: {
Expand Down
5 changes: 5 additions & 0 deletions packages/localizations/src/be-BY.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -137,6 +140,7 @@ export const beBY: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
Expand Down Expand Up @@ -215,6 +219,7 @@ export const beBY: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
years: undefined,
},
configureSSO: {
activate: {
Expand Down
5 changes: 5 additions & 0 deletions packages/localizations/src/bg-BG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -138,6 +141,7 @@ export const bgBG: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: undefined,
months: undefined,
pastDue: undefined,
pay: undefined,
payerCreditRemainder: undefined,
Expand Down Expand Up @@ -216,6 +220,7 @@ export const bgBG: LocalizationResource = {
year: undefined,
yearAbbreviation: undefined,
yearPerUnit: undefined,
years: undefined,
},
configureSSO: {
activate: {
Expand Down
5 changes: 5 additions & 0 deletions packages/localizations/src/bn-IN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ export const bnIN: LocalizationResource = {
credit: 'ক্রেডিট',
creditRemainder: 'আপনার বর্তমান সাবস্ক্রিপশনের অবশিষ্ট সময়ের জন্য ক্রেডিট।',
defaultFreePlanActive: 'আপনি বর্তমানে বিনামূল্যের প্ল্যানে আছেন',
discountAmount: undefined,
discountCyclesRemaining: undefined,
discountDuration: undefined,
free: 'বিনামূল্যে',
getStarted: 'শুরু করুন',
highlightedPlanBadge: 'জনপ্রিয়',
Expand All @@ -143,6 +146,7 @@ export const bnIN: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'মাসিক',
months: undefined,
pastDue: 'বকেয়া',
pay: '{{amount}} পরিশোধ করুন',
payerCreditRemainder: undefined,
Expand Down Expand Up @@ -221,6 +225,7 @@ export const bnIN: LocalizationResource = {
year: 'বছর',
yearAbbreviation: undefined,
yearPerUnit: undefined,
years: undefined,
},
configureSSO: {
activate: {
Expand Down
5 changes: 5 additions & 0 deletions packages/localizations/src/ca-ES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -144,6 +147,7 @@ export const caES: LocalizationResource = {
monthAbbreviation: undefined,
monthPerUnit: undefined,
monthly: 'Mensual',
months: undefined,
pastDue: 'Pagament pendent',
pay: 'Paga {{amount}}',
payerCreditRemainder: undefined,
Expand Down Expand Up @@ -222,6 +226,7 @@ export const caES: LocalizationResource = {
year: 'Any',
yearAbbreviation: undefined,
yearPerUnit: undefined,
years: undefined,
},
configureSSO: {
activate: {
Expand Down
5 changes: 5 additions & 0 deletions packages/localizations/src/cs-CZ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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í',
Expand All @@ -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,
Expand Down Expand Up @@ -219,6 +223,7 @@ export const csCZ: LocalizationResource = {
year: 'Rok',
yearAbbreviation: undefined,
yearPerUnit: undefined,
years: undefined,
},
configureSSO: {
activate: {
Expand Down
Loading
Loading