@automattic/plans-grid-next 1.0.0 → 1.0.2

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.
Files changed (196) hide show
  1. package/dist/cjs/__mocks__/wpcom-proxy-request.js +3 -4
  2. package/dist/cjs/__mocks__/wpcom-proxy-request.js.map +1 -1
  3. package/dist/cjs/_shared.scss +9 -4
  4. package/dist/cjs/components/comparison-grid/index.js +62 -50
  5. package/dist/cjs/components/comparison-grid/index.js.map +1 -1
  6. package/dist/cjs/components/comparison-grid/index.stories.js +1 -0
  7. package/dist/cjs/components/comparison-grid/index.stories.js.map +1 -1
  8. package/dist/cjs/components/comparison-grid/style.scss +0 -17
  9. package/dist/cjs/components/dropdown-option.js +1 -1
  10. package/dist/cjs/components/features-grid/index.js +21 -6
  11. package/dist/cjs/components/features-grid/index.js.map +1 -1
  12. package/dist/cjs/components/features-grid/index.stories.js +1 -0
  13. package/dist/cjs/components/features-grid/index.stories.js.map +1 -1
  14. package/dist/cjs/components/features-grid/style.scss +6 -21
  15. package/dist/cjs/components/item.js +1 -2
  16. package/dist/cjs/components/item.js.map +1 -1
  17. package/dist/cjs/components/plan-button/style.scss +12 -11
  18. package/dist/cjs/components/plan-type-selector/hooks/use-interval-options.js +1 -1
  19. package/dist/cjs/components/plan-type-selector/hooks/use-interval-options.js.map +1 -1
  20. package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js +1 -1
  21. package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
  22. package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +1 -1
  23. package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
  24. package/dist/cjs/components/plan-type-selector/style.scss +3 -1
  25. package/dist/cjs/components/shared/billing-timeframe/index.js +13 -5
  26. package/dist/cjs/components/shared/billing-timeframe/index.js.map +1 -1
  27. package/dist/cjs/components/shared/header-price/style.scss +4 -2
  28. package/dist/cjs/components/shared/storage/hooks/use-default-storage-option.js +1 -1
  29. package/dist/cjs/components/shared/storage/hooks/use-default-storage-option.js.map +1 -1
  30. package/dist/cjs/components/shared/storage/hooks/use-purchased-storage-add-on.js +1 -1
  31. package/dist/cjs/components/shared/storage/hooks/use-purchased-storage-add-on.js.map +1 -1
  32. package/dist/cjs/components/shared/storage/index.js +3 -2
  33. package/dist/cjs/components/shared/storage/index.js.map +1 -1
  34. package/dist/cjs/components/sticky-container.js +66 -6
  35. package/dist/cjs/components/sticky-container.js.map +1 -1
  36. package/dist/cjs/hooks/data-store/is-popular-plan.js +1 -2
  37. package/dist/cjs/hooks/data-store/is-popular-plan.js.map +1 -1
  38. package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js +14 -11
  39. package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
  40. package/dist/cjs/hooks/data-store/use-plan-billing-description.js +2 -2
  41. package/dist/cjs/hooks/data-store/use-plan-billing-description.js.map +1 -1
  42. package/dist/cjs/hooks/data-store/use-plan-billing-period.js +14 -0
  43. package/dist/cjs/hooks/data-store/use-plan-billing-period.js.map +1 -0
  44. package/dist/cjs/hooks/use-grid-size.js +2 -4
  45. package/dist/cjs/hooks/use-grid-size.js.map +1 -1
  46. package/dist/cjs/hooks/use-is-large-currency.js +1 -1
  47. package/dist/cjs/hooks/use-is-large-currency.js.map +1 -1
  48. package/dist/cjs/hooks/use-manage-tooltip-toggle.js +1 -2
  49. package/dist/cjs/hooks/use-manage-tooltip-toggle.js.map +1 -1
  50. package/dist/cjs/hooks/use-plan-pricing-info-from-grid-plans.js +1 -2
  51. package/dist/cjs/hooks/use-plan-pricing-info-from-grid-plans.js.map +1 -1
  52. package/dist/cjs/index.js +3 -1
  53. package/dist/cjs/index.js.map +1 -1
  54. package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js +1 -2
  55. package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js.map +1 -1
  56. package/dist/cjs/lib/is-same-plan.js +1 -2
  57. package/dist/cjs/lib/is-same-plan.js.map +1 -1
  58. package/dist/cjs/lib/touch-detect/index.js +1 -2
  59. package/dist/cjs/lib/touch-detect/index.js.map +1 -1
  60. package/dist/esm/_shared.scss +9 -4
  61. package/dist/esm/components/comparison-grid/index.js +62 -50
  62. package/dist/esm/components/comparison-grid/index.js.map +1 -1
  63. package/dist/esm/components/comparison-grid/index.stories.js +1 -0
  64. package/dist/esm/components/comparison-grid/index.stories.js.map +1 -1
  65. package/dist/esm/components/comparison-grid/style.scss +0 -17
  66. package/dist/esm/components/dropdown-option.js +1 -1
  67. package/dist/esm/components/features-grid/index.js +21 -6
  68. package/dist/esm/components/features-grid/index.js.map +1 -1
  69. package/dist/esm/components/features-grid/index.stories.js +1 -0
  70. package/dist/esm/components/features-grid/index.stories.js.map +1 -1
  71. package/dist/esm/components/features-grid/style.scss +6 -21
  72. package/dist/esm/components/plan-button/style.scss +12 -11
  73. package/dist/esm/components/plan-type-selector/style.scss +3 -1
  74. package/dist/esm/components/shared/billing-timeframe/index.js +14 -6
  75. package/dist/esm/components/shared/billing-timeframe/index.js.map +1 -1
  76. package/dist/esm/components/shared/header-price/style.scss +4 -2
  77. package/dist/esm/components/sticky-container.js +66 -5
  78. package/dist/esm/components/sticky-container.js.map +1 -1
  79. package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js +14 -11
  80. package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
  81. package/dist/esm/hooks/data-store/use-plan-billing-description.js +1 -1
  82. package/dist/esm/hooks/data-store/use-plan-billing-period.js +12 -0
  83. package/dist/esm/hooks/data-store/use-plan-billing-period.js.map +1 -0
  84. package/dist/esm/hooks/use-grid-size.js +0 -1
  85. package/dist/esm/hooks/use-grid-size.js.map +1 -1
  86. package/dist/esm/index.js +2 -1
  87. package/dist/esm/index.js.map +1 -1
  88. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  89. package/dist/tsconfig.tsbuildinfo +1 -1
  90. package/dist/types/components/comparison-grid/index.d.ts +1 -1
  91. package/dist/types/components/comparison-grid/index.d.ts.map +1 -1
  92. package/dist/types/components/comparison-grid/index.stories.d.ts +5 -3
  93. package/dist/types/components/comparison-grid/index.stories.d.ts.map +1 -1
  94. package/dist/types/components/dropdown-option.d.ts +0 -1
  95. package/dist/types/components/dropdown-option.d.ts.map +1 -1
  96. package/dist/types/components/features-grid/billing-timeframes.d.ts.map +1 -1
  97. package/dist/types/components/features-grid/client-logo-list/client-list.d.ts +0 -1
  98. package/dist/types/components/features-grid/client-logo-list/client-list.d.ts.map +1 -1
  99. package/dist/types/components/features-grid/client-logo-list/index.d.ts.map +1 -1
  100. package/dist/types/components/features-grid/enterprise-features.d.ts.map +1 -1
  101. package/dist/types/components/features-grid/index.d.ts.map +1 -1
  102. package/dist/types/components/features-grid/index.stories.d.ts +5 -1
  103. package/dist/types/components/features-grid/index.stories.d.ts.map +1 -1
  104. package/dist/types/components/features-grid/mobile-free-domain.d.ts.map +1 -1
  105. package/dist/types/components/features-grid/plan-features-list.d.ts.map +1 -1
  106. package/dist/types/components/features-grid/plan-headers.d.ts.map +1 -1
  107. package/dist/types/components/features-grid/plan-logos.d.ts.map +1 -1
  108. package/dist/types/components/features-grid/plan-prices.d.ts.map +1 -1
  109. package/dist/types/components/features-grid/plan-tagline.d.ts.map +1 -1
  110. package/dist/types/components/features-grid/previous-features-included-title.d.ts.map +1 -1
  111. package/dist/types/components/features-grid/spotlight-plan.d.ts.map +1 -1
  112. package/dist/types/components/features-grid/table.d.ts.map +1 -1
  113. package/dist/types/components/features-grid/top-buttons.d.ts.map +1 -1
  114. package/dist/types/components/plan-button/index.d.ts +10 -10
  115. package/dist/types/components/plan-button/index.d.ts.map +1 -1
  116. package/dist/types/components/plan-div-td-container.d.ts +0 -1
  117. package/dist/types/components/plan-div-td-container.d.ts.map +1 -1
  118. package/dist/types/components/plan-logo.d.ts +0 -1
  119. package/dist/types/components/plan-logo.d.ts.map +1 -1
  120. package/dist/types/components/plan-type-selector/components/interval-type-dropdown.d.ts +0 -1
  121. package/dist/types/components/plan-type-selector/components/interval-type-dropdown.d.ts.map +1 -1
  122. package/dist/types/components/plan-type-selector/components/interval-type-selector.d.ts +0 -1
  123. package/dist/types/components/plan-type-selector/components/interval-type-selector.d.ts.map +1 -1
  124. package/dist/types/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.d.ts.map +1 -1
  125. package/dist/types/components/plans-2023-tooltip.d.ts.map +1 -1
  126. package/dist/types/components/popular-badge.d.ts +0 -1
  127. package/dist/types/components/popular-badge.d.ts.map +1 -1
  128. package/dist/types/components/shared/action-button/index.d.ts.map +1 -1
  129. package/dist/types/components/shared/billing-timeframe/index.d.ts.map +1 -1
  130. package/dist/types/components/shared/header-price/header-price-context.d.ts +0 -1
  131. package/dist/types/components/shared/header-price/header-price-context.d.ts.map +1 -1
  132. package/dist/types/components/shared/header-price/index.d.ts.map +1 -1
  133. package/dist/types/components/shared/storage/components/plan-storage.d.ts.map +1 -1
  134. package/dist/types/components/shared/storage/components/storage-dropdown.d.ts.map +1 -1
  135. package/dist/types/components/shared/storage/components/storage-feature-label.d.ts.map +1 -1
  136. package/dist/types/components/shared/storage/hooks/use-storage-string.d.ts +0 -1
  137. package/dist/types/components/shared/storage/hooks/use-storage-string.d.ts.map +1 -1
  138. package/dist/types/components/sticky-container.d.ts +22 -0
  139. package/dist/types/components/sticky-container.d.ts.map +1 -1
  140. package/dist/types/css-mixins.d.ts.map +1 -1
  141. package/dist/types/grid-context.d.ts +0 -1
  142. package/dist/types/grid-context.d.ts.map +1 -1
  143. package/dist/types/hooks/data-store/types.d.ts +1 -0
  144. package/dist/types/hooks/data-store/types.d.ts.map +1 -1
  145. package/dist/types/hooks/data-store/use-grid-plan-for-spotlight.d.ts.map +1 -1
  146. package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts.map +1 -1
  147. package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts +1 -1
  148. package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts.map +1 -1
  149. package/dist/types/hooks/data-store/use-grid-plans.d.ts +1 -1
  150. package/dist/types/hooks/data-store/use-grid-plans.d.ts.map +1 -1
  151. package/dist/types/hooks/data-store/use-highlight-labels.d.ts +0 -1
  152. package/dist/types/hooks/data-store/use-highlight-labels.d.ts.map +1 -1
  153. package/dist/types/hooks/data-store/use-plan-billing-description.d.ts +0 -1
  154. package/dist/types/hooks/data-store/use-plan-billing-description.d.ts.map +1 -1
  155. package/dist/types/hooks/data-store/use-plan-billing-period.d.ts +8 -0
  156. package/dist/types/hooks/data-store/use-plan-billing-period.d.ts.map +1 -0
  157. package/dist/types/hooks/data-store/use-plans-from-types.d.ts.map +1 -1
  158. package/dist/types/hooks/use-grid-size.d.ts +3 -3
  159. package/dist/types/hooks/use-grid-size.d.ts.map +1 -1
  160. package/dist/types/hooks/use-highlight-adjacency-matrix.d.ts.map +1 -1
  161. package/dist/types/index.d.ts +2 -1
  162. package/dist/types/index.d.ts.map +1 -1
  163. package/dist/types/lib/filter-unused-features-object.d.ts.map +1 -1
  164. package/dist/types/lib/get-plan-features-object.d.ts.map +1 -1
  165. package/dist/types/types.d.ts +5 -5
  166. package/dist/types/types.d.ts.map +1 -1
  167. package/package.json +16 -15
  168. package/src/_shared.scss +9 -4
  169. package/src/components/comparison-grid/index.stories.tsx +2 -1
  170. package/src/components/comparison-grid/index.tsx +69 -55
  171. package/src/components/comparison-grid/style.scss +0 -17
  172. package/src/components/dropdown-option.tsx +1 -1
  173. package/src/components/features-grid/index.stories.tsx +1 -0
  174. package/src/components/features-grid/index.tsx +22 -9
  175. package/src/components/features-grid/style.scss +6 -21
  176. package/src/components/plan-button/style.scss +12 -11
  177. package/src/components/plan-type-selector/style.scss +3 -1
  178. package/src/components/shared/billing-timeframe/index.tsx +15 -7
  179. package/src/components/shared/header-price/style.scss +4 -2
  180. package/src/components/sticky-container.tsx +74 -3
  181. package/src/components/test/billing-timeframe.tsx +2 -2
  182. package/src/hooks/data-store/types.ts +1 -0
  183. package/src/hooks/data-store/use-grid-plans-for-features-grid.ts +14 -10
  184. package/src/hooks/data-store/use-plan-billing-description.tsx +1 -1
  185. package/src/hooks/data-store/use-plan-billing-period.tsx +28 -0
  186. package/src/hooks/use-grid-size.ts +3 -3
  187. package/src/index.tsx +2 -0
  188. package/src/types.ts +5 -4
  189. package/dist/cjs/lib/sort-plan-properties.js +0 -39
  190. package/dist/cjs/lib/sort-plan-properties.js.map +0 -1
  191. package/dist/esm/lib/sort-plan-properties.js +0 -35
  192. package/dist/esm/lib/sort-plan-properties.js.map +0 -1
  193. package/dist/types/lib/sort-plan-properties.d.ts +0 -3
  194. package/dist/types/lib/sort-plan-properties.d.ts.map +0 -1
  195. package/src/lib/sort-plan-properties.ts +0 -46
  196. package/src/lib/test/sort-plan-properties.ts +0 -104
@@ -6,6 +6,7 @@
6
6
  padding: 10px 12px;
7
7
  border: unset;
8
8
  text-align: center;
9
+ text-wrap: balance;
9
10
  width: 100%;
10
11
  color: var(--color-text-inverted);
11
12
 
@@ -20,7 +21,7 @@
20
21
  box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-wordpress-blue-50);
21
22
  }
22
23
 
23
- &:hover {
24
+ &:hover:not([disabled]) {
24
25
  background-color: var(--studio-wordpress-blue-60);
25
26
  }
26
27
 
@@ -33,7 +34,7 @@
33
34
  box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-wordpress-blue-60);
34
35
  }
35
36
 
36
- &:hover {
37
+ &:hover:not([disabled]) {
37
38
  background-color: var(--studio-wordpress-blue-70);
38
39
  }
39
40
  }
@@ -45,30 +46,30 @@
45
46
  box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-wordpress-blue-70);
46
47
  }
47
48
 
48
- &:hover {
49
+ &:hover:not([disabled]) {
49
50
  background-color: var(--studio-wordpress-blue-80);
50
51
  }
51
52
  }
52
53
 
53
54
  &.is-business-plan {
54
- background-color: var(--studio-woocommerce-purple-50);
55
+ background-color: var(--studio-woocommerce-purple-60);
55
56
 
56
57
  &:focus {
57
- box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-woocommerce-purple-50);
58
+ box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-woocommerce-purple-60);
58
59
  }
59
60
 
60
- &:hover {
61
+ &:hover:not([disabled]) {
61
62
  background-color: var(--studio-woocommerce-purple-70);
62
63
  }
63
64
 
64
65
  + .button.is-borderless {
65
66
  background: transparent;
66
67
  font-size: $font-body-small;
67
- color: var(--studio-woocommerce-purple-50);
68
+ color: var(--studio-woocommerce-purple-60);
68
69
  text-decoration: none;
69
70
 
70
71
  &:focus {
71
- box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-woocommerce-purple-50);
72
+ box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-woocommerce-purple-60);
72
73
  }
73
74
  }
74
75
  }
@@ -101,14 +102,14 @@
101
102
  }
102
103
 
103
104
  &.is-ecommerce-plan {
104
- background-color: var(--studio-woocommerce-purple-70);
105
+ background-color: var(--studio-woocommerce-purple-40);
105
106
 
106
107
  &:focus {
107
- box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-woocommerce-purple-70);
108
+ box-shadow: 0 0 0 2px var(--studio-white), 0 0 0 4px var(--studio-woocommerce-purple-40);
108
109
  }
109
110
 
110
111
  &:hover {
111
- background-color: var(--studio-woocommerce-purple-80);
112
+ background-color: var(--studio-woocommerce-purple-50);
112
113
  }
113
114
  }
114
115
 
@@ -162,7 +162,9 @@
162
162
  display: none;
163
163
  }
164
164
  }
165
- .components-custom-select-control__label {
165
+
166
+ .components-custom-select-control__label,
167
+ .components-base-control__label {
166
168
  display: none;
167
169
  }
168
170
  }
@@ -5,7 +5,7 @@ import {
5
5
  isFreePlan,
6
6
  } from '@automattic/calypso-products';
7
7
  import styled from '@emotion/styled';
8
- import { useTranslate, formatCurrency } from 'i18n-calypso';
8
+ import { useTranslate, formatCurrency, fixMe } from 'i18n-calypso';
9
9
  import { usePlansGridContext } from '../../../grid-context';
10
10
  import usePlanBillingDescription from '../../../hooks/data-store/use-plan-billing-description';
11
11
  import type { GridPlan } from '../../../types';
@@ -78,14 +78,22 @@ const BillingTimeframe = ( { showRefundPeriod, planSlug }: Props ) => {
78
78
  }
79
79
 
80
80
  if ( isWpcomEnterpriseGridPlan( planSlug ) ) {
81
- const price = formatCurrency( 25000, 'USD' );
81
+ const price = formatCurrency( 25000, 'USD', { stripZeros: true } );
82
82
 
83
83
  return (
84
- <div className="plans-grid-next__billing-timeframe-vip-price">
85
- { translate( 'Starts at {{b}}%(price)s{{/b}} yearly', {
86
- args: { price },
87
- components: { b: <b /> },
88
- comment: 'Translators: the price is in US dollars for all users (US$25,000)',
84
+ <div>
85
+ { fixMe( {
86
+ text: 'Starts at {{b}}%(price)s{{/b}} annually',
87
+ newCopy: translate( 'Starts at {{b}}%(price)s{{/b}} annually', {
88
+ args: { price },
89
+ components: { b: <b /> },
90
+ comment: 'Translators: the price is in US dollars for all users (US$25,000)',
91
+ } ),
92
+ oldCopy: translate( 'Starts at {{b}}%(price)s{{/b}} yearly', {
93
+ args: { price },
94
+ components: { b: <b /> },
95
+ comment: 'Translators: the price is in US dollars for all users (US$25,000)',
96
+ } ),
89
97
  } ) }
90
98
  </div>
91
99
  );
@@ -1,3 +1,5 @@
1
+ @import "@automattic/typography/styles/variables";
2
+
1
3
  .plans-grid-next-header-price {
2
4
  padding: 0 20px;
3
5
  margin: 0 0 4px 0;
@@ -76,9 +78,9 @@
76
78
  }
77
79
 
78
80
  .plans-grid-next-header-price__badge {
79
- background-color: var(--studio-green-0);
81
+ background-color: var(--studio-green-5);
80
82
  border-radius: 4px;
81
- color: var(--studio-green-40);
83
+ color: var(--studio-green-80);
82
84
  display: inline-block;
83
85
  font-size: 0.75rem;
84
86
  font-weight: 500;
@@ -1,7 +1,7 @@
1
1
  import { Global, css } from '@emotion/react';
2
2
  import styled from '@emotion/styled';
3
3
  import clsx from 'clsx';
4
- import { useRef, type ElementType, useState, useLayoutEffect, ReactNode } from 'react';
4
+ import { useRef, type ElementType, useState, useLayoutEffect, ReactNode, useEffect } from 'react';
5
5
 
6
6
  type Props = {
7
7
  /**
@@ -41,17 +41,19 @@ type Props = {
41
41
  const styles = ( {
42
42
  disabled,
43
43
  stickyOffset,
44
+ stickyPadding,
44
45
  zIndex,
45
46
  }: {
46
47
  disabled: boolean;
47
48
  stickyOffset: number;
49
+ stickyPadding: number;
48
50
  zIndex: number;
49
51
  } ) =>
50
52
  disabled
51
53
  ? ''
52
54
  : css`
53
55
  position: sticky;
54
- top: ${ stickyOffset + 'px' };
56
+ top: ${ stickyOffset - stickyPadding + 'px' };
55
57
  z-index: ${ zIndex };
56
58
  `;
57
59
 
@@ -59,6 +61,28 @@ const Container = styled.div`
59
61
  ${ styles }
60
62
  `;
61
63
 
64
+ /**
65
+ * Renders a sticky container.
66
+ *
67
+ * The following is an illustration on how the container's top property is calculated.
68
+ *
69
+ * +~~~~~~~~ stickyParent (where the container scrolls)
70
+ * stickyOffset ~~~~~~~~~~+ |
71
+ * (e.g. masterbar) | |
72
+ * v v
73
+ * +------#-----------------+
74
+ * | # |<~~~~~~~+~~~~~ stickyPadding
75
+ * | +----#--------------+ |
76
+ * | | # @ |<~+~~~~~ stickyParent's content area
77
+ * | | # @ | |
78
+ * | | # @ <~~~~~~~~+~~+~~~~~ the container's top
79
+ * | | # @ | | (= stickyOffset - stickyPadding)
80
+ * | | ============= | |
81
+ * | | ^ | |
82
+ * | | | | |
83
+ * | | +~~~~~~~~~~~~~+~~+~~~~~ the container
84
+ * | | | |
85
+ */
62
86
  export function StickyContainer( props: Props ) {
63
87
  const {
64
88
  stickyOffset = 0,
@@ -70,8 +94,53 @@ export function StickyContainer( props: Props ) {
70
94
  } = props;
71
95
 
72
96
  const stickyRef = useRef( null );
97
+ const [ stickyParent, setStickyParent ] = useState< HTMLElement | null >( null );
98
+ const [ stickyPadding, setStickyPadding ] = useState( 0 );
73
99
  const [ isStuck, setIsStuck ] = useState( false );
74
100
 
101
+ /**
102
+ * Calculate the first scrollable parent and its padding-top.
103
+ */
104
+ useEffect( () => {
105
+ if ( ! stickyRef.current || typeof getComputedStyle === 'undefined' ) {
106
+ return;
107
+ }
108
+
109
+ let scrollParent = stickyRef.current as HTMLElement | null;
110
+ while ( scrollParent ) {
111
+ const style = getComputedStyle( scrollParent );
112
+ const overflowY = style.overflowY;
113
+ if ( overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay' ) {
114
+ break;
115
+ }
116
+ scrollParent = scrollParent.parentElement;
117
+ }
118
+
119
+ const receiveScrollParent = ( el: HTMLElement ) => {
120
+ const styles = getComputedStyle( el );
121
+ const paddingTop = parseFloat( styles.paddingTop );
122
+ setStickyParent( scrollParent );
123
+ setStickyPadding( paddingTop );
124
+ };
125
+
126
+ if ( scrollParent ) {
127
+ scrollParent.style.position = 'relative';
128
+ receiveScrollParent( scrollParent );
129
+
130
+ if ( typeof ResizeObserver !== 'undefined' ) {
131
+ const observer = new ResizeObserver(
132
+ ( [ parent ]: Parameters< ResizeObserverCallback >[ 0 ] ) => {
133
+ receiveScrollParent( parent.target as HTMLElement );
134
+ }
135
+ );
136
+ observer.observe( scrollParent );
137
+ return () => {
138
+ observer.disconnect();
139
+ };
140
+ }
141
+ }
142
+ }, [] );
143
+
75
144
  /**
76
145
  * This effect sets the value of `isStuck` state when it detects that
77
146
  * the element is sticky.
@@ -102,6 +171,7 @@ export function StickyContainer( props: Props ) {
102
171
  }
103
172
  },
104
173
  {
174
+ root: stickyParent,
105
175
  rootMargin: `-${ stickyOffset + 1 }px 0px 0px 0px`,
106
176
  threshold: [ 0, 1 ],
107
177
  }
@@ -114,7 +184,7 @@ export function StickyContainer( props: Props ) {
114
184
  return () => {
115
185
  observer.disconnect();
116
186
  };
117
- }, [ disabled, stickyOffset ] );
187
+ }, [ disabled, stickyParent, stickyOffset, stickyPadding ] );
118
188
 
119
189
  const isStuckFinalState = ! disabled && isStuck;
120
190
  return (
@@ -135,6 +205,7 @@ export function StickyContainer( props: Props ) {
135
205
  as={ element }
136
206
  ref={ stickyRef }
137
207
  stickyOffset={ stickyOffset }
208
+ stickyPadding={ stickyPadding }
138
209
  disabled={ disabled }
139
210
  className={ clsx( { [ stickyClass ]: isStuckFinalState } ) }
140
211
  zIndex={ zIndex }
@@ -49,7 +49,7 @@ describe( 'BillingTimeframe', () => {
49
49
  jest.clearAllMocks();
50
50
  } );
51
51
 
52
- test( `should show savings with yearly when plan is monthly`, () => {
52
+ test( 'should show savings with yearly when plan is monthly', () => {
53
53
  const planMonthlyPricing = {
54
54
  currencyCode: 'USD',
55
55
  originalPrice: { full: 120, monthly: 10 },
@@ -309,7 +309,7 @@ describe( 'BillingTimeframe', () => {
309
309
  expect( getByText( /Refundable within 7 days. No questions asked./ ) ).toBeInTheDocument();
310
310
  } );
311
311
 
312
- test( `refund period can't be shown for free plan`, () => {
312
+ test( "refund period can't be shown for free plan", () => {
313
313
  const pricing = {
314
314
  currencyCode: 'USD',
315
315
  originalPrice: { full: 0, monthly: 0 },
@@ -10,6 +10,7 @@ export interface UseGridPlansParams {
10
10
  eligibleForFreeHostingTrial?: boolean;
11
11
  hasRedeemedDomainCredit?: boolean;
12
12
  hiddenPlans?: HiddenPlans;
13
+ hideCurrentPlan?: boolean;
13
14
  intent?: PlansIntent;
14
15
  isDisplayingPlansNeededForFeature?: boolean;
15
16
  isInSignup?: boolean;
@@ -10,6 +10,7 @@ const useGridPlansForFeaturesGrid = ( {
10
10
  eligibleForFreeHostingTrial,
11
11
  hasRedeemedDomainCredit,
12
12
  hiddenPlans,
13
+ hideCurrentPlan,
13
14
  intent,
14
15
  isDisplayingPlansNeededForFeature,
15
16
  isInSignup,
@@ -62,18 +63,21 @@ const useGridPlansForFeaturesGrid = ( {
62
63
  }
63
64
 
64
65
  return gridPlans.reduce( ( acc, gridPlan ) => {
65
- if ( gridPlan.isVisible ) {
66
- return [
67
- ...acc,
68
- {
69
- ...gridPlan,
70
- features: planFeaturesForFeaturesGrid[ gridPlan.planSlug ],
71
- },
72
- ];
66
+ if ( ! gridPlan.isVisible ) {
67
+ return acc;
73
68
  }
74
- return acc;
69
+ if ( hideCurrentPlan && gridPlan.current ) {
70
+ return acc;
71
+ }
72
+ return [
73
+ ...acc,
74
+ {
75
+ ...gridPlan,
76
+ features: planFeaturesForFeaturesGrid[ gridPlan.planSlug ],
77
+ },
78
+ ];
75
79
  }, [] as GridPlan[] );
76
- }, [ gridPlans, planFeaturesForFeaturesGrid ] );
80
+ }, [ gridPlans, planFeaturesForFeaturesGrid, hideCurrentPlan ] );
77
81
  };
78
82
 
79
83
  export default useGridPlansForFeaturesGrid;
@@ -73,7 +73,7 @@ export default function usePlanBillingDescription( {
73
73
  yearlyVariantMaybeDiscountedPrice &&
74
74
  yearlyVariantMaybeDiscountedPrice < originalPrice.monthly
75
75
  ) {
76
- return translate( `Save %(discountRate)s%% by paying annually`, {
76
+ return translate( 'Save %(discountRate)s%% by paying annually', {
77
77
  args: {
78
78
  discountRate: Math.floor(
79
79
  ( 100 * ( originalPrice.monthly - yearlyVariantMaybeDiscountedPrice ) ) /
@@ -0,0 +1,28 @@
1
+ import {
2
+ TERMS_LIST,
3
+ TERM_ANNUALLY,
4
+ TERM_BIENNIALLY,
5
+ TERM_MONTHLY,
6
+ TERM_TRIENNIALLY,
7
+ } from '@automattic/calypso-products';
8
+ import { EFFECTIVE_TERMS_LIST } from '../../constants';
9
+ import type { SupportedUrlFriendlyTermType } from '../../types';
10
+
11
+ const usePlanBillingPeriod = ( {
12
+ intervalType,
13
+ defaultValue,
14
+ }: {
15
+ intervalType: SupportedUrlFriendlyTermType;
16
+ defaultValue?: ( typeof TERMS_LIST )[ number ];
17
+ } ) => {
18
+ const plans: Record< SupportedUrlFriendlyTermType, ( typeof EFFECTIVE_TERMS_LIST )[ number ] > = {
19
+ monthly: TERM_MONTHLY,
20
+ yearly: TERM_ANNUALLY,
21
+ '2yearly': TERM_BIENNIALLY,
22
+ '3yearly': TERM_TRIENNIALLY,
23
+ } as const;
24
+
25
+ return plans[ intervalType ] || defaultValue || TERM_ANNUALLY;
26
+ };
27
+
28
+ export default usePlanBillingPeriod;
@@ -1,5 +1,5 @@
1
1
  import { useLayoutEffect, useState } from '@wordpress/element';
2
- import ResizeObserver from 'resize-observer-polyfill';
2
+ import { GridSize } from '../types';
3
3
 
4
4
  interface Props {
5
5
  containerRef: React.MutableRefObject< HTMLDivElement | null >;
@@ -9,7 +9,7 @@ interface Props {
9
9
  * but they could be used in the future in a containment context.
10
10
  * The keys are the labels, the values are the minimum widths.
11
11
  */
12
- containerBreakpoints: Map< string, number >;
12
+ containerBreakpoints: Map< GridSize, number >;
13
13
  }
14
14
 
15
15
  /**
@@ -17,7 +17,7 @@ interface Props {
17
17
  * and the breakpoints passed through as props.
18
18
  */
19
19
  export default function useGridSize( { containerRef, containerBreakpoints }: Props ) {
20
- const [ gridSize, setGridSize ] = useState< string | null >( null );
20
+ const [ gridSize, setGridSize ] = useState< GridSize | null >( null );
21
21
 
22
22
  useLayoutEffect( () => {
23
23
  if ( ! containerRef.current ) {
package/src/index.tsx CHANGED
@@ -9,6 +9,7 @@ import useGridPlans, { usePlanTypesWithIntent } from './hooks/data-store/use-gri
9
9
  import useGridPlansForComparisonGrid from './hooks/data-store/use-grid-plans-for-comparison-grid';
10
10
  import useGridPlansForFeaturesGrid from './hooks/data-store/use-grid-plans-for-features-grid';
11
11
  import usePlanBillingDescription from './hooks/data-store/use-plan-billing-description';
12
+ import usePlanBillingPeriod from './hooks/data-store/use-plan-billing-period';
12
13
  import usePlanFeaturesForGridPlans from './hooks/data-store/use-plan-features-for-grid-plans';
13
14
  import usePlansFromTypes from './hooks/data-store/use-plans-from-types';
14
15
  import useRestructuredPlanFeaturesForComparisonGrid from './hooks/data-store/use-restructured-plan-features-for-comparison-grid';
@@ -33,6 +34,7 @@ export {
33
34
  useGridPlansForFeaturesGrid,
34
35
  useGridPlansForComparisonGrid,
35
36
  useGridPlanForSpotlight,
37
+ usePlanBillingPeriod,
36
38
  usePlanBillingDescription,
37
39
  usePlanFeaturesForGridPlans,
38
40
  usePlansFromTypes,
package/src/types.ts CHANGED
@@ -51,7 +51,7 @@ export interface GridPlan {
51
51
  * Grid Component Types:
52
52
  ***********************/
53
53
 
54
- export type GridSize = 'small' | 'medium' | 'large';
54
+ export type GridSize = 'small' | 'smedium' | 'medium' | 'large' | 'xlarge';
55
55
 
56
56
  export type PlansIntent =
57
57
  | 'plans-affiliate'
@@ -104,8 +104,9 @@ export interface CommonGridProps {
104
104
  siteId?: number | null;
105
105
  isInSignup: boolean;
106
106
  isInAdmin: boolean;
107
+ isInSiteDashboard: boolean;
107
108
  onStorageAddOnClick?: ( addOnSlug: AddOns.StorageAddOnSlug ) => void;
108
- currentSitePlanSlug?: string | null;
109
+ currentSitePlanSlug?: PlanSlug | null;
109
110
  hideUnavailableFeatures?: boolean; // used to hide features that are not available, instead of strike-through as explained in #76206
110
111
  planActionOverrides?: PlanActionOverrides;
111
112
  // Value of the `?feature=` query param, so we can highlight a given feature and hide plans without it.
@@ -116,7 +117,7 @@ export interface CommonGridProps {
116
117
  // only used for comparison grid
117
118
  planTypeSelectorProps?: PlanTypeSelectorProps;
118
119
  gridContainerRef?: React.MutableRefObject< HTMLDivElement | null >;
119
- gridSize?: string;
120
+ gridSize?: GridSize;
120
121
  }
121
122
 
122
123
  export interface FeaturesGridProps extends CommonGridProps {
@@ -133,7 +134,7 @@ export interface FeaturesGridProps extends CommonGridProps {
133
134
  export interface ComparisonGridProps extends CommonGridProps {
134
135
  // Value of the `?plan=` query param, so we can highlight a given plan.
135
136
  selectedPlan?: string;
136
- intervalType: string;
137
+ intervalType: SupportedUrlFriendlyTermType;
137
138
  }
138
139
 
139
140
  export type UseActionCallback = ( {
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sortPlans = void 0;
4
- const calypso_products_1 = require("@automattic/calypso-products");
5
- const is_popular_plan_1 = require("../hooks/data-store/is-popular-plan");
6
- function sortPlans(gridPlans, currentSitePlanProductSlug, isMobile) {
7
- let firstPlanIndex = -1;
8
- // Try to find the current paid plan in the plans list
9
- if (currentSitePlanProductSlug && !(0, calypso_products_1.isFreePlan)(currentSitePlanProductSlug)) {
10
- firstPlanIndex = gridPlans.findIndex((gridPlan) => {
11
- return gridPlan.planSlug === currentSitePlanProductSlug;
12
- });
13
- }
14
- if (firstPlanIndex < 0) {
15
- // Site is on a free plan or the current plan is not in the list. Try to find the popular plan.
16
- firstPlanIndex = gridPlans.findIndex(({ planSlug }) => {
17
- return (0, is_popular_plan_1.isPopularPlan)(planSlug);
18
- });
19
- // If the popular plan exists, on mobile, it will be second plan for comparison.
20
- if (firstPlanIndex > 0 && isMobile) {
21
- firstPlanIndex = firstPlanIndex - 1;
22
- }
23
- }
24
- if (firstPlanIndex < 0) {
25
- return gridPlans;
26
- }
27
- return [
28
- // The first plan
29
- gridPlans[firstPlanIndex],
30
- // Rest of the plans in default order
31
- ...gridPlans.slice(firstPlanIndex + 1),
32
- // Leftover plans (before the first plan) in descending order of value
33
- ...gridPlans.slice(0, firstPlanIndex).sort((planA, planB) => {
34
- return ((planB?.pricing.originalPrice.full || 0) - (planA?.pricing.originalPrice.full || 0));
35
- }),
36
- ].filter((gridPlan) => Boolean(gridPlan));
37
- }
38
- exports.sortPlans = sortPlans;
39
- //# sourceMappingURL=sort-plan-properties.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sort-plan-properties.js","sourceRoot":"","sources":["../../../src/lib/sort-plan-properties.ts"],"names":[],"mappings":";;;AAAA,mEAA0D;AAC1D,yEAAoE;AAGpE,SAAgB,SAAS,CACxB,SAAqB,EACrB,0BAA0C,EAC1C,QAAkB;IAElB,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC;IAExB,sDAAsD;IACtD,IAAK,0BAA0B,IAAI,CAAE,IAAA,6BAAU,EAAE,0BAA0B,CAAE,EAAG,CAAC;QAChF,cAAc,GAAG,SAAS,CAAC,SAAS,CAAE,CAAE,QAAQ,EAAG,EAAE;YACpD,OAAO,QAAQ,CAAC,QAAQ,KAAK,0BAA0B,CAAC;QACzD,CAAC,CAAE,CAAC;IACL,CAAC;IAED,IAAK,cAAc,GAAG,CAAC,EAAG,CAAC;QAC1B,+FAA+F;QAC/F,cAAc,GAAG,SAAS,CAAC,SAAS,CAAE,CAAE,EAAE,QAAQ,EAAE,EAAG,EAAE;YACxD,OAAO,IAAA,+BAAa,EAAE,QAAQ,CAAE,CAAC;QAClC,CAAC,CAAE,CAAC;QACJ,gFAAgF;QAChF,IAAK,cAAc,GAAG,CAAC,IAAI,QAAQ,EAAG,CAAC;YACtC,cAAc,GAAG,cAAc,GAAG,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAED,IAAK,cAAc,GAAG,CAAC,EAAG,CAAC;QAC1B,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO;QACN,iBAAiB;QACjB,SAAS,CAAE,cAAc,CAAE;QAC3B,qCAAqC;QACrC,GAAG,SAAS,CAAC,KAAK,CAAE,cAAc,GAAG,CAAC,CAAE;QACxC,sEAAsE;QACtE,GAAG,SAAS,CAAC,KAAK,CAAE,CAAC,EAAE,cAAc,CAAE,CAAC,IAAI,CAAE,CAAE,KAAK,EAAE,KAAK,EAAG,EAAE;YAChE,OAAO,CACN,CAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,CAAE,GAAG,CAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,CAAE,CACvF,CAAC;QACH,CAAC,CAAE;KACH,CAAC,MAAM,CAAE,CAAE,QAAQ,EAAG,EAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAE,CAAC;AACjD,CAAC;AAzCD,8BAyCC"}
@@ -1,35 +0,0 @@
1
- import { isFreePlan } from '@automattic/calypso-products';
2
- import { isPopularPlan } from '../hooks/data-store/is-popular-plan';
3
- export function sortPlans(gridPlans, currentSitePlanProductSlug, isMobile) {
4
- let firstPlanIndex = -1;
5
- // Try to find the current paid plan in the plans list
6
- if (currentSitePlanProductSlug && !isFreePlan(currentSitePlanProductSlug)) {
7
- firstPlanIndex = gridPlans.findIndex((gridPlan) => {
8
- return gridPlan.planSlug === currentSitePlanProductSlug;
9
- });
10
- }
11
- if (firstPlanIndex < 0) {
12
- // Site is on a free plan or the current plan is not in the list. Try to find the popular plan.
13
- firstPlanIndex = gridPlans.findIndex(({ planSlug }) => {
14
- return isPopularPlan(planSlug);
15
- });
16
- // If the popular plan exists, on mobile, it will be second plan for comparison.
17
- if (firstPlanIndex > 0 && isMobile) {
18
- firstPlanIndex = firstPlanIndex - 1;
19
- }
20
- }
21
- if (firstPlanIndex < 0) {
22
- return gridPlans;
23
- }
24
- return [
25
- // The first plan
26
- gridPlans[firstPlanIndex],
27
- // Rest of the plans in default order
28
- ...gridPlans.slice(firstPlanIndex + 1),
29
- // Leftover plans (before the first plan) in descending order of value
30
- ...gridPlans.slice(0, firstPlanIndex).sort((planA, planB) => {
31
- return ((planB?.pricing.originalPrice.full || 0) - (planA?.pricing.originalPrice.full || 0));
32
- }),
33
- ].filter((gridPlan) => Boolean(gridPlan));
34
- }
35
- //# sourceMappingURL=sort-plan-properties.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sort-plan-properties.js","sourceRoot":"","sources":["../../../src/lib/sort-plan-properties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAGpE,MAAM,UAAU,SAAS,CACxB,SAAqB,EACrB,0BAA0C,EAC1C,QAAkB;IAElB,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC;IAExB,sDAAsD;IACtD,IAAK,0BAA0B,IAAI,CAAE,UAAU,CAAE,0BAA0B,CAAE,EAAG,CAAC;QAChF,cAAc,GAAG,SAAS,CAAC,SAAS,CAAE,CAAE,QAAQ,EAAG,EAAE;YACpD,OAAO,QAAQ,CAAC,QAAQ,KAAK,0BAA0B,CAAC;QACzD,CAAC,CAAE,CAAC;IACL,CAAC;IAED,IAAK,cAAc,GAAG,CAAC,EAAG,CAAC;QAC1B,+FAA+F;QAC/F,cAAc,GAAG,SAAS,CAAC,SAAS,CAAE,CAAE,EAAE,QAAQ,EAAE,EAAG,EAAE;YACxD,OAAO,aAAa,CAAE,QAAQ,CAAE,CAAC;QAClC,CAAC,CAAE,CAAC;QACJ,gFAAgF;QAChF,IAAK,cAAc,GAAG,CAAC,IAAI,QAAQ,EAAG,CAAC;YACtC,cAAc,GAAG,cAAc,GAAG,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAED,IAAK,cAAc,GAAG,CAAC,EAAG,CAAC;QAC1B,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO;QACN,iBAAiB;QACjB,SAAS,CAAE,cAAc,CAAE;QAC3B,qCAAqC;QACrC,GAAG,SAAS,CAAC,KAAK,CAAE,cAAc,GAAG,CAAC,CAAE;QACxC,sEAAsE;QACtE,GAAG,SAAS,CAAC,KAAK,CAAE,CAAC,EAAE,cAAc,CAAE,CAAC,IAAI,CAAE,CAAE,KAAK,EAAE,KAAK,EAAG,EAAE;YAChE,OAAO,CACN,CAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,CAAE,GAAG,CAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,CAAE,CACvF,CAAC;QACH,CAAC,CAAE;KACH,CAAC,MAAM,CAAE,CAAE,QAAQ,EAAG,EAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAE,CAAC;AACjD,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { GridPlan } from '../types';
2
- export declare function sortPlans(gridPlans: GridPlan[], currentSitePlanProductSlug?: string | null, isMobile?: boolean): GridPlan[];
3
- //# sourceMappingURL=sort-plan-properties.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sort-plan-properties.d.ts","sourceRoot":"","sources":["../../../src/lib/sort-plan-properties.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,wBAAgB,SAAS,CACxB,SAAS,EAAE,QAAQ,EAAE,EACrB,0BAA0B,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1C,QAAQ,CAAC,EAAE,OAAO,GAChB,QAAQ,EAAE,CAqCZ"}
@@ -1,46 +0,0 @@
1
- import { isFreePlan } from '@automattic/calypso-products';
2
- import { isPopularPlan } from '../hooks/data-store/is-popular-plan';
3
- import type { GridPlan } from '../types';
4
-
5
- export function sortPlans(
6
- gridPlans: GridPlan[],
7
- currentSitePlanProductSlug?: string | null,
8
- isMobile?: boolean
9
- ): GridPlan[] {
10
- let firstPlanIndex = -1;
11
-
12
- // Try to find the current paid plan in the plans list
13
- if ( currentSitePlanProductSlug && ! isFreePlan( currentSitePlanProductSlug ) ) {
14
- firstPlanIndex = gridPlans.findIndex( ( gridPlan ) => {
15
- return gridPlan.planSlug === currentSitePlanProductSlug;
16
- } );
17
- }
18
-
19
- if ( firstPlanIndex < 0 ) {
20
- // Site is on a free plan or the current plan is not in the list. Try to find the popular plan.
21
- firstPlanIndex = gridPlans.findIndex( ( { planSlug } ) => {
22
- return isPopularPlan( planSlug );
23
- } );
24
- // If the popular plan exists, on mobile, it will be second plan for comparison.
25
- if ( firstPlanIndex > 0 && isMobile ) {
26
- firstPlanIndex = firstPlanIndex - 1;
27
- }
28
- }
29
-
30
- if ( firstPlanIndex < 0 ) {
31
- return gridPlans;
32
- }
33
-
34
- return [
35
- // The first plan
36
- gridPlans[ firstPlanIndex ],
37
- // Rest of the plans in default order
38
- ...gridPlans.slice( firstPlanIndex + 1 ),
39
- // Leftover plans (before the first plan) in descending order of value
40
- ...gridPlans.slice( 0, firstPlanIndex ).sort( ( planA, planB ) => {
41
- return (
42
- ( planB?.pricing.originalPrice.full || 0 ) - ( planA?.pricing.originalPrice.full || 0 )
43
- );
44
- } ),
45
- ].filter( ( gridPlan ) => Boolean( gridPlan ) );
46
- }