File size: 1,288 Bytes
97ee7cb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /**
* Billing-mode resolution for pricing-card CTAs (#4946 round 4).
*
* Pure and React-free so the annual-toggle contract is directly unit-
* testable: with the page-level toggle on "Annual", a tier that has no
* annual product (API Business) must still check out its monthly product
* — but EXPLICITLY, with `billedMonthlyOnly` driving a visible "billed
* monthly" note on the card. Silently selling the monthly product from
* an annual-selected state is the bug this module exists to prevent.
*/
export interface BillingModeTier {
monthlyProductId?: string;
annualProductId?: string;
}
export interface ResolvedCheckoutProduct {
productId: string;
/**
* True when the user is in annual mode but this tier only exists as a
* monthly product — the card must say so next to the price.
*/
billedMonthlyOnly: boolean;
}
export function resolveCheckoutProduct(
tier: BillingModeTier,
billing: 'monthly' | 'annual',
): ResolvedCheckoutProduct | null {
if (!tier.monthlyProductId) return null;
if (billing === 'annual' && tier.annualProductId) {
return { productId: tier.annualProductId, billedMonthlyOnly: false };
}
return {
productId: tier.monthlyProductId,
billedMonthlyOnly: billing === 'annual' && !tier.annualProductId,
};
}
|