Merge pull request #23498 from overleaf/ii-flexible-group-licensing-paused-subscription

[web] Paused subscription support

GitOrigin-RevId: 76482011f9a75786722b4cc0c074e8c2ac3d6fb4
This commit is contained in:
ilkin-overleaf
2025-02-11 11:45:44 +02:00
committed by Copybot
parent 40f4b5bee7
commit fdb48eaacc

View File

@@ -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 <CancelSubscription />
@@ -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 (
<>
<div className="notification-list">
<FlashMessage />
{isErrorPause && (
<Notification
type="error"
content={t('generic_something_went_wrong')}
/>
)}
</div>
<h2 className={classnames('h3', bsVersion({ bs5: 'fw-bold' }))}>
{t('billing')}
</h2>
@@ -193,6 +219,27 @@ export function ActiveSubscriptionNew({
)}
</p>
)}
{hasPendingPause && (
<>
<p>
<Trans
i18nKey="your_subscription_will_pause_on"
values={{
planName: subscription.plan.name,
pauseDate: subscription.recurly.nextPaymentDueAt,
reactivationDate: getFormattedRenewalDate(),
}}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
</p>
<p>{t('you_can_still_use_your_premium_features')}</p>
</>
)}
{!onStandalonePlan && (
<p className="mb-1">
{subscription.plan.annual
@@ -209,6 +256,8 @@ export function ActiveSubscriptionNew({
subscription={subscription}
onStandalonePlan={onStandalonePlan}
handlePlanChange={handlePlanChange}
hasPendingPause={hasPendingPause}
cancelPauseReq={cancelPauseReq}
/>
)}
<hr />
@@ -223,6 +272,7 @@ export function ActiveSubscriptionNew({
<KeepCurrentPlanModal />
<ChangeToGroupModal />
<CancelAiAddOnModal />
<PauseSubscriptionModal />
</>
)
}
@@ -231,17 +281,36 @@ type PlanActionsProps = {
subscription: RecurlySubscription
onStandalonePlan: boolean
handlePlanChange: () => void
hasPendingPause: boolean
cancelPauseReq: ReturnType<typeof useAsync>
}
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 (
<div className="mt-3">
@@ -249,13 +318,27 @@ function PlanActions({
<FlexibleGroupLicensingActions subscription={subscription} />
) : (
<>
{subscription.recurly.account.has_past_due_invoice._ !== 'true' && (
<OLButton variant="secondary" onClick={handlePlanChange}>
{t('upgrade_plan')}
</OLButton>
)}
{!hasPendingPause &&
subscription.recurly.account.has_past_due_invoice._ !== 'true' && (
<OLButton variant="secondary" onClick={handlePlanChange}>
{t('upgrade_plan')}
</OLButton>
)}
</>
)}
{hasPendingPause && (
<OLButton
variant="primary"
onClick={handleCancelPendingPauseClick}
disabled={isLoadingCancelPause}
>
{isLoadingCancelPause ? (
<LoadingSpinner />
) : (
t('unpause_subscription')
)}
</OLButton>
)}
{!onStandalonePlan && (
<>
{' '}