@automattic/plans-grid-next 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -1
- package/dist/cjs/_shared.scss +4 -3
- package/dist/cjs/components/comparison-grid/index.js +99 -92
- package/dist/cjs/components/comparison-grid/index.js.map +1 -1
- package/dist/cjs/components/comparison-grid/style.scss +10 -2
- package/dist/cjs/components/features-grid/client-logo-list/client-list.js +0 -12
- package/dist/cjs/components/features-grid/client-logo-list/client-list.js.map +1 -1
- package/dist/cjs/components/features-grid/index.js +9 -6
- package/dist/cjs/components/features-grid/index.js.map +1 -1
- package/dist/cjs/components/features-grid/plan-features-list.js +10 -3
- package/dist/cjs/components/features-grid/plan-features-list.js.map +1 -1
- package/dist/cjs/components/features-grid/plan-headers.js +2 -2
- package/dist/cjs/components/features-grid/plan-headers.js.map +1 -1
- package/dist/cjs/components/features-grid/plan-tagline.js +1 -1
- package/dist/cjs/components/features-grid/plan-tagline.js.map +1 -1
- package/dist/cjs/components/features-grid/style.scss +107 -19
- package/dist/cjs/components/features-grid/table.js +1 -1
- package/dist/cjs/components/features-grid/table.js.map +1 -1
- package/dist/cjs/components/features.js +43 -4
- package/dist/cjs/components/features.js.map +1 -1
- package/dist/cjs/components/item.js +1 -1
- package/dist/cjs/components/item.js.map +1 -1
- package/dist/cjs/components/plan-button/index.js +5 -3
- package/dist/cjs/components/plan-button/index.js.map +1 -1
- package/dist/cjs/components/plan-button/style.scss +75 -51
- package/dist/cjs/components/plan-div-td-container.js +4 -1
- package/dist/cjs/components/plan-div-td-container.js.map +1 -1
- package/dist/cjs/components/plan-logo.js +6 -3
- package/dist/cjs/components/plan-logo.js.map +1 -1
- package/dist/cjs/components/plan-type-selector/components/interval-type-dropdown.js +12 -1
- package/dist/cjs/components/plan-type-selector/components/interval-type-dropdown.js.map +1 -1
- package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js +4 -33
- package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
- package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +11 -13
- package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
- package/dist/cjs/components/plans-2023-tooltip.js +16 -5
- package/dist/cjs/components/plans-2023-tooltip.js.map +1 -1
- package/dist/cjs/components/shared/action-button/index.js +22 -7
- package/dist/cjs/components/shared/action-button/index.js.map +1 -1
- package/dist/cjs/components/shared/action-button/style.scss +4 -0
- package/dist/cjs/components/shared/billing-timeframe/index.js +8 -4
- package/dist/cjs/components/shared/billing-timeframe/index.js.map +1 -1
- package/dist/cjs/components/shared/header-price/index.js +60 -15
- package/dist/cjs/components/shared/header-price/index.js.map +1 -1
- package/dist/cjs/components/shared/header-price/style.scss +9 -3
- package/dist/cjs/components/shared/storage/components/plan-storage.js +2 -2
- package/dist/cjs/components/shared/storage/components/plan-storage.js.map +1 -1
- package/dist/cjs/components/shared/storage/components/storage-dropdown.js +29 -6
- package/dist/cjs/components/shared/storage/components/storage-dropdown.js.map +1 -1
- package/dist/cjs/components/shared/storage/components/storage-feature-label.js +2 -1
- package/dist/cjs/components/shared/storage/components/storage-feature-label.js.map +1 -1
- package/dist/cjs/components/shared/storage/hooks/use-plan-storage.js +2 -0
- package/dist/cjs/components/shared/storage/hooks/use-plan-storage.js.map +1 -1
- package/dist/cjs/fixtures/sites-purchases.js +2 -4
- package/dist/cjs/fixtures/sites-purchases.js.map +1 -1
- package/dist/cjs/grid-context.js +4 -1
- package/dist/cjs/grid-context.js.map +1 -1
- package/dist/cjs/hooks/data-store/get-renewal-pricing-text.js +50 -0
- package/dist/cjs/hooks/data-store/get-renewal-pricing-text.js.map +1 -0
- package/dist/cjs/hooks/data-store/use-grid-plans-for-comparison-grid.js +6 -1
- package/dist/cjs/hooks/data-store/use-grid-plans-for-comparison-grid.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js +6 -1
- package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-grid-plans.js +175 -21
- package/dist/cjs/hooks/data-store/use-grid-plans.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-highlight-labels.js +13 -4
- package/dist/cjs/hooks/data-store/use-highlight-labels.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-plan-billing-description.js +68 -13
- package/dist/cjs/hooks/data-store/use-plan-billing-description.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-plan-features-for-grid-plans.js +76 -2
- package/dist/cjs/hooks/data-store/use-plan-features-for-grid-plans.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js +60 -12
- package/dist/cjs/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js.map +1 -1
- package/dist/cjs/hooks/data-store/use-title-badges.js +19 -0
- package/dist/cjs/hooks/data-store/use-title-badges.js.map +1 -0
- package/dist/cjs/hooks/use-is-large-currency.js +2 -2
- package/dist/cjs/hooks/use-is-large-currency.js.map +1 -1
- package/dist/cjs/hooks/use-visible-grid-plans.js +70 -0
- package/dist/cjs/hooks/use-visible-grid-plans.js.map +1 -0
- package/dist/cjs/index.js +6 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/get-plan-features-object.js +15 -2
- package/dist/cjs/lib/get-plan-features-object.js.map +1 -1
- package/dist/cjs/lib/plan-pricing-utils.js +135 -0
- package/dist/cjs/lib/plan-pricing-utils.js.map +1 -0
- package/dist/esm/_shared.scss +4 -3
- package/dist/esm/components/comparison-grid/index.js +100 -93
- package/dist/esm/components/comparison-grid/index.js.map +1 -1
- package/dist/esm/components/comparison-grid/style.scss +10 -2
- package/dist/esm/components/features-grid/client-logo-list/client-list.js +0 -12
- package/dist/esm/components/features-grid/client-logo-list/client-list.js.map +1 -1
- package/dist/esm/components/features-grid/index.js +9 -6
- package/dist/esm/components/features-grid/index.js.map +1 -1
- package/dist/esm/components/features-grid/plan-features-list.js +10 -3
- package/dist/esm/components/features-grid/plan-features-list.js.map +1 -1
- package/dist/esm/components/features-grid/plan-headers.js +3 -3
- package/dist/esm/components/features-grid/plan-headers.js.map +1 -1
- package/dist/esm/components/features-grid/plan-tagline.js +1 -1
- package/dist/esm/components/features-grid/plan-tagline.js.map +1 -1
- package/dist/esm/components/features-grid/style.scss +107 -19
- package/dist/esm/components/features-grid/table.js +1 -1
- package/dist/esm/components/features-grid/table.js.map +1 -1
- package/dist/esm/components/features.js +44 -5
- package/dist/esm/components/features.js.map +1 -1
- package/dist/esm/components/item.js +1 -1
- package/dist/esm/components/item.js.map +1 -1
- package/dist/esm/components/plan-button/index.js +5 -3
- package/dist/esm/components/plan-button/index.js.map +1 -1
- package/dist/esm/components/plan-button/style.scss +75 -51
- package/dist/esm/components/plan-div-td-container.js +4 -1
- package/dist/esm/components/plan-div-td-container.js.map +1 -1
- package/dist/esm/components/plan-logo.js +7 -4
- package/dist/esm/components/plan-logo.js.map +1 -1
- package/dist/esm/components/plan-type-selector/components/interval-type-dropdown.js +12 -1
- package/dist/esm/components/plan-type-selector/components/interval-type-dropdown.js.map +1 -1
- package/dist/esm/components/plan-type-selector/hooks/use-max-discount.js +3 -33
- package/dist/esm/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
- package/dist/esm/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +11 -13
- package/dist/esm/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
- package/dist/esm/components/plans-2023-tooltip.js +16 -5
- package/dist/esm/components/plans-2023-tooltip.js.map +1 -1
- package/dist/esm/components/shared/action-button/index.js +22 -7
- package/dist/esm/components/shared/action-button/index.js.map +1 -1
- package/dist/esm/components/shared/action-button/style.scss +4 -0
- package/dist/esm/components/shared/billing-timeframe/index.js +8 -4
- package/dist/esm/components/shared/billing-timeframe/index.js.map +1 -1
- package/dist/esm/components/shared/header-price/index.js +60 -15
- package/dist/esm/components/shared/header-price/index.js.map +1 -1
- package/dist/esm/components/shared/header-price/style.scss +9 -3
- package/dist/esm/components/shared/storage/components/plan-storage.js +2 -2
- package/dist/esm/components/shared/storage/components/plan-storage.js.map +1 -1
- package/dist/esm/components/shared/storage/components/storage-dropdown.js +30 -7
- package/dist/esm/components/shared/storage/components/storage-dropdown.js.map +1 -1
- package/dist/esm/components/shared/storage/components/storage-feature-label.js +2 -1
- package/dist/esm/components/shared/storage/components/storage-feature-label.js.map +1 -1
- package/dist/esm/components/shared/storage/hooks/use-plan-storage.js +3 -1
- package/dist/esm/components/shared/storage/hooks/use-plan-storage.js.map +1 -1
- package/dist/esm/fixtures/sites-purchases.js +2 -4
- package/dist/esm/fixtures/sites-purchases.js.map +1 -1
- package/dist/esm/grid-context.js +4 -1
- package/dist/esm/grid-context.js.map +1 -1
- package/dist/esm/hooks/data-store/get-renewal-pricing-text.js +47 -0
- package/dist/esm/hooks/data-store/get-renewal-pricing-text.js.map +1 -0
- package/dist/esm/hooks/data-store/use-grid-plans-for-comparison-grid.js +6 -1
- package/dist/esm/hooks/data-store/use-grid-plans-for-comparison-grid.js.map +1 -1
- package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js +6 -1
- package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
- package/dist/esm/hooks/data-store/use-grid-plans.js +176 -22
- package/dist/esm/hooks/data-store/use-grid-plans.js.map +1 -1
- package/dist/esm/hooks/data-store/use-highlight-labels.js +14 -5
- package/dist/esm/hooks/data-store/use-highlight-labels.js.map +1 -1
- package/dist/esm/hooks/data-store/use-plan-billing-description.js +66 -11
- package/dist/esm/hooks/data-store/use-plan-billing-description.js.map +1 -1
- package/dist/esm/hooks/data-store/use-plan-features-for-grid-plans.js +77 -3
- package/dist/esm/hooks/data-store/use-plan-features-for-grid-plans.js.map +1 -1
- package/dist/esm/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js +59 -11
- package/dist/esm/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js.map +1 -1
- package/dist/esm/hooks/data-store/use-title-badges.js +17 -0
- package/dist/esm/hooks/data-store/use-title-badges.js.map +1 -0
- package/dist/esm/hooks/use-is-large-currency.js +1 -1
- package/dist/esm/hooks/use-is-large-currency.js.map +1 -1
- package/dist/esm/hooks/use-visible-grid-plans.js +66 -0
- package/dist/esm/hooks/use-visible-grid-plans.js.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/get-plan-features-object.js +15 -2
- package/dist/esm/lib/get-plan-features-object.js.map +1 -1
- package/dist/esm/lib/plan-pricing-utils.js +129 -0
- package/dist/esm/lib/plan-pricing-utils.js.map +1 -0
- package/dist/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/components/comparison-grid/index.d.ts +1 -1
- package/dist/types/components/comparison-grid/index.d.ts.map +1 -1
- package/dist/types/components/features-grid/client-logo-list/client-list.d.ts.map +1 -1
- package/dist/types/components/features-grid/index.d.ts.map +1 -1
- package/dist/types/components/features-grid/plan-features-list.d.ts.map +1 -1
- package/dist/types/components/features-grid/plan-headers.d.ts +2 -0
- package/dist/types/components/features-grid/plan-headers.d.ts.map +1 -1
- package/dist/types/components/features-grid/table.d.ts.map +1 -1
- package/dist/types/components/features.d.ts.map +1 -1
- package/dist/types/components/item.d.ts +2 -1
- package/dist/types/components/item.d.ts.map +1 -1
- package/dist/types/components/plan-button/index.d.ts +2 -1
- package/dist/types/components/plan-button/index.d.ts.map +1 -1
- package/dist/types/components/plan-div-td-container.d.ts +2 -0
- package/dist/types/components/plan-div-td-container.d.ts.map +1 -1
- package/dist/types/components/plan-logo.d.ts.map +1 -1
- package/dist/types/components/plan-type-selector/components/interval-type-dropdown.d.ts.map +1 -1
- package/dist/types/components/plan-type-selector/hooks/use-max-discount.d.ts.map +1 -1
- package/dist/types/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.d.ts.map +1 -1
- package/dist/types/components/plans-2023-tooltip.d.ts.map +1 -1
- package/dist/types/components/shared/action-button/index.d.ts +2 -1
- package/dist/types/components/shared/action-button/index.d.ts.map +1 -1
- package/dist/types/components/shared/billing-timeframe/index.d.ts.map +1 -1
- package/dist/types/components/shared/header-price/index.d.ts.map +1 -1
- package/dist/types/components/shared/storage/components/storage-dropdown.d.ts.map +1 -1
- package/dist/types/components/shared/storage/components/storage-feature-label.d.ts.map +1 -1
- package/dist/types/components/shared/storage/hooks/use-plan-storage.d.ts +1 -1
- package/dist/types/components/shared/storage/hooks/use-plan-storage.d.ts.map +1 -1
- package/dist/types/fixtures/sites-purchases.d.ts +2 -4
- package/dist/types/fixtures/sites-purchases.d.ts.map +1 -1
- package/dist/types/grid-context.d.ts +4 -1
- package/dist/types/grid-context.d.ts.map +1 -1
- package/dist/types/hooks/data-store/get-renewal-pricing-text.d.ts +14 -0
- package/dist/types/hooks/data-store/get-renewal-pricing-text.d.ts.map +1 -0
- package/dist/types/hooks/data-store/types.d.ts +21 -0
- package/dist/types/hooks/data-store/types.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts +1 -1
- package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts +1 -1
- package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-grid-plans.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-highlight-labels.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-plan-billing-description.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-plan-features-for-grid-plans.d.ts +4 -1
- package/dist/types/hooks/data-store/use-plan-features-for-grid-plans.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-restructured-plan-features-for-comparison-grid.d.ts +4 -1
- package/dist/types/hooks/data-store/use-restructured-plan-features-for-comparison-grid.d.ts.map +1 -1
- package/dist/types/hooks/data-store/use-title-badges.d.ts +9 -0
- package/dist/types/hooks/data-store/use-title-badges.d.ts.map +1 -0
- package/dist/types/hooks/use-visible-grid-plans.d.ts +14 -0
- package/dist/types/hooks/use-visible-grid-plans.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/get-plan-features-object.d.ts +1 -1
- package/dist/types/lib/get-plan-features-object.d.ts.map +1 -1
- package/dist/types/lib/plan-pricing-utils.d.ts +105 -0
- package/dist/types/lib/plan-pricing-utils.d.ts.map +1 -0
- package/dist/types/types.d.ts +29 -2
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +38 -28
- package/src/_shared.scss +4 -3
- package/src/components/comparison-grid/index.tsx +258 -181
- package/src/components/comparison-grid/style.scss +10 -2
- package/src/components/features-grid/client-logo-list/client-list.tsx +0 -25
- package/src/components/features-grid/index.tsx +35 -18
- package/src/components/features-grid/plan-features-list.tsx +15 -4
- package/src/components/features-grid/plan-headers.tsx +10 -3
- package/src/components/features-grid/plan-tagline.tsx +1 -1
- package/src/components/features-grid/style.scss +107 -19
- package/src/components/features-grid/table.tsx +4 -2
- package/src/components/features.tsx +66 -6
- package/src/components/item.tsx +6 -3
- package/src/components/plan-button/index.tsx +7 -1
- package/src/components/plan-button/style.scss +75 -51
- package/src/components/plan-div-td-container.tsx +6 -2
- package/src/components/plan-logo.tsx +16 -9
- package/src/components/plan-type-selector/components/interval-type-dropdown.tsx +14 -1
- package/src/components/plan-type-selector/hooks/use-max-discount.ts +8 -47
- package/src/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.ts +19 -17
- package/src/components/plans-2023-tooltip.tsx +17 -5
- package/src/components/shared/action-button/index.tsx +46 -5
- package/src/components/shared/action-button/style.scss +4 -0
- package/src/components/shared/billing-timeframe/index.tsx +12 -7
- package/src/components/shared/header-price/index.tsx +129 -27
- package/src/components/shared/header-price/style.scss +9 -3
- package/src/components/shared/storage/components/plan-storage.tsx +2 -2
- package/src/components/shared/storage/components/storage-dropdown.tsx +36 -15
- package/src/components/shared/storage/components/storage-feature-label.tsx +2 -1
- package/src/components/shared/storage/hooks/use-plan-storage.ts +3 -0
- package/src/components/test/actions-button.tsx +5 -0
- package/src/components/test/billing-timeframe.tsx +1 -1
- package/src/components/test/header-price.tsx +342 -4
- package/src/fixtures/sites-purchases.ts +2 -4
- package/src/grid-context.tsx +9 -0
- package/src/hooks/data-store/get-renewal-pricing-text.ts +73 -0
- package/src/hooks/data-store/types.ts +21 -0
- package/src/hooks/data-store/use-grid-plans-for-comparison-grid.ts +10 -0
- package/src/hooks/data-store/use-grid-plans-for-features-grid.ts +10 -0
- package/src/hooks/data-store/use-grid-plans.tsx +189 -23
- package/src/hooks/data-store/use-highlight-labels.ts +12 -3
- package/src/hooks/data-store/use-plan-billing-description.tsx +80 -15
- package/src/hooks/data-store/use-plan-features-for-grid-plans.ts +135 -1
- package/src/hooks/data-store/use-restructured-plan-features-for-comparison-grid.ts +93 -20
- package/src/hooks/data-store/use-title-badges.ts +31 -0
- package/src/hooks/test/use-visible-grid-plans.tsx +116 -0
- package/src/hooks/use-is-large-currency.ts +1 -1
- package/src/hooks/use-visible-grid-plans.tsx +102 -0
- package/src/index.tsx +18 -0
- package/src/lib/get-plan-features-object.ts +23 -2
- package/src/lib/plan-pricing-utils.ts +211 -0
- package/src/lib/test/plan-pricing-utils.ts +594 -0
- package/src/style-imports.d.ts +3 -0
- package/src/types.ts +41 -0
- package/dist/cjs/components/features-grid/mobile-free-domain.js +0 -25
- package/dist/cjs/components/features-grid/mobile-free-domain.js.map +0 -1
- package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js +0 -15
- package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js.map +0 -1
- package/dist/esm/components/features-grid/mobile-free-domain.js +0 -23
- package/dist/esm/components/features-grid/mobile-free-domain.js.map +0 -1
- package/dist/esm/lib/get-plan-pricing-info-from-grid-plans.js +0 -12
- package/dist/esm/lib/get-plan-pricing-info-from-grid-plans.js.map +0 -1
- package/dist/types/components/features-grid/mobile-free-domain.d.ts +0 -8
- package/dist/types/components/features-grid/mobile-free-domain.d.ts.map +0 -1
- package/dist/types/lib/get-plan-pricing-info-from-grid-plans.d.ts +0 -9
- package/dist/types/lib/get-plan-pricing-info-from-grid-plans.d.ts.map +0 -1
- package/src/components/features-grid/mobile-free-domain.tsx +0 -51
- package/src/lib/get-plan-pricing-info-from-grid-plans.ts +0 -31
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { Plans } from '@automattic/data-stores';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Intermediate structure that normalizes plan pricing from different sources
|
|
5
|
+
* (PricingMetaForGridPlan, WPCOMProductVariant) into a common shape suitable
|
|
6
|
+
* for discount calculations.
|
|
7
|
+
*
|
|
8
|
+
* All prices are in the smallest currency unit (e.g. cents).
|
|
9
|
+
*/
|
|
10
|
+
export interface PlanPriceInfo {
|
|
11
|
+
/** Billing period length in months (1, 12, 24, 36) */
|
|
12
|
+
termMonths: number;
|
|
13
|
+
/** Regular price per month — no intro offer, no site-level discount */
|
|
14
|
+
regularPricePerMonth: number;
|
|
15
|
+
/** Site-level discounted price per month (currency conversion / proration credit), if any */
|
|
16
|
+
discountedPricePerMonth?: number;
|
|
17
|
+
introOffer?: {
|
|
18
|
+
/** Monthly-equivalent price during the intro period */
|
|
19
|
+
pricePerMonth: number;
|
|
20
|
+
/** How many months the intro offer lasts */
|
|
21
|
+
durationMonths: number;
|
|
22
|
+
/** False once the offer has already been used by this user */
|
|
23
|
+
isActive: boolean;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// billingPeriod values are in days (from PERIOD_LIST in calypso-products)
|
|
28
|
+
const BILLING_PERIOD_DAYS_TO_MONTHS: Record< number, number > = {
|
|
29
|
+
31: 1,
|
|
30
|
+
365: 12,
|
|
31
|
+
730: 24,
|
|
32
|
+
1095: 36,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function billingPeriodDaysToMonths( billingPeriod: number | undefined ): number | null {
|
|
36
|
+
if ( billingPeriod === undefined || billingPeriod === null ) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return BILLING_PERIOD_DAYS_TO_MONTHS[ billingPeriod ] ?? null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Calculates the total cost of a plan over `durationMonths` months.
|
|
44
|
+
*
|
|
45
|
+
* Handles partial billing periods via pro-ration (e.g. a yearly plan priced at
|
|
46
|
+
* $200/year costs $100 for 6 months).
|
|
47
|
+
*
|
|
48
|
+
* When `useIntroOffer` is true (default) and an active intro offer exists, the
|
|
49
|
+
* intro price is applied for the first `introOffer.durationMonths` months, and
|
|
50
|
+
* the regular (or discounted) price for the remainder.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* // Monthly plan: $10 intro for 1 month, then $20/month; cost for 6 months:
|
|
54
|
+
* // 1×$10 + 5×$20 = $110 (in cents: 1100 + 10000 = 11000)
|
|
55
|
+
* getPlanPriceForDuration( info, 6, { useIntroOffer: true } ) // 11000
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* // Yearly plan: $100/yr intro, $200/yr regular; cost for 6 months:
|
|
59
|
+
* // useIntroOffer=true → 6×($100/12) = $50 (5000 cents)
|
|
60
|
+
* // useIntroOffer=false → 6×($200/12) = $100 (10000 cents)
|
|
61
|
+
*/
|
|
62
|
+
export function getPlanPriceForDuration(
|
|
63
|
+
info: PlanPriceInfo,
|
|
64
|
+
durationMonths: number,
|
|
65
|
+
{ useIntroOffer = true }: { useIntroOffer?: boolean } = {}
|
|
66
|
+
): number {
|
|
67
|
+
const basePricePerMonth = info.discountedPricePerMonth ?? info.regularPricePerMonth;
|
|
68
|
+
|
|
69
|
+
if ( useIntroOffer && info.introOffer?.isActive ) {
|
|
70
|
+
const introMonths = Math.min( durationMonths, info.introOffer.durationMonths );
|
|
71
|
+
const regularMonths = Math.max( 0, durationMonths - info.introOffer.durationMonths );
|
|
72
|
+
return introMonths * info.introOffer.pricePerMonth + regularMonths * basePricePerMonth;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return durationMonths * basePricePerMonth;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Calculates the percentage discount between a reference price and a cheaper price.
|
|
80
|
+
*
|
|
81
|
+
* Always uses Math.floor — conservative, never overstates savings.
|
|
82
|
+
*
|
|
83
|
+
* Returns `undefined` (not 0) when there is no saving, allowing callers to
|
|
84
|
+
* distinguish "no discount" from a computed "0% discount".
|
|
85
|
+
*/
|
|
86
|
+
export function calculateDiscountPercentage(
|
|
87
|
+
referencePrice: number,
|
|
88
|
+
cheaperPrice: number
|
|
89
|
+
): number | undefined {
|
|
90
|
+
if ( cheaperPrice >= referencePrice || referencePrice <= 0 ) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
return Math.floor( ( 100 * ( referencePrice - cheaperPrice ) ) / referencePrice );
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Converts a `PricingMetaForGridPlan` (from @automattic/data-stores Plans hooks)
|
|
98
|
+
* into a `PlanPriceInfo` suitable for use with `getPlanPriceForDuration` and
|
|
99
|
+
* `calculateDiscountPercentage`.
|
|
100
|
+
*
|
|
101
|
+
* Returns null when required pricing data is absent (e.g. free/enterprise plans
|
|
102
|
+
* that have no monthly price, or plans whose billing period is unknown).
|
|
103
|
+
*/
|
|
104
|
+
export function fromPricingMetaForGridPlan(
|
|
105
|
+
meta: Plans.PricingMetaForGridPlan
|
|
106
|
+
): PlanPriceInfo | null {
|
|
107
|
+
const termMonths = billingPeriodDaysToMonths( meta.billingPeriod );
|
|
108
|
+
if ( termMonths === null || meta.originalPrice.monthly === null ) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const isIntroActive = !! meta.introOffer && ! meta.introOffer.isOfferComplete;
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
termMonths,
|
|
116
|
+
regularPricePerMonth: meta.originalPrice.monthly,
|
|
117
|
+
// The API sometimes sets discountedPrice.monthly to the intro offer price rather than
|
|
118
|
+
// a genuine site-level discount (e.g. currency conversion, proration credit). When an
|
|
119
|
+
// intro offer is active the intro structure already captures the discounted period, so
|
|
120
|
+
// using discountedPrice here would contaminate the post-intro "regular" rate used by
|
|
121
|
+
// getPlanPriceForDuration — producing incorrect totals for the non-intro months.
|
|
122
|
+
discountedPricePerMonth: isIntroActive ? undefined : meta.discountedPrice.monthly ?? undefined,
|
|
123
|
+
introOffer: meta.introOffer
|
|
124
|
+
? {
|
|
125
|
+
pricePerMonth: meta.introOffer.rawPrice.monthly,
|
|
126
|
+
durationMonths:
|
|
127
|
+
meta.introOffer.intervalCount * ( meta.introOffer.intervalUnit === 'year' ? 12 : 1 ),
|
|
128
|
+
isActive: isIntroActive,
|
|
129
|
+
}
|
|
130
|
+
: undefined,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Minimal structural type describing the pricing fields needed from a product
|
|
136
|
+
* variant. `WPCOMProductVariant` (defined in checkout) satisfies this interface
|
|
137
|
+
* structurally, so it can be passed directly without importing the checkout type
|
|
138
|
+
* into this package.
|
|
139
|
+
*
|
|
140
|
+
* Key invariants:
|
|
141
|
+
* - `priceBeforeDiscounts` is always the full-term cost at the regular rate.
|
|
142
|
+
* - `priceInteger` is the actual amount charged, which embeds both intro and
|
|
143
|
+
* non-intro portions when an intro offer spans only part of the term
|
|
144
|
+
* (e.g. a 1-year intro on a 2-year plan).
|
|
145
|
+
* - When `priceInteger < priceBeforeDiscounts`, the intro price portion is
|
|
146
|
+
* derived by subtracting the non-intro months at the regular rate.
|
|
147
|
+
*/
|
|
148
|
+
export interface VariantPriceData {
|
|
149
|
+
introductoryInterval: number;
|
|
150
|
+
/** 'month' | 'year' */
|
|
151
|
+
introductoryTerm: string;
|
|
152
|
+
/** Full-term price at the regular (non-intro) rate */
|
|
153
|
+
priceBeforeDiscounts: number;
|
|
154
|
+
/** Actual price charged for the full term (may embed an intro offer) */
|
|
155
|
+
priceInteger: number;
|
|
156
|
+
termIntervalInMonths: number;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Converts a variant price data object (structurally compatible with
|
|
161
|
+
* `WPCOMProductVariant`) into a `PlanPriceInfo`.
|
|
162
|
+
*
|
|
163
|
+
* `discountedPricePerMonth` is intentionally not set: `WPCOMProductVariant`
|
|
164
|
+
* does not separate site-level discounts from the intro price. Coupon discounts
|
|
165
|
+
* in checkout are tracked separately via `product.coupon_savings_integer`.
|
|
166
|
+
*
|
|
167
|
+
* Per-month values are derived by dividing full-term prices (integers in the
|
|
168
|
+
* smallest currency unit) by the number of months. The result is rounded to the
|
|
169
|
+
* nearest integer (Math.round) so that all fields in the returned `PlanPriceInfo`
|
|
170
|
+
* remain whole-cent values safe for use with currency formatters. The rounding
|
|
171
|
+
* error is at most 0.5¢ per month and is negligible for percentage comparisons.
|
|
172
|
+
*/
|
|
173
|
+
export function fromVariantPriceData( variant: VariantPriceData ): PlanPriceInfo {
|
|
174
|
+
const {
|
|
175
|
+
termIntervalInMonths: termMonths,
|
|
176
|
+
priceBeforeDiscounts,
|
|
177
|
+
priceInteger,
|
|
178
|
+
introductoryInterval,
|
|
179
|
+
introductoryTerm,
|
|
180
|
+
} = variant;
|
|
181
|
+
|
|
182
|
+
const regularPricePerMonth = Math.round( priceBeforeDiscounts / termMonths );
|
|
183
|
+
|
|
184
|
+
const introDurationMonths =
|
|
185
|
+
introductoryInterval > 0 ? introductoryInterval * ( introductoryTerm === 'year' ? 12 : 1 ) : 0;
|
|
186
|
+
|
|
187
|
+
let introOffer: PlanPriceInfo[ 'introOffer' ] | undefined;
|
|
188
|
+
|
|
189
|
+
if ( introDurationMonths > 0 && priceInteger < priceBeforeDiscounts ) {
|
|
190
|
+
// When the intro spans the full term (introDurationMonths >= termMonths), all of
|
|
191
|
+
// priceInteger is at the intro rate and there are zero non-intro months.
|
|
192
|
+
// When the intro is shorter than the term (introDurationMonths < termMonths), we
|
|
193
|
+
// subtract the non-intro portion (billed at the regular rate) to isolate the intro cost.
|
|
194
|
+
const nonIntroMonths = Math.max( 0, termMonths - introDurationMonths );
|
|
195
|
+
const introPriceTotal = priceInteger - nonIntroMonths * regularPricePerMonth;
|
|
196
|
+
|
|
197
|
+
// A non-positive introPriceTotal means inconsistent data (e.g. a sub-term intro
|
|
198
|
+
// with a priceInteger that is less than the non-intro months at the regular rate).
|
|
199
|
+
if ( introPriceTotal > 0 ) {
|
|
200
|
+
// When introDurationMonths > termMonths the whole billing term is within the
|
|
201
|
+
// intro period, so we spread introPriceTotal over termMonths (not introDurationMonths).
|
|
202
|
+
introOffer = {
|
|
203
|
+
pricePerMonth: Math.round( introPriceTotal / Math.min( introDurationMonths, termMonths ) ),
|
|
204
|
+
durationMonths: introDurationMonths,
|
|
205
|
+
isActive: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { termMonths, regularPricePerMonth, introOffer };
|
|
211
|
+
}
|