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'