Skip to content

Self service downgrade: Show refund text for eligible users#101893

Merged
claudiucelfilip merged 6 commits intotrunkfrom
add/downgrade-refund-text
Mar 27, 2025
Merged

Self service downgrade: Show refund text for eligible users#101893
claudiucelfilip merged 6 commits intotrunkfrom
add/downgrade-refund-text

Conversation

@claudiucelfilip
Copy link
Contributor

@claudiucelfilip claudiucelfilip commented Mar 26, 2025

Proposed Changes

  • Show refund text in the Downgrade screen: When you downgrade from %(currentPlan)s to %(targetPlan)s, we'll immediately process a refund of %(amount)s to your original payment method.
  • Show the Refund available beneath the Downgrade button (similar to Cancel)

Why are these changes being made?

  • Part of an epic to support self service downgrades in wpcom

Testing Instructions

  • Go to the purchases screen for a plan subscription found within the refund window
  • You should see the Refund available text in Downgrade button
Screenshot 2025-03-26 at 13 00 50
  • The Downgrade screen should show the refund text
Screenshot 2025-03-27 at 11 36 59
  • Switch to a plan outside the refund window
  • The Refund available should not be visible
  • The Downgrade screen should show the default text
Screenshot 2025-03-26 at 13 01 09

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 UI changes, have we tested the change in various languages (for example, ES, PT, FR, or DE)? The length of text and words vary significantly between languages.
  • 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)?

@claudiucelfilip claudiucelfilip requested review from a team and ddc22 March 26, 2025 12:29
@claudiucelfilip claudiucelfilip self-assigned this Mar 26, 2025
@claudiucelfilip claudiucelfilip requested a review from a team as a code owner March 26, 2025 12:29
@matticbot matticbot added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels Mar 26, 2025
@github-actions
Copy link

github-actions bot commented Mar 26, 2025

@matticbot
Copy link
Contributor

matticbot commented Mar 26, 2025

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

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

  • blaze-dashboard
  • help-center
  • notifications
  • wpcom-block-editor

To test WordPress.com changes, run install-plugin.sh $pluginSlug add/downgrade-refund-text on your sandbox.

@matticbot
Copy link
Contributor

matticbot commented Mar 26, 2025

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

Sections (~229 bytes added 📈 [gzipped])

Details
name            parsed_size           gzip_size
site-purchases       +695 B  (+0.0%)     +229 B  (+0.0%)
purchases            +695 B  (+0.0%)     +229 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.

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.

@jasmussen
Copy link
Member

jasmussen commented Mar 26, 2025

Thanks for the ping. A quick broader ping also to @Automattic/dotcom-design for any nuance I'm missing, in my supporting-work capacity. Since this is mostly a text-change (thanks for including the screenshots), it seems like this one can just move forward.

However I can't help but look at the mockup and find a lot of details missing:

plan-downgrade-1

Note that in the following I'm reviewing purely based on the screenshot, as this is a flow that's hard to test in my dev env.—so I may be missing nuance. Let me know.

The space below the list of features you're losing is slightly larger than it is above. In the mockup, it's the same spacing:

Screenshot 2025-03-26 at 13 47 27

This gap may be addressed by other semantic changes I'll get to in a minute (line-heights, etc)—and we want to avoid that you write custom CSS to address this. But coming from a WordPress core context, we would've used something like a VStack component to ensure perfect spacing. Sharing mostly for awareness.

The buttons look like core components. Nice. Please set the "Downgrade to Personal" button to destructive so it's red.

I was looking through the general Settings screens, and honestly it looks like the font sizes are a bit all over the place, headings at 14px and default text at 16px, it's a curious mess. Because I don't want you to add additional CSS just for this one screen, I'll defer some of these details to you on how to implement in a clean way with as little CSS as possible, so it's just the componentry. But really, we should have a single font size for all content inside this card. All the text—heading, description, list items, button text, "Need help with purchase", all of that text should be the same font size. Because there's such a mix of font sizes, it's unclear what is the near-term best choice here. But I expect the long term choice to be: 13px font size for all body text.

@claudiucelfilip
Copy link
Contributor Author

claudiucelfilip commented Mar 26, 2025

Thank you @jasmussen for outlining these.
We will address them in a follow-up PR.

@claudiucelfilip claudiucelfilip added the [Status] String Freeze Add the [Status] String Freeze label to your PR to ensure new strings are translated before merging label Mar 26, 2025
@DavidRothstein
Copy link
Contributor

Should we also show the actual refund amount here too? If they're getting money back it's probably a good idea to tell them in advance how much it will be.

Note that in the current self-serve downgrade flow that's live in production (i.e. the one that's hidden away in the cancellation flow) we do already show the exact amount of money that will be refunded -- see screenshot below. So you could hopefully look at that code for where the number comes from and use it here too.

downgrade-premium-to-personal

@claudiucelfilip
Copy link
Contributor Author

@DavidRothstein Thanks for reviewing this!

Should we also show the actual refund amount here too?

Good point. I copied over the approach from the hidden downgrade flow from cancellation and applied it here.

Copy link
Contributor

@ddc22 ddc22 left a comment

Choose a reason for hiding this comment

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

LGTM 🚢
Tests well.

We could probably move some logic to a hook. I will try to work on this on a subsequent PR.

@claudiucelfilip claudiucelfilip requested a review from ddc22 March 27, 2025 11:01
@michaelpick
Copy link
Contributor

Hey @claudiucelfilip ! Thanks for reaching out on Slack. A little feedback on the copy mentioned in case it helps:

We will change the plan immediately and refund the remaining value of {AMOUNT} from {CURRENT_PLAN} to {TARGET_PLAN}.

This is generally clear, but there are a few potential improvements we could make:

  • The phrasing "refund the remaining value of {AMOUNT}" is slightly awkward since the amount itself is the value being refunded.
  • We could be more direct about what happens with the refund (is it credited to their account or returned to their original payment method?)
  • "from {CURRENT_PLAN} to {TARGET_PLAN}" might be clearer?

As it looks like this is a refund, how about:

When you downgrade from {CURRENT_PLAN} to {TARGET_PLAN}, we'll immediately process a refund of {AMOUNT} to your original payment method.

Or if the credit's transferred from the older more expensive plan to the new plan, 'refund' might be confusing, and something like this might be a better fit:

When you downgrade from {CURRENT_PLAN} to {TARGET_PLAN}, we'll immediately apply {AMOUNT} as credit from your current plan to your new subscription.

Just to cover all bases, if it's one of those 'it depends' moments, a fallback might be:

When you downgrade from {CURRENT_PLAN} to {TARGET_PLAN}, we'll immediately apply {AMOUNT} as credit or process it as a refund to your original payment method

(Although the more precise we can be, the better!)

Hope that helps!

@claudiucelfilip
Copy link
Contributor Author

Thank you @michaelpick!
We're going to go with the first option, as the current approach is to only refund (ie. no credits).
When you downgrade from {CURRENT_PLAN} to {TARGET_PLAN}, we'll immediately process a refund of {AMOUNT} to your original payment method.

@a8ci18n
Copy link

a8ci18n commented Mar 27, 2025

This Pull Request is now available for translation here: https://translate.wordpress.com/deliverables/17317926

Some locales (Hebrew, Japanese) have been temporarily machine-translated due to translator availability. All other translations are usually ready within a few days. Untranslated and machine-translated strings will be sent for translation next Monday and are expected to be completed by the following Friday.

Thank you @claudiucelfilip for including a screenshot in the description! This is really helpful for our translators.

@DavidRothstein
Copy link
Contributor

Hm, it seems to be showing the wrong refund amount (see screenshot below). $252 is the expected refund for downgrading to Personal (not Premium). $204 is the expected amount for Premium (and the actual amount that I receive if I go through with the downgrade)... However, this may be a separate bug.

downgrade-refund

Can we also change the wording here to remove the word "immediately"? We shouldn't say that because it won't necessarily show up in their bank account right away. We normally say things more like "you will receive a refund of $X" but I think the wording in this pull request is OK too as long as it doesn't imply that the refund is immediate.

Speaking of which, we usually send a confirmation email after a refund (which explains more about how/when the refund will appear in their bank account) but for downgrades we apparently don't. This applies for both the old (hidden) downgrade flow and the new one, so I've made a separate issue about it here: https://github.com/Automattic/payments-shilling/issues/3660

const amount =
isRefundable( purchase ) &&
Array.isArray( refundOptions ) &&
refundOptions[ 0 ]?.refund_amount
Copy link
Contributor

Choose a reason for hiding this comment

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

I debugged a bit and I think this is the reason it's showing the wrong refund amount (see my earlier comment). The code is using the first element of the array here, but it actually needs to pick the correct element of the array depending on which product is being downgraded to.

As you mentioned, you basically just copied this code from the existing self-serve downgrade flow within cancellation, so a version of the bug exists there too. The code has been there for years, but perhaps it never mattered much in practice (until recently when the server started returning more downgrade options than it did before). Eventually it will need to be fixed in both places.

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 debugging this. I added a search to match to_product_id to the target plan's.

@claudiucelfilip claudiucelfilip merged commit 11e599e into trunk Mar 27, 2025
13 checks passed
@claudiucelfilip claudiucelfilip deleted the add/downgrade-refund-text branch March 27, 2025 22:32
@github-actions github-actions bot removed [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. [Status] String Freeze Add the [Status] String Freeze label to your PR to ensure new strings are translated before merging labels Mar 27, 2025
@a8ci18n
Copy link

a8ci18n commented Mar 27, 2025

This Pull Request is now available for translation here: https://translate.wordpress.com/deliverables/17317926

Some locales (Hebrew, Japanese) have been temporarily machine-translated due to translator availability. All other translations are usually ready within a few days. Untranslated and machine-translated strings will be sent for translation next Monday and are expected to be completed by the following Friday.

Thank you @claudiucelfilip for including a screenshot in the description! This is really helpful for our translators.

@a8ci18n
Copy link

a8ci18n commented Mar 28, 2025

Translation for this Pull Request has now been finished.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

Comments