diff --git a/client/my-sites/plan-features-2023-grid/hooks/npm-ready/use-upgrade-click-handler.ts b/client/my-sites/plan-features-2023-grid/hooks/npm-ready/use-upgrade-click-handler.ts new file mode 100644 index 00000000000000..a2d4af905d2d72 --- /dev/null +++ b/client/my-sites/plan-features-2023-grid/hooks/npm-ready/use-upgrade-click-handler.ts @@ -0,0 +1,51 @@ +import { isFreePlan, type PlanSlug } from '@automattic/calypso-products'; +import { WpcomPlansUI } from '@automattic/data-stores'; +import { useSelect } from '@wordpress/data'; +import { useCallback } from '@wordpress/element'; +import type { GridPlan } from './data-store/use-grid-plans'; +import type { MinimalRequestCartProduct } from '@automattic/shopping-cart'; + +interface Props { + gridPlansForFeaturesGrid: GridPlan[]; // TODO clk: to be removed, grabbed from context + onUpgradeClick?: ( cartItems?: MinimalRequestCartProduct[] | null ) => void; +} + +const useUpgradeClickHandler = ( { gridPlansForFeaturesGrid, onUpgradeClick }: Props ) => { + const selectedStorageOptions = useSelect( ( select ) => { + return select( WpcomPlansUI.store ).getSelectedStorageOptions(); + }, [] ); + + return useCallback( + ( planSlug: PlanSlug ) => { + const selectedStorageOption = selectedStorageOptions?.[ planSlug ]; + const { cartItemForPlan, storageAddOnsForPlan } = + gridPlansForFeaturesGrid.find( ( gridPlan ) => gridPlan.planSlug === planSlug ) ?? {}; + const storageAddOn = storageAddOnsForPlan?.find( ( addOn ) => { + return selectedStorageOption && addOn + ? addOn.featureSlugs?.includes( selectedStorageOption ) + : false; + } ); + const storageAddOnCartItem = storageAddOn && { + product_slug: storageAddOn.productSlug, + quantity: storageAddOn.quantity, + volume: 1, + }; + + if ( cartItemForPlan ) { + onUpgradeClick?.( [ + cartItemForPlan, + ...( storageAddOnCartItem ? [ storageAddOnCartItem ] : [] ), + ] ); + return; + } + + if ( isFreePlan( planSlug ) ) { + onUpgradeClick?.( null ); + return; + } + }, + [ gridPlansForFeaturesGrid, onUpgradeClick, selectedStorageOptions ] + ); +}; + +export default useUpgradeClickHandler; diff --git a/client/my-sites/plan-features-2023-grid/index.tsx b/client/my-sites/plan-features-2023-grid/index.tsx index 5b26d6aad312a6..6c0665c4d438ed 100644 --- a/client/my-sites/plan-features-2023-grid/index.tsx +++ b/client/my-sites/plan-features-2023-grid/index.tsx @@ -20,10 +20,8 @@ import { SlackLogo, TimeLogo, } from '@automattic/components'; -import { WpcomPlansUI } from '@automattic/data-stores'; import { isAnyHostingFlow } from '@automattic/onboarding'; import { MinimalRequestCartProduct } from '@automattic/shopping-cart'; -import { useSelect } from '@wordpress/data'; import classNames from 'classnames'; import { LocalizeProps, useTranslate } from 'i18n-calypso'; import { Component, ForwardedRef, forwardRef } from 'react'; @@ -50,6 +48,7 @@ import { StickyContainer } from './components/sticky-container'; import StorageAddOnDropdown from './components/storage-add-on-dropdown'; import PlansGridContextProvider, { type PlansIntent } from './grid-context'; import useIsLargeCurrency from './hooks/npm-ready/use-is-large-currency'; +import useUpgradeClickHandler from './hooks/npm-ready/use-upgrade-click-handler'; import { isStorageUpgradeableForPlan } from './lib/is-storage-upgradeable-for-plan'; import { DataResponse } from './types'; import { getStorageStringFromFeature } from './util'; @@ -58,7 +57,7 @@ import type { UsePricingMetaForGridPlans, } from './hooks/npm-ready/data-store/use-grid-plans'; import type { PlanActionOverrides } from './types'; -import type { DomainSuggestion, SelectedStorageOptionForPlans } from '@automattic/data-stores'; +import type { DomainSuggestion } from '@automattic/data-stores'; import type { IAppState } from 'calypso/state/types'; import './style.scss'; @@ -115,7 +114,7 @@ interface PlanFeatures2023GridType extends PlanFeatures2023GridProps { isPlanUpgradeCreditEligible: boolean; // temporary: element ref to scroll comparison grid into view once "Compare plans" button is clicked plansComparisonGridRef: ForwardedRef< HTMLDivElement >; - selectedStorageOptions?: SelectedStorageOptionForPlans; + handleUpgradeClick: ( planSlug: PlanSlug ) => void; } export class PlanFeatures2023Grid extends Component< PlanFeatures2023GridType > { @@ -421,44 +420,6 @@ export class PlanFeatures2023Grid extends Component< PlanFeatures2023GridType > } ); } - handleUpgradeClick = ( planSlug: PlanSlug ) => { - const { - onUpgradeClick: ownPropsOnUpgradeClick, - gridPlansForFeaturesGrid, - selectedStorageOptions, - } = this.props; - const { cartItemForPlan, storageAddOnsForPlan } = - gridPlansForFeaturesGrid.find( ( gridPlan ) => gridPlan.planSlug === planSlug ) ?? {}; - - const selectedStorageOption = selectedStorageOptions?.[ planSlug ]; - const storageAddOn = storageAddOnsForPlan?.find( ( addOn ) => { - return selectedStorageOption && addOn - ? addOn.featureSlugs?.includes( selectedStorageOption ) - : false; - } ); - - const storageAddOnCartItem = storageAddOn && { - product_slug: storageAddOn.productSlug, - quantity: storageAddOn.quantity, - volume: 1, - extra: { feature_slug: selectedStorageOption }, - }; - - // TODO clk: Revisit. Could this suffice: `ownPropsOnUpgradeClick?.( cartItemForPlan )` - if ( cartItemForPlan ) { - ownPropsOnUpgradeClick?.( [ - cartItemForPlan, - ...( storageAddOnCartItem ? [ storageAddOnCartItem ] : [] ), - ] ); - return; - } - - if ( isFreePlan( planSlug ) ) { - ownPropsOnUpgradeClick?.( null ); - return; - } - }; - renderTopButtons( renderedGridPlans: GridPlan[], options?: PlanRowOptions ) { const { isInSignup, @@ -472,6 +433,7 @@ export class PlanFeatures2023Grid extends Component< PlanFeatures2023GridType > planActionOverrides, siteId, isLargeCurrency, + handleUpgradeClick, } = this.props; return renderedGridPlans.map( ( { planSlug, availableForPurchase } ) => { @@ -512,7 +474,7 @@ export class PlanFeatures2023Grid extends Component< PlanFeatures2023GridType > isWooExpressPlusPlan={ isWooExpressPlusPlan( planSlug ) } isInSignup={ isInSignup } isLaunchPage={ isLaunchPage } - onUpgradeClick={ () => this.handleUpgradeClick( planSlug ) } + onUpgradeClick={ () => handleUpgradeClick( planSlug ) } planSlug={ planSlug } flowName={ flowName } currentSitePlanSlug={ currentSitePlanSlug } @@ -731,6 +693,7 @@ export class PlanFeatures2023Grid extends Component< PlanFeatures2023GridType > showUpgradeableStorage, observableForOdieRef, onStorageAddOnClick, + handleUpgradeClick, } = this.props; return ( @@ -798,7 +761,7 @@ export class PlanFeatures2023Grid extends Component< PlanFeatures2023GridType > manageHref={ manageHref } canUserPurchasePlan={ canUserPurchasePlan } selectedSiteSlug={ selectedSiteSlug } - onUpgradeClick={ this.handleUpgradeClick } + onUpgradeClick={ handleUpgradeClick } siteId={ siteId } selectedPlan={ selectedPlan } selectedFeature={ selectedFeature } @@ -830,10 +793,6 @@ export default forwardRef< HTMLDivElement, PlanFeatures2023GridProps >( gridPlans: props.gridPlansForFeaturesGrid, } ); - const selectedStorageOptions = useSelect( ( select ) => { - return select( WpcomPlansUI.store ).getSelectedStorageOptions(); - }, [] ); - // TODO clk: canUserManagePlan should be passed through props instead of being calculated here const canUserPurchasePlan = useSelector( ( state: IAppState ) => siteId @@ -851,6 +810,11 @@ export default forwardRef< HTMLDivElement, PlanFeatures2023GridProps >( ? getManagePurchaseUrlFor( selectedSiteSlug, purchaseId ) : `/plans/my-plan/${ siteId }`; + const handleUpgradeClick = useUpgradeClickHandler( { + gridPlansForFeaturesGrid: props.gridPlansForFeaturesGrid, + onUpgradeClick: props.onUpgradeClick, + } ); + if ( props.isInSignup ) { return ( ( manageHref={ manageHref } selectedSiteSlug={ selectedSiteSlug } translate={ translate } - selectedStorageOptions={ selectedStorageOptions } + handleUpgradeClick={ handleUpgradeClick } /> ); } @@ -878,6 +842,7 @@ export default forwardRef< HTMLDivElement, PlanFeatures2023GridProps >( manageHref={ manageHref } selectedSiteSlug={ selectedSiteSlug } translate={ translate } + handleUpgradeClick={ handleUpgradeClick } /> );