Просмотр исходного кода

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

GitOrigin-RevId: 4eb6bb445f9911fcf74ff2f9bdcc01b420c7afaf
Davinder Singh 6 месяцев назад
Родитель
Сommit
187ffbf108

+ 3 - 15
services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs

@@ -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,

+ 1 - 0
services/web/frontend/extracted-translations.json

@@ -1299,6 +1299,7 @@
   "pending_additional_licenses": "",
   "pending_addon_cancellation": "",
   "pending_invite": "",
+  "pending_subscription_message": "",
   "per_license": "",
   "per_month": "",
   "per_month_x_annually": "",

+ 6 - 4
services/web/frontend/js/features/subscription/components/dashboard/states/active/active.tsx

@@ -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}

+ 33 - 0
services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx

@@ -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 - 0
services/web/locales/en.json

@@ -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",

+ 2 - 5
services/web/test/unit/src/Subscription/SubscriptionViewModelBuilder.test.mjs

@@ -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