Recurly Pending subscription bug fixes and display Notification Banner (#29811)

GitOrigin-RevId: 4eb6bb445f9911fcf74ff2f9bdcc01b420c7afaf
This commit is contained in:
Davinder Singh
2026-01-20 09:06:42 +00:00
committed by Copybot
parent ae5e3543c5
commit 187ffbf108
6 changed files with 46 additions and 24 deletions
@@ -320,30 +320,18 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
throw new Error(`No plan found for planCode '${pendingPlanCode}'`)
}
let pendingAdditionalLicenses = 0
let pendingAddOnTax = 0
let pendingAddOnPrice = 0
if (paymentRecord.subscription.pendingChange.nextAddOns) {
const pendingAddOns =
paymentRecord.subscription.pendingChange.nextAddOns
pendingAddOns.forEach(addOn => {
pendingAddOnPrice += addOn.quantity * addOn.unitPrice
if (addOn.code === pendingPlan.membersLimitAddOn) {
pendingAdditionalLicenses += addOn.quantity
}
})
// Need to calculate tax ourselves as we don't get tax amounts for pending subs
pendingAddOnTax =
personalSubscription.payment.taxRate * pendingAddOnPrice
pendingPlan.addOns = pendingAddOns
}
const pendingSubscriptionTax =
personalSubscription.payment.taxRate *
paymentRecord.subscription.pendingChange.nextPlanPrice
const totalPrice =
paymentRecord.subscription.pendingChange.nextPlanPrice +
pendingAddOnPrice +
pendingAddOnTax +
pendingSubscriptionTax
const totalPrice = paymentRecord.subscription.planPrice + addOnPrice + tax
personalSubscription.payment.displayPrice = formatCurrency(
totalPrice,
@@ -1299,6 +1299,7 @@
"pending_additional_licenses": "",
"pending_addon_cancellation": "",
"pending_invite": "",
"pending_subscription_message": "",
"per_license": "",
"per_month": "",
"per_month_x_annually": "",
@@ -186,10 +186,6 @@ export function ActiveSubscription({
<hr />
<h2 className="h3 fw-bold">{t('plan')}</h2>
<h3 className="h5 mt-0 mb-1 fw-bold">{planName}</h3>
{subscription.pendingPlan &&
subscription.pendingPlan.name !== subscription.plan.name && (
<p className="mb-1">{t('want_change_to_apply_before_plan_end')}</p>
)}
{isInFreeTrial(subscription.payment.trialEndsAt) &&
subscription.payment.trialEndsAtFormatted && (
<TrialEnding
@@ -262,6 +258,12 @@ export function ActiveSubscription({
})}
</p>
)}
{subscription.pendingPlan &&
subscription.pendingPlan.name !== subscription.plan.name && (
<p className="mb-1">{t('want_change_to_apply_before_plan_end')}</p>
)}
{!recurlyLoadError && (
<PlanActions
subscription={subscription}
@@ -16,6 +16,7 @@ import OLCol from '@/shared/components/ol/ol-col'
import OLNotification from '@/shared/components/ol/ol-notification'
import WritefullManagedBundleAddOn from './states/active/change-plan/modals/writefull-bundle-management-modal'
import RedirectAlerts from './redirect-alerts'
import { PaidSubscription } from '@ol-types/subscription/dashboard/subscription'
function SubscriptionDashboard() {
const { t } = useTranslation()
@@ -26,16 +27,48 @@ function SubscriptionDashboard() {
personalSubscription,
} = useSubscriptionDashboardContext()
const subscription = personalSubscription as PaidSubscription
const hasAiAssistViaWritefull = getMeta('ol-hasAiAssistViaWritefull')
const fromPlansPage = getMeta('ol-fromPlansPage')
const hasRedirectedPaymentError = Boolean(
getMeta('ol-subscriptionPaymentErrorCode')
)
const hasPendingPlan =
subscription &&
subscription.pendingPlan &&
subscription.pendingPlan.name !== subscription.plan.name
const nextPaymentDueDate = subscription?.payment?.nextPaymentDueDate
return (
<div className="container">
<OLRow>
<OLCol lg={{ span: 8, offset: 2 }}>
{hasPendingPlan && (
<OLNotification
className="mb-4"
aria-live="polite"
content={
<div>
<Trans
i18nKey="pending_subscription_message"
values={{
planName: personalSubscription?.pendingPlan?.name,
activationDate: nextPaymentDueDate,
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
</div>
}
type="success"
/>
)}
{fromPlansPage && (
<OLNotification
className="mb-4"
+1
View File
@@ -1690,6 +1690,7 @@
"pending_additional_licenses": "Your subscription is changing to include <0>__pendingAdditionalLicenses__</0> additional license(s) for a total of <1>__pendingTotalLicenses__</1> licenses.",
"pending_addon_cancellation": "Your subscription will change to remove the <strong>__addOnName__</strong> add-on at the end of the current billing period.",
"pending_invite": "Pending invite",
"pending_subscription_message": "You’ve switched to <0>__planName__</0>. This change will come into effect on <0>__activationDate__</0> at the end of your current billing cycle. When your plan switches, your billing and subscription information will be updated.",
"per_license": "per license",
"per_month": "per month",
"per_month_billed_annually": "per month, billed annually",
@@ -999,13 +999,10 @@ describe('SubscriptionViewModelBuilder', function () {
await ctx.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
ctx.user
)
assert.equal(
result.personalSubscription.payment.displayPrice,
'€1,756.92'
)
assert.equal(result.personalSubscription.payment.displayPrice, '€16.50')
assert.equal(
result.personalSubscription.payment.planOnlyDisplayPrice,
'€1,754.72'
'€14.30'
)
assert.deepEqual(
result.personalSubscription.payment