@@ -23,3 +28,18 @@ export function RowLink({ href, heading, subtext, icon }: RowLinkProps) {
)
}
+
+function BS5RowLink({ href, heading, subtext, icon }: RowLinkProps) {
+ return (
+
+
+
+
+
{heading}
+
{subtext}
+
+
+
+
+ )
+}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/active.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/active.tsx
index ce35dedd13..b24a71113e 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/active.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/active.tsx
@@ -14,6 +14,7 @@ import { ChangePlanModal } from './change-plan/modals/change-plan-modal'
import { ConfirmChangePlanModal } from './change-plan/modals/confirm-change-plan-modal'
import { KeepCurrentPlanModal } from './change-plan/modals/keep-current-plan-modal'
import { ChangeToGroupModal } from './change-plan/modals/change-to-group-modal'
+import OLButton from '@/features/ui/components/ol/ol-button'
export function ActiveSubscription({
subscription,
@@ -62,12 +63,13 @@ export function ActiveSubscription({
subscription.recurly.account.has_past_due_invoice._ !== 'true' && (
<>
{' '}
-
+
>
)}
@@ -103,7 +105,7 @@ export function ActiveSubscription({
/>
-
+
{!recurlyLoadError && (
-
+ <>
+ {' '}
+
+ >
)}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx
index 83e3fe5f54..8bfac39904 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx
@@ -9,41 +9,40 @@ import {
redirectAfterCancelSubscriptionUrl,
} from '../../../../../data/subscription-url'
import showDowngradeOption from '../../../../../util/show-downgrade-option'
-import ActionButtonText from '../../../action-button-text'
import GenericErrorAlert from '../../../generic-error-alert'
import DowngradePlanButton from './downgrade-plan-button'
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'
const planCodeToDowngradeTo = 'paid-personal'
function ConfirmCancelSubscriptionButton({
- buttonClass,
- buttonText,
- handleCancelSubscription,
- isLoadingCancel,
- isSuccessCancel,
- isButtonDisabled,
+ showNoThanks,
+ onClick,
+ disabled,
+ isLoading,
}: {
- buttonClass: string
- buttonText: string
- handleCancelSubscription: () => void
- isLoadingCancel: boolean
- isSuccessCancel: boolean
- isButtonDisabled: boolean
+ showNoThanks: boolean
+ onClick: () => void
+ disabled: boolean
+ isLoading: boolean
}) {
+ const { t } = useTranslation()
+ const text = showNoThanks ? t('no_thanks_cancel_now') : t('cancel_my_account')
return (
-
+ {text}
+
)
}
@@ -85,8 +84,7 @@ function NotCancelOption({
@@ -114,8 +112,7 @@ function NotCancelOption({
@@ -130,12 +127,9 @@ function NotCancelOption({
return (
-
+
)
}
@@ -188,13 +182,6 @@ export function CancelSubscription() {
const showExtendFreeTrial = userCanExtendTrial
- let confirmCancelButtonText = t('cancel_my_account')
- let confirmCancelButtonClass = 'btn-primary'
- if (showExtendFreeTrial || showDowngrade) {
- confirmCancelButtonText = t('no_thanks_cancel_now')
- confirmCancelButtonClass = 'btn-inline-link'
- }
-
return (
@@ -214,12 +201,10 @@ export function CancelSubscription() {
/>
)
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/downgrade-plan-button.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/downgrade-plan-button.tsx
index 4fcac209d7..cf8f3a9f7a 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/downgrade-plan-button.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/downgrade-plan-button.tsx
@@ -2,20 +2,18 @@ import { useTranslation } from 'react-i18next'
import { Plan } from '../../../../../../../../../types/subscription/plan'
import { postJSON } from '../../../../../../../infrastructure/fetch-json'
import { subscriptionUpdateUrl } from '../../../../../data/subscription-url'
-import ActionButtonText from '../../../action-button-text'
import { useLocation } from '../../../../../../../shared/hooks/use-location'
import { debugConsole } from '@/utils/debugging'
+import OLButton from '@/features/ui/components/ol/ol-button'
export default function DowngradePlanButton({
isButtonDisabled,
- isLoadingSecondaryAction,
- isSuccessSecondaryAction,
+ isLoading,
planToDowngradeTo,
runAsyncSecondaryAction,
}: {
isButtonDisabled: boolean
- isLoadingSecondaryAction: boolean
- isSuccessSecondaryAction: boolean
+ isLoading: boolean
planToDowngradeTo: Plan
runAsyncSecondaryAction: (promise: Promise
) => Promise
}) {
@@ -37,17 +35,16 @@ export default function DowngradePlanButton({
}
return (
- <>
-
- >
+
+ {buttonText}
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/extend-trial-button.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/extend-trial-button.tsx
index 116436610d..107ec00a1c 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/extend-trial-button.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/extend-trial-button.tsx
@@ -1,19 +1,17 @@
import { useTranslation } from 'react-i18next'
import { putJSON } from '../../../../../../../infrastructure/fetch-json'
import { extendTrialUrl } from '../../../../../data/subscription-url'
-import ActionButtonText from '../../../action-button-text'
import { useLocation } from '../../../../../../../shared/hooks/use-location'
import { debugConsole } from '@/utils/debugging'
+import OLButton from '@/features/ui/components/ol/ol-button'
export default function ExtendTrialButton({
isButtonDisabled,
- isLoadingSecondaryAction,
- isSuccessSecondaryAction,
+ isLoading,
runAsyncSecondaryAction,
}: {
isButtonDisabled: boolean
- isLoadingSecondaryAction: boolean
- isSuccessSecondaryAction: boolean
+ isLoading: boolean
runAsyncSecondaryAction: (promise: Promise) => Promise
}) {
const { t } = useTranslation()
@@ -30,17 +28,16 @@ export default function ExtendTrialButton({
}
return (
- <>
-
- >
+
+ {buttonText}
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-subscription-button.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-subscription-button.tsx
index 962b81a694..eae299cd88 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-subscription-button.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-subscription-button.tsx
@@ -1,10 +1,9 @@
import { useTranslation } from 'react-i18next'
import * as eventTracking from '../../../../../../infrastructure/event-tracking'
import { useSubscriptionDashboardContext } from '../../../../context/subscription-dashboard-context'
+import OLButton from '@/features/ui/components/ol/ol-button'
-export function CancelSubscriptionButton(
- props: React.ComponentProps<'button'>
-) {
+export function CancelSubscriptionButton() {
const { t } = useTranslation()
const { recurlyLoadError, setShowCancellation } =
useSubscriptionDashboardContext()
@@ -17,8 +16,8 @@ export function CancelSubscriptionButton(
if (recurlyLoadError) return null
return (
-
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-to-group-plan.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-to-group-plan.tsx
index 8c977efc39..ed7e929916 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-to-group-plan.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-to-group-plan.tsx
@@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next'
import { useSubscriptionDashboardContext } from '../../../../../context/subscription-dashboard-context'
+import OLButton from '@/features/ui/components/ol/ol-button'
export function ChangeToGroupPlan() {
const { t } = useTranslation()
@@ -10,13 +11,13 @@ export function ChangeToGroupPlan() {
}
return (
-
+
{t('looking_multiple_licenses')}
{t('reduce_costs_group_licenses')}
-
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/individual-plans-table.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/individual-plans-table.tsx
index 98d8c2aa36..019c3f81d0 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/individual-plans-table.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/individual-plans-table.tsx
@@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next'
import { Plan } from '../../../../../../../../../types/subscription/plan'
import Icon from '../../../../../../../shared/components/icon'
import { useSubscriptionDashboardContext } from '../../../../../context/subscription-dashboard-context'
+import OLButton from '@/features/ui/components/ol/ol-button'
function ChangeToPlanButton({ planCode }: { planCode: string }) {
const { t } = useTranslation()
@@ -12,9 +13,9 @@ function ChangeToPlanButton({ planCode }: { planCode: string }) {
}
return (
-
+
)
}
@@ -27,9 +28,9 @@ function KeepCurrentPlanButton({ plan }: { plan: Plan }) {
}
return (
-
+
)
}
@@ -66,13 +67,13 @@ function PlansRow({ plan }: { plan: Plan }) {
return (
-
+ |
{plan.name}
|
-
+ |
{plan.displayPrice} / {plan.annual ? t('year') : t('month')}
|
-
+ |
|
@@ -97,9 +98,9 @@ export function IndividualPlansTable({ plans }: { plans: Array
}) {
if (!plans || recurlyLoadError) return null
return (
-
+
-
+
{t('name')} |
{t('price')} |
|
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-plan-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-plan-modal.tsx
index 7c365525f2..519da10665 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-plan-modal.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-plan-modal.tsx
@@ -1,11 +1,14 @@
-import { Modal } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { SubscriptionDashModalIds } from '../../../../../../../../../../types/subscription/dashboard/modal-ids'
-import AccessibleModal from '../../../../../../../../shared/components/accessible-modal'
import LoadingSpinner from '../../../../../../../../shared/components/loading-spinner'
import { useSubscriptionDashboardContext } from '../../../../../../context/subscription-dashboard-context'
import { ChangeToGroupPlan } from '../change-to-group-plan'
import { IndividualPlansTable } from '../individual-plans-table'
+import OLModal, {
+ OLModalBody,
+ OLModalHeader,
+ OLModalTitle,
+} from '@/features/ui/components/ol/ol-modal'
function ChangePlanOptions() {
const { plans, queryingIndividualPlansData, recurlyLoadError } =
@@ -22,7 +25,7 @@ function ChangePlanOptions() {
} else {
return (
<>
-
+
@@ -39,14 +42,14 @@ export function ChangePlanModal() {
if (modalIdShown !== modalId) return null
return (
-
-
- {t('change_plan')}
-
+
+
+ {t('change_plan')}
+
-
+
-
-
+
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx
index be079e377f..7888deaadf 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx
@@ -1,16 +1,29 @@
import { useEffect, useState } from 'react'
-import { Modal } from 'react-bootstrap'
import { useTranslation, Trans } from 'react-i18next'
import { Subscription } from '../../../../../../../../../../types/subscription/dashboard/subscription'
import { PriceForDisplayData } from '../../../../../../../../../../types/subscription/plan'
import { postJSON } from '../../../../../../../../infrastructure/fetch-json'
-import AccessibleModal from '../../../../../../../../shared/components/accessible-modal'
import getMeta from '../../../../../../../../utils/meta'
import { useSubscriptionDashboardContext } from '../../../../../../context/subscription-dashboard-context'
import GenericErrorAlert from '../../../../generic-error-alert'
import { subscriptionUpdateUrl } from '../../../../../../data/subscription-url'
import { getRecurlyGroupPlanCode } from '../../../../../../util/recurly-group-plan-code'
import { useLocation } from '../../../../../../../../shared/hooks/use-location'
+import OLModal, {
+ OLModalBody,
+ OLModalFooter,
+ OLModalHeader,
+ OLModalTitle,
+} from '@/features/ui/components/ol/ol-modal'
+import OLFormSelect from '@/features/ui/components/ol/ol-form-select'
+import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
+import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
+import OLFormCheckbox from '@/features/ui/components/ol/ol-form-checkbox'
+import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal'
+import { UserProvider } from '@/shared/context/user-context'
+import OLButton from '@/features/ui/components/ol/ol-button'
+import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
+import OLNotification from '@/features/ui/components/ol/ol-notification'
const educationalPercentDiscount = 40
const groupSizeForEducationalDiscount = 10
@@ -88,7 +101,7 @@ function GroupPrice({
})}
-
+
} />
@@ -124,6 +137,8 @@ export function ChangeToGroupModal() {
setGroupPlanToChangeToSize,
setGroupPlanToChangeToUsage,
} = useSubscriptionDashboardContext()
+ const { modal: contactModal, showModal: showContactModal } =
+ useContactUsModal({ autofillProjectUrl: false })
const groupPlans = getMeta('ol-groupPlans')
const personalSubscription = getMeta('ol-subscription') as Subscription
const [error, setError] = useState(false)
@@ -157,11 +172,6 @@ export function ChangeToGroupModal() {
}
}, [personalSubscription, setGroupPlanToChangeToCode])
- function handleGetInTouchButton() {
- handleCloseModal()
- $('[data-ol-contact-form-modal="contact-us"]').modal()
- }
-
if (
modalIdShown !== modalId ||
!groupPlans ||
@@ -172,197 +182,199 @@ export function ChangeToGroupModal() {
return null
return (
-
-
-
-
-
{t('customize_your_group_subscription')}
-
- {t('save_x_percent_or_more', {
- percent: '30',
- })}
-
-
-
+ <>
+ {contactModal}
+
+
+
+ {t('customize_your_group_subscription')}
+
+
+ {t('save_x_percent_or_more', {
+ percent: '30',
+ })}
+
+
+
-
-
- {groupPlanToChangeToPriceError &&
}
-
-
-
-
+
+
+ {groupPlanToChangeToPriceError &&
}
+
+
+
+
+
+
{t('each_user_will_have_access_to')}:
+
+ -
+
+
+
+
+ -
+ {t('all_premium_features')}
+
+ - {t('sync_dropbox_github')}
+ - {t('full_doc_history')}
+ - {t('track_changes')}
+ -
+ + {t('more').toLowerCase()}
+ {t('plus_more')}
+
+
-
{t('each_user_will_have_access_to')}:
-
- -
-
-
-
-
- -
- {t('all_premium_features')}
-
- - {t('sync_dropbox_github')}
- - {t('full_doc_history')}
- - {t('track_changes')}
- -
- + {t('more').toLowerCase()}
- {t('plus_more')}
-
-
-
-
-
-
-
-
- {groupPlanToChangeToUsage === 'educational' && (
-
+
+ {t('percent_discount_for_groups', {
+ percent: educationalPercentDiscount,
+ size: groupSizeForEducationalDiscount,
+ })}
+
+
+
+ {
+ if (e.target.checked) {
+ setGroupPlanToChangeToUsage('educational')
+ } else {
+ setGroupPlanToChangeToUsage('enterprise')
+ }
+ }}
+ label={t('license_for_educational_purposes')}
/>
- )}
+
-
-
-
-
-
-
- {groupPlanToChangeToPrice?.includesTax && (
-
- ,
- ]}
- />
-
- )}
-
- {t('new_subscription_will_be_billed_immediately')}
-
-
- {error && (
-
- {t('generic_something_went_wrong')}. {t('try_again')}.{' '}
- {t('generic_if_problem_continues_contact_us')}.
+
+ {groupPlanToChangeToUsage === 'educational' && (
+
+ )}
- )}
-
-
-
-
-
-
+
+
+
+
+
+ {groupPlanToChangeToPrice?.includesTax && (
+
+ ,
+ ]}
+ />
+
+ )}
+
+
+ {t('new_subscription_will_be_billed_immediately')}
+
+
+
+ {error && (
+
+ {t('generic_something_went_wrong')}. {t('try_again')}.{' '}
+ {t('generic_if_problem_continues_contact_us')}.
+ >
+ }
+ />
+ )}
+
+ {t('upgrade_now')}
+
+
+
+ {t('need_more_than_x_licenses', {
+ x: 50,
+ })}{' '}
+ {t('please_get_in_touch')}
+
+
+
+
+ >
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/confirm-change-plan-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/confirm-change-plan-modal.tsx
index a534c5bcc4..75b5b56d62 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/confirm-change-plan-modal.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/confirm-change-plan-modal.tsx
@@ -1,13 +1,19 @@
import { useState } from 'react'
-import { Modal } from 'react-bootstrap'
import { useTranslation, Trans } from 'react-i18next'
import { SubscriptionDashModalIds } from '../../../../../../../../../../types/subscription/dashboard/modal-ids'
import { postJSON } from '../../../../../../../../infrastructure/fetch-json'
-import AccessibleModal from '../../../../../../../../shared/components/accessible-modal'
import getMeta from '../../../../../../../../utils/meta'
import { useSubscriptionDashboardContext } from '../../../../../../context/subscription-dashboard-context'
import { subscriptionUpdateUrl } from '../../../../../../data/subscription-url'
import { useLocation } from '../../../../../../../../shared/hooks/use-location'
+import OLModal, {
+ OLModalBody,
+ OLModalFooter,
+ OLModalHeader,
+ OLModalTitle,
+} from '@/features/ui/components/ol/ol-modal'
+import OLButton from '@/features/ui/components/ol/ol-button'
+import OLNotification from '@/features/ui/components/ol/ol-notification'
export function ConfirmChangePlanModal() {
const modalId: SubscriptionDashModalIds = 'change-to-plan'
@@ -46,23 +52,29 @@ export function ConfirmChangePlanModal() {
planCodesChangingAtTermEnd.indexOf(planCodeToChangeTo) > -1
return (
-
-
- {t('change_plan')}
-
+
+ {t('change_plan')}
+
-
+
{error && (
-
- {t('generic_something_went_wrong')}. {t('try_again')}.{' '}
- {t('generic_if_problem_continues_contact_us')}.
-
+
+ {t('generic_something_went_wrong')}. {t('try_again')}.{' '}
+ {t('generic_if_problem_continues_contact_us')}.
+ >
+ }
+ />
)}
{t('want_change_to_apply_before_plan_end')}
>
)}
-
+
-
-
-
-
-
+ {t('change_plan')}
+
+
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/keep-current-plan-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/keep-current-plan-modal.tsx
index 788539b90b..963e6bed67 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/keep-current-plan-modal.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/keep-current-plan-modal.tsx
@@ -1,12 +1,18 @@
import { useState } from 'react'
-import { Modal } from 'react-bootstrap'
import { useTranslation, Trans } from 'react-i18next'
import { SubscriptionDashModalIds } from '../../../../../../../../../../types/subscription/dashboard/modal-ids'
import { postJSON } from '../../../../../../../../infrastructure/fetch-json'
-import AccessibleModal from '../../../../../../../../shared/components/accessible-modal'
import { useSubscriptionDashboardContext } from '../../../../../../context/subscription-dashboard-context'
import { cancelPendingSubscriptionChangeUrl } from '../../../../../../data/subscription-url'
import { useLocation } from '../../../../../../../../shared/hooks/use-location'
+import OLModal, {
+ OLModalBody,
+ OLModalFooter,
+ OLModalHeader,
+ OLModalTitle,
+} from '@/features/ui/components/ol/ol-modal'
+import OLButton from '@/features/ui/components/ol/ol-button'
+import OLNotification from '@/features/ui/components/ol/ol-notification'
export function KeepCurrentPlanModal() {
const modalId: SubscriptionDashModalIds = 'keep-current-plan'
@@ -33,23 +39,29 @@ export function KeepCurrentPlanModal() {
if (modalIdShown !== modalId || !personalSubscription) return null
return (
-
-
- {t('change_plan')}
-
+
+ {t('change_plan')}
+
-
+
{error && (
-
- {t('generic_something_went_wrong')}. {t('try_again')}.{' '}
- {t('generic_if_problem_continues_contact_us')}.
-
+
+ {t('generic_something_went_wrong')}. {t('try_again')}.{' '}
+ {t('generic_if_problem_continues_contact_us')}.
+ >
+ }
+ />
)}
-
+
-
-
-
-
-
+ {t('revert_pending_plan_change')}
+
+
+
)
}
diff --git a/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx b/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx
index 74463929c9..afa5d0d7ea 100644
--- a/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx
+++ b/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx
@@ -10,6 +10,10 @@ import ManagedInstitutions from './managed-institutions'
import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
import getMeta from '../../../../utils/meta'
import PremiumFeaturesLink from './premium-features-link'
+import OLCard from '@/features/ui/components/ol/ol-card'
+import OLRow from '@/features/ui/components/ol/ol-row'
+import OLCol from '@/features/ui/components/ol/ol-col'
+import OLNotification from '@/features/ui/components/ol/ol-notification'
function SubscriptionDashboard() {
const { t } = useTranslation()
@@ -23,30 +27,35 @@ function SubscriptionDashboard() {
return (
-
-
+
+
{fromPlansPage && (
-
- {t('you_already_have_a_subscription')}
-
+
)}
-
+
{t('your_subscription')}
-
-
-
-
-
-
- {hasValidActiveSubscription && }
- {!hasDisplayedSubscription &&
- (hasSubscription ? : )}
-
-
-
+
+
+
+
+
+
+
+ {hasValidActiveSubscription &&
}
+ {!hasDisplayedSubscription &&
+ (hasSubscription ?
:
)}
+
+
+
+
)
}
diff --git a/services/web/frontend/js/features/ui/components/ol/ol-modal.tsx b/services/web/frontend/js/features/ui/components/ol/ol-modal.tsx
index 579e20cbfe..fb25cc5628 100644
--- a/services/web/frontend/js/features/ui/components/ol/ol-modal.tsx
+++ b/services/web/frontend/js/features/ui/components/ol/ol-modal.tsx
@@ -50,6 +50,8 @@ export default function OLModal({ children, ...props }: OLModalProps) {
backdrop: bs5Props.backdrop,
animation: bs5Props.animation,
id: bs5Props.id,
+ className: bs5Props.className,
+ backdropClassName: bs5Props.backdropClassName,
...bs3Props,
}
diff --git a/services/web/frontend/js/shared/hooks/use-contact-us-modal.tsx b/services/web/frontend/js/shared/hooks/use-contact-us-modal.tsx
index 6225830c33..19810f627a 100644
--- a/services/web/frontend/js/shared/hooks/use-contact-us-modal.tsx
+++ b/services/web/frontend/js/shared/hooks/use-contact-us-modal.tsx
@@ -1,5 +1,10 @@
import importOverleafModules from '../../../macros/import-overleaf-module.macro'
-import { JSXElementConstructor, useCallback, useState } from 'react'
+import {
+ JSXElementConstructor,
+ useCallback,
+ useState,
+ type UIEvent,
+} from 'react'
const [contactUsModalModules] = importOverleafModules('contactUsModal')
const ContactUsModal: JSXElementConstructor<{
@@ -16,7 +21,7 @@ export const useContactUsModal = (options = { autofillProjectUrl: true }) => {
setShow(false)
}, [])
- const showModal = useCallback((event?: Event) => {
+ const showModal = useCallback((event?: Event | UIEvent) => {
event?.preventDefault()
setShow(true)
}, [])
diff --git a/services/web/frontend/stylesheets/app/contact-us.less b/services/web/frontend/stylesheets/app/contact-us.less
index 468cbd874b..48400dee10 100644
--- a/services/web/frontend/stylesheets/app/contact-us.less
+++ b/services/web/frontend/stylesheets/app/contact-us.less
@@ -1,3 +1,12 @@
+// Hack to make the contact modal appear above other modals
+.contact-modal {
+ z-index: 1065;
+}
+
+.contact-backdrop {
+ z-index: 1060;
+}
+
.contact-us-modal {
textarea {
height: 120px;
diff --git a/services/web/frontend/stylesheets/app/group-subscription-modal.less b/services/web/frontend/stylesheets/app/group-subscription-modal.less
index 78c2fccff3..20ddc90617 100644
--- a/services/web/frontend/stylesheets/app/group-subscription-modal.less
+++ b/services/web/frontend/stylesheets/app/group-subscription-modal.less
@@ -1,3 +1,11 @@
+#change-to-group .modal-header h4 {
+ line-height: 1.33rem;
+
+ .h5 {
+ font-family: @font-family-sans-serif;
+ }
+}
+
.group-subscription-modal {
.modal-header {
text-align: center;
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/card.scss b/services/web/frontend/stylesheets/bootstrap-5/components/card.scss
index 46fa38e207..af16932f7c 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/components/card.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/card.scss
@@ -150,3 +150,7 @@
}
}
}
+
+.card-gray {
+ background-color: var(--neutral-10);
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/modals/contact-us-modal.scss b/services/web/frontend/stylesheets/bootstrap-5/modals/contact-us-modal.scss
index 57711a799d..7ac5e62cbc 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/modals/contact-us-modal.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/modals/contact-us-modal.scss
@@ -1,3 +1,12 @@
+// Hack to make the contact modal appear above other modals
+.contact-modal {
+ z-index: 1065;
+}
+
+.contact-backdrop {
+ z-index: 1060;
+}
+
.contact-us-modal-textarea {
height: 120px;
}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss
index 8734714ced..ea5e4c10c2 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/all.scss
@@ -11,5 +11,6 @@
@import 'editor/outline';
@import 'editor/file-tree';
@import 'editor/figure-modal';
+@import 'subscription';
@import 'website-redesign';
@import 'group-settings';
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss
new file mode 100644
index 0000000000..d7a46ea6d3
--- /dev/null
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/subscription.scss
@@ -0,0 +1,140 @@
+/**
+ * MAIN CONTENT
+ */
+
+#subscription-dashboard-root {
+ .hover-highlight {
+ &:hover,
+ &:focus {
+ background-color: var(--neutral-10);
+ }
+ }
+
+ li.row-link {
+ display: flex;
+ border: 0;
+ padding: 0;
+
+ a {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--spacing-02) 0;
+ text-decoration: none;
+ color: var(--neutral-90);
+ width: 100%;
+
+ &:hover {
+ background-color: var(--neutral-10);
+ }
+ }
+ }
+}
+
+/**
+ * MODALS
+ */
+
+.group-subscription-modal {
+ .circle {
+ font-size: var(--font-size-06);
+ border-radius: 50%;
+ background-color: var(--green-70);
+ color: white;
+ white-space: nowrap;
+ height: 180px;
+ width: 180px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: var(--spacing-02);
+ font-weight: bold;
+
+ .small {
+ opacity: 0.85;
+ }
+
+ .circle-subtext {
+ font-size: var(--font-size-03);
+ }
+ }
+
+ .legend-as-label {
+ font-size: var(--font-size-02);
+ font-weight: 600;
+ color: var(--content-secondary);
+ margin-bottom: 0;
+ }
+
+ .educational-discount-badge {
+ height: 50px;
+
+ p {
+ display: inline-block;
+ font-weight: bold;
+ padding-left: var(--spacing-02);
+ padding-right: var(--spacing-02);
+ }
+
+ .applied {
+ background-color: rgba($green-70, 0.1);
+ color: var(--green-70);
+ }
+
+ .ineligible {
+ background-color: var(--neutral-10);
+ }
+ }
+}
+
+#change-plan {
+ table {
+ @include media-breakpoint-up(lg) {
+ th:last-child,
+ td:last-child {
+ width: 1%; // will expand to fit the content
+ }
+ }
+
+ @include media-breakpoint-down(lg) {
+ display: block;
+
+ thead {
+ display: none;
+ }
+
+ tbody,
+ td,
+ tr {
+ display: inline-block;
+ padding-top: 0;
+ padding-bottom: 0;
+ text-align: center;
+ width: 100%;
+ }
+
+ td:first-child {
+ padding-top: var(--spacing-07);
+ }
+
+ td:last-child {
+ padding-top: var(--spacing-03);
+ padding-bottom: var(--spacing-07);
+ }
+
+ tr {
+ border-bottom: 1px solid var(--bs-border-color);
+
+ td,
+ th {
+ border: 0 !important;
+ }
+ }
+
+ tr:last-child {
+ border-bottom: 0;
+ }
+ }
+ }
+}
diff --git a/services/web/frontend/stylesheets/components/forms.less b/services/web/frontend/stylesheets/components/forms.less
index 830bf92f3c..d0b7087a1a 100755
--- a/services/web/frontend/stylesheets/components/forms.less
+++ b/services/web/frontend/stylesheets/components/forms.less
@@ -42,6 +42,8 @@ label {
font-size: @font-size-base;
color: @text-color;
border: 0;
+ margin-bottom: 0;
+ line-height: @line-height-01;
}
// Normalize form controls
diff --git a/services/web/frontend/stylesheets/components/lists.less b/services/web/frontend/stylesheets/components/lists.less
index 9ed8c726bc..755941664c 100644
--- a/services/web/frontend/stylesheets/components/lists.less
+++ b/services/web/frontend/stylesheets/components/lists.less
@@ -48,7 +48,3 @@
}
}
}
-
-.list-item-with-margin-bottom {
- margin-bottom: @line-height-computed;
-}
diff --git a/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx b/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx
index c3eb45dd2a..f3603d484a 100644
--- a/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx
+++ b/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx
@@ -30,6 +30,7 @@ export function renderWithSubscriptionDashContext(
options?.metaTags?.forEach(tag =>
window.metaAttributesCache.set(tag.name, tag.value)
)
+ window.metaAttributesCache.set('ol-user', {})
if (!options?.recurlyNotLoaded) {
// @ts-ignore