From fdb48eaacc6db825c68aa89bc583680fe9372af3 Mon Sep 17 00:00:00 2001 From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> Date: Tue, 11 Feb 2025 11:45:44 +0200 Subject: [PATCH] Merge pull request #23498 from overleaf/ii-flexible-group-licensing-paused-subscription [web] Paused subscription support GitOrigin-RevId: 76482011f9a75786722b4cc0c074e8c2ac3d6fb4 --- .../dashboard/states/active/active-new.tsx | 93 ++++++++++++++++++- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/active-new.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/active-new.tsx index 070a68275e..83fc027dcd 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/active-new.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/active-new.tsx @@ -24,6 +24,14 @@ import getMeta from '@/utils/meta' import classnames from 'classnames' import SubscriptionRemainder from '@/features/subscription/components/dashboard/states/active/subscription-remainder' import { sendMB } from '../../../../../../infrastructure/event-tracking' +import PauseSubscriptionModal from '@/features/subscription/components/dashboard/pause-modal' +import LoadingSpinner from '@/shared/components/loading-spinner' +import { postJSON } from '@/infrastructure/fetch-json' +import { debugConsole } from '@/utils/debugging' +import useAsync from '@/shared/hooks/use-async' +import { useLocation } from '@/shared/hooks/use-location' +import { FlashMessage } from '@/features/subscription/components/dashboard/states/active/flash-message' +import Notification from '@/shared/components/notification' export function ActiveSubscriptionNew({ subscription, @@ -37,7 +45,10 @@ export function ActiveSubscriptionNew({ showCancellation, institutionMemberships, memberGroupSubscriptions, + getFormattedRenewalDate, } = useSubscriptionDashboardContext() + const cancelPauseReq = useAsync() + const { isError: isErrorPause } = cancelPauseReq if (showCancellation) return @@ -68,6 +79,11 @@ export function ActiveSubscriptionNew({ setModalIdShown('cancel-ai-add-on') } } + const hasPendingPause = Boolean( + subscription.recurly.state === 'active' && + subscription.recurly.remainingPauseCycles && + subscription.recurly.remainingPauseCycles > 0 + ) const isLegacyPlan = subscription.recurly.totalLicenses !== @@ -75,6 +91,16 @@ export function ActiveSubscriptionNew({ return ( <> +
+ + + {isErrorPause && ( + + )} +

{t('billing')}

@@ -193,6 +219,27 @@ export function ActiveSubscriptionNew({ )}

)} + {hasPendingPause && ( + <> +

+ , + ]} + /> +

+

{t('you_can_still_use_your_premium_features')}

+ + )} {!onStandalonePlan && (

{subscription.plan.annual @@ -209,6 +256,8 @@ export function ActiveSubscriptionNew({ subscription={subscription} onStandalonePlan={onStandalonePlan} handlePlanChange={handlePlanChange} + hasPendingPause={hasPendingPause} + cancelPauseReq={cancelPauseReq} /> )}


@@ -223,6 +272,7 @@ export function ActiveSubscriptionNew({ + ) } @@ -231,17 +281,36 @@ type PlanActionsProps = { subscription: RecurlySubscription onStandalonePlan: boolean handlePlanChange: () => void + hasPendingPause: boolean + cancelPauseReq: ReturnType } function PlanActions({ subscription, onStandalonePlan, handlePlanChange, + hasPendingPause, + cancelPauseReq, }: PlanActionsProps) { const { t } = useTranslation() const isSubscriptionEligibleForFlexibleGroupLicensing = getMeta( 'ol-canUseFlexibleLicensing' ) + const location = useLocation() + const { runAsync: runAsyncCancelPause, isLoading: isLoadingCancelPause } = + cancelPauseReq + + const handleCancelPendingPauseClick = async () => { + try { + await runAsyncCancelPause(postJSON('/user/subscription/pause/0')) + const newUrl = new URL(location.toString()) + newUrl.searchParams.set('flash', 'unpaused') + window.history.replaceState(null, '', newUrl) + location.reload() + } catch (e) { + debugConsole.error(e) + } + } return (
@@ -249,13 +318,27 @@ function PlanActions({ ) : ( <> - {subscription.recurly.account.has_past_due_invoice._ !== 'true' && ( - - {t('upgrade_plan')} - - )} + {!hasPendingPause && + subscription.recurly.account.has_past_due_invoice._ !== 'true' && ( + + {t('upgrade_plan')} + + )} )} + {hasPendingPause && ( + + {isLoadingCancelPause ? ( + + ) : ( + t('unpause_subscription') + )} + + )} {!onStandalonePlan && ( <> {' '}