client/utilities/pricingConfig/suggestedAmounts.ts (356 lines of code) (raw):
import { isOneOf } from '@guardian/libs';
import type { PaidSubscriptionPlan } from '../../../shared/productResponse';
import type { CurrencyIso } from '../currencyIso';
import { isCurrencyIso } from '../currencyIso';
/* Recurring Contributions */
type SuggestedAmountsLookup = Record<
CurrencyIso | 'international',
{
month: (amount: number) => number[];
year: (amount: number) => number[];
}
>;
const billingPeriods = ['month', 'year'] as const;
export function getContributionSuggestedAmounts(
mainPlan: PaidSubscriptionPlan,
) {
const currentAmount = mainPlan.price / 100;
const currencyISO = isCurrencyIso(mainPlan.currencyISO)
? mainPlan.currencyISO
: 'international';
if (!isOneOf(billingPeriods)(mainPlan.billingPeriod)) {
throw new Error(`Unexpected billing period: ${mainPlan.billingPeriod}`);
}
return suggestedAmountsLookup[currencyISO][mainPlan.billingPeriod](
currentAmount,
);
}
const suggestedAmountsLookup: SuggestedAmountsLookup = {
GBP: {
month: getGbpMonthly,
year: getGbpAnnual,
},
USD: {
month: getUsdMonthly,
year: getUsdAnnual,
},
EUR: {
month: getEuroMonthly,
year: getEuroAnnual,
},
AUD: {
month: getAusMonthly,
year: getAusAnnual,
},
NZD: {
month: getAusMonthly,
year: getAusAnnual,
},
CAD: {
month: getUsdMonthly,
year: getUsdAnnual,
},
international: {
month: getUsdMonthly,
year: getUsdAnnual,
},
};
function getGbpMonthly(amount: number) {
if (amount <= 3) {
return [5, 7, 12];
}
if (amount <= 8) {
return [10, 12, 15];
}
if (amount === 9) {
return [12, 15, 17];
}
if (amount <= 13) {
return [15, 17, 20];
}
if (amount <= 23) {
return [25, 27, 30];
}
if (amount <= 23) {
return [25, 27, 30];
}
if (amount <= 28) {
return [30, 32, 35];
}
if (amount === 29) {
return [35, 37, 40];
}
if (amount <= 35) {
return [40, 42, 45];
} else {
return getSupporterPlusSuggestedAmountsMonthly(amount);
}
}
function getGbpAnnual(amount: number) {
if (amount <= 11) {
return [20, 30, 120];
}
if (amount <= 13) {
return [25, 40, 120];
}
if (amount <= 16) {
return [30, 40, 120];
}
if (amount <= 18) {
return [35, 40, 120];
}
if (amount === 19) {
return [40, 50, 120];
}
if (amount <= 50) {
return [60, 70, 120];
}
if (amount <= 59) {
return [70, 80, 120];
}
if (amount <= 59) {
return [70, 80, 120];
}
if (amount <= 69) {
return [80, 90, 120];
}
if (amount <= 89) {
return [95, 110, 120];
}
if (amount <= 94) {
return [95, 130, 140];
}
if (amount <= 100) {
return [120, 130, 140];
}
if (amount <= 119) {
return [150, 160, 170];
}
if (amount <= 140) {
return [240, 250, 260];
} else {
return getSupporterPlusSuggestedAmountsAnnual(amount);
}
}
function getUsdMonthly(amount: number) {
if (amount <= 4) {
return [5, 7, 15];
}
if (amount <= 8) {
return [10, 13, 15];
}
if (amount === 9) {
return [13, 15, 17];
}
if (amount <= 18) {
return [20, 22, 25];
}
if (amount <= 23) {
return [25, 27, 30];
}
if (amount <= 28) {
return [30, 32, 35];
}
if (amount === 29) {
return [35, 37, 40];
}
if (amount <= 35) {
return [40, 42, 45];
} else {
return getSupporterPlusSuggestedAmountsMonthly(amount);
}
}
function getUsdAnnual(amount: number) {
if (amount <= 10) {
return [20, 30, 150];
}
if (amount <= 20) {
return [40, 50, 150];
}
if (amount <= 30) {
return [50, 60, 150];
}
if (amount <= 39) {
return [60, 70, 150];
}
if (amount <= 50) {
return [75, 80, 150];
}
if (amount <= 55) {
return [80, 90, 150];
}
if (amount <= 59) {
return [90, 100, 150];
}
if (amount <= 70) {
return [100, 110, 150];
}
if (amount <= 89) {
return [120, 130, 150];
}
if (amount <= 99) {
return [130, 140, 150];
}
if (amount <= 114) {
return [150, 160, 170];
}
if (amount <= 119) {
return [160, 170, 180];
}
if (amount <= 139) {
return [180, 190, 200];
}
if (amount <= 150) {
return [200, 210, 220];
} else {
return getSupporterPlusSuggestedAmountsAnnual(amount);
}
}
function getEuroMonthly(amount: number) {
if (amount <= 4) {
return [6, 8, 12];
}
if (amount <= 8) {
return [10, 12, 15];
}
if (amount === 9) {
return [15, 17, 20];
}
if (amount <= 18) {
return [20, 22, 25];
}
if (amount <= 28) {
return [30, 32, 35];
}
if (amount === 29) {
return [35, 37, 40];
}
if (amount <= 35) {
return [40, 42, 45];
} else {
return getSupporterPlusSuggestedAmountsMonthly(amount);
}
}
function getEuroAnnual(amount: number) {
if (amount <= 11) {
return [20, 30, 95];
}
if (amount <= 14) {
return [25, 30, 95];
}
if (amount <= 19) {
return [30, 40, 95];
}
if (amount <= 44) {
return [60, 70, 95];
}
if (amount <= 49) {
return [75, 80, 95];
}
if (amount <= 89) {
return [95, 110, 120];
}
if (amount <= 99) {
return [120, 130, 140];
}
if (amount <= 119) {
return [150, 160, 170];
}
if (amount <= 149) {
return [240, 250, 260];
}
if (amount <= 150) {
return [250, 260, 270];
} else {
return getSupporterPlusSuggestedAmountsAnnual(amount);
}
}
function getAusMonthly(amount: number) {
if (amount <= 9) {
return [15, 17, 20];
}
if (amount <= 18) {
return [20, 22, 25];
}
if (amount <= 27) {
return [30, 32, 35];
}
if (amount <= 29) {
return [35, 37, 40];
}
if (amount <= 35) {
return [40, 42, 45];
}
if (amount <= 39) {
return [45, 47, 50];
}
if (amount <= 45) {
return [50, 52, 55];
}
if (amount <= 50) {
return [60, 62, 65];
} else {
return getSupporterPlusSuggestedAmountsMonthly(amount);
}
}
function getAusAnnual(amount: number) {
if (amount <= 19) {
return [40, 50, 200];
}
if (amount <= 29) {
return [50, 60, 200];
}
if (amount <= 44) {
return [60, 70, 200];
}
if (amount <= 49) {
return [70, 80, 200];
}
if (amount <= 69) {
return [80, 90, 200];
}
if (amount <= 79) {
return [100, 110, 200];
}
if (amount <= 151) {
return [160, 170, 200];
}
if (amount <= 169) {
return [180, 190, 200];
}
if (amount <= 179) {
return [200, 210, 220];
}
if (amount <= 190) {
return [230, 240, 250];
}
if (amount <= 199) {
return [250, 260, 270];
}
if (amount <= 250) {
return [300, 310, 320];
} else {
return getSupporterPlusSuggestedAmountsAnnual(amount);
}
}
/* Supporter Plus */
export function getSupporterPlusSuggestedAmountsFromMainPlan(
mainPlan: PaidSubscriptionPlan,
) {
const currentAmount = mainPlan.price / 100;
return mainPlan.billingPeriod === 'month'
? getSupporterPlusSuggestedAmountsMonthly(currentAmount)
: getSupporterPlusSuggestedAmountsAnnual(currentAmount);
}
export function getSupporterPlusSuggestedAmountsMonthly(currentAmount: number) {
const firstValue = currentAmount + 2;
const secondValue = Math.ceil((firstValue + 1) / 5) * 5;
const thirdValue = secondValue + 5;
return [firstValue, secondValue, thirdValue];
}
export function getSupporterPlusSuggestedAmountsAnnual(currentAmount: number) {
// ToDo: what if this goes over the max?
const percentageStepUps = [1.1, 1.25, 1.5];
return percentageStepUps.map(
(p) => Math.round((currentAmount * p) / 5) * 5,
);
}