From f67e1411e50a596ea6c947c656302bdbccb61816 Mon Sep 17 00:00:00 2001 From: Christos Date: Thu, 12 Sep 2024 11:26:41 +0300 Subject: [PATCH] Plans (State): Update useMaxPlanUpgradeCredits to utilise Plans data-store pricing (#92925) --- .../wordpress/upgrade-plan/test/index.tsx | 15 +++ .../components/plan-notice-credit-update.tsx | 5 +- .../components/test/plan-notice.tsx | 8 +- .../test/use-max-plan-upgrade-credits.tsx | 107 ++++++++---------- .../hooks/use-max-plan-upgrade-credits.ts | 49 ++++---- 5 files changed, 99 insertions(+), 85 deletions(-) diff --git a/client/blocks/importer/wordpress/upgrade-plan/test/index.tsx b/client/blocks/importer/wordpress/upgrade-plan/test/index.tsx index 65ec53334e3e76..6b5567103316ec 100644 --- a/client/blocks/importer/wordpress/upgrade-plan/test/index.tsx +++ b/client/blocks/importer/wordpress/upgrade-plan/test/index.tsx @@ -9,6 +9,7 @@ import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import nock from 'nock'; import React, { type ComponentPropsWithoutRef } from 'react'; +import useCheckPlanAvailabilityForPurchase from 'calypso/my-sites/plans-features-main/hooks/use-check-plan-availability-for-purchase'; import { renderWithProvider } from 'calypso/test-helpers/testing-library'; import { useUpgradePlanHostingDetailsList } from '../hooks/use-get-upgrade-plan-hosting-details-list'; import { UpgradePlan, UnwrappedUpgradePlan } from '../index'; @@ -19,6 +20,11 @@ jest.mock( '../upgrade-plan-details', () => ( { default: ( { children } ) =>
{ children }
, } ) ); +jest.mock( + 'calypso/my-sites/plans-features-main/hooks/use-check-plan-availability-for-purchase', + () => jest.fn() +); + jest.mock( '@automattic/calypso-analytics' ); jest.mock( '../hooks/use-get-upgrade-plan-hosting-details-list' ); @@ -165,8 +171,17 @@ describe( 'UpgradePlan', () => { beforeAll( () => nock.disableNetConnect() ); beforeEach( () => { + jest.clearAllMocks(); mockUseUpgradePlanHostingDetailsList( false ); mockUsePricingMetaForGridPlans(); + useCheckPlanAvailabilityForPurchase.mockImplementation( ( { planSlugs } ) => + planSlugs.reduce( ( acc, planSlug ) => { + return { + ...acc, + [ planSlug ]: true, + }; + }, {} ) + ); } ); it( 'should call onCtaClick when the user clicks on the Continue button', async () => { diff --git a/client/my-sites/plans-features-main/components/plan-notice-credit-update.tsx b/client/my-sites/plans-features-main/components/plan-notice-credit-update.tsx index 6fc6721314a1ff..ccdd7428875300 100644 --- a/client/my-sites/plans-features-main/components/plan-notice-credit-update.tsx +++ b/client/my-sites/plans-features-main/components/plan-notice-credit-update.tsx @@ -56,7 +56,10 @@ const PlanNoticeCreditUpgrade = ( { args: { amountInCurrency: formatCurrency( planUpgradeCreditsApplicable, - currencyCode ?? '' + currencyCode ?? '', + { + isSmallestUnit: true, + } ), }, components: { diff --git a/client/my-sites/plans-features-main/components/test/plan-notice.tsx b/client/my-sites/plans-features-main/components/test/plan-notice.tsx index c440af0d4d2915..230a150f5d6ecd 100644 --- a/client/my-sites/plans-features-main/components/test/plan-notice.tsx +++ b/client/my-sites/plans-features-main/components/test/plan-notice.tsx @@ -104,14 +104,14 @@ describe( ' Tests', () => { mIsCurrentUserCurrentPlanOwner.mockImplementation( () => true ); mIsRequestingSitePlans.mockImplementation( () => true ); mGetCurrentUserCurrencyCode.mockImplementation( () => 'USD' ); - mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 1 ); + mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 100 ); mGetByPurchaseId.mockImplementation( () => ( { isInAppPurchase: false } ) as Purchase ); mIsProPlan.mockImplementation( () => false ); } ); test( 'A contact site owner should be shown no matter what other conditions are met, when the current site owner is not logged in, and the site plan is paid', () => { mGetDiscountByName.mockImplementation( () => discount ); - mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 1 ); + mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 100 ); mIsCurrentPlanPaid.mockImplementation( () => true ); mIsCurrentUserCurrentPlanOwner.mockImplementation( () => false ); @@ -132,7 +132,7 @@ describe( ' Tests', () => { mIsCurrentUserCurrentPlanOwner.mockImplementation( () => true ); mIsCurrentPlanPaid.mockImplementation( () => true ); mGetDiscountByName.mockImplementation( () => discount ); - mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 1 ); + mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 100 ); renderWithProvider( Tests', () => { mIsCurrentUserCurrentPlanOwner.mockImplementation( () => true ); mIsCurrentPlanPaid.mockImplementation( () => true ); mGetDiscountByName.mockImplementation( () => false ); - mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 100 ); + mUsePlanUpgradeCreditsApplicable.mockImplementation( () => 10000 ); renderWithProvider( ( { - __esModule: true, - default: jest.fn(), -} ) ); +jest.mock( + 'calypso/my-sites/plans-features-main/hooks/use-check-plan-availability-for-purchase', + () => jest.fn() +); -jest.mock( 'calypso/state/sites/plans/selectors', () => ( { - getPlanDiscountedRawPrice: jest.fn(), -} ) ); -jest.mock( 'calypso/state/sites/plans/selectors/get-site-plan-raw-price', () => ( { - getSitePlanRawPrice: jest.fn(), +jest.mock( '@automattic/data-stores', () => ( { + ...jest.requireActual( '@automattic/data-stores' ), + Plans: { + ...jest.requireActual( '@automattic/data-stores' ).Plans, + usePricingMetaForGridPlans: jest.fn(), + }, } ) ); -const mGetPlanDiscountedRawPrice = getPlanDiscountedRawPrice as jest.MockedFunction< - typeof getPlanDiscountedRawPrice ->; -const mGetSitePlanRawPrice = getSitePlanRawPrice as jest.MockedFunction< - typeof getSitePlanRawPrice ->; -const mIsPlanAvailableForPurchase = isPlanAvailableForPurchase as jest.MockedFunction< - typeof isPlanAvailableForPurchase ->; - const siteId = 9999999; const plans: PlanSlug[] = [ PLAN_FREE, PLAN_PERSONAL, PLAN_PREMIUM, PLAN_BUSINESS, PLAN_ECOMMERCE ]; describe( 'useCalculateMaxPlanUpgradeCredit hook', () => { beforeEach( () => { jest.resetAllMocks(); - mGetSitePlanRawPrice.mockImplementation( ( _state, _siteId, planSlug ) => { - switch ( planSlug ) { - case PLAN_FREE: - return 2000; - case PLAN_PERSONAL: - return 4000; - case PLAN_PREMIUM: - return 6000; - case PLAN_BUSINESS: - return 8000; - case PLAN_ECOMMERCE: - return 10000; - default: - return 0; - } - } ); - mGetPlanDiscountedRawPrice.mockImplementation( ( _state, _siteId, planSlug ) => { - switch ( planSlug ) { - case PLAN_FREE: - return 2000 * 0.9; - case PLAN_PERSONAL: - return 4000 * 0.9; - case PLAN_PREMIUM: - return 6000 * 0.9; - case PLAN_BUSINESS: - return 8000 * 0.9; - case PLAN_ECOMMERCE: - return 10000 * 0.9; - default: - return 0; - } - } ); - - mIsPlanAvailableForPurchase.mockImplementation( () => true ); + Plans.usePricingMetaForGridPlans.mockImplementation( () => ( { + [ PLAN_FREE ]: { + originalPrice: { full: 2000 }, + discountedPrice: { full: 2000 * 0.9 }, + }, + [ PLAN_PERSONAL ]: { + originalPrice: { full: 4000 }, + discountedPrice: { full: 4000 * 0.9 }, + }, + [ PLAN_PREMIUM ]: { + originalPrice: { full: 6000 }, + discountedPrice: { full: 6000 * 0.9 }, + }, + [ PLAN_BUSINESS ]: { + originalPrice: { full: 8000 }, + discountedPrice: { full: 8000 * 0.9 }, + }, + [ PLAN_ECOMMERCE ]: { + originalPrice: { full: 10000 }, + discountedPrice: { full: 10000 * 0.9 }, + }, + } ) ); + useCheckPlanAvailabilityForPurchase.mockImplementation( ( { planSlugs } ) => + planSlugs.reduce( ( acc, planSlug ) => { + return { + ...acc, + [ planSlug ]: true, + }; + }, {} ) + ); } ); test( 'Return the correct amount of credits given a plan list', () => { @@ -87,8 +73,13 @@ describe( 'useCalculateMaxPlanUpgradeCredit hook', () => { } ); test( 'Return the next correct credit amount when ecommerce plan is not available for purchase', () => { - mIsPlanAvailableForPurchase.mockImplementation( - ( _state, _siteId, planName ) => ! ( planName === PLAN_ECOMMERCE ) + useCheckPlanAvailabilityForPurchase.mockImplementation( ( { planSlugs } ) => + planSlugs.reduce( ( acc, planSlug ) => { + return { + ...acc, + [ planSlug ]: planSlug !== PLAN_ECOMMERCE, + }; + }, {} ) ); const { result } = renderHookWithProvider( () => diff --git a/client/my-sites/plans-features-main/hooks/use-max-plan-upgrade-credits.ts b/client/my-sites/plans-features-main/hooks/use-max-plan-upgrade-credits.ts index 4287f58292e909..fed2705d51c65c 100644 --- a/client/my-sites/plans-features-main/hooks/use-max-plan-upgrade-credits.ts +++ b/client/my-sites/plans-features-main/hooks/use-max-plan-upgrade-credits.ts @@ -1,7 +1,5 @@ -import { useSelector } from 'calypso/state'; -import { getPlanDiscountedRawPrice } from 'calypso/state/sites/plans/selectors'; -import { getSitePlanRawPrice } from 'calypso/state/sites/plans/selectors/get-site-plan-raw-price'; -import isPlanAvailableForPurchase from 'calypso/state/sites/plans/selectors/is-plan-available-for-purchase'; +import { Plans } from '@automattic/data-stores'; +import useCheckPlanAvailabilityForPurchase from './use-check-plan-availability-for-purchase'; import type { PlanSlug } from '@automattic/calypso-products'; interface Props { @@ -15,30 +13,37 @@ interface Props { * @returns {number} The maximum amount of credits possible for a given set of plans */ export function useMaxPlanUpgradeCredits( { siteId, plans }: Props ): number { - const plansDetails = useSelector( ( state ) => - plans.map( ( planName ) => ( { - isPlanAvailableForPurchase: isPlanAvailableForPurchase( state, siteId ?? 0, planName ), - planDiscountedRawPrice: getPlanDiscountedRawPrice( state, siteId ?? 0, planName ), - sitePlanRawPrice: getSitePlanRawPrice( state, siteId ?? 0, planName ), - } ) ) - ); + const planAvailabilityForPurchase = useCheckPlanAvailabilityForPurchase( { + planSlugs: plans, + siteId, + } ); + const pricing = Plans.usePricingMetaForGridPlans( { + siteId, + planSlugs: plans, + storageAddOns: null, + coupon: undefined, + useCheckPlanAvailabilityForPurchase, + withProratedDiscounts: true, + } ); - if ( ! siteId ) { + if ( ! siteId || ! pricing ) { return 0; } - const creditsPerPlan = plansDetails.map( - ( { isPlanAvailableForPurchase, planDiscountedRawPrice, sitePlanRawPrice } ) => { - if ( ! isPlanAvailableForPurchase ) { - return 0; - } - if ( typeof planDiscountedRawPrice !== 'number' || typeof sitePlanRawPrice !== 'number' ) { - return 0; - } + const creditsPerPlan = plans.map( ( planSlug ) => { + const discountedPrice = pricing?.[ planSlug ]?.discountedPrice.full; + const originalPrice = pricing?.[ planSlug ]?.originalPrice.full; - return sitePlanRawPrice - planDiscountedRawPrice; + if ( + ! planAvailabilityForPurchase[ planSlug ] || + typeof discountedPrice !== 'number' || + typeof originalPrice !== 'number' + ) { + return 0; } - ); + + return originalPrice - discountedPrice; + } ); return Math.max( ...creditsPerPlan ); }