Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plans 2023: Implement storage add on dropdown #79041

Merged
merged 57 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
5a85096
Add storage upgrade dropdown behind feature flag
jeyip Jul 5, 2023
267171f
Update default selected value to empty string
jeyip Jul 5, 2023
c6f8f58
Create plans add ons list
jeyip Jul 6, 2023
c8ee9dc
Remove references to feature in add ons list
jeyip Jul 6, 2023
dcf8c14
Add 100gb and 200gb constants
jeyip Jul 6, 2023
20e46e2
Isolate storage add ons from storage features
jeyip Jul 6, 2023
d531bb2
Update constants
jeyip Jul 6, 2023
0315d30
Update inline comment
jeyip Jul 6, 2023
7178410
Add feature flag to dropdowns
jeyip Jul 6, 2023
d1feb85
Refine storage option and storage feature naming
jeyip Jul 7, 2023
cd335f2
Fix storageFeatures type
jeyip Jul 7, 2023
93096a6
Fix typescript errors
jeyip Jul 7, 2023
685cc91
Remove unnecessary AddOns type
jeyip Jul 7, 2023
07d4adf
Update inline comment
jeyip Jul 7, 2023
0f86021
Move add ons list into calypso products
jeyip Jul 8, 2023
9fdef31
Export add ons list from calypso products
jeyip Jul 8, 2023
f63d006
Pass feature flag as props through plans features main
jeyip Jul 8, 2023
6db6897
Update OnboardingPricingGrid2023Props type
jeyip Jul 8, 2023
778e27a
Remove unnecessary selected storage initialization
jeyip Jul 10, 2023
f2c2900
Switch dropdown to a component from @wordpress/component
jeyip Jul 11, 2023
db287e3
Remove unnecessary storageFeature check
jeyip Jul 11, 2023
da951d9
Fix dropdown alignment
jeyip Jul 11, 2023
1fcd3bf
Initialize state as a class member
jeyip Jul 11, 2023
4d7f798
Explicitly type state initialization
jeyip Jul 11, 2023
dafb61b
Convert storage add on dropdown to functional component
jeyip Jul 11, 2023
dfdf23b
Fix add on dropdown typescript errors
jeyip Jul 11, 2023
02e9020
Fix features grid props typescript error
jeyip Jul 12, 2023
1e78d5b
Refine selected storage type
jeyip Jul 12, 2023
9463235
Update storageOptions transform
jeyip Jul 12, 2023
af8a1ca
Fix storage label bug
jeyip Jul 12, 2023
1fbb2aa
Fix dropdown label color
jeyip Jul 12, 2023
ae34c26
Add inline comment
jeyip Jul 12, 2023
c8932c9
Fix select control change handler typescript error
jeyip Jul 12, 2023
a9e8a4d
Remove unnecessary inline comment
jeyip Jul 13, 2023
c364c93
Update storage title condition
jeyip Jul 14, 2023
b501a7a
Move all storage addons into features list
jeyip Jul 21, 2023
3e75322
Remove add ons list export
jeyip Jul 24, 2023
c9a86ef
Remove unnecessary addons export
jeyip Jul 24, 2023
61ecf55
Update WPComStorageAddOnSlug type
jeyip Jul 25, 2023
b125058
Fix typescript errors
jeyip Jul 26, 2023
a699304
Update wpcom storage add on type
jeyip Jul 28, 2023
756a19a
Update to add-on string
jeyip Jul 28, 2023
4255382
Add inline comment for showUpgradeableStorage
jeyip Jul 28, 2023
f228e42
Replace getFeatureByKey method
jeyip Jul 29, 2023
fafa524
Use slug instead of key
jeyip Jul 29, 2023
301cce1
Add feature object to storageOptions
jeyip Jul 29, 2023
b471ec0
Fix typescript errors
jeyip Jul 29, 2023
3adb0f7
Fix storage rendering bug
jeyip Jul 29, 2023
f1cd050
Create storageOption exportable type
jeyip Jul 31, 2023
7883c73
Update feature object add on slugs and labels
jeyip Jul 31, 2023
8f4a237
Generate storage add on label in presentation layer
jeyip Jul 31, 2023
ba03159
Switch to isAddOn property
jeyip Aug 1, 2023
5c8ae30
Determine isAddOn property in get2023PricingGridSignupStorageOptions
jeyip Aug 2, 2023
847acb4
Add inline comment describing isAddOn property
jeyip Aug 2, 2023
e23a589
Remove unused featureObject isAddOn property
jeyip Aug 2, 2023
e836e80
Fix comparison grid strings
jeyip Aug 2, 2023
aa00ccc
Remove unnecessary components prop
jeyip Aug 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions client/lib/plans/features-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
FEATURE_3GB_STORAGE,
FEATURE_1GB_STORAGE,
FEATURE_50GB_STORAGE,
FEATURE_50GB_STORAGE_ADD_ON,
FEATURE_100GB_STORAGE_ADD_ON,
FEATURE_6GB_STORAGE,
FEATURE_ACCEPT_PAYMENTS,
FEATURE_ACTIVITY_LOG,
Expand Down Expand Up @@ -296,6 +298,7 @@ import {
isBusinessPlan,
isFreePlan,
FEATURE_GROUP_PAYMENT_TRANSACTION_FEES,
PRODUCT_1GB_SPACE,
} from '@automattic/calypso-products';
import { localizeUrl } from '@automattic/i18n-utils';
import i18n, { TranslateResult } from 'i18n-calypso';
Expand All @@ -320,6 +323,8 @@ export type FeatureObject = {
getIcon?: () => string | { icon: string; component: MemoExoticComponent< any > } | JSX.Element;
isPlan?: boolean;
getFeatureGroup?: () => string;
getQuantity?: () => number; // storage add-ons are a quantity based product. this determines checkout price
getUnitProductSlug?: () => string; // used for storage add-ons to determine the checkout item
};
export type FeatureList = {
[ key: string ]: FeatureObject;
Expand Down Expand Up @@ -833,61 +838,47 @@ export const FEATURES_LIST: FeatureList = {

[ FEATURE_1GB_STORAGE ]: {
getSlug: () => FEATURE_1GB_STORAGE,
getTitle: () => i18n.translate( '1GB storage space' ),
getTitle: () => i18n.translate( '1GB' ),
getCompareTitle: () => i18n.translate( '1 GB' ),
getDescription: () =>
i18n.translate( 'Storage space for adding images and documents to your website.' ),
},

[ FEATURE_3GB_STORAGE ]: {
getSlug: () => FEATURE_3GB_STORAGE,
getTitle: () => i18n.translate( '3 GB storage space' ),
getTitle: () => i18n.translate( '3 GB' ),
getDescription: () =>
i18n.translate( 'Storage space for adding images and documents to your website.' ),
},

[ FEATURE_6GB_STORAGE ]: {
getSlug: () => FEATURE_6GB_STORAGE,
getCompareTitle: () => i18n.translate( '6 GB' ),
getTitle: () =>
i18n.translate( '{{strong}}6 GB{{/strong}} storage space', {
components: {
strong: <strong />,
},
} ),
getTitle: () => i18n.translate( '6 GB' ),
getDescription: () =>
i18n.translate( 'Upload more images, audio, and documents to your website.' ),
},

[ FEATURE_13GB_STORAGE ]: {
getSlug: () => FEATURE_13GB_STORAGE,
getTitle: () =>
i18n.translate( '{{strong}}13 GB{{/strong}} storage space', {
components: {
strong: <strong />,
},
} ),
getTitle: () => i18n.translate( '13 GB' ),
getCompareTitle: () => i18n.translate( '13 GB' ),
getDescription: () =>
i18n.translate( 'Upload more images, videos, audio, and documents to your website.' ),
},

[ FEATURE_50GB_STORAGE ]: {
getSlug: () => FEATURE_50GB_STORAGE,
getTitle: () => i18n.translate( '50 GB storage space' ),
getTitle: () => i18n.translate( '50 GB' ),
getCompareTitle: () => i18n.translate( '50 GB' ),
getDescription: () =>
i18n.translate( 'Storage space for adding images and documents to your website.' ),
},

// TODO: Consider removing this because it is no longer standard on any plans
[ FEATURE_200GB_STORAGE ]: {
getSlug: () => FEATURE_200GB_STORAGE,
getTitle: () =>
i18n.translate( '{{strong}}200 GB{{/strong}} storage space', {
components: {
strong: <strong />,
},
} ),
getTitle: () => i18n.translate( '200 GB' ),
getCompareTitle: () => i18n.translate( '200 GB' ),
getDescription: () =>
i18n.translate( 'Upload more images, videos, audio, and documents to your website.' ),
Expand Down Expand Up @@ -1769,6 +1760,24 @@ export const FEATURES_LIST: FeatureList = {
getAlternativeTitle: () => '0%',
getFeatureGroup: () => FEATURE_GROUP_PAYMENT_TRANSACTION_FEES,
},
[ FEATURE_50GB_STORAGE_ADD_ON ]: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To top it up, I would also question the need for FEATURE_50GB_STORAGE_ADD_ON as a separate object here. It's just a repeated structure to FEATURE_50GB_STORAGE for the most part with a different slug right? Obviously, alternative (to use same structure) needs a little deeper consideration.

Copy link
Contributor Author

@jeyip jeyip Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The distinct difference will be the inclusion of getQuantity on the feature object. and the label strings. https://github.com/Automattic/wp-calypso/pull/79041/files/afe13155242a279e041c346515508fe2383fd22a#r1279555091

In my head, it's natural to have them as two distinct objects. One is functionality to be purchased and another represents functionality inherent to a plan.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm gotcha. Potentially separate things. Although, both could be described in terms of x * unit right? 🤔

Copy link
Contributor Author

@jeyip jeyip Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although, both could be described in terms of x * unit right? 🤔

We could 👍 My decision to separate was more of an intuition -- it seems natural to see add ons and features as two different concepts, and I wouldn't be surprised if there's more divergent attributes in the future. As of right now though, they both totally could be described in terms of x * unit.

If we feel strongly about joining the two, I can make that happen.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we feel strongly about joining the two, I can make that happen.

I don't feel too strongly. On one end, I feel a separate object allows us to "do more". On the other end, I feel strongly about NOT replicating anything, and YAGNI (are we actually going to have any unique functionality for these "add-on" features)?

Let's maybe confirm whether we have standard features being used as add-ons already. I think I'm seeing a few in my-sites/add-ons/hooks/use-add-ons. If that's the case, then we have a mixture of things happening already:

  1. new features created that are prefixed with add_on and for the most part replicate the original "non add-on" feature to introduce other wording, properties, etc.
  2. feature definitions used as both add-ons and plan features (so no add_on prefix, probably no alternative titles).

Make the best judgment. with @southp pushing for this to move forward, I'll retract from this conversation.

Copy link
Contributor

@gmovr gmovr Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't followed the conversation here too closely, but just chiming in regarding the feature check.

Yes, the existing 50, 100, etc. are the ones used in bundles -- and are individual products mapped to a feature. They have no quantity.

As the features system isn't aware of quantity, the feature that's mapped to this new product is "Space 1 GB" (signaling that the subscription has this product), and the packages are just "stacks" of 50 or 100 of this product.

We keep track of quantity on subscription level, but there's no easy way to do it on feature level (e.g. by mapping a certain quantity to a certain feature), as the feature checks are boolean -- either the subscription has it, or it doesn't. :)

Copy link
Contributor

@chriskmnds chriskmnds Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for chiming in @gmovr .

I think we are just complicating things. Somehow this FeaturesList doesn't feel like a clearly defined structure. Is an add-on a feature? Does it ever map to the plan features? Would it make sense to return that from an endpoint /plan-features/[plan_id]? Are features meant to be something else than what plans or other products are bundled with?

My guess the answer to all of the above is "no". and if so, then "add-on" has no place in this list. Separate list, fine. Separate hook, even better (and looks like we have one already from the "add-ons" work).

and maybe no clear answers to any of the above - it might not be yes/no, maybe a "depends on how you look at it" approach (and how should we look at it then?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for exploring this concept in follow-up PRs and pinpointg core issues from there @jeyip , and thanks for further clarifcation, @chriskmnds :)

To summarize, the baseline thing we need to see are:

  1. FEATURE_XXGB_STORAGE_ADD_ON needs to be gone.
  2. The storage add-ons need to be defined in its own add-on data structure. (I didn't have a chance to look into how the other add-ons are defined yet, e.g. no-ads, premium themes, whatever can be seen from https://wordpress.com/add-ons/, but there should be an existing way. If somehow it's not enough to express the Storage add-ons, we should also expand from there.)

If that's correct, then unfortunately the exploratory PR #80114 is not in the right direction since that unwanted feature slug is still there. In that case, I think it would be the best if we can create a focal issue/PR solely for sorting this out –– the exploratory PR seems also to want to implement the dropdown functionality, but I feel it would add too much other concerns and deviate from our original purpose of shipping this PR first. I might be wrong, though :)

@jeyip Could you help create an issue for this, add it to the epic issue, and priortize it as the topmost from here? I'd be grateful :)

Copy link
Contributor

@chriskmnds chriskmnds Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are aligned on this. What @southp described and the exploration in #80114 speak of the same concerns to me.

Maybe we could have defined a separate structure or hook for add-ons here and avoid conflating with the features list. Then a follow-up could be to bridge that structure with the existing use-add-ons (which would be a bigger undertaking).


Speaking of which - @jeyip - I don't think plan ui package (plans-features-2023-grid) should host that hook. As a pointer for #80114 , I would suggest a separate add-ons package in the monorepo and export the hook from there. Maybe data-stores, but separate one can also exist to migrate rest of add-ons section there (I wonder when that will be put on pedestal for reuse). Definitely not under plans ui package though IMO. But lets this convo there / #80114

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for chiming in y'all!

Could you help create an issue for this, add it to https://github.com/Automattic/martech/issues/2023, and priortize it as the topmost from here? I'd be grateful :)

Of course -- I'll take care of this on Monday

getSlug: () => FEATURE_50GB_STORAGE_ADD_ON,
getUnitProductSlug: () => PRODUCT_1GB_SPACE,
getQuantity: () => 50,
getTitle: () => i18n.translate( '50 GB' ),
getCompareTitle: () => i18n.translate( '50 GB' ),
getDescription: () =>
i18n.translate( 'Storage space for adding images and documents to your website.' ),
},
[ FEATURE_100GB_STORAGE_ADD_ON ]: {
getSlug: () => FEATURE_100GB_STORAGE_ADD_ON,
getUnitProductSlug: () => PRODUCT_1GB_SPACE,
getQuantity: () => 100,
getTitle: () => i18n.translate( '100 GB' ),
getCompareTitle: () => i18n.translate( '100 GB' ),
getDescription: () =>
i18n.translate( 'Storage space for adding images and documents to your website.' ),
},
[ FEATURE_UNLIMITED_TRAFFIC ]: {
getSlug: () => FEATURE_UNLIMITED_TRAFFIC,
getTitle: () => i18n.translate( 'Unlimited traffic' ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ import useIsLargeCurrency from '../hooks/use-is-large-currency';
import { sortPlans } from '../lib/sort-plan-properties';
import { plansBreakSmall } from '../media-queries';
import { PlanProperties } from '../types';
import { usePricingBreakpoint } from '../util';
import { getStorageStringFromFeature, usePricingBreakpoint } from '../util';
import PlanFeatures2023GridActions from './actions';
import PlanFeatures2023GridBillingTimeframe from './billing-timeframe';
import PlanFeatures2023GridHeaderPrice from './header-price';
import { Plans2023Tooltip } from './plans-2023-tooltip';
import PopularBadge from './popular-badge';
import type { PlanActionOverrides } from '../types';
import type { StorageOption } from '@automattic/calypso-products';

function DropdownIcon() {
return (
Expand Down Expand Up @@ -342,7 +343,7 @@ type PlanComparisonGridHeaderProps = {
type RestructuredFeatures = {
featureMap: Record< string, Set< string > >;
conditionalFeatureMap: Record< string, Set< string > >;
planStorageOptionsMap: Record< string, string >;
planStorageOptionsMap: Record< string, StorageOption | undefined >;
};

type RestructuredFootnotes = {
Expand Down Expand Up @@ -559,9 +560,7 @@ const PlanComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
const hasConditionalFeature = featureSlug
? restructuredFeatures.conditionalFeatureMap[ planName ].has( featureSlug )
: false;
const [ storageFeature ] = getPlanFeaturesObject( [
restructuredFeatures.planStorageOptionsMap[ planName ],
] );
const storageOption = restructuredFeatures.planStorageOptionsMap[ planName ];
const cellClasses = classNames(
'plan-comparison-grid__feature-group-row-cell',
'plan-comparison-grid__plan',
Expand Down Expand Up @@ -589,7 +588,7 @@ const PlanComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
<>
<span className="plan-comparison-grid__plan-title">{ translate( 'Storage' ) }</span>
<StorageButton className="plan-features-2023-grid__storage-button" key={ planName }>
{ storageFeature?.getCompareTitle?.() }
{ getStorageStringFromFeature( storageOption?.slug || '' ) }
</StorageButton>
</>
) : (
Expand Down Expand Up @@ -854,7 +853,7 @@ export const PlanComparisonGrid: React.FC< PlanComparisonGridProps > = ( {
let previousPlan = null;
const planFeatureMap: Record< string, Set< string > > = {};
const conditionalFeatureMap: Record< string, Set< string > > = {};
const planStorageOptionsMap: Record< string, string > = {};
const planStorageOptionsMap: Record< string, StorageOption | undefined > = {};

for ( const plan of planProperties ?? [] ) {
const { planName } = plan;
Expand Down Expand Up @@ -890,8 +889,7 @@ export const PlanComparisonGrid: React.FC< PlanComparisonGridProps > = ( {
] );
}
previousPlan = planName;
const [ storageOption ] =
planObject.get2023PricingGridSignupStorageOptions?.( showLegacyStorageFeature ) ?? [];
const storageOption = plan.storageOptions.find( ( option ) => ! option.isAddOn );
planStorageOptionsMap[ planName ] = storageOption;

conditionalFeatureMap[ planName ] = new Set(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { CustomSelectControl } from '@wordpress/components';
import { TranslateResult, useTranslate } from 'i18n-calypso';
import { PlanSelectedStorage } from '..';
import { PlanProperties } from '../types';
import { getStorageStringFromFeature } from '../util';

type StorageAddOnDropdownProps = {
planProperties: PlanProperties;
selectedStorage: PlanSelectedStorage;
setSelectedStorage: ( selectedStorage: PlanSelectedStorage ) => void;
};

export const StorageAddOnDropdown = ( {
planProperties,
selectedStorage,
setSelectedStorage,
}: StorageAddOnDropdownProps ) => {
const { planName, storageOptions } = planProperties;
const translate = useTranslate();

// TODO: Consider transforming storageOptions outside of this component
const selectControlOptions = storageOptions.reduce(
( acc: { key: string; name: TranslateResult }[], storageOption ) => {
const title = getStorageStringFromFeature( storageOption.slug );
if ( title ) {
acc.push( {
key: storageOption?.slug,
name: title,
} );
}

return acc;
},
[]
);

const defaultStorageOption = storageOptions.find( ( storageOption ) => ! storageOption?.isAddOn );
const selectedOptionKey = selectedStorage[ planName ] || defaultStorageOption?.slug || '';
const selectedOption = {
key: selectedOptionKey,
name: getStorageStringFromFeature( selectedOptionKey ),
};
return (
<CustomSelectControl
label={ translate( 'Storage' ) }
options={ selectControlOptions }
value={ selectedOption }
onChange={ ( { selectedItem }: { selectedItem: { key?: string } } ) => {
const updatedSelectedStorage = {
[ planName ]: selectedItem?.key || '',
} as PlanSelectedStorage;

setSelectedStorage( updatedSelectedStorage );
} }
/>
);
};
60 changes: 46 additions & 14 deletions client/my-sites/plan-features-2023-grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
isWooExpressPlan,
PlanSlug,
isWooExpressPlusPlan,
WPComStorageAddOnSlug,
} from '@automattic/calypso-products';
import {
JetpackLogo,
Expand Down Expand Up @@ -60,6 +61,7 @@ import { PlanFeaturesItem } from './components/item';
import { PlanComparisonGrid } from './components/plan-comparison-grid';
import { Plans2023Tooltip } from './components/plans-2023-tooltip';
import PopularBadge from './components/popular-badge';
import { StorageAddOnDropdown } from './components/storage-add-on-dropdown';
import PlansGridContextProvider, { usePlansGridContext } from './grid-context';
import useHighlightAdjacencyMatrix from './hooks/npm-ready/use-highlight-adjacency-matrix';
import useIsLargeCurrency from './hooks/use-is-large-currency';
Expand All @@ -76,6 +78,8 @@ type PlanRowOptions = {
isTableCell?: boolean;
};

export type PlanSelectedStorage = { [ key: string ]: WPComStorageAddOnSlug | null };
chriskmnds marked this conversation as resolved.
Show resolved Hide resolved

const Container = (
props: (
| React.HTMLAttributes< HTMLDivElement >
Expand Down Expand Up @@ -115,6 +119,7 @@ export type PlanFeatures2023GridProps = {
isGlobalStylesOnPersonal?: boolean;
showLegacyStorageFeature?: boolean;
spotlightPlanSlug?: PlanSlug;
showUpgradeableStorage: boolean; // feature flag used to show the storage add-on dropdown
};

type PlanFeatures2023GridConnectedProps = {
Expand All @@ -137,6 +142,7 @@ type PlanFeatures2023GridType = PlanFeatures2023GridProps &

type PlanFeatures2023GridState = {
showPlansComparisonGrid: boolean;
selectedStorage: PlanSelectedStorage;
jeyip marked this conversation as resolved.
Show resolved Hide resolved
};

const PlanLogo: React.FunctionComponent< {
Expand Down Expand Up @@ -214,8 +220,9 @@ export class PlanFeatures2023Grid extends Component<
PlanFeatures2023GridType,
PlanFeatures2023GridState
> {
state = {
state: PlanFeatures2023GridState = {
showPlansComparisonGrid: false,
selectedStorage: {},
};

plansComparisonGridContainerRef = createRef< HTMLDivElement >();
Expand All @@ -232,6 +239,15 @@ export class PlanFeatures2023Grid extends Component<
} ) );
};

setSelectedStorage = ( updatedSelectedStorage: PlanSelectedStorage ) => {
this.setState( ( { selectedStorage } ) => ( {
selectedStorage: {
...selectedStorage,
...updatedSelectedStorage,
},
} ) );
};

componentDidUpdate(
prevProps: Readonly< PlanFeatures2023GridType >,
prevState: Readonly< PlanFeatures2023GridState >
Expand Down Expand Up @@ -892,7 +908,9 @@ export class PlanFeatures2023Grid extends Component<
}

renderPlanStorageOptions( planPropertiesObj: PlanProperties[], options?: PlanRowOptions ) {
const { translate } = this.props;
const { translate, intervalType, showUpgradeableStorage } = this.props;
const { selectedStorage } = this.state;

return planPropertiesObj
.filter( ( { isVisible } ) => isVisible )
.map( ( properties ) => {
Expand All @@ -901,24 +919,39 @@ export class PlanFeatures2023Grid extends Component<
}

const { planName, storageOptions } = properties;
const storageJSX = storageOptions.map( ( storageFeature: string ) => {
if ( storageFeature.length <= 0 ) {
return;
}
return (
<div className="plan-features-2023-grid__storage-buttons" key={ planName }>
{ getStorageStringFromFeature( storageFeature ) }
</div>
);
} );

const shouldRenderStorageTitle =
storageOptions.length === 1 ||
( intervalType === 'monthly' && storageOptions.length !== 0 ) ||
( ! showUpgradeableStorage && storageOptions.length !== 0 );
const canUpgradeStorageForPlan =
storageOptions.length > 1 && intervalType === 'yearly' && showUpgradeableStorage;

const storageJSX = canUpgradeStorageForPlan ? (
<StorageAddOnDropdown
planProperties={ properties }
selectedStorage={ selectedStorage }
setSelectedStorage={ this.setSelectedStorage }
/>
) : (
storageOptions.map( ( storageOption ) => {
if ( ! storageOption?.isAddOn ) {
return (
<div className="plan-features-2023-grid__storage-buttons" key={ planName }>
{ getStorageStringFromFeature( storageOption?.slug ) }
</div>
);
}
} )
);

return (
<Container
key={ planName }
className="plan-features-2023-grid__table-item plan-features-2023-grid__storage"
isTableCell={ options?.isTableCell }
>
{ storageOptions.length ? (
{ shouldRenderStorageTitle ? (
<div className="plan-features-2023-grid__storage-title">
{ translate( 'Storage' ) }
</div>
Expand Down Expand Up @@ -1066,7 +1099,6 @@ const ConnectedPlanFeatures2023Grid = connect(
isCurrentPlan
) ) ||
[];

const availableForPurchase =
isInSignup || ( siteId ? isPlanAvailableForPurchase( state, siteId, plan ) : false );

Expand Down
8 changes: 8 additions & 0 deletions client/my-sites/plan-features-2023-grid/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,14 @@ $mobile-card-max-width: 440px;
&.has-4-cols {
max-width: $table-cell-max-width * 4;
}

.components-custom-select-control__label {
color: var(--studio-gray-100);
}

.components-custom-select-control__menu {
margin-left: 0;
}
}

.plan-features-2023-grid__header-title {
Expand Down
Loading