From e9dd128371f0fca3dd2b9d8111207aa83e600e38 Mon Sep 17 00:00:00 2001 From: MoxAmber Date: Tue, 7 Jan 2025 08:56:18 +0000 Subject: [PATCH] [Group Pricing] Add price change warning to cancellation flow (#22640) * Add price change warning to cancellation flow * Fixes lint error from translated string * update pricing effective date --------- Co-authored-by: Kristina Hjertberg GitOrigin-RevId: d1b6982ff437d931144feffddcbddd96f5a3405b --- .../web/frontend/extracted-translations.json | 2 + .../cancel-plan/cancel-subscription.tsx | 69 +++++++++++++------ .../stylesheets/app/subscription.less | 8 +++ .../bootstrap-5/pages/subscription.scss | 6 ++ services/web/locales/en.json | 2 + .../subscription/fixtures/subscriptions.ts | 11 +++ .../subscription/dashboard/subscription.ts | 1 + 7 files changed, 78 insertions(+), 21 deletions(-) diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 05a30c1fdb..7d75882750 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -183,6 +183,8 @@ "cancel": "", "cancel_add_on": "", "cancel_anytime": "", + "cancel_group_price_warning": "", + "cancel_group_price_warning_heading": "", "cancel_my_account": "", "cancel_my_subscription": "", "cancel_personal_subscription_first": "", diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx index 8bfac39904..1b1a3dcf3f 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx @@ -15,6 +15,9 @@ import ExtendTrialButton from './extend-trial-button' import { useLocation } from '../../../../../../../shared/hooks/use-location' import { debugConsole } from '@/utils/debugging' import OLButton from '@/features/ui/components/ol/ol-button' +import moment from 'moment' +import { getSplitTestVariant } from '@/utils/splitTestUtils' +import OLNotification from '@/features/ui/components/ol/ol-notification' const planCodeToDowngradeTo = 'paid-personal' @@ -157,6 +160,8 @@ export function CancelSubscription() { isSuccessSecondaryAction || isSuccessCancel + const groupPricingVariant = getSplitTestVariant('group-pricing-2025') + if (!personalSubscription || !('recurly' in personalSubscription)) return null const showDowngrade = showDowngradeOption( @@ -171,6 +176,13 @@ export function CancelSubscription() { return } + const startDate = moment.utc(personalSubscription.recurly.account.created_at) + const pricingChangeEffectiveDate = moment.utc('2025-01-08T12:00:00Z') + const displayPricingWarning = + groupPricingVariant === 'enabled' && + personalSubscription.plan.groupPlan && + startDate.isBefore(pricingChangeEffectiveDate) + async function handleCancelSubscription() { try { await runAsyncCancel(postJSON(cancelSubscriptionUrl)) @@ -183,29 +195,44 @@ export function CancelSubscription() { const showExtendFreeTrial = userCanExtendTrial return ( -
-

- {t('wed_love_you_to_stay')} -

+ <> + {displayPricingWarning && ( + +

+ {t('cancel_group_price_warning_heading')} +

+

{t('cancel_group_price_warning')}

+ + } + /> + )} +
+

+ {t('wed_love_you_to_stay')} +

- {(isErrorCancel || isErrorSecondaryAction) && } + {(isErrorCancel || isErrorSecondaryAction) && } - + - -
+ +
+ ) } diff --git a/services/web/frontend/stylesheets/app/subscription.less b/services/web/frontend/stylesheets/app/subscription.less index 85dbabb630..ee915bc641 100644 --- a/services/web/frontend/stylesheets/app/subscription.less +++ b/services/web/frontend/stylesheets/app/subscription.less @@ -298,3 +298,11 @@ a.row-link { color: @content-secondary; } } + +.pricing-warning-heading { + font-size: @font-size-03; + font-weight: 600; + font-family: @font-family-sans-serif; + margin-top: 0; + color: @content-primary-on-dark-bg; +} diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss index 2c6f49689d..9241b68bcc 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss @@ -410,3 +410,9 @@ @include body-lg; } } + +.pricing-warning-heading { + @include body-base; + + font-weight: 600; +} diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 262b5eb6bf..e2a64ffe73 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -248,6 +248,8 @@ "cancel": "Cancel", "cancel_add_on": "Cancel add-on", "cancel_anytime": "We’re confident that you’ll love __appName__, but if not you can cancel anytime. We’ll give you your money back, no questions asked, if you let us know within 30 days.", + "cancel_group_price_warning": "Our per-user prices are increasing in 2025. Keep your current rate for existing and new users by staying with us.", + "cancel_group_price_warning_heading": "Don’t lose your current pricing", "cancel_my_account": "Cancel my subscription", "cancel_my_subscription": "Cancel my subscription", "cancel_personal_subscription_first": "You already have an individual subscription, would you like us to cancel this first before joining the group licence?", diff --git a/services/web/test/frontend/features/subscription/fixtures/subscriptions.ts b/services/web/test/frontend/features/subscription/fixtures/subscriptions.ts index f823e9f003..9bdde3f181 100644 --- a/services/web/test/frontend/features/subscription/fixtures/subscriptions.ts +++ b/services/web/test/frontend/features/subscription/fixtures/subscriptions.ts @@ -49,6 +49,7 @@ export const annualActiveSubscription: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, @@ -90,6 +91,7 @@ export const annualActiveSubscriptionEuro: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, @@ -130,6 +132,7 @@ export const annualActiveSubscriptionPro: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, @@ -171,6 +174,7 @@ export const pastDueExpiredSubscription: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'true', $: { type: 'boolean' } }, }, @@ -212,6 +216,7 @@ export const canceledSubscription: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'true', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, @@ -253,6 +258,7 @@ export const pendingSubscriptionChange: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, @@ -305,6 +311,7 @@ export const groupActiveSubscription: GroupSubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, @@ -351,6 +358,7 @@ export const groupActiveSubscriptionWithPendingLicenseChange: GroupSubscription activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { @@ -415,6 +423,7 @@ export const trialSubscription: RecurlySubscription = { activeCoupons: [], account: { email: 'fake@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { @@ -487,6 +496,7 @@ export const trialCollaboratorSubscription: RecurlySubscription = { activeCoupons: [], account: { email: 'foo@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { @@ -537,6 +547,7 @@ export const monthlyActiveCollaborator: RecurlySubscription = { activeCoupons: [], account: { email: 'foo@example.com', + created_at: '2024-12-31T09:40:27.000Z', has_canceled_subscription: { _: 'false', $: { type: 'boolean' } }, has_past_due_invoice: { _: 'false', $: { type: 'boolean' } }, }, diff --git a/services/web/types/subscription/dashboard/subscription.ts b/services/web/types/subscription/dashboard/subscription.ts index 7afe6fa815..5474ea1edd 100644 --- a/services/web/types/subscription/dashboard/subscription.ts +++ b/services/web/types/subscription/dashboard/subscription.ts @@ -26,6 +26,7 @@ type Recurly = { activeCoupons: any[] // TODO: confirm type in array account: { email: string + created_at: string // data via Recurly API has_canceled_subscription: { _: 'false' | 'true'