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: Make storage selection calculations in plan prices optional #96520

Merged

Conversation

jeyip
Copy link
Contributor

@jeyip jeyip commented Nov 19, 2024

Related to https://github.com/Automattic/martech/issues/3403 and #96357 (review)

Proposed Changes

  • Disable storage add-on selection updates in header price for the calypso_plans_page_emphasize_longer_plan_savings experiment with a new reflectStorageSelectionInPlanPrices flag
  • Pass reflectStorageSelectionInPlanPrices to context to reference throughout plans-grid-next. If false, prevent storage add-on calculations in features grid + comparison grid plan pricing.

Why are these changes being made?

  • See p1726619377025979/1724962428.022989-slack-C07ABDFQEMS

Testing Instructions

  • Go to /start/plans?flags=plans/term-savings-price-display
  • Ensure that when storage add-ons are selected for business or ecommerce annual plans, the header price doesn't change

Pre-merge Checklist

  • Has the general commit checklist been followed? (PCYsg-hS-p2)
  • Have you written new tests for your changes?
  • Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
  • Have you checked for TypeScript, React or other console errors?
  • Have you used memoizing on expensive computations? More info in Memoizing with create-selector and Using memoizing selectors and Our Approach to Data
  • Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
  • For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?

@jeyip jeyip self-assigned this Nov 19, 2024
@jeyip jeyip requested a review from a team as a code owner November 19, 2024 01:40
@jeyip jeyip requested a review from southp November 19, 2024 01:40
@matticbot matticbot added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels Nov 19, 2024
Copy link
Contributor Author

@jeyip jeyip left a comment

Choose a reason for hiding this comment

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

This is the first approach that came to mind. Totally possible that there might be a more neat / tidy solution. I'll give it more thought tomorrow.

@matticbot
Copy link
Contributor

matticbot commented Nov 19, 2024

This PR modifies the release build for the following Calypso Apps:

For info about this notification, see here: PCYsg-OT6-p2

  • notifications
  • odyssey-stats
  • wpcom-block-editor

To test WordPress.com changes, run install-plugin.sh $pluginSlug update/term-savings-pricing-to-ignore-storage-addon-selections on your sandbox.

@matticbot
Copy link
Contributor

matticbot commented Nov 19, 2024

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

Sections (~867 bytes added 📈 [gzipped])

name                     parsed_size           gzip_size
site-overview                +1485 B  (+0.1%)     +370 B  (+0.1%)
hosting                      +1485 B  (+0.1%)     +370 B  (+0.1%)
update-design-flow           +1434 B  (+0.1%)     +292 B  (+0.1%)
plugins                      +1434 B  (+0.0%)     +289 B  (+0.0%)
plans                        +1434 B  (+0.1%)     +292 B  (+0.1%)
link-in-bio-tld-flow         +1434 B  (+0.1%)     +285 B  (+0.1%)
jetpack-app                  +1434 B  (+0.4%)     +291 B  (+0.2%)
theme                          +44 B  (+0.0%)      +25 B  (+0.0%)
stats                          +44 B  (+0.0%)      +22 B  (+0.0%)
site-purchases                 +44 B  (+0.0%)      +27 B  (+0.0%)
purchases                      +44 B  (+0.0%)      +27 B  (+0.0%)
posts-custom                   +44 B  (+0.0%)      +26 B  (+0.0%)
posts                          +44 B  (+0.0%)      +26 B  (+0.0%)
migrate                        +44 B  (+0.0%)      +28 B  (+0.0%)
import-hosted-site-flow        +44 B  (+0.0%)      +28 B  (+0.0%)
domains                        +44 B  (+0.0%)      +26 B  (+0.0%)
checkout                       +44 B  (+0.0%)      +27 B  (+0.0%)

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.

Async-loaded Components (~317 bytes added 📈 [gzipped])

name                                             parsed_size           gzip_size
async-load-signup-steps-plans-theme-preselected      +1434 B  (+0.4%)     +291 B  (+0.2%)
async-load-signup-steps-plans                        +1434 B  (+0.4%)     +291 B  (+0.2%)
async-load-design-blocks                               +44 B  (+0.0%)      +26 B  (+0.0%)

React components that are loaded lazily, when a certain part of UI is displayed for the first time.

Legend

What is parsed and gzip size?

Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.

Generated by performance advisor bot at iscalypsofastyet.com.

@jeyip jeyip requested a review from chriskmnds November 19, 2024 01:48
Copy link
Contributor

@chriskmnds chriskmnds left a comment

Choose a reason for hiding this comment

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

Hey @jeyip. Do we also need to pass this along from usePlanBillingDescription? It makes a call to Plans.usePricingMetaForGridPlans and passes storageAddOns through (so they are definitely accounted for).

I think we'd just need to add the prop to plans-grid-context and grab from usePlanBillingDescription.

@jeyip
Copy link
Contributor Author

jeyip commented Nov 21, 2024

Hey @chriskmnds just leaving a message here to say I didn't miss your comments. Will get to them tomorrow 😎

@chriskmnds chriskmnds force-pushed the update/plans-grid-header-price-cleanup branch from 9ece3ab to 14945ae Compare November 21, 2024 07:33
@jeyip
Copy link
Contributor Author

jeyip commented Nov 22, 2024

It's getting near the end of my day. I started reviewing the comment, but will continue tomorrow. Thanks for the patience!

@chriskmnds chriskmnds force-pushed the update/plans-grid-header-price-cleanup branch 2 times, most recently from c8e0442 to d196100 Compare November 25, 2024 09:55
Base automatically changed from update/plans-grid-header-price-cleanup to trunk November 25, 2024 10:13
@jeyip
Copy link
Contributor Author

jeyip commented Nov 25, 2024

Addressing merge conflicts and CR comments now :D

@jeyip jeyip force-pushed the update/term-savings-pricing-to-ignore-storage-addon-selections branch 2 times, most recently from 86db0e8 to a182e23 Compare November 26, 2024 23:02
@jeyip jeyip force-pushed the update/term-savings-pricing-to-ignore-storage-addon-selections branch 3 times, most recently from 4e4bd2f to 9598f54 Compare December 2, 2024 18:59
@jeyip jeyip changed the title Plans: Make storage selection reflection in header price optional Plans: Make storage selection reflection in plan prices optional Dec 6, 2024
@jeyip jeyip changed the title Plans: Make storage selection reflection in plan prices optional Plans: Make storage selection calculations in plan prices optional Dec 6, 2024
@jeyip
Copy link
Contributor Author

jeyip commented Dec 6, 2024

@chriskmnds would love your input on 57e2f8a. There's one change that's definitely worth discussing, and it's around the useEligibilityForTermSavingsPriceDisplay hook.

Context

Although we disable storage add-on calculations in this PR, I believe it makes sense to re-enable storage add-on calculations when term savings are not shown. With #96631, this includes re-enabling storage add-on calculations when there are discounts or special offers in the plans grid.

To do so, I leverage the enableTermSavingsPriceDisplay and the useEligibilityForTermSavingsPriceDisplay hook here.

The tricky part is that we handle reflectStorageSelectionInPlanPrices in the usePricingMetaForGridPlans hook, which is called by useGridPlans. We want the results of useEligibilityForTermSavingsPriceDisplay to determine if we reflect storage selection, but useEligibilityForTermSavingsPriceDisplay currently depends on the results of useGridPlans.

Reiterated more linearly:

  • We handle reflectStorageSelectionInPlanPrices in the pricing meta for grid plans
  • We join pricing meta to plans metadata in useGridPlans
  • We use the generated gridPlans to determine useEligibilityForTermSavingsPriceDisplay
  • We, however, need the results of useEligibilityForTermSavingsPriceDisplay to properly determine reflectStorageSelectionInPlanPrices, which is handled in useGridPlans, which useEligibilityForTermSavingsPriceDisplay depends on

Hoping that makes sense, but happy to clarify further if needed.

Possible Solutions

I've pushed one possible solution in 57e2f8a, where, instead of useEligibilityForTermSavingsPriceDisplay depending on generated grid plans, we generate the required data ourselves and calculate allAvailablePlanSlugs within the hook instead. I would clean this up further if this seems reasonable

Another alternative might be to prop drill the useEligibilityForTermSavingsPriceDisplay through useGridPlansForComparisonGrid and useGridPlansForFeaturesGrid into useGridPlans. I don't have a strong opinion of if this is more or less ideal yet. Will sleep on this and think of other ways to handle this as well.

Lemme know your thoughts 🙂

Comment on lines 39 to 54
const availablePlanSlugs = usePlansFromTypes( {
planTypes: usePlanTypesWithIntent( {
intent: 'default',
selectedPlan,
siteId,
hiddenPlans,
isSubdomainNotGenerated,
} ),
term,
intent,
} );
const planSlugsForAllDisplayedIntervals = availablePlanSlugs.flatMap(
Copy link
Contributor

Choose a reason for hiding this comment

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

This does make the hook a lot more complicated, also indirectly linked to how we generate plan slugs in useGridPlans, which might be hard to keep aligned going forward.

I wonder if we relax the criteria a bit (of reflecting or not reflecting storage selection) might help? e.g. let's show it
by default, and not show it if the experiment.isEligibleForTermSavings is set. Simple. So we disconnect it from needing access to useEligibilityForTermSavingsPriceDisplay, which does a lot more than that. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

Although, not sure if that might help after we conclude the experiment and we run into this problem again 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm so yeah, I think what you have here might be the way forward. Happy to give it some more thought later and get back to you.

p.s. we'd need to use the actual intent passed through here (without a default value), and also export usePlansFromTypes to import normally (not from the src folder). if we stick with this.

Copy link
Contributor Author

@jeyip jeyip Dec 6, 2024

Choose a reason for hiding this comment

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

I wonder if we relax the criteria a bit (of reflecting or not reflecting storage selection) might help? e.g. let's show it
by default, and not show it if the experiment.isEligibleForTermSavings is set. Simple. So we disconnect it from needing access to useEligibilityForTermSavingsPriceDisplay, which does a lot more than that. WDYT?

Although, not sure if that might help after we conclude the experiment and we run into this problem again 🤔

The more I look at the code and weigh the complexity we introduce with the functionality we gain, the more I'm considering this 👍 But yes, like you say, if the experiment concludes successfully we'd have to revisit this discussion

p.s. we'd need to use the actual intent passed through here (without a default value), and also export usePlansFromTypes to import normally (not from the src folder). if we stick with this.

On it

Happy to give it some more thought later and get back to you.

Sounds great -- would love your thoughts as we move forward 🙂

displayedIntervals: UrlFriendlyTermType[];
storageAddOns: ( AddOns.AddOnMeta | null )[] | null;
coupon?: string;
siteId?: number | null;
isInSignup?: boolean;
} ) => {
const longerPlanTermDefaultExperiment = useLongerPlanTermDefaultExperiment();
const planSlugs = gridPlans.map( ( { planSlug } ) => planSlug );
Copy link
Contributor

Choose a reason for hiding this comment

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

p.s. NIT - if we bring back the original (prior to these changes), would it make sense to pass planSlugs instead? So do the mapping at consuming end perhaps.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh good question. I'll think this over 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we go back to the original, I prefer planSlugs. It more concisely describes what's needed for the hook, and it generalizes the interface more.

@chriskmnds
Copy link
Contributor

Good thinking @jeyip . I replied in a couple of comments, so we can have discussion there instead quoting each other here :-)

@jeyip
Copy link
Contributor Author

jeyip commented Dec 13, 2024

Starting to revisit this PR. Planning to merge later today for two reasons:

  1. to close the loop on remaining work for https://github.com/Automattic/martech/issues/3403
  2. this work isn't user facing at the moment, so our changes are easily reversible

@jeyip jeyip force-pushed the update/term-savings-pricing-to-ignore-storage-addon-selections branch from 82f95b3 to acd3c2d Compare December 13, 2024 20:39
@jeyip
Copy link
Contributor Author

jeyip commented Dec 14, 2024

Testing

Requirements

For each of the flows listed below:

  • Verified header price and billing timeframe price with production
  • Verified pricing for monthly and yearly pricing
  • Ensured that a plan could be purchased
  • Verified that storage add-ons do not affect price when plan term savings are shown
  • Verified that storage add-ons do affect price when plan term savings are not shown
  • In /plans, verified that long term plan savings are never shown

Flows:

  • /start
  • /setup/link-in-bio-tld
  • /plans

Browsers

  • Chrome

@jeyip jeyip merged commit b8226dd into trunk Dec 14, 2024
11 checks passed
@jeyip jeyip deleted the update/term-savings-pricing-to-ignore-storage-addon-selections branch December 14, 2024 07:14
@github-actions github-actions bot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Dec 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants