@automattic/plans-grid-next 1.0.1 → 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.
Files changed (339) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/dist/cjs/_shared.scss +4 -3
  3. package/dist/cjs/components/comparison-grid/index.js +101 -71
  4. package/dist/cjs/components/comparison-grid/index.js.map +1 -1
  5. package/dist/cjs/components/comparison-grid/index.stories.js.map +1 -1
  6. package/dist/cjs/components/comparison-grid/style.scss +10 -2
  7. package/dist/cjs/components/features-grid/client-logo-list/client-list.js +0 -12
  8. package/dist/cjs/components/features-grid/client-logo-list/client-list.js.map +1 -1
  9. package/dist/cjs/components/features-grid/index.js +9 -6
  10. package/dist/cjs/components/features-grid/index.js.map +1 -1
  11. package/dist/cjs/components/features-grid/plan-features-list.js +10 -3
  12. package/dist/cjs/components/features-grid/plan-features-list.js.map +1 -1
  13. package/dist/cjs/components/features-grid/plan-headers.js +2 -2
  14. package/dist/cjs/components/features-grid/plan-headers.js.map +1 -1
  15. package/dist/cjs/components/features-grid/plan-tagline.js +1 -1
  16. package/dist/cjs/components/features-grid/plan-tagline.js.map +1 -1
  17. package/dist/cjs/components/features-grid/style.scss +111 -21
  18. package/dist/cjs/components/features-grid/table.js +1 -1
  19. package/dist/cjs/components/features-grid/table.js.map +1 -1
  20. package/dist/cjs/components/features.js +43 -4
  21. package/dist/cjs/components/features.js.map +1 -1
  22. package/dist/cjs/components/item.js +1 -1
  23. package/dist/cjs/components/item.js.map +1 -1
  24. package/dist/cjs/components/plan-button/index.js +5 -3
  25. package/dist/cjs/components/plan-button/index.js.map +1 -1
  26. package/dist/cjs/components/plan-button/style.scss +71 -47
  27. package/dist/cjs/components/plan-div-td-container.js +4 -1
  28. package/dist/cjs/components/plan-div-td-container.js.map +1 -1
  29. package/dist/cjs/components/plan-logo.js +6 -3
  30. package/dist/cjs/components/plan-logo.js.map +1 -1
  31. package/dist/cjs/components/plan-type-selector/components/interval-type-dropdown.js +12 -1
  32. package/dist/cjs/components/plan-type-selector/components/interval-type-dropdown.js.map +1 -1
  33. package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js +4 -33
  34. package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
  35. package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +11 -13
  36. package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
  37. package/dist/cjs/components/plans-2023-tooltip.js +16 -5
  38. package/dist/cjs/components/plans-2023-tooltip.js.map +1 -1
  39. package/dist/cjs/components/shared/action-button/index.js +22 -7
  40. package/dist/cjs/components/shared/action-button/index.js.map +1 -1
  41. package/dist/cjs/components/shared/action-button/style.scss +4 -0
  42. package/dist/cjs/components/shared/billing-timeframe/index.js +8 -4
  43. package/dist/cjs/components/shared/billing-timeframe/index.js.map +1 -1
  44. package/dist/cjs/components/shared/header-price/index.js +60 -15
  45. package/dist/cjs/components/shared/header-price/index.js.map +1 -1
  46. package/dist/cjs/components/shared/header-price/style.scss +10 -2
  47. package/dist/cjs/components/shared/storage/components/plan-storage.js +2 -2
  48. package/dist/cjs/components/shared/storage/components/plan-storage.js.map +1 -1
  49. package/dist/cjs/components/shared/storage/components/storage-dropdown.js +29 -6
  50. package/dist/cjs/components/shared/storage/components/storage-dropdown.js.map +1 -1
  51. package/dist/cjs/components/shared/storage/components/storage-feature-label.js +2 -1
  52. package/dist/cjs/components/shared/storage/components/storage-feature-label.js.map +1 -1
  53. package/dist/cjs/components/shared/storage/hooks/use-plan-storage.js +2 -0
  54. package/dist/cjs/components/shared/storage/hooks/use-plan-storage.js.map +1 -1
  55. package/dist/cjs/fixtures/sites-purchases.js +2 -4
  56. package/dist/cjs/fixtures/sites-purchases.js.map +1 -1
  57. package/dist/cjs/grid-context.js +4 -1
  58. package/dist/cjs/grid-context.js.map +1 -1
  59. package/dist/cjs/hooks/data-store/get-renewal-pricing-text.js +50 -0
  60. package/dist/cjs/hooks/data-store/get-renewal-pricing-text.js.map +1 -0
  61. package/dist/cjs/hooks/data-store/use-grid-plans-for-comparison-grid.js +6 -1
  62. package/dist/cjs/hooks/data-store/use-grid-plans-for-comparison-grid.js.map +1 -1
  63. package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js +6 -1
  64. package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
  65. package/dist/cjs/hooks/data-store/use-grid-plans.js +175 -21
  66. package/dist/cjs/hooks/data-store/use-grid-plans.js.map +1 -1
  67. package/dist/cjs/hooks/data-store/use-highlight-labels.js +13 -4
  68. package/dist/cjs/hooks/data-store/use-highlight-labels.js.map +1 -1
  69. package/dist/cjs/hooks/data-store/use-plan-billing-description.js +68 -13
  70. package/dist/cjs/hooks/data-store/use-plan-billing-description.js.map +1 -1
  71. package/dist/cjs/hooks/data-store/use-plan-billing-period.js +14 -0
  72. package/dist/cjs/hooks/data-store/use-plan-billing-period.js.map +1 -0
  73. package/dist/cjs/hooks/data-store/use-plan-features-for-grid-plans.js +76 -2
  74. package/dist/cjs/hooks/data-store/use-plan-features-for-grid-plans.js.map +1 -1
  75. package/dist/cjs/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js +60 -12
  76. package/dist/cjs/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js.map +1 -1
  77. package/dist/cjs/hooks/data-store/use-title-badges.js +19 -0
  78. package/dist/cjs/hooks/data-store/use-title-badges.js.map +1 -0
  79. package/dist/cjs/hooks/use-grid-size.js.map +1 -1
  80. package/dist/cjs/hooks/use-is-large-currency.js +2 -2
  81. package/dist/cjs/hooks/use-is-large-currency.js.map +1 -1
  82. package/dist/cjs/hooks/use-visible-grid-plans.js +70 -0
  83. package/dist/cjs/hooks/use-visible-grid-plans.js.map +1 -0
  84. package/dist/cjs/index.js +8 -1
  85. package/dist/cjs/index.js.map +1 -1
  86. package/dist/cjs/lib/get-plan-features-object.js +15 -2
  87. package/dist/cjs/lib/get-plan-features-object.js.map +1 -1
  88. package/dist/cjs/lib/plan-pricing-utils.js +135 -0
  89. package/dist/cjs/lib/plan-pricing-utils.js.map +1 -0
  90. package/dist/esm/_shared.scss +4 -3
  91. package/dist/esm/components/comparison-grid/index.js +102 -72
  92. package/dist/esm/components/comparison-grid/index.js.map +1 -1
  93. package/dist/esm/components/comparison-grid/index.stories.js.map +1 -1
  94. package/dist/esm/components/comparison-grid/style.scss +10 -2
  95. package/dist/esm/components/features-grid/client-logo-list/client-list.js +0 -12
  96. package/dist/esm/components/features-grid/client-logo-list/client-list.js.map +1 -1
  97. package/dist/esm/components/features-grid/index.js +9 -6
  98. package/dist/esm/components/features-grid/index.js.map +1 -1
  99. package/dist/esm/components/features-grid/plan-features-list.js +10 -3
  100. package/dist/esm/components/features-grid/plan-features-list.js.map +1 -1
  101. package/dist/esm/components/features-grid/plan-headers.js +3 -3
  102. package/dist/esm/components/features-grid/plan-headers.js.map +1 -1
  103. package/dist/esm/components/features-grid/plan-tagline.js +1 -1
  104. package/dist/esm/components/features-grid/plan-tagline.js.map +1 -1
  105. package/dist/esm/components/features-grid/style.scss +111 -21
  106. package/dist/esm/components/features-grid/table.js +1 -1
  107. package/dist/esm/components/features-grid/table.js.map +1 -1
  108. package/dist/esm/components/features.js +44 -5
  109. package/dist/esm/components/features.js.map +1 -1
  110. package/dist/esm/components/item.js +1 -1
  111. package/dist/esm/components/item.js.map +1 -1
  112. package/dist/esm/components/plan-button/index.js +5 -3
  113. package/dist/esm/components/plan-button/index.js.map +1 -1
  114. package/dist/esm/components/plan-button/style.scss +71 -47
  115. package/dist/esm/components/plan-div-td-container.js +4 -1
  116. package/dist/esm/components/plan-div-td-container.js.map +1 -1
  117. package/dist/esm/components/plan-logo.js +7 -4
  118. package/dist/esm/components/plan-logo.js.map +1 -1
  119. package/dist/esm/components/plan-type-selector/components/interval-type-dropdown.js +12 -1
  120. package/dist/esm/components/plan-type-selector/components/interval-type-dropdown.js.map +1 -1
  121. package/dist/esm/components/plan-type-selector/hooks/use-max-discount.js +3 -33
  122. package/dist/esm/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
  123. package/dist/esm/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +11 -13
  124. package/dist/esm/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
  125. package/dist/esm/components/plans-2023-tooltip.js +16 -5
  126. package/dist/esm/components/plans-2023-tooltip.js.map +1 -1
  127. package/dist/esm/components/shared/action-button/index.js +22 -7
  128. package/dist/esm/components/shared/action-button/index.js.map +1 -1
  129. package/dist/esm/components/shared/action-button/style.scss +4 -0
  130. package/dist/esm/components/shared/billing-timeframe/index.js +8 -4
  131. package/dist/esm/components/shared/billing-timeframe/index.js.map +1 -1
  132. package/dist/esm/components/shared/header-price/index.js +60 -15
  133. package/dist/esm/components/shared/header-price/index.js.map +1 -1
  134. package/dist/esm/components/shared/header-price/style.scss +10 -2
  135. package/dist/esm/components/shared/storage/components/plan-storage.js +2 -2
  136. package/dist/esm/components/shared/storage/components/plan-storage.js.map +1 -1
  137. package/dist/esm/components/shared/storage/components/storage-dropdown.js +30 -7
  138. package/dist/esm/components/shared/storage/components/storage-dropdown.js.map +1 -1
  139. package/dist/esm/components/shared/storage/components/storage-feature-label.js +2 -1
  140. package/dist/esm/components/shared/storage/components/storage-feature-label.js.map +1 -1
  141. package/dist/esm/components/shared/storage/hooks/use-plan-storage.js +3 -1
  142. package/dist/esm/components/shared/storage/hooks/use-plan-storage.js.map +1 -1
  143. package/dist/esm/fixtures/sites-purchases.js +2 -4
  144. package/dist/esm/fixtures/sites-purchases.js.map +1 -1
  145. package/dist/esm/grid-context.js +4 -1
  146. package/dist/esm/grid-context.js.map +1 -1
  147. package/dist/esm/hooks/data-store/get-renewal-pricing-text.js +47 -0
  148. package/dist/esm/hooks/data-store/get-renewal-pricing-text.js.map +1 -0
  149. package/dist/esm/hooks/data-store/use-grid-plans-for-comparison-grid.js +6 -1
  150. package/dist/esm/hooks/data-store/use-grid-plans-for-comparison-grid.js.map +1 -1
  151. package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js +6 -1
  152. package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
  153. package/dist/esm/hooks/data-store/use-grid-plans.js +176 -22
  154. package/dist/esm/hooks/data-store/use-grid-plans.js.map +1 -1
  155. package/dist/esm/hooks/data-store/use-highlight-labels.js +14 -5
  156. package/dist/esm/hooks/data-store/use-highlight-labels.js.map +1 -1
  157. package/dist/esm/hooks/data-store/use-plan-billing-description.js +66 -11
  158. package/dist/esm/hooks/data-store/use-plan-billing-description.js.map +1 -1
  159. package/dist/esm/hooks/data-store/use-plan-billing-period.js +12 -0
  160. package/dist/esm/hooks/data-store/use-plan-billing-period.js.map +1 -0
  161. package/dist/esm/hooks/data-store/use-plan-features-for-grid-plans.js +77 -3
  162. package/dist/esm/hooks/data-store/use-plan-features-for-grid-plans.js.map +1 -1
  163. package/dist/esm/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js +59 -11
  164. package/dist/esm/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js.map +1 -1
  165. package/dist/esm/hooks/data-store/use-title-badges.js +17 -0
  166. package/dist/esm/hooks/data-store/use-title-badges.js.map +1 -0
  167. package/dist/esm/hooks/use-grid-size.js.map +1 -1
  168. package/dist/esm/hooks/use-is-large-currency.js +1 -1
  169. package/dist/esm/hooks/use-is-large-currency.js.map +1 -1
  170. package/dist/esm/hooks/use-visible-grid-plans.js +66 -0
  171. package/dist/esm/hooks/use-visible-grid-plans.js.map +1 -0
  172. package/dist/esm/index.js +4 -1
  173. package/dist/esm/index.js.map +1 -1
  174. package/dist/esm/lib/get-plan-features-object.js +15 -2
  175. package/dist/esm/lib/get-plan-features-object.js.map +1 -1
  176. package/dist/esm/lib/plan-pricing-utils.js +129 -0
  177. package/dist/esm/lib/plan-pricing-utils.js.map +1 -0
  178. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  179. package/dist/tsconfig.tsbuildinfo +1 -1
  180. package/dist/types/components/comparison-grid/index.d.ts +1 -1
  181. package/dist/types/components/comparison-grid/index.d.ts.map +1 -1
  182. package/dist/types/components/comparison-grid/index.stories.d.ts +2 -2
  183. package/dist/types/components/dropdown-option.d.ts.map +1 -1
  184. package/dist/types/components/features-grid/billing-timeframes.d.ts.map +1 -1
  185. package/dist/types/components/features-grid/client-logo-list/client-list.d.ts.map +1 -1
  186. package/dist/types/components/features-grid/client-logo-list/index.d.ts.map +1 -1
  187. package/dist/types/components/features-grid/enterprise-features.d.ts.map +1 -1
  188. package/dist/types/components/features-grid/index.d.ts.map +1 -1
  189. package/dist/types/components/features-grid/plan-features-list.d.ts.map +1 -1
  190. package/dist/types/components/features-grid/plan-headers.d.ts +2 -0
  191. package/dist/types/components/features-grid/plan-headers.d.ts.map +1 -1
  192. package/dist/types/components/features-grid/plan-logos.d.ts.map +1 -1
  193. package/dist/types/components/features-grid/plan-prices.d.ts.map +1 -1
  194. package/dist/types/components/features-grid/plan-tagline.d.ts.map +1 -1
  195. package/dist/types/components/features-grid/previous-features-included-title.d.ts.map +1 -1
  196. package/dist/types/components/features-grid/spotlight-plan.d.ts.map +1 -1
  197. package/dist/types/components/features-grid/table.d.ts.map +1 -1
  198. package/dist/types/components/features-grid/top-buttons.d.ts.map +1 -1
  199. package/dist/types/components/features.d.ts.map +1 -1
  200. package/dist/types/components/item.d.ts +2 -1
  201. package/dist/types/components/item.d.ts.map +1 -1
  202. package/dist/types/components/plan-button/index.d.ts +2 -1
  203. package/dist/types/components/plan-button/index.d.ts.map +1 -1
  204. package/dist/types/components/plan-div-td-container.d.ts +2 -0
  205. package/dist/types/components/plan-div-td-container.d.ts.map +1 -1
  206. package/dist/types/components/plan-logo.d.ts.map +1 -1
  207. package/dist/types/components/plan-type-selector/components/interval-type-dropdown.d.ts.map +1 -1
  208. package/dist/types/components/plan-type-selector/hooks/use-max-discount.d.ts.map +1 -1
  209. package/dist/types/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.d.ts.map +1 -1
  210. package/dist/types/components/plans-2023-tooltip.d.ts.map +1 -1
  211. package/dist/types/components/shared/action-button/index.d.ts +2 -1
  212. package/dist/types/components/shared/action-button/index.d.ts.map +1 -1
  213. package/dist/types/components/shared/billing-timeframe/index.d.ts.map +1 -1
  214. package/dist/types/components/shared/header-price/header-price-context.d.ts.map +1 -1
  215. package/dist/types/components/shared/header-price/index.d.ts.map +1 -1
  216. package/dist/types/components/shared/storage/components/plan-storage.d.ts.map +1 -1
  217. package/dist/types/components/shared/storage/components/storage-dropdown.d.ts.map +1 -1
  218. package/dist/types/components/shared/storage/components/storage-feature-label.d.ts.map +1 -1
  219. package/dist/types/components/shared/storage/hooks/use-plan-storage.d.ts +1 -1
  220. package/dist/types/components/shared/storage/hooks/use-plan-storage.d.ts.map +1 -1
  221. package/dist/types/css-mixins.d.ts.map +1 -1
  222. package/dist/types/fixtures/sites-purchases.d.ts +2 -4
  223. package/dist/types/fixtures/sites-purchases.d.ts.map +1 -1
  224. package/dist/types/grid-context.d.ts +4 -1
  225. package/dist/types/grid-context.d.ts.map +1 -1
  226. package/dist/types/hooks/data-store/get-renewal-pricing-text.d.ts +14 -0
  227. package/dist/types/hooks/data-store/get-renewal-pricing-text.d.ts.map +1 -0
  228. package/dist/types/hooks/data-store/types.d.ts +21 -0
  229. package/dist/types/hooks/data-store/types.d.ts.map +1 -1
  230. package/dist/types/hooks/data-store/use-grid-plan-for-spotlight.d.ts.map +1 -1
  231. package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts +1 -1
  232. package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts.map +1 -1
  233. package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts +1 -1
  234. package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts.map +1 -1
  235. package/dist/types/hooks/data-store/use-grid-plans.d.ts.map +1 -1
  236. package/dist/types/hooks/data-store/use-highlight-labels.d.ts.map +1 -1
  237. package/dist/types/hooks/data-store/use-plan-billing-description.d.ts.map +1 -1
  238. package/dist/types/hooks/data-store/use-plan-billing-period.d.ts +8 -0
  239. package/dist/types/hooks/data-store/use-plan-billing-period.d.ts.map +1 -0
  240. package/dist/types/hooks/data-store/use-plan-features-for-grid-plans.d.ts +4 -1
  241. package/dist/types/hooks/data-store/use-plan-features-for-grid-plans.d.ts.map +1 -1
  242. package/dist/types/hooks/data-store/use-plans-from-types.d.ts.map +1 -1
  243. package/dist/types/hooks/data-store/use-restructured-plan-features-for-comparison-grid.d.ts +4 -1
  244. package/dist/types/hooks/data-store/use-restructured-plan-features-for-comparison-grid.d.ts.map +1 -1
  245. package/dist/types/hooks/data-store/use-title-badges.d.ts +9 -0
  246. package/dist/types/hooks/data-store/use-title-badges.d.ts.map +1 -0
  247. package/dist/types/hooks/use-grid-size.d.ts +3 -2
  248. package/dist/types/hooks/use-grid-size.d.ts.map +1 -1
  249. package/dist/types/hooks/use-highlight-adjacency-matrix.d.ts.map +1 -1
  250. package/dist/types/hooks/use-visible-grid-plans.d.ts +14 -0
  251. package/dist/types/hooks/use-visible-grid-plans.d.ts.map +1 -0
  252. package/dist/types/index.d.ts +9 -1
  253. package/dist/types/index.d.ts.map +1 -1
  254. package/dist/types/lib/filter-unused-features-object.d.ts.map +1 -1
  255. package/dist/types/lib/get-plan-features-object.d.ts +1 -1
  256. package/dist/types/lib/get-plan-features-object.d.ts.map +1 -1
  257. package/dist/types/lib/plan-pricing-utils.d.ts +105 -0
  258. package/dist/types/lib/plan-pricing-utils.d.ts.map +1 -0
  259. package/dist/types/types.d.ts +33 -6
  260. package/dist/types/types.d.ts.map +1 -1
  261. package/package.json +39 -28
  262. package/src/_shared.scss +4 -3
  263. package/src/components/comparison-grid/index.stories.tsx +1 -1
  264. package/src/components/comparison-grid/index.tsx +263 -158
  265. package/src/components/comparison-grid/style.scss +10 -2
  266. package/src/components/features-grid/client-logo-list/client-list.tsx +0 -25
  267. package/src/components/features-grid/index.tsx +37 -19
  268. package/src/components/features-grid/plan-features-list.tsx +15 -4
  269. package/src/components/features-grid/plan-headers.tsx +10 -3
  270. package/src/components/features-grid/plan-tagline.tsx +1 -1
  271. package/src/components/features-grid/style.scss +111 -21
  272. package/src/components/features-grid/table.tsx +4 -2
  273. package/src/components/features.tsx +66 -6
  274. package/src/components/item.tsx +6 -3
  275. package/src/components/plan-button/index.tsx +7 -1
  276. package/src/components/plan-button/style.scss +71 -47
  277. package/src/components/plan-div-td-container.tsx +6 -2
  278. package/src/components/plan-logo.tsx +16 -9
  279. package/src/components/plan-type-selector/components/interval-type-dropdown.tsx +14 -1
  280. package/src/components/plan-type-selector/hooks/use-max-discount.ts +8 -47
  281. package/src/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.ts +19 -17
  282. package/src/components/plans-2023-tooltip.tsx +17 -5
  283. package/src/components/shared/action-button/index.tsx +46 -5
  284. package/src/components/shared/action-button/style.scss +4 -0
  285. package/src/components/shared/billing-timeframe/index.tsx +12 -7
  286. package/src/components/shared/header-price/index.tsx +129 -27
  287. package/src/components/shared/header-price/style.scss +10 -2
  288. package/src/components/shared/storage/components/plan-storage.tsx +2 -2
  289. package/src/components/shared/storage/components/storage-dropdown.tsx +36 -15
  290. package/src/components/shared/storage/components/storage-feature-label.tsx +2 -1
  291. package/src/components/shared/storage/hooks/use-plan-storage.ts +3 -0
  292. package/src/components/test/actions-button.tsx +5 -0
  293. package/src/components/test/billing-timeframe.tsx +1 -1
  294. package/src/components/test/header-price.tsx +342 -4
  295. package/src/fixtures/sites-purchases.ts +2 -4
  296. package/src/grid-context.tsx +9 -0
  297. package/src/hooks/data-store/get-renewal-pricing-text.ts +73 -0
  298. package/src/hooks/data-store/types.ts +21 -0
  299. package/src/hooks/data-store/use-grid-plans-for-comparison-grid.ts +10 -0
  300. package/src/hooks/data-store/use-grid-plans-for-features-grid.ts +10 -0
  301. package/src/hooks/data-store/use-grid-plans.tsx +189 -23
  302. package/src/hooks/data-store/use-highlight-labels.ts +12 -3
  303. package/src/hooks/data-store/use-plan-billing-description.tsx +80 -15
  304. package/src/hooks/data-store/use-plan-billing-period.tsx +28 -0
  305. package/src/hooks/data-store/use-plan-features-for-grid-plans.ts +135 -1
  306. package/src/hooks/data-store/use-restructured-plan-features-for-comparison-grid.ts +93 -20
  307. package/src/hooks/data-store/use-title-badges.ts +31 -0
  308. package/src/hooks/test/use-visible-grid-plans.tsx +116 -0
  309. package/src/hooks/use-grid-size.ts +3 -2
  310. package/src/hooks/use-is-large-currency.ts +1 -1
  311. package/src/hooks/use-visible-grid-plans.tsx +102 -0
  312. package/src/index.tsx +20 -0
  313. package/src/lib/get-plan-features-object.ts +23 -2
  314. package/src/lib/plan-pricing-utils.ts +211 -0
  315. package/src/lib/test/plan-pricing-utils.ts +594 -0
  316. package/src/style-imports.d.ts +3 -0
  317. package/src/types.ts +45 -4
  318. package/dist/cjs/components/features-grid/mobile-free-domain.js +0 -25
  319. package/dist/cjs/components/features-grid/mobile-free-domain.js.map +0 -1
  320. package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js +0 -15
  321. package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js.map +0 -1
  322. package/dist/cjs/lib/sort-plan-properties.js +0 -26
  323. package/dist/cjs/lib/sort-plan-properties.js.map +0 -1
  324. package/dist/esm/components/features-grid/mobile-free-domain.js +0 -23
  325. package/dist/esm/components/features-grid/mobile-free-domain.js.map +0 -1
  326. package/dist/esm/lib/get-plan-pricing-info-from-grid-plans.js +0 -12
  327. package/dist/esm/lib/get-plan-pricing-info-from-grid-plans.js.map +0 -1
  328. package/dist/esm/lib/sort-plan-properties.js +0 -23
  329. package/dist/esm/lib/sort-plan-properties.js.map +0 -1
  330. package/dist/types/components/features-grid/mobile-free-domain.d.ts +0 -8
  331. package/dist/types/components/features-grid/mobile-free-domain.d.ts.map +0 -1
  332. package/dist/types/lib/get-plan-pricing-info-from-grid-plans.d.ts +0 -9
  333. package/dist/types/lib/get-plan-pricing-info-from-grid-plans.d.ts.map +0 -1
  334. package/dist/types/lib/sort-plan-properties.d.ts +0 -3
  335. package/dist/types/lib/sort-plan-properties.d.ts.map +0 -1
  336. package/src/components/features-grid/mobile-free-domain.tsx +0 -51
  337. package/src/lib/get-plan-pricing-info-from-grid-plans.ts +0 -31
  338. package/src/lib/sort-plan-properties.ts +0 -27
  339. package/src/lib/test/sort-plan-properties.ts +0 -122
@@ -8,6 +8,8 @@ import {
8
8
  TYPE_PREMIUM,
9
9
  TYPE_WOOEXPRESS_MEDIUM,
10
10
  TYPE_WOOEXPRESS_SMALL,
11
+ TYPE_WOO_HOSTED_BASIC,
12
+ TYPE_WOO_HOSTED_PRO,
11
13
  getPlan,
12
14
  isBloggerPlan,
13
15
  applyTestFiltersToPlansList,
@@ -23,12 +25,16 @@ import {
23
25
  isPremiumPlan,
24
26
  isFreePlan,
25
27
  isPersonalPlan,
28
+ planHasFeature,
29
+ getPlanClass,
26
30
  } from '@automattic/calypso-products';
27
31
  import { Plans } from '@automattic/data-stores';
32
+ import i18n, { useTranslate } from 'i18n-calypso';
28
33
  import { isSamePlan } from '../../lib/is-same-plan';
29
34
  import { UseGridPlansParams, UseGridPlansType } from './types';
30
35
  import useHighlightLabels from './use-highlight-labels';
31
36
  import usePlansFromTypes from './use-plans-from-types';
37
+ import useTitleBadges from './use-title-badges';
32
38
  import type { HiddenPlans, PlansIntent } from '../../types';
33
39
  import type { TranslateResult } from 'i18n-calypso';
34
40
 
@@ -51,39 +57,57 @@ const isGridPlanVisible = ( {
51
57
  hideEcommercePlan,
52
58
  } = {},
53
59
  isDisplayingPlansNeededForFeature,
54
- planSlug,
60
+ gridPlanSlug,
55
61
  planSlugsForIntent,
56
62
  selectedPlan,
63
+ selectedFeature,
64
+ currentPlanSlug,
57
65
  }: {
58
66
  hiddenPlans?: HiddenPlans;
59
67
  isDisplayingPlansNeededForFeature?: boolean;
60
- planSlug: PlanSlug;
68
+ gridPlanSlug: PlanSlug;
61
69
  planSlugsForIntent: PlanSlug[];
62
70
  selectedPlan?: PlanSlug;
71
+ selectedFeature?: string | null;
72
+ currentPlanSlug?: PlanSlug;
63
73
  } ): boolean => {
64
- let isVisible = planSlugsForIntent.includes( planSlug );
74
+ let isVisible = planSlugsForIntent.includes( gridPlanSlug );
65
75
 
66
- if ( isDisplayingPlansNeededForFeature && selectedPlan ) {
67
- if ( isEcommercePlan( selectedPlan ) ) {
68
- isVisible = isEcommercePlan( planSlug );
76
+ if ( isDisplayingPlansNeededForFeature ) {
77
+ // Feature-based filtering: Show the plan being evaluated if it includes the selected feature,
78
+ // or if it's the user's current plan (ignoring billing term length)
79
+ if ( selectedFeature && ! selectedPlan ) {
80
+ const hasFeature = planHasFeature( gridPlanSlug, selectedFeature );
81
+ const isCurrentPlan =
82
+ currentPlanSlug && getPlanClass( currentPlanSlug ) === getPlanClass( gridPlanSlug );
83
+ isVisible = isVisible && ( isCurrentPlan || hasFeature );
69
84
  }
85
+ // Plan-tier-based filtering: When a specific plan is pre-selected,
86
+ // show that plan tier and all higher tiers (e.g., if Premium is selected, show Premium + Business + Commerce)
87
+ else if ( selectedPlan ) {
88
+ if ( isEcommercePlan( selectedPlan ) ) {
89
+ isVisible = isEcommercePlan( gridPlanSlug );
90
+ }
70
91
 
71
- if ( isBusinessPlan( selectedPlan ) ) {
72
- isVisible = isBusinessPlan( planSlug ) || isEcommercePlan( planSlug );
73
- }
92
+ if ( isBusinessPlan( selectedPlan ) ) {
93
+ isVisible = isBusinessPlan( gridPlanSlug ) || isEcommercePlan( gridPlanSlug );
94
+ }
74
95
 
75
- if ( isPremiumPlan( selectedPlan ) ) {
76
- isVisible =
77
- isPremiumPlan( planSlug ) || isBusinessPlan( planSlug ) || isEcommercePlan( planSlug );
96
+ if ( isPremiumPlan( selectedPlan ) ) {
97
+ isVisible =
98
+ isPremiumPlan( gridPlanSlug ) ||
99
+ isBusinessPlan( gridPlanSlug ) ||
100
+ isEcommercePlan( gridPlanSlug );
101
+ }
78
102
  }
79
103
  }
80
104
 
81
105
  if (
82
- ( hideFreePlan && isFreePlan( planSlug ) ) ||
83
- ( hidePersonalPlan && isPersonalPlan( planSlug ) ) ||
84
- ( hidePremiumPlan && isPremiumPlan( planSlug ) ) ||
85
- ( hideBusinessPlan && isBusinessPlan( planSlug ) ) ||
86
- ( hideEcommercePlan && isEcommercePlan( planSlug ) )
106
+ ( hideFreePlan && isFreePlan( gridPlanSlug ) ) ||
107
+ ( hidePersonalPlan && isPersonalPlan( gridPlanSlug ) ) ||
108
+ ( hidePremiumPlan && isPremiumPlan( gridPlanSlug ) ) ||
109
+ ( hideBusinessPlan && isBusinessPlan( gridPlanSlug ) ) ||
110
+ ( hideEcommercePlan && isEcommercePlan( gridPlanSlug ) )
87
111
  ) {
88
112
  isVisible = false;
89
113
  }
@@ -122,6 +146,8 @@ export const usePlanTypesWithIntent = ( {
122
146
  ...( isEnterpriseAvailable ? [ TYPE_ENTERPRISE_GRID_WPCOM ] : [] ),
123
147
  TYPE_WOOEXPRESS_SMALL,
124
148
  TYPE_WOOEXPRESS_MEDIUM,
149
+ TYPE_WOO_HOSTED_BASIC,
150
+ TYPE_WOO_HOSTED_PRO,
125
151
  TYPE_P2_PLUS,
126
152
  ];
127
153
 
@@ -150,11 +176,14 @@ export const usePlanTypesWithIntent = ( {
150
176
  planTypes = [ TYPE_FREE, TYPE_PERSONAL, TYPE_PREMIUM ];
151
177
  break;
152
178
  case 'plans-new-hosted-site':
153
- planTypes = [ TYPE_BUSINESS, TYPE_ECOMMERCE ];
179
+ planTypes = [ TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
154
180
  break;
155
181
  case 'plans-new-hosted-site-business-only':
156
182
  planTypes = [ TYPE_BUSINESS ];
157
183
  break;
184
+ case 'plans-ai-assembler-free-trial':
185
+ planTypes = [ TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS ];
186
+ break;
158
187
  case 'plans-import':
159
188
  planTypes = [ TYPE_FREE, TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS ];
160
189
  break;
@@ -165,6 +194,42 @@ export const usePlanTypesWithIntent = ( {
165
194
  TYPE_ECOMMERCE,
166
195
  ];
167
196
  break;
197
+ case 'plans-upgrade': {
198
+ // Show current plan plus all higher-tier plans (upgrade options only)
199
+ const upgradePlanTypes = [
200
+ TYPE_FREE,
201
+ TYPE_PERSONAL,
202
+ TYPE_PREMIUM,
203
+ TYPE_BUSINESS,
204
+ TYPE_ECOMMERCE,
205
+ ];
206
+ if ( isEnterpriseAvailable ) {
207
+ upgradePlanTypes.push( TYPE_ENTERPRISE_GRID_WPCOM );
208
+ }
209
+
210
+ // Find the index of the current plan in the hierarchy
211
+ const currentPlanIndex = currentSitePlanType
212
+ ? upgradePlanTypes.findIndex( ( planType ) => planType === currentSitePlanType )
213
+ : -1;
214
+
215
+ if ( currentPlanIndex >= 0 ) {
216
+ // Show current plan and all plans after it (higher tiers)
217
+ planTypes = upgradePlanTypes.slice( currentPlanIndex );
218
+ } else {
219
+ // If current plan not found or no current plan, show all plans
220
+ planTypes = upgradePlanTypes;
221
+ }
222
+ break;
223
+ }
224
+ case 'plans-upgrade-or-downgrade': {
225
+ // Show all plans — used when the current plan is expired and the user
226
+ // may want to downgrade as well as upgrade.
227
+ planTypes = [ TYPE_FREE, TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
228
+ if ( isEnterpriseAvailable ) {
229
+ planTypes.push( TYPE_ENTERPRISE_GRID_WPCOM );
230
+ }
231
+ break;
232
+ }
168
233
  case 'plans-jetpack-app':
169
234
  planTypes = [ TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
170
235
  break;
@@ -199,9 +264,35 @@ export const usePlanTypesWithIntent = ( {
199
264
  planTypes = [ TYPE_PREMIUM, TYPE_BUSINESS ];
200
265
  break;
201
266
  case 'plans-affiliate':
267
+ planTypes = [ TYPE_BUSINESS, TYPE_ECOMMERCE ];
268
+ break;
202
269
  case 'plans-site-selected-legacy':
203
270
  planTypes = [ TYPE_FREE, TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
204
271
  break;
272
+ case 'plans-playground':
273
+ planTypes = [ TYPE_BUSINESS, TYPE_ECOMMERCE ];
274
+ break;
275
+ case 'plans-playground-premium':
276
+ // This plan intent is currently not utilized but will be soon
277
+ planTypes = [ TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
278
+ break;
279
+ case 'plans-wordpress-hosting':
280
+ planTypes = [ TYPE_BUSINESS, TYPE_ECOMMERCE, TYPE_ENTERPRISE_GRID_WPCOM ];
281
+ break;
282
+ case 'plans-website-builder':
283
+ planTypes = [ TYPE_FREE, TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS ];
284
+ break;
285
+ case 'plans-woo-hosted':
286
+ planTypes = [ TYPE_WOO_HOSTED_BASIC, TYPE_WOO_HOSTED_PRO ];
287
+ break;
288
+ // Used by the woo-hosting-solutions-flow ref: only show plans that support
289
+ // post-checkout WooCommerce auto-install.
290
+ case 'plans-woo-hosting-solutions':
291
+ planTypes = [ TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
292
+ break;
293
+ case 'plans-migration':
294
+ planTypes = [ TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS, TYPE_ECOMMERCE ];
295
+ break;
205
296
  default:
206
297
  planTypes = availablePlanTypes;
207
298
  }
@@ -223,6 +314,7 @@ const useGridPlans: UseGridPlansType = ( {
223
314
  term = TERM_MONTHLY,
224
315
  intent,
225
316
  selectedPlan,
317
+ selectedFeature,
226
318
  hiddenPlans,
227
319
  isInSignup,
228
320
  eligibleForFreeHostingTrial,
@@ -233,7 +325,10 @@ const useGridPlans: UseGridPlansType = ( {
233
325
  highlightLabelOverrides,
234
326
  isDomainOnlySite,
235
327
  reflectStorageSelectionInPlanPrices,
328
+ useFocusedNewCopyTaglines,
329
+ showBillingDescriptionForIncreasedRenewalPrice,
236
330
  } ) => {
331
+ const translate = useTranslate();
237
332
  const freeTrialPlanSlugs = useFreeTrialPlanSlugs?.( {
238
333
  intent: intent ?? 'default',
239
334
  eligibleForFreeHostingTrial,
@@ -281,6 +376,11 @@ const useGridPlans: UseGridPlansType = ( {
281
376
  isDomainOnlySite: isDomainOnlySite || false,
282
377
  } );
283
378
 
379
+ const titleBadges = useTitleBadges( {
380
+ intent,
381
+ planSlugs: planSlugsForIntent,
382
+ } );
383
+
284
384
  // TODO: pricedAPIPlans to be queried from data-store package
285
385
  const pricedAPIPlans = Plans.usePlans( { coupon } );
286
386
  const pricingMeta = Plans.usePricingMetaForGridPlans( {
@@ -289,6 +389,7 @@ const useGridPlans: UseGridPlansType = ( {
289
389
  siteId,
290
390
  useCheckPlanAvailabilityForPurchase,
291
391
  reflectStorageSelectionInPlanPrices,
392
+ showBillingDescriptionForIncreasedRenewalPrice,
292
393
  } );
293
394
 
294
395
  // Null return would indicate that we are still loading the data. No grid without grid plans.
@@ -313,14 +414,76 @@ const useGridPlans: UseGridPlansType = ( {
313
414
  tagline = planConstantObj.getNewsletterTagLine?.() ?? '';
314
415
  } else if ( 'plans-blog-onboarding' === intent ) {
315
416
  tagline = planConstantObj.getBlogOnboardingTagLine?.() ?? '';
417
+ } else if ( 'plans-woo-hosting-solutions' === intent ) {
418
+ if ( isPersonalPlan( planSlug ) ) {
419
+ tagline = translate(
420
+ 'Try out a store idea with low commitment. Custom domain and basic tools.'
421
+ );
422
+ } else if ( isPremiumPlan( planSlug ) ) {
423
+ tagline = translate(
424
+ 'A solid foundation for new stores. More design options and faster support when you need help.'
425
+ );
426
+ } else if ( isBusinessPlan( planSlug ) ) {
427
+ tagline = translate(
428
+ 'Built for real stores. 24/7 priority support, advanced features, and the performance your customers expect.'
429
+ );
430
+ } else if ( isEcommercePlan( planSlug ) ) {
431
+ tagline = translate(
432
+ 'For serious stores. Priority support, advanced extensions, and premium store themes.'
433
+ );
434
+ } else {
435
+ tagline = planConstantObj.getPlanTagline?.() ?? '';
436
+ }
316
437
  } else {
317
438
  tagline = planConstantObj.getPlanTagline?.() ?? '';
318
439
  }
319
440
 
320
- const productNameShort =
321
- isWpcomEnterpriseGridPlan( planSlug ) && planConstantObj.getPathSlug
322
- ? planConstantObj.getPathSlug()
323
- : planObject?.productNameShort ?? null;
441
+ if ( useFocusedNewCopyTaglines ) {
442
+ const existingTagline = tagline;
443
+ if ( isFreePlan( planSlug ) ) {
444
+ tagline =
445
+ i18n.getLocaleSlug()?.startsWith( 'en' ) ||
446
+ i18n.hasTranslation( 'Start your WordPress journey.' )
447
+ ? translate( 'Start your WordPress journey.' )
448
+ : existingTagline;
449
+ } else if ( isPersonalPlan( planSlug ) ) {
450
+ tagline =
451
+ i18n.getLocaleSlug()?.startsWith( 'en' ) ||
452
+ i18n.hasTranslation( 'Build your presence with a site you can customize.' )
453
+ ? translate( 'Build your presence with a site you can customize.' )
454
+ : existingTagline;
455
+ } else if ( isPremiumPlan( planSlug ) ) {
456
+ tagline =
457
+ i18n.getLocaleSlug()?.startsWith( 'en' ) ||
458
+ i18n.hasTranslation( 'Accept payments on your site and reach more people.' )
459
+ ? translate( 'Accept payments on your site and reach more people.' )
460
+ : existingTagline;
461
+ } else if ( isBusinessPlan( planSlug ) ) {
462
+ tagline =
463
+ i18n.getLocaleSlug()?.startsWith( 'en' ) ||
464
+ i18n.hasTranslation( 'Grow your business with powerful tools and priority support.' )
465
+ ? translate( 'Grow your business with powerful tools and priority support.' )
466
+ : existingTagline;
467
+ } else if ( isEcommercePlan( planSlug ) ) {
468
+ tagline =
469
+ i18n.getLocaleSlug()?.startsWith( 'en' ) ||
470
+ i18n.hasTranslation( 'Run an online store and keep more of what you earn.' )
471
+ ? translate( 'Run an online store and keep more of what you earn.' )
472
+ : existingTagline;
473
+ } else if ( isWpcomEnterpriseGridPlan( planSlug ) ) {
474
+ tagline =
475
+ i18n.getLocaleSlug()?.startsWith( 'en' ) ||
476
+ i18n.hasTranslation( 'Publish securely at enterprise scale.' )
477
+ ? translate( 'Publish securely at enterprise scale.' )
478
+ : existingTagline;
479
+ }
480
+ }
481
+
482
+ // The enterprise plan isn't returned by the plans endpoint, so it has no
483
+ // server-provided product name; fall back to its fixed path slug.
484
+ const productNameShort = isWpcomEnterpriseGridPlan( planSlug )
485
+ ? 'enterprise'
486
+ : planObject?.productNameShort ?? null;
324
487
 
325
488
  // cartItemForPlan done in line here as it's a small piece of logic to pass another selector for
326
489
  const cartItemForPlan =
@@ -331,9 +494,11 @@ const useGridPlans: UseGridPlansType = ( {
331
494
  };
332
495
 
333
496
  const isVisible = isGridPlanVisible( {
334
- planSlug,
497
+ gridPlanSlug: planSlug,
335
498
  planSlugsForIntent,
336
499
  selectedPlan,
500
+ selectedFeature,
501
+ currentPlanSlug: sitePlanSlug,
337
502
  hiddenPlans,
338
503
  isDisplayingPlansNeededForFeature,
339
504
  } );
@@ -352,6 +517,7 @@ const useGridPlans: UseGridPlansType = ( {
352
517
  isMonthlyPlan,
353
518
  cartItemForPlan,
354
519
  highlightLabel: highlightLabels[ planSlug ],
520
+ titleBadge: titleBadges[ planSlug ],
355
521
  pricing: pricingMeta[ planSlug ],
356
522
  };
357
523
  } );
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  isBusinessPlan,
3
+ isEcommercePlan,
3
4
  isPremiumPlan,
4
5
  isPersonalPlan,
5
6
  planLevelsMatch,
@@ -34,6 +35,8 @@ const useHighlightLabels = ( {
34
35
  isDomainOnlySite,
35
36
  }: Props ) => {
36
37
  const translate = useTranslate();
38
+ const isVisualSplitIntent =
39
+ intent === 'plans-wordpress-hosting' || intent === 'plans-website-builder';
37
40
 
38
41
  return planSlugs.reduce(
39
42
  ( acc, planSlug ) => {
@@ -70,10 +73,16 @@ const useHighlightLabels = ( {
70
73
  if ( isPremiumPlan( planSlug ) ) {
71
74
  label = translate( 'Best for Blog' );
72
75
  }
73
- } else if ( isBusinessPlan( planSlug ) && ! selectedPlan ) {
74
- label = translate( 'Best for devs' );
75
- } else if ( isPopularPlan( planSlug ) && ! selectedPlan ) {
76
+ } else if ( 'plans-affiliate' === intent && isBusinessPlan( planSlug ) ) {
76
77
  label = translate( 'Popular' );
78
+ } else if ( 'plans-woo-hosting-solutions' === intent ) {
79
+ if ( isEcommercePlan( planSlug ) ) {
80
+ label = translate( 'Best value' );
81
+ }
82
+ } else if ( isBusinessPlan( planSlug ) && ! selectedPlan && ! isVisualSplitIntent ) {
83
+ label = translate( 'Best value' );
84
+ } else if ( isPopularPlan( planSlug ) && ! selectedPlan && ! isVisualSplitIntent ) {
85
+ label = translate( 'Most popular' );
77
86
  }
78
87
 
79
88
  return {
@@ -10,8 +10,11 @@ import {
10
10
  PLAN_HOSTING_TRIAL_MONTHLY,
11
11
  } from '@automattic/calypso-products';
12
12
  import { Plans } from '@automattic/data-stores';
13
- import { useTranslate, formatCurrency } from 'i18n-calypso';
13
+ import { formatCurrency } from '@automattic/number-formatters';
14
+ import { useTranslate } from 'i18n-calypso';
14
15
  import { usePlansGridContext } from '../../grid-context';
16
+ import { calculateDiscountPercentage } from '../../lib/plan-pricing-utils';
17
+ import { getRenewalPricingText } from './get-renewal-pricing-text';
15
18
  import type { GridPlan } from '../../types';
16
19
 
17
20
  interface UsePlanBillingDescriptionProps {
@@ -34,7 +37,12 @@ export default function usePlanBillingDescription( {
34
37
  }: UsePlanBillingDescriptionProps ) {
35
38
  const translate = useTranslate();
36
39
  const { currencyCode, originalPrice, discountedPrice, billingPeriod, introOffer } = pricing || {};
37
- const { reflectStorageSelectionInPlanPrices } = usePlansGridContext();
40
+ const {
41
+ reflectStorageSelectionInPlanPrices,
42
+ showSimplifiedBillingDescription,
43
+ showBillingDescriptionForIncreasedRenewalPrice,
44
+ enableCategorisedFeatures,
45
+ } = usePlansGridContext();
38
46
  const yearlyVariantPlanSlug = getPlanSlugForTermVariant( planSlug, TERM_ANNUALLY );
39
47
 
40
48
  const yearlyVariantPricing = Plans.usePricingMetaForGridPlans( {
@@ -63,23 +71,33 @@ export default function usePlanBillingDescription( {
63
71
  yearlyVariantPricing &&
64
72
  ( ! introOffer || introOffer.isOfferComplete )
65
73
  ) {
66
- const yearlyVariantMaybeDiscountedPrice = Number.isFinite(
74
+ // For renewal pricing experiment in FeaturesGrid, show "per month" and move savings text to post-button area
75
+ // For ComparisonGrid, keep the original savings text above the button
76
+ if ( showBillingDescriptionForIncreasedRenewalPrice && enableCategorisedFeatures ) {
77
+ return translate( 'per month' );
78
+ }
79
+
80
+ let yearlyVariantMaybeDiscountedPrice = Number.isFinite(
67
81
  yearlyVariantPricing.discountedPrice?.monthly
68
82
  )
69
83
  ? yearlyVariantPricing.discountedPrice?.monthly
70
84
  : yearlyVariantPricing.originalPrice?.monthly;
71
85
 
72
- if (
73
- yearlyVariantMaybeDiscountedPrice &&
74
- yearlyVariantMaybeDiscountedPrice < originalPrice.monthly
75
- ) {
86
+ if ( showBillingDescriptionForIncreasedRenewalPrice ) {
87
+ yearlyVariantMaybeDiscountedPrice = Number.isFinite(
88
+ yearlyVariantPricing.discountedPrice?.monthly
89
+ )
90
+ ? yearlyVariantPricing.discountedPrice?.monthly
91
+ : yearlyVariantPricing.introOffer?.rawPrice?.monthly ?? null;
92
+ }
93
+
94
+ const discountRate =
95
+ yearlyVariantMaybeDiscountedPrice != null
96
+ ? calculateDiscountPercentage( originalPrice.monthly, yearlyVariantMaybeDiscountedPrice )
97
+ : undefined;
98
+ if ( discountRate !== undefined ) {
76
99
  return translate( 'Save %(discountRate)s%% by paying annually', {
77
- args: {
78
- discountRate: Math.floor(
79
- ( 100 * ( originalPrice.monthly - yearlyVariantMaybeDiscountedPrice ) ) /
80
- originalPrice.monthly
81
- ),
82
- },
100
+ args: { discountRate },
83
101
  } );
84
102
  }
85
103
 
@@ -106,7 +124,12 @@ export default function usePlanBillingDescription( {
106
124
  * 1. We only expose introOffers to monthly & yearly plans for now (so no need to introduce more translations just yet)
107
125
  * 2. We only expose month & year based intervals for now (so no need to introduce more translations just yet)
108
126
  */
109
- if ( introOffer?.intervalCount && introOffer.intervalUnit && ! introOffer.isOfferComplete ) {
127
+ if (
128
+ introOffer?.intervalCount &&
129
+ introOffer.intervalUnit &&
130
+ ! introOffer.isOfferComplete &&
131
+ ! showBillingDescriptionForIncreasedRenewalPrice
132
+ ) {
110
133
  const discountedPriceFull =
111
134
  typeof discountedPrice?.full === 'number' ? discountedPrice.full : introOffer?.rawPrice?.full;
112
135
 
@@ -252,7 +275,15 @@ export default function usePlanBillingDescription( {
252
275
  return null;
253
276
  }
254
277
 
255
- if ( discountedPriceFullTermText ) {
278
+ // For renewal pricing experiment with intro pricing
279
+ if ( showBillingDescriptionForIncreasedRenewalPrice && discountedPriceFullTermText ) {
280
+ // In FeaturesGrid, show "per month" above button
281
+ if ( enableCategorisedFeatures ) {
282
+ return translate( 'per month' );
283
+ }
284
+ // In ComparisonGrid, continue to renewal pricing section below (don't return here)
285
+ } else if ( discountedPriceFullTermText ) {
286
+ // Show intro pricing for non-experiment users
256
287
  if ( PLAN_ANNUAL_PERIOD === billingPeriod ) {
257
288
  return translate(
258
289
  'per month, %(fullTermDiscountedPriceText)s for the first year, excl. taxes',
@@ -282,6 +313,40 @@ export default function usePlanBillingDescription( {
282
313
  }
283
314
  );
284
315
  }
316
+ }
317
+
318
+ if ( showBillingDescriptionForIncreasedRenewalPrice ) {
319
+ // For renewal pricing experiment, show variation-specific text
320
+ // In FeaturesGrid (enableCategorisedFeatures), show "per month" and move renewal text below CTA
321
+ // In ComparisonGrid, show full renewal text above CTA
322
+ if ( enableCategorisedFeatures ) {
323
+ return translate( 'per month' );
324
+ }
325
+
326
+ return getRenewalPricingText( {
327
+ pricing,
328
+ showBillingDescriptionForIncreasedRenewalPrice,
329
+ translate,
330
+ } );
331
+ } else if ( showSimplifiedBillingDescription ) {
332
+ // Use simplified billing description
333
+ if ( PLAN_ANNUAL_PERIOD === billingPeriod ) {
334
+ return translate( 'per month, billed every %(months)s months', {
335
+ args: { months: 12 },
336
+ } );
337
+ }
338
+
339
+ if ( PLAN_BIENNIAL_PERIOD === billingPeriod ) {
340
+ return translate( 'per month, billed every %(months)s months', {
341
+ args: { months: 24 },
342
+ } );
343
+ }
344
+
345
+ if ( PLAN_TRIENNIAL_PERIOD === billingPeriod ) {
346
+ return translate( 'per month, billed every %(months)s months', {
347
+ args: { months: 36 },
348
+ } );
349
+ }
285
350
  } else if ( originalPriceFullTermText ) {
286
351
  if ( PLAN_ANNUAL_PERIOD === billingPeriod ) {
287
352
  return translate( 'per month, %(rawPrice)s billed annually, excl. taxes', {
@@ -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;