Skip to content

Commit

Permalink
Plans (Storage): Enable storage selection for current plan, and other…
Browse files Browse the repository at this point in the history
… fixes/refactors (#91050)

* Plans (Storage): Always reflect selected storage option in the plan price

* also remove exceedsSiteStorageLimits condition

* Plans: Add storage dropdown/selection for current plan

continuing

continuing - make the filtering on site storage across all plan storage options. fix price not upgraded when exceeding - e.g. on enterprise plan with current creator plus 50gb - should filter the option out instead

continuing. introducing useStorageStringFromFeature to account for current site storage

update storage titles to reflect upgrade from the existing/real site storage

disable when any storage upgrade purchased. as before

show the actual storage size in the badge.. but TODO added

show the actual storage size in the badge.. but TODO added

cleanup. move things around into hooks, folders, etc.

cleanup

* include added price/cost in upgraded storage label

* styling fixes after rebase
  • Loading branch information
chriskmnds committed May 31, 2024
1 parent 97dd7d3 commit 0107d53
Show file tree
Hide file tree
Showing 13 changed files with 395 additions and 164 deletions.
1 change: 1 addition & 0 deletions packages/data-stores/src/add-ons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { default as useAddOns } from './hooks/use-add-ons';
export { default as useAddOnCheckoutLink } from './hooks/use-add-on-checkout-link';
export { default as useAddOnPurchaseStatus } from './hooks/use-add-on-purchase-status';
export { default as useStorageAddOns } from './hooks/use-storage-add-ons';
export * from './constants';

/** Types */
export * from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -98,20 +98,16 @@ const usePricingMetaForGridPlans = ( {
} else {
planPrices = Object.fromEntries(
planSlugs.map( ( planSlug ) => {
const availableForPurchase = planAvailabilityForPurchase[ planSlug ];
const selectedStorageOption = selectedStorageOptions?.[ planSlug ];
const selectedStorageAddOn = storageAddOns?.find( ( addOn ) => {
return selectedStorageOption && addOn?.featureSlugs?.includes( selectedStorageOption );
} );
const storageAddOnPrices =
selectedStorageAddOn?.purchased || selectedStorageAddOn?.exceedsSiteStorageLimits
? null
: selectedStorageAddOn?.prices;
const storageAddOnPriceMonthly = storageAddOnPrices?.monthlyPrice || 0;
const storageAddOnPriceYearly = storageAddOnPrices?.yearlyPrice || 0;

const plan = plans.data?.[ planSlug ];
const sitePlan = sitePlans.data?.[ planSlug ];
const selectedStorageOption = selectedStorageOptions?.[ planSlug ];
const selectedStorageAddOn = selectedStorageOption
? storageAddOns?.find( ( addOn ) => {
return addOn?.featureSlugs?.includes( selectedStorageOption );
} )
: null;
const storageAddOnPriceMonthly = selectedStorageAddOn?.prices?.monthlyPrice || 0;
const storageAddOnPriceYearly = selectedStorageAddOn?.prices?.yearlyPrice || 0;

/**
* 0. No plan or sitePlan (when selected site exists): planSlug is for a priceless plan.
Expand Down Expand Up @@ -176,7 +172,7 @@ const usePricingMetaForGridPlans = ( {
/**
* 2. Original and Discounted prices for plan available for purchase.
*/
if ( availableForPurchase ) {
if ( planAvailabilityForPurchase[ planSlug ] ) {
const originalPrice = {
monthly: getTotalPrice( plan.pricing.originalPrice.monthly, storageAddOnPriceMonthly ),
full: getTotalPrice( plan.pricing.originalPrice.full, storageAddOnPriceYearly ),
Expand Down
2 changes: 2 additions & 0 deletions packages/plans-grid-next/src/components/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,12 @@ const PlanFeatures2023GridActions = ( {
const canPurchaseStorageAddOns = storageAddOnsForPlan?.some(
( storageAddOn ) => ! storageAddOn?.purchased && ! storageAddOn?.exceedsSiteStorageLimits
);

const storageAddOnCheckoutHref = storageAddOnsForPlan?.find(
( addOn ) =>
selectedStorageOptionForPlan && addOn?.featureSlugs?.includes( selectedStorageOptionForPlan )
)?.checkoutLink;

const nonDefaultStorageOptionSelected = defaultStorageOption !== selectedStorageOptionForPlan;

let actionButton = (
Expand Down
73 changes: 34 additions & 39 deletions packages/plans-grid-next/src/components/comparison-grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ import filterUnusedFeaturesObject from '../../lib/filter-unused-features-object'
import getPlanFeaturesObject from '../../lib/get-plan-features-object';
import { isStorageUpgradeableForPlan } from '../../lib/is-storage-upgradeable-for-plan';
import { sortPlans } from '../../lib/sort-plan-properties';
import { getStorageStringFromFeature } from '../../util';
import PlanFeatures2023GridActions from '../actions';
import PlanFeatures2023GridHeaderPrice from '../header-price';
import PlanTypeSelector from '../plan-type-selector';
import { Plans2023Tooltip } from '../plans-2023-tooltip';
import PopularBadge from '../popular-badge';
import BillingTimeframe from '../shared/billing-timeframe';
import { StickyContainer } from '../sticky-container';
import { PlanStorageLabel, useGetAvailableStorageOptions } from '../storage';
import StorageAddOnDropdown from '../storage-add-on-dropdown';
import type {
GridPlan,
Expand Down Expand Up @@ -299,25 +299,6 @@ const PlanSelector = styled.header`
}
`;

const StorageButton = styled.div`
background: #f2f2f2;
border-radius: 5px;
padding: 4px 0;
width: -moz-fit-content;
width: fit-content;
text-align: center;
font-size: 0.75rem;
font-weight: 400;
line-height: 20px;
color: var( --studio-gray-90 );
min-width: 64px;
margin-top: 10px;
${ plansGridMediumLarge( css`
margin-top: 0;
` ) }
`;

const FeatureFootnotes = styled.div`
ol {
margin: 2em 0 0 1em;
Expand Down Expand Up @@ -584,6 +565,38 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
renderedGridPlans: visibleGridPlans,
} );

/**
* TODO: Consider centralising `canUpgradeStorageForPlan` behind `availableStorageOptions`
*/
const availableStorageOptions = useGetAvailableStorageOptions()( {
storageOptions: gridPlan.features.storageOptions,
} );
/**
* The current plan is not marked as `availableForPurchase`, hence check on `current`.
*/
const canUpgradeStorageForPlan =
( gridPlan.current || gridPlan.availableForPurchase ) &&
isStorageUpgradeableForPlan( {
intervalType,
showUpgradeableStorage,
storageOptions: availableStorageOptions,
} );

const storageJSX = canUpgradeStorageForPlan ? (
<StorageAddOnDropdown
planSlug={ planSlug }
onStorageAddOnClick={ onStorageAddOnClick }
storageOptions={ availableStorageOptions }
priceOnSeparateLine
/>
) : (
gridPlan.features.storageOptions.map( ( storageOption ) => {
if ( ! storageOption?.isAddOn ) {
return <PlanStorageLabel storageOption={ storageOption } planSlug={ planSlug } />;
}
} )
);

if ( ! gridPlan ) {
return null;
}
Expand All @@ -605,13 +618,6 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
( feature ) => feature.getSlug() === featureSlug
)
: false;
const storageOptions = gridPlan.features.storageOptions;
const defaultStorageOption = storageOptions.find( ( option ) => ! option.isAddOn );
const canUpgradeStorageForPlan = isStorageUpgradeableForPlan( {
intervalType,
showUpgradeableStorage,
storageOptions,
} );

const cellClasses = classNames(
'plan-comparison-grid__feature-group-row-cell',
Expand All @@ -638,18 +644,7 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
{ isStorageFeature ? (
<>
<span className="plan-comparison-grid__plan-title">{ translate( 'Storage' ) }</span>
{ canUpgradeStorageForPlan ? (
<StorageAddOnDropdown
planSlug={ planSlug }
storageOptions={ gridPlan.features.storageOptions }
onStorageAddOnClick={ onStorageAddOnClick }
priceOnSeparateLine
/>
) : (
<StorageButton className="plan-features-2023-grid__storage-button" key={ planSlug }>
{ getStorageStringFromFeature( defaultStorageOption?.slug || '' ) }
</StorageButton>
) }
{ storageJSX }
</>
) : (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
} from '@automattic/calypso-products';
import { usePlansGridContext } from '../../grid-context';
import { isStorageUpgradeableForPlan } from '../../lib/is-storage-upgradeable-for-plan';
import { getStorageStringFromFeature } from '../../util';
import { PlanFeaturesItem } from '../item';
import { PlanStorageLabel, useGetAvailableStorageOptions } from '../storage';
import StorageAddOnDropdown from '../storage-add-on-dropdown';

type PlanStorageOptionsProps = {
Expand All @@ -30,36 +30,43 @@ const PlanStorageOptions = ( {
const {
availableForPurchase,
features: { storageOptions },
current,
} = gridPlansIndex[ planSlug ];
const canUpgradeStorageForPlan = isStorageUpgradeableForPlan( {
intervalType,
showUpgradeableStorage,
storageOptions,
} );

const storageJSX =
canUpgradeStorageForPlan && availableForPurchase ? (
<StorageAddOnDropdown
planSlug={ planSlug }
onStorageAddOnClick={ onStorageAddOnClick }
storageOptions={ storageOptions }
/>
) : (
storageOptions.map( ( storageOption ) => {
if ( ! storageOption?.isAddOn ) {
return (
<div className="plan-features-2023-grid__storage-buttons" key={ planSlug }>
{ getStorageStringFromFeature( storageOption?.slug ) }
</div>
);
}
} )
);
const getAvailableStorageOptions = useGetAvailableStorageOptions();

if ( ! options?.isTableCell && isWpcomEnterpriseGridPlan( planSlug ) ) {
return null;
}

/**
* TODO: Consider centralising `canUpgradeStorageForPlan` behind `availableStorageOptions`
*/
const availableStorageOptions = getAvailableStorageOptions( { storageOptions } );
/**
* The current plan is not marked as `availableForPurchase`, hence check on `current`.
*/
const canUpgradeStorageForPlan =
( current || availableForPurchase ) &&
isStorageUpgradeableForPlan( {
intervalType,
showUpgradeableStorage,
storageOptions: availableStorageOptions,
} );

const storageJSX = canUpgradeStorageForPlan ? (
<StorageAddOnDropdown
planSlug={ planSlug }
onStorageAddOnClick={ onStorageAddOnClick }
storageOptions={ availableStorageOptions }
/>
) : (
storageOptions.map( ( storageOption ) => {
if ( ! storageOption?.isAddOn ) {
return <PlanStorageLabel storageOption={ storageOption } planSlug={ planSlug } />;
}
} )
);

return (
<div className="plan-features-2023-grid__storage">
<PlanFeaturesItem>{ storageJSX }</PlanFeaturesItem>
Expand Down
32 changes: 17 additions & 15 deletions packages/plans-grid-next/src/components/storage-add-on-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { useTranslate } from 'i18n-calypso';
import { usePlansGridContext } from '../grid-context';
import useDefaultStorageOption from '../hooks/data-store/use-default-storage-option';
import useIsLargeCurrency from '../hooks/use-is-large-currency';
import { getStorageStringFromFeature } from '../util';
import DropdownOption from './dropdown-option';
import { useStorageStringFromFeature } from './storage';
import type { PlanSlug, StorageOption, WPComStorageAddOnSlug } from '@automattic/calypso-products';
import type { AddOnMeta } from '@automattic/data-stores';

Expand All @@ -19,8 +19,9 @@ type StorageAddOnDropdownProps = {
};

type StorageAddOnOptionProps = {
title?: string;
planSlug: PlanSlug;
price?: string;
storageFeature: string;
isLargeCurrency?: boolean;
priceOnSeparateLine?: boolean;
};
Expand All @@ -35,16 +36,15 @@ const getStorageOptionPrice = (
};

const StorageAddOnOption = ( {
title,
planSlug,
price,
storageFeature,
isLargeCurrency = false,
priceOnSeparateLine,
}: StorageAddOnOptionProps ) => {
const translate = useTranslate();

if ( ! title ) {
return null;
}
const { siteId } = usePlansGridContext();
const title = useStorageStringFromFeature( { storageFeature, siteId, planSlug } ) ?? '';

return (
<>
Expand Down Expand Up @@ -114,28 +114,30 @@ export const StorageAddOnDropdown = ( {
}, [] );

const selectControlOptions = storageOptions.map( ( storageOption ) => {
const title = getStorageStringFromFeature( storageOption.slug ) || '';
const price = getStorageOptionPrice( storageAddOnsForPlan, storageOption.slug );
return {
key: storageOption.slug,
name: <StorageAddOnOption title={ title } price={ price } />,
name: (
<StorageAddOnOption
planSlug={ planSlug }
price={ getStorageOptionPrice( storageAddOnsForPlan, storageOption.slug ) }
storageFeature={ storageOption.slug }
/>
),
};
} );

const selectedOptionKey = selectedStorageOptionForPlan
? selectedStorageOptionForPlan
: defaultStorageOption;
const selectedOptionPrice =
selectedOptionKey && getStorageOptionPrice( storageAddOnsForPlan, selectedOptionKey );
const selectedOptionTitle =
( selectedOptionKey && getStorageStringFromFeature( selectedOptionKey ) ) || '';
const selectedOptionPrice = getStorageOptionPrice( storageAddOnsForPlan, selectedOptionKey );

const selectedOption = {
key: selectedOptionKey,
name: (
<StorageAddOnOption
title={ selectedOptionTitle }
planSlug={ planSlug }
price={ selectedOptionPrice }
storageFeature={ selectedOptionKey }
isLargeCurrency={ isLargeCurrency }
priceOnSeparateLine={ priceOnSeparateLine }
/>
Expand Down
Loading

0 comments on commit 0107d53

Please sign in to comment.