[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 <kristina.hjertberg@overleaf.com>
GitOrigin-RevId: d1b6982ff437d931144feffddcbddd96f5a3405b
This commit is contained in:
MoxAmber
2025-01-07 08:56:18 +00:00
committed by Copybot
parent 654268d070
commit e9dd128371
7 changed files with 78 additions and 21 deletions
@@ -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": "",
@@ -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 <LoadingSpinner />
}
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 (
<div className="text-center">
<p>
<strong>{t('wed_love_you_to_stay')}</strong>
</p>
<>
{displayPricingWarning && (
<OLNotification
type="warning"
content={
<>
<h2 className="pricing-warning-heading">
{t('cancel_group_price_warning_heading')}
</h2>
<p>{t('cancel_group_price_warning')}</p>
</>
}
/>
)}
<div className="text-center">
<p>
<strong>{t('wed_love_you_to_stay')}</strong>
</p>
{(isErrorCancel || isErrorSecondaryAction) && <GenericErrorAlert />}
{(isErrorCancel || isErrorSecondaryAction) && <GenericErrorAlert />}
<NotCancelOption
showExtendFreeTrial={showExtendFreeTrial}
showDowngrade={showDowngrade}
isButtonDisabled={isButtonDisabled}
isLoadingSecondaryAction={isLoadingSecondaryAction}
isSuccessSecondaryAction={isSuccessSecondaryAction}
planToDowngradeTo={planToDowngradeTo}
runAsyncSecondaryAction={runAsyncSecondaryAction}
/>
<NotCancelOption
showExtendFreeTrial={showExtendFreeTrial}
showDowngrade={showDowngrade}
isButtonDisabled={isButtonDisabled}
isLoadingSecondaryAction={isLoadingSecondaryAction}
isSuccessSecondaryAction={isSuccessSecondaryAction}
planToDowngradeTo={planToDowngradeTo}
runAsyncSecondaryAction={runAsyncSecondaryAction}
/>
<ConfirmCancelSubscriptionButton
showNoThanks={showExtendFreeTrial || showDowngrade}
onClick={handleCancelSubscription}
disabled={isButtonDisabled}
isLoading={isSuccessCancel || isLoadingCancel}
/>
</div>
<ConfirmCancelSubscriptionButton
showNoThanks={showExtendFreeTrial || showDowngrade}
onClick={handleCancelSubscription}
disabled={isButtonDisabled}
isLoading={isSuccessCancel || isLoadingCancel}
/>
</div>
</>
)
}
@@ -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;
}
@@ -410,3 +410,9 @@
@include body-lg;
}
}
.pricing-warning-heading {
@include body-base;
font-weight: 600;
}
+2
View File
@@ -248,6 +248,8 @@
"cancel": "Cancel",
"cancel_add_on": "Cancel add-on",
"cancel_anytime": "Were confident that youll love __appName__, but if not you can cancel anytime. Well 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": "Dont 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?",
@@ -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' } },
},
@@ -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'