diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index b68d0a8d1f..4abe726c1f 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -224,6 +224,7 @@ "error": "", "error_performing_request": "", "example_project": "", + "existing_plan_active_until_term_end": "", "expand": "", "export_csv": "", "export_project_to_github": "", @@ -286,6 +287,7 @@ "galileo_suggestion_feedback_button": "", "galileo_suggestions_loading_error": "", "galileo_toggle_description": "", + "generic_if_problem_continues_contact_us": "", "generic_linked_file_compile_error": "", "generic_something_went_wrong": "", "get_collaborative_benefits": "", @@ -566,6 +568,7 @@ "proceed_to_paypal": "", "proceeding_to_paypal_takes_you_to_the_paypal_site_to_pay": "", "processing": "", + "processing_uppercase": "", "professional": "", "project": "", "project_approaching_file_limit": "", @@ -633,6 +636,7 @@ "resend_confirmation_email": "", "resending_confirmation_email": "", "reverse_x_sort_order": "", + "revert_pending_plan_change": "", "review": "", "revoke": "", "revoke_invite": "", @@ -733,6 +737,8 @@ "subscription_admins_cannot_be_deleted": "", "subscription_canceled_and_terminate_on_x": "", "subscription_will_remain_active_until_end_of_billing_period_x": "", + "sure_you_want_to_cancel_plan_change": "", + "sure_you_want_to_change_plan": "", "sure_you_want_to_delete": "", "switch_to_editor": "", "switch_to_pdf": "", diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-plan.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-plan.tsx index 0316d4de42..adeb755ed8 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-plan.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-plan.tsx @@ -2,7 +2,9 @@ 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 './confirm-change-plan-modal' import { IndividualPlansTable } from './individual-plans-table' +import { KeepCurrentPlanModal } from './keep-current-plan-modal' export function ChangePlan() { const { t } = useTranslation() @@ -28,6 +30,8 @@ export function ChangePlan() {

{t('change_plan')}

+ + ) } diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/confirm-change-plan-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/confirm-change-plan-modal.tsx new file mode 100644 index 0000000000..6818c15e4b --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/confirm-change-plan-modal.tsx @@ -0,0 +1,101 @@ +import { useState } from 'react' +import { Modal } from 'react-bootstrap' +import { useTranslation, Trans } from 'react-i18next' +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 { subscriptionUrl } from '../../../../../data/subscription-url' + +export function ConfirmChangePlanModal() { + const modalId = 'change-to-plan' + const [error, setError] = useState(false) + const [inflight, setInflight] = useState(false) + const { t } = useTranslation() + const { handleCloseModal, modalIdShown, plans, planCodeToChangeTo } = + useSubscriptionDashboardContext() + const planCodesChangingAtTermEnd = getMeta('ol-planCodesChangingAtTermEnd') + + async function handleConfirmChange() { + setError(false) + setInflight(true) + + try { + await postJSON(`${subscriptionUrl}?origin=confirmChangePlan`, { + body: { + plan_code: planCodeToChangeTo, + }, + }) + } catch (e) { + setError(true) + setInflight(false) + } + window.location.reload() + } + + if (modalIdShown !== modalId || !planCodeToChangeTo) return null + + const plan = plans.find(p => p.planCode === planCodeToChangeTo) + if (!plan) return null + + const planWillChangeAtTermEnd = + planCodesChangingAtTermEnd?.indexOf(planCodeToChangeTo) > -1 + + return ( + + + {t('change_plan')} + + + + {error && ( +
+ {t('generic_something_went_wrong')}. {t('try_again')}.{' '} + {t('generic_if_problem_continues_contact_us')}. +
+ )} +

+ , + ]} + /> +

+ {planWillChangeAtTermEnd && ( + <> +

{t('existing_plan_active_until_term_end')}

+

{t('want_change_to_apply_before_plan_end')}

+ + )} +
+ + + + + +
+ ) +} 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 dac9f40f6b..b7b53bd58c 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 @@ -3,37 +3,33 @@ import { Plan } from '../../../../../../../../../types/subscription/plan' import Icon from '../../../../../../../shared/components/icon' import { useSubscriptionDashboardContext } from '../../../../../context/subscription-dashboard-context' -function ChangeToPlanButton({ plan }: { plan: Plan }) { +function ChangeToPlanButton({ planCode }: { planCode: string }) { const { t } = useTranslation() - // for when the user selected to change a plan, but the plan change is still pending + const { handleOpenModal } = useSubscriptionDashboardContext() + + const handleClick = () => { + handleOpenModal('change-to-plan', planCode) + } + return ( -
- {/* todo: ng-model="plan_code" */} - - {/* todo: handle submit changePlan */} - -
+ ) } function KeepCurrentPlanButton({ plan }: { plan: Plan }) { const { t } = useTranslation() - // for when the user selected to change a plan, but the plan change is still pending + const { handleOpenModal } = useSubscriptionDashboardContext() + + const handleClick = () => { + handleOpenModal('keep-current-plan') + } + return ( -
- {/* todo: ng-model="plan_code" */} - - {/* todo: handle submit cancelPendingPlanChange */} - -
+ ) } @@ -61,7 +57,7 @@ function ChangePlanButton({ plan }: { plan: Plan }) { ) } else { - return + return } } diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/keep-current-plan-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/keep-current-plan-modal.tsx new file mode 100644 index 0000000000..46e30701b7 --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/keep-current-plan-modal.tsx @@ -0,0 +1,85 @@ +import { useState } from 'react' +import { Modal } from 'react-bootstrap' +import { useTranslation, Trans } from 'react-i18next' +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' + +export function KeepCurrentPlanModal() { + const modalId = 'keep-current-plan' + const [error, setError] = useState(false) + const [inflight, setInflight] = useState(false) + const { t } = useTranslation() + const { modalIdShown, handleCloseModal, personalSubscription } = + useSubscriptionDashboardContext() + + async function confirmCancelPendingPlanChange() { + setError(false) + setInflight(true) + + try { + await postJSON(cancelPendingSubscriptionChangeUrl) + } catch (e) { + setError(true) + setInflight(false) + } + window.location.reload() + } + + if (modalIdShown !== modalId || !personalSubscription) return null + + return ( + + + {t('change_plan')} + + + + {error && ( +
+ {t('generic_something_went_wrong')}. {t('try_again')}.{' '} + {t('generic_if_problem_continues_contact_us')}. +
+ )} +

+ , + ]} + /> +

+
+ + + + + +
+ ) +} diff --git a/services/web/frontend/js/features/subscription/context/subscription-dashboard-context.tsx b/services/web/frontend/js/features/subscription/context/subscription-dashboard-context.tsx index d562d6fff2..75c828cb54 100644 --- a/services/web/frontend/js/features/subscription/context/subscription-dashboard-context.tsx +++ b/services/web/frontend/js/features/subscription/context/subscription-dashboard-context.tsx @@ -19,15 +19,23 @@ import { loadDisplayPriceWithTaxPromise } from '../util/recurly-pricing' import { isRecurlyLoaded } from '../util/is-recurly-loaded' type SubscriptionDashboardContextValue = { + handleCloseModal: () => void + handleOpenModal: (modalIdToOpen: string, planCode?: string) => void hasDisplayedSubscription: boolean institutionMemberships?: Institution[] managedGroupSubscriptions: ManagedGroupSubscription[] managedInstitutions: ManagedInstitution[] updateManagedInstitution: (institution: ManagedInstitution) => void + modalIdShown?: string personalSubscription?: Subscription plans: Plan[] + planCodeToChangeTo?: string queryingIndividualPlansData: boolean recurlyLoadError: boolean + setModalIdShown: React.Dispatch> + setPlanCodeToChangeTo: React.Dispatch< + React.SetStateAction + > setRecurlyLoadError: React.Dispatch> showCancellation: boolean setShowCancellation: React.Dispatch> @@ -44,12 +52,16 @@ export function SubscriptionDashboardProvider({ }: { children: ReactNode }) { + const [modalIdShown, setModalIdShown] = useState() const [recurlyLoadError, setRecurlyLoadError] = useState(false) const [showCancellation, setShowCancellation] = useState(false) const [showChangePersonalPlan, setShowChangePersonalPlan] = useState(false) const [plans, setPlans] = useState([]) const [queryingIndividualPlansData, setQueryingIndividualPlansData] = useState(true) + const [planCodeToChangeTo, setPlanCodeToChangeTo] = useState< + string | undefined + >() const plansWithoutDisplayPrice = getMeta('ol-plans') const institutionMemberships = getMeta('ol-currentInstitutionsWithLicence') @@ -111,18 +123,36 @@ export function SubscriptionDashboardProvider({ }, [] ) + const handleCloseModal = useCallback(() => { + setModalIdShown('') + setPlanCodeToChangeTo(undefined) + }, [setModalIdShown, setPlanCodeToChangeTo]) + + const handleOpenModal = useCallback( + (id, planCode) => { + setModalIdShown(id) + setPlanCodeToChangeTo(planCode) + }, + [setModalIdShown, setPlanCodeToChangeTo] + ) const value = useMemo( () => ({ + handleCloseModal, + handleOpenModal, hasDisplayedSubscription, institutionMemberships, managedGroupSubscriptions, managedInstitutions, updateManagedInstitution, + modalIdShown, personalSubscription, plans, + planCodeToChangeTo, queryingIndividualPlansData, recurlyLoadError, + setModalIdShown, + setPlanCodeToChangeTo, setRecurlyLoadError, showCancellation, setShowCancellation, @@ -130,15 +160,21 @@ export function SubscriptionDashboardProvider({ setShowChangePersonalPlan, }), [ + handleCloseModal, + handleOpenModal, hasDisplayedSubscription, institutionMemberships, managedGroupSubscriptions, managedInstitutions, updateManagedInstitution, + modalIdShown, personalSubscription, plans, + planCodeToChangeTo, queryingIndividualPlansData, recurlyLoadError, + setModalIdShown, + setPlanCodeToChangeTo, setRecurlyLoadError, showCancellation, setShowCancellation, diff --git a/services/web/frontend/js/features/subscription/data/subscription-url.ts b/services/web/frontend/js/features/subscription/data/subscription-url.ts new file mode 100644 index 0000000000..3fe149eda9 --- /dev/null +++ b/services/web/frontend/js/features/subscription/data/subscription-url.ts @@ -0,0 +1,3 @@ +export const subscriptionUrl = '/user/subscription/update' +export const cancelPendingSubscriptionChangeUrl = + '/user/subscription/cancel-pending' diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 1acef3f5e6..77226c01d4 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1117,6 +1117,7 @@ "proceed_to_paypal": "Proceed to PayPal", "proceeding_to_paypal_takes_you_to_the_paypal_site_to_pay": "Proceeding to PayPal will take you to the PayPal site to pay for your subscription.", "processing": "processing", + "processing_uppercase": "Processing", "processing_your_request": "Please wait while we process your request.", "professional": "Professional", "project": "project", diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx index d46ff04f82..61044d9f66 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx @@ -1,7 +1,6 @@ import { expect } from 'chai' import { fireEvent, screen } from '@testing-library/react' import * as eventTracking from '../../../../../../../../frontend/js/infrastructure/event-tracking' -import { ActiveSubscription } from '../../../../../../../../frontend/js/features/subscription/components/dashboard/states/active/active' import { Subscription } from '../../../../../../../../types/subscription/dashboard/subscription' import { annualActiveSubscription, @@ -11,11 +10,8 @@ import { trialSubscription, } from '../../../../fixtures/subscriptions' import sinon from 'sinon' -import { plans } from '../../../../fixtures/plans' -import { - cleanUpContext, - renderWithSubscriptionDashContext, -} from '../../../../helpers/render-with-subscription-dash-context' +import { cleanUpContext } from '../../../../helpers/render-with-subscription-dash-context' +import { renderActiveSubscription } from '../../../../helpers/render-active-subscription' describe('', function () { let sendMBSpy: sinon.SinonSpy @@ -61,19 +57,6 @@ describe('', function () { screen.getByRole('link', { name: 'View Your Invoices' }) } - function renderActiveSubscription(subscription: Subscription) { - const renderOptions = { - metaTags: [ - { name: 'ol-plans', value: plans }, - { name: 'ol-subscription', value: subscription }, - ], - } - renderWithSubscriptionDashContext( - , - renderOptions - ) - } - it('renders the dash annual active subscription', function () { renderActiveSubscription(annualActiveSubscription) expectedInActiveSubscription(annualActiveSubscription) diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx index 70190af80f..f0767df4e6 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx @@ -1,5 +1,5 @@ import { expect } from 'chai' -import { fireEvent, screen } from '@testing-library/react' +import { fireEvent, screen, waitFor, within } from '@testing-library/react' import { ChangePlan } from '../../../../../../../../../frontend/js/features/subscription/components/dashboard/states/active/change-plan/change-plan' import { plans } from '../../../../../fixtures/plans' import { @@ -11,40 +11,45 @@ import { cleanUpContext, renderWithSubscriptionDashContext, } from '../../../../../helpers/render-with-subscription-dash-context' +import sinon from 'sinon' +import fetchMock from 'fetch-mock' +import { + cancelPendingSubscriptionChangeUrl, + subscriptionUrl, +} from '../../../../../../../../../frontend/js/features/subscription/data/subscription-url' +import { renderActiveSubscription } from '../../../../../helpers/render-active-subscription' describe('', function () { + let reloadStub: () => void + const originalLocation = window.location const plansMetaTag = { name: 'ol-plans', value: plans } - const renderOptions = { metaTags: [plansMetaTag] } + + beforeEach(function () { + reloadStub = sinon.stub() + Object.defineProperty(window, 'location', { + value: { reload: reloadStub }, + }) + }) afterEach(function () { cleanUpContext() + fetchMock.reset() + Object.defineProperty(window, 'location', { + value: originalLocation, + }) }) it('does not render the UI when showChangePersonalPlan is false', function () { window.metaAttributesCache.delete('ol-plans') - const { container } = renderWithSubscriptionDashContext( - , - renderOptions - ) + const { container } = renderWithSubscriptionDashContext(, { + metaTags: [plansMetaTag], + }) expect(container.firstChild).to.be.null }) it('renders the individual plans table and group plans UI', async function () { - renderWithSubscriptionDashContext( - , - { - metaTags: [ - { name: 'ol-subscription', value: annualActiveSubscription }, - plansMetaTag, - { - name: 'ol-recommendedCurrency', - value: 'USD', - }, - ], - } - ) - + renderActiveSubscription(annualActiveSubscription) const button = screen.getByRole('button', { name: 'Change plan' }) fireEvent.click(button) @@ -68,15 +73,7 @@ describe('', function () { }) it('renders "Your new plan" and "Keep current plan" when there is a pending plan change', async function () { - renderWithSubscriptionDashContext( - , - { - metaTags: [ - { name: 'ol-subscription', value: pendingSubscriptionChange }, - plansMetaTag, - ], - } - ) + renderActiveSubscription(pendingSubscriptionChange) const button = screen.getByRole('button', { name: 'Change plan' }) fireEvent.click(button) @@ -98,13 +95,12 @@ describe('', function () { expect(container).not.to.be.null }) - it('shows a loading message while still querying Recurly for prices', function () { + it('shows a loading message while still querying Recurly for prices', async function () { renderWithSubscriptionDashContext( , { metaTags: [ { name: 'ol-subscription', value: pendingSubscriptionChange }, - plansMetaTag, ], } ) @@ -112,6 +108,218 @@ describe('', function () { const button = screen.getByRole('button', { name: 'Change plan' }) fireEvent.click(button) - screen.findByText('Loading', { exact: false }) + await screen.findByText('Loading', { exact: false }) + }) + + describe('Change plan modal', function () { + it('open confirmation modal when "Change to this plan" clicked', async function () { + renderActiveSubscription(annualActiveSubscription) + + const button = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(button) + + const buttons = await screen.findAllByRole('button', { + name: 'Change to this plan', + }) + fireEvent.click(buttons[0]) + + await screen.findByText('Are you sure you want to change plan to', { + exact: false, + }) + screen.getByRole('button', { name: 'Change plan' }) + + expect( + screen.queryByText( + 'Your existing plan and its features will remain active until the end of the current billing period.' + ) + ).to.be.null + + expect( + screen.queryByText( + 'If you wish this change to apply before the end of your current billing period, please contact us.' + ) + ).to.be.null + }) + + it('shows message in confirmation dialog about plan remaining active until end of term when expected', async function () { + let planIndex = 0 + const planThatWillChange = plans.find((p, i) => { + if (p.planCode !== annualActiveSubscription.planCode) { + planIndex = i + } + return p.planCode !== annualActiveSubscription.planCode + }) + + renderActiveSubscription(annualActiveSubscription, [ + { + name: 'ol-planCodesChangingAtTermEnd', + value: [planThatWillChange!.planCode], + }, + ]) + + const button = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(button) + + const buttons = await screen.findAllByRole('button', { + name: 'Change to this plan', + }) + fireEvent.click(buttons[planIndex]) + + const confirmModal = screen.getByRole('dialog') + await within(confirmModal).findByText( + 'Your existing plan and its features will remain active until the end of the current billing period.' + ) + + screen.getByText( + 'If you wish this change to apply before the end of your current billing period, please contact us.' + ) + }) + + it('changes plan after confirmed in modal', async function () { + const endPointResponse = { + status: 200, + } + fetchMock.post( + `${subscriptionUrl}?origin=confirmChangePlan`, + endPointResponse + ) + + renderActiveSubscription(annualActiveSubscription, [ + { + name: 'ol-planCodesChangingAtTermEnd', + value: [annualActiveSubscription.planCode], + }, + ]) + + const button = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(button) + + const buttons = await screen.findAllByRole('button', { + name: 'Change to this plan', + }) + fireEvent.click(buttons[0]) + + await screen.findByText('Are you sure you want to change plan to', { + exact: false, + }) + const buttonConfirm = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(buttonConfirm) + + screen.getByText('processing', { exact: false }) + + // page is reloaded on success + await waitFor(() => { + expect(reloadStub).to.have.been.called + }) + }) + + it('shows error if changing plan failed', async function () { + const endPointResponse = { + status: 500, + } + fetchMock.post( + `${subscriptionUrl}?origin=confirmChangePlan`, + endPointResponse + ) + + renderActiveSubscription(annualActiveSubscription) + + const button = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(button) + + const buttons = await screen.findAllByRole('button', { + name: 'Change to this plan', + }) + fireEvent.click(buttons[0]) + + await screen.findByText('Are you sure you want to change plan to', { + exact: false, + }) + const buttonConfirm = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(buttonConfirm) + + screen.getByText('processing', { exact: false }) + + await screen.findByText('Sorry, something went wrong. ', { exact: false }) + await screen.findByText('Please try again. ', { exact: false }) + await screen.findByText('If the problem continues please contact us.', { + exact: false, + }) + + expect( + within(screen.getByRole('dialog')) + .getByRole('button', { name: 'Change plan' }) + .getAttribute('disabled') + ).to.not.exist + }) + }) + + describe('Keep current plan modal', function () { + let confirmModal: HTMLElement + + beforeEach(async function () { + renderActiveSubscription(pendingSubscriptionChange) + + const button = screen.getByRole('button', { name: 'Change plan' }) + fireEvent.click(button) + + const keepPlanButton = await screen.findByRole('button', { + name: 'Keep my current plan', + }) + fireEvent.click(keepPlanButton) + + confirmModal = screen.getByRole('dialog') + }) + + it('opens confirmation modal when "Keep my current plan" is clicked', async function () { + within(confirmModal).getByText( + 'Are you sure you want to revert your scheduled plan change? You will remain subscribed to the', + { + exact: false, + } + ) + screen.getByRole('button', { name: 'Revert scheduled plan change' }) + }) + + it('keeps current plan when "Revert scheduled plan change" is clicked in modal', async function () { + const endPointResponse = { + status: 200, + } + fetchMock.post(cancelPendingSubscriptionChangeUrl, endPointResponse) + const buttonConfirm = within(confirmModal).getByRole('button', { + name: 'Revert scheduled plan change', + }) + fireEvent.click(buttonConfirm) + + screen.getByText('processing', { exact: false }) + + // page is reloaded on success + await waitFor(() => { + expect(reloadStub).to.have.been.called + }) + }) + + it('shows error if keeping plan failed', async function () { + const endPointResponse = { + status: 500, + } + fetchMock.post(cancelPendingSubscriptionChangeUrl, endPointResponse) + const buttonConfirm = within(confirmModal).getByRole('button', { + name: 'Revert scheduled plan change', + }) + fireEvent.click(buttonConfirm) + + screen.getByText('processing', { exact: false }) + await screen.findByText('Sorry, something went wrong. ', { exact: false }) + await screen.findByText('Please try again. ', { exact: false }) + await screen.findByText('If the problem continues please contact us.', { + exact: false, + }) + expect( + within(screen.getByRole('dialog')) + .getByRole('button', { name: 'Revert scheduled plan change' }) + .getAttribute('disabled') + ).to.not.exist + }) }) }) diff --git a/services/web/test/frontend/features/subscription/helpers/render-active-subscription.tsx b/services/web/test/frontend/features/subscription/helpers/render-active-subscription.tsx new file mode 100644 index 0000000000..4a1d6f9de4 --- /dev/null +++ b/services/web/test/frontend/features/subscription/helpers/render-active-subscription.tsx @@ -0,0 +1,25 @@ +import { ActiveSubscription } from '../../../../../frontend/js/features/subscription/components/dashboard/states/active/active' +import { Subscription } from '../../../../../types/subscription/dashboard/subscription' +import { plans } from '../fixtures/plans' +import { renderWithSubscriptionDashContext } from './render-with-subscription-dash-context' + +export function renderActiveSubscription( + subscription: Subscription, + tags: { name: string; value: string | object | Array }[] = [] +) { + const renderOptions = { + metaTags: [ + ...tags, + { name: 'ol-plans', value: plans }, + { name: 'ol-subscription', value: subscription }, + { + name: 'ol-recommendedCurrency', + value: 'USD', + }, + ], + } + renderWithSubscriptionDashContext( + , + renderOptions + ) +}