Merge pull request #12042 from overleaf/jel-change-plan

[web] Change plan UI now in a modal and update the style

GitOrigin-RevId: 1b501b4a972ca676cff32f531862c15c0c8f9e61
This commit is contained in:
Jessica Lawshe
2023-03-08 08:43:42 -06:00
committed by Copybot
parent db4d9f0562
commit b10b7b1f91
13 changed files with 156 additions and 69 deletions
@@ -7,10 +7,13 @@ import { CancelSubscriptionButton } from './cancel-subscription-button'
import { CancelSubscription } from './cancel-plan/cancel-subscription'
import { PendingPlanChange } from './pending-plan-change'
import { TrialEnding } from './trial-ending'
import { ChangePlan } from './change-plan/change-plan'
import { PendingAdditionalLicenses } from './pending-additional-licenses'
import { ContactSupportToChangeGroupPlan } from './contact-support-to-change-group-plan'
import isInFreeTrial from '../../../../util/is-in-free-trial'
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'
export function ActiveSubscription({
subscription,
@@ -18,7 +21,7 @@ export function ActiveSubscription({
subscription: RecurlySubscription
}) {
const { t } = useTranslation()
const { recurlyLoadError, setShowChangePersonalPlan, showCancellation } =
const { recurlyLoadError, setModalIdShown, showCancellation } =
useSubscriptionDashboardContext()
if (showCancellation) return <CancelSubscription />
@@ -59,7 +62,7 @@ export function ActiveSubscription({
{' '}
<button
className="btn-inline-link"
onClick={() => setShowChangePersonalPlan(true)}
onClick={() => setModalIdShown('change-plan')}
>
{t('change_plan')}
</button>
@@ -120,7 +123,10 @@ export function ActiveSubscription({
<CancelSubscriptionButton subscription={subscription} />
)}
<ChangePlan />
<ChangePlanModal />
<ConfirmChangePlanModal />
<KeepCurrentPlanModal />
<ChangeToGroupModal />
</>
)
}
@@ -1,40 +0,0 @@
import { useTranslation } from 'react-i18next'
import LoadingSpinner from '../../../../../../../shared/components/loading-spinner'
import { useSubscriptionDashboardContext } from '../../../../../context/subscription-dashboard-context'
import { ChangeToGroupPlan } from './change-to-group-plan'
import { ConfirmChangePlanModal } from './modals/confirm-change-plan-modal'
import { IndividualPlansTable } from './individual-plans-table'
import { KeepCurrentPlanModal } from './modals/keep-current-plan-modal'
import { ChangeToGroupModal } from './modals/change-to-group-modal'
export function ChangePlan() {
const { t } = useTranslation()
const {
plans,
queryingIndividualPlansData,
recurlyLoadError,
showChangePersonalPlan,
} = useSubscriptionDashboardContext()
if (!showChangePersonalPlan || !plans || recurlyLoadError) return null
if (queryingIndividualPlansData) {
return (
<>
<h2>{t('change_plan')}</h2>
<LoadingSpinner />
</>
)
} else {
return (
<>
<h2>{t('change_plan')}</h2>
<IndividualPlansTable plans={plans} />
<ChangeToGroupPlan />
<ConfirmChangePlanModal />
<KeepCurrentPlanModal />
<ChangeToGroupModal />
</>
)
}
}
@@ -10,13 +10,13 @@ export function ChangeToGroupPlan() {
}
return (
<>
<h2>{t('looking_multiple_licenses')}</h2>
<div className="card-gray text-center mt-3">
<h2 style={{ marginTop: 0 }}>{t('looking_multiple_licenses')}</h2>
<p style={{ margin: 0 }}>{t('reduce_costs_group_licenses')}</p>
<br />
<button className="btn btn-primary" onClick={handleClick}>
{t('change_to_group_plan')}
</button>
</>
</div>
)
}
@@ -92,10 +92,9 @@ function PlansRows({ plans }: { plans: Array<Plan> }) {
export function IndividualPlansTable({ plans }: { plans: Array<Plan> }) {
const { t } = useTranslation()
const { recurlyLoadError, showChangePersonalPlan } =
useSubscriptionDashboardContext()
const { recurlyLoadError } = useSubscriptionDashboardContext()
if (!showChangePersonalPlan || !plans || recurlyLoadError) return null
if (!plans || recurlyLoadError) return null
return (
<table className="table table-vertically-centered-cells">
@@ -0,0 +1,52 @@
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'
function ChangePlanOptions() {
const { plans, queryingIndividualPlansData, recurlyLoadError } =
useSubscriptionDashboardContext()
if (!plans || recurlyLoadError) return null
if (queryingIndividualPlansData) {
return (
<>
<LoadingSpinner />
</>
)
} else {
return (
<>
<div className="table-outlined-container">
<IndividualPlansTable plans={plans} />
</div>
<ChangeToGroupPlan />
</>
)
}
}
export function ChangePlanModal() {
const modalId: SubscriptionDashModalIds = 'change-plan'
const { t } = useTranslation()
const { handleCloseModal, modalIdShown } = useSubscriptionDashboardContext()
if (modalIdShown !== modalId) return null
return (
<AccessibleModal id={modalId} show animation onHide={handleCloseModal}>
<Modal.Header closeButton>
<Modal.Title>{t('change_plan')}</Modal.Title>
</Modal.Header>
<Modal.Body>
<ChangePlanOptions />
</Modal.Body>
</AccessibleModal>
)
}
@@ -66,8 +66,6 @@ type SubscriptionDashboardContextValue = {
setRecurlyLoadError: React.Dispatch<React.SetStateAction<boolean>>
showCancellation: boolean
setShowCancellation: React.Dispatch<React.SetStateAction<boolean>>
showChangePersonalPlan: boolean
setShowChangePersonalPlan: React.Dispatch<React.SetStateAction<boolean>>
leavingGroupId?: string
setLeavingGroupId: React.Dispatch<React.SetStateAction<string | undefined>>
}
@@ -86,7 +84,6 @@ export function SubscriptionDashboardProvider({
>()
const [recurlyLoadError, setRecurlyLoadError] = useState(false)
const [showCancellation, setShowCancellation] = useState(false)
const [showChangePersonalPlan, setShowChangePersonalPlan] = useState(false)
const [plans, setPlans] = useState([])
const [queryingIndividualPlansData, setQueryingIndividualPlansData] =
useState(true)
@@ -268,8 +265,6 @@ export function SubscriptionDashboardProvider({
setRecurlyLoadError,
showCancellation,
setShowCancellation,
showChangePersonalPlan,
setShowChangePersonalPlan,
leavingGroupId,
setLeavingGroupId,
}),
@@ -304,8 +299,6 @@ export function SubscriptionDashboardProvider({
setRecurlyLoadError,
showCancellation,
setShowCancellation,
showChangePersonalPlan,
setShowChangePersonalPlan,
leavingGroupId,
setLeavingGroupId,
]
@@ -578,3 +578,67 @@
}
}
}
/**
Subscription Dash
*/
#change-plan {
.modal-dialog {
&:extend(.modal-lg);
}
table {
@media only screen and (min-width: @screen-md-min) {
th:last-child,
td:last-child {
width: 1%; // will expand to fit the content
text-align: center;
}
}
@media only screen and (max-width: @screen-sm-max) {
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: @padding-md;
}
td:last-child {
padding-top: @padding-sm;
padding-bottom: @padding-md;
}
tr:first-child {
td:first-child {
padding-top: @padding-sm;
}
}
tr {
border-bottom: 1px solid @table-border-color;
td,
th {
border: 0 !important;
}
}
tr:last-child {
border-bottom: 0;
}
}
}
}
@@ -65,3 +65,9 @@
.card-content {
padding: @padding-md;
}
.card-gray {
&:extend(.card);
background-color: @neutral-10;
border-radius: @card-border-radius;
}
@@ -83,7 +83,7 @@ th {
}
}
// Bordered version
// Bordered versions
//
// Add borders all around the table and between all the columns.
@@ -233,3 +233,13 @@ table {
}
}
}
.table-outlined-container {
border: @border-width-sm solid @table-border-color;
padding: @padding-sm @padding-sm 0 @padding-sm;
border-radius: @border-radius-base-new;
table {
margin-bottom: 0;
}
}
@@ -165,8 +165,10 @@
@line-height-small: 1.5;
@border-radius-base: 3px;
@border-radius-base-new: 4px;
@border-radius-large: 5px;
@border-radius-small: 2px;
@border-width-sm: 1px;
@border-width-base: 3px;
@border-color-base: @ol-blue-gray-2;
@@ -932,6 +934,7 @@
// Cards
@card-box-shadow: none;
@card-border-radius: @border-radius-base-new;
// Project table
@structured-list-link-color: @ol-blue;
@@ -107,8 +107,10 @@
@line-height-small: 1.5;
@border-radius-base: 3px;
@border-radius-base-new: 4px;
@border-radius-large: 5px;
@border-radius-small: 2px;
@border-width-sm: 1px;
@border-width-base: 3px; // only used by plans and cards
@border-size: 1px;
@border-color-base: @neutral-60;
@@ -720,6 +722,7 @@
// Cards
@card-box-shadow: none;
@card-border-radius: @border-radius-base-new;
// Project table
@structured-list-link-color: @blue;
@@ -1,7 +1,6 @@
import { expect } from 'chai'
import { fireEvent, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { ChangePlan } from '../../../../../../../../../frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-plan'
import { groupPlans, plans } from '../../../../../fixtures/plans'
import {
annualActiveSubscription,
@@ -22,7 +21,7 @@ import {
} from '../../../../../../../../../frontend/js/features/subscription/data/subscription-url'
import { renderActiveSubscription } from '../../../../../helpers/render-active-subscription'
describe('<ChangePlan />', function () {
describe('<ChangePlanModal />', function () {
let reloadStub: () => void
const originalLocation = window.location
const plansMetaTag = { name: 'ol-plans', value: plans }
@@ -42,15 +41,6 @@ describe('<ChangePlan />', function () {
})
})
it('does not render the UI when showChangePersonalPlan is false', function () {
window.metaAttributesCache.delete('ol-plans')
const { container } = renderWithSubscriptionDashContext(<ChangePlan />, {
metaTags: [plansMetaTag],
})
expect(container.firstChild).to.be.null
})
it('renders the individual plans table and group plans UI', async function () {
renderActiveSubscription(annualActiveSubscription)
const button = screen.getByRole('button', { name: 'Change plan' })
@@ -3,3 +3,4 @@ export type SubscriptionDashModalIds =
| 'change-to-group'
| 'keep-current-plan'
| 'leave-group'
| 'change-plan'