mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-12 23:16:09 +00:00
Merge pull request #11919 from overleaf/ii-react-subscription-dash-user-email-not-matching-recurly-email
[web] Subscription dash user email not matching recurly email section - react migration GitOrigin-RevId: 8d89dbc804694afffea2a92cebdeb5d4e9389810
This commit is contained in:
parent
41b5bb5bae
commit
9f95c7c2ab
9 changed files with 150 additions and 26 deletions
|
@ -636,6 +636,8 @@
|
|||
"recompile_from_scratch": "",
|
||||
"recompile_pdf": "",
|
||||
"reconnect": "",
|
||||
"recurly_email_update_needed": "",
|
||||
"recurly_email_updated": "",
|
||||
"redirect_to_editor": "",
|
||||
"reduce_costs_group_licenses": "",
|
||||
"reference_error_relink_hint": "",
|
||||
|
@ -876,6 +878,7 @@
|
|||
"update_account_info": "",
|
||||
"update_dropbox_settings": "",
|
||||
"update_your_billing_details": "",
|
||||
"updating": "",
|
||||
"upgrade": "",
|
||||
"upgrade_cc_btn": "",
|
||||
"upgrade_for_longer_compiles": "",
|
||||
|
|
|
@ -20,32 +20,32 @@ function InstitutionMemberships() {
|
|||
)
|
||||
}
|
||||
|
||||
if (!institutionMemberships.length) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{institutionMemberships.map((institution: Institution) => (
|
||||
<div key={`${institution.id}`}>
|
||||
<Trans
|
||||
i18nKey="you_are_on_x_plan_as_a_confirmed_member_of_institution_y"
|
||||
values={{
|
||||
planName: 'Professional',
|
||||
institutionName: institution.name || '',
|
||||
}}
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
|
||||
<a href="/user/subscription/plans" rel="noopener" />,
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
]}
|
||||
/>
|
||||
<hr />
|
||||
</div>
|
||||
))}
|
||||
{institutionMemberships.length > 0 && <PremiumFeaturesLink />}
|
||||
</div>
|
||||
</>
|
||||
<div>
|
||||
{institutionMemberships.map((institution: Institution) => (
|
||||
<div key={`${institution.id}`}>
|
||||
<Trans
|
||||
i18nKey="you_are_on_x_plan_as_a_confirmed_member_of_institution_y"
|
||||
values={{
|
||||
planName: 'Professional',
|
||||
institutionName: institution.name || '',
|
||||
}}
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
|
||||
<a href="/user/subscription/plans" rel="noopener" />,
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
]}
|
||||
/>
|
||||
<hr />
|
||||
</div>
|
||||
))}
|
||||
<PremiumFeaturesLink />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
|
||||
import { FormGroup, Alert } from 'react-bootstrap'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import useAsync from '../../../../shared/hooks/use-async'
|
||||
import { postJSON } from '../../../../infrastructure/fetch-json'
|
||||
|
||||
function PersonalSubscriptionRecurlySyncEmail() {
|
||||
const { t } = useTranslation()
|
||||
const { personalSubscription } = useSubscriptionDashboardContext()
|
||||
const userEmail = getMeta('ol-usersEmail') as string
|
||||
const { isLoading, isSuccess, runAsync } = useAsync()
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
runAsync(postJSON('/user/subscription/account/email'))
|
||||
}
|
||||
|
||||
if (!personalSubscription || !('recurly' in personalSubscription)) return null
|
||||
|
||||
const recurlyEmail = personalSubscription.recurly.account.email
|
||||
|
||||
if (!userEmail || recurlyEmail === userEmail) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<FormGroup>
|
||||
{isSuccess ? (
|
||||
<Alert bsStyle="success">{t('recurly_email_updated')}</Alert>
|
||||
) : (
|
||||
<>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="recurly_email_update_needed"
|
||||
components={[<em />, <em />]} // eslint-disable-line react/jsx-key
|
||||
values={{ recurlyEmail, userEmail }}
|
||||
/>
|
||||
</p>
|
||||
<div>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? <>{t('updating')}…</> : t('update')}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</FormGroup>
|
||||
</form>
|
||||
<hr />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PersonalSubscriptionRecurlySyncEmail
|
|
@ -4,6 +4,7 @@ import { ActiveSubscription } from './states/active/active'
|
|||
import { CanceledSubscription } from './states/canceled'
|
||||
import { ExpiredSubscription } from './states/expired'
|
||||
import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
|
||||
import PersonalSubscriptionRecurlySyncEmail from './personal-subscription-recurly-sync-email'
|
||||
|
||||
function PastDueSubscriptionAlert({
|
||||
subscription,
|
||||
|
@ -79,6 +80,7 @@ function PersonalSubscription() {
|
|||
</div>
|
||||
)}
|
||||
<hr />
|
||||
<PersonalSubscriptionRecurlySyncEmail />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1607,6 +1607,7 @@
|
|||
"update_account_info": "Update Account Info",
|
||||
"update_dropbox_settings": "Update Dropbox Settings",
|
||||
"update_your_billing_details": "Update Your Billing Details",
|
||||
"updating": "Updating",
|
||||
"updating_site": "Updating Site",
|
||||
"upgrade": "Upgrade",
|
||||
"upgrade_cc_btn": "Upgrade now, pay after 7 days",
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import { expect } from 'chai'
|
||||
import { screen } from '@testing-library/react'
|
||||
import {
|
||||
screen,
|
||||
fireEvent,
|
||||
waitForElementToBeRemoved,
|
||||
within,
|
||||
} from '@testing-library/react'
|
||||
import PersonalSubscription from '../../../../../../frontend/js/features/subscription/components/dashboard/personal-subscription'
|
||||
import {
|
||||
annualActiveSubscription,
|
||||
|
@ -11,6 +16,7 @@ import {
|
|||
cleanUpContext,
|
||||
renderWithSubscriptionDashContext,
|
||||
} from '../../helpers/render-with-subscription-dash-context'
|
||||
import fetchMock from 'fetch-mock'
|
||||
|
||||
describe('<PersonalSubscription />', function () {
|
||||
afterEach(function () {
|
||||
|
@ -145,4 +151,45 @@ describe('<PersonalSubscription />', function () {
|
|||
screen.getByText('Change plan')
|
||||
})
|
||||
})
|
||||
|
||||
it('shows different recurly email address section', async function () {
|
||||
fetchMock.post('/user/subscription/account/email', 200)
|
||||
const usersEmail = 'foo@example.com'
|
||||
renderWithSubscriptionDashContext(<PersonalSubscription />, {
|
||||
metaTags: [
|
||||
{ name: 'ol-subscription', value: annualActiveSubscription },
|
||||
{ name: 'ol-usersEmail', value: usersEmail },
|
||||
],
|
||||
})
|
||||
|
||||
const billingText = screen.getByText(
|
||||
/your billing email address is currently/i
|
||||
).textContent
|
||||
expect(billingText).to.contain(
|
||||
`Your billing email address is currently ${annualActiveSubscription.recurly.account.email}.` +
|
||||
` If needed you can update your billing address to ${usersEmail}`
|
||||
)
|
||||
|
||||
const submitBtn = screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: /update/i,
|
||||
})
|
||||
expect(submitBtn.disabled).to.be.false
|
||||
fireEvent.click(submitBtn)
|
||||
expect(submitBtn.disabled).to.be.true
|
||||
expect(
|
||||
screen.getByRole<HTMLButtonElement>('button', { name: /updating/i })
|
||||
.disabled
|
||||
).to.be.true
|
||||
|
||||
await waitForElementToBeRemoved(() =>
|
||||
screen.getByText(/your billing email address is currently/i)
|
||||
)
|
||||
|
||||
within(screen.getByRole('alert')).getByText(
|
||||
/your billing email address was successfully updated/i
|
||||
)
|
||||
|
||||
expect(screen.queryByRole('button', { name: /update/i })).to.be.null
|
||||
expect(screen.queryByRole('button', { name: /updating/i })).to.be.null
|
||||
})
|
||||
})
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
GroupSubscription,
|
||||
RecurlySubscription,
|
||||
} from '../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
const dateformat = require('dateformat')
|
||||
const today = new Date()
|
||||
const oneYearFromToday = new Date().setFullYear(today.getFullYear() + 1)
|
||||
|
@ -45,6 +46,7 @@ export const annualActiveSubscription: RecurlySubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'false', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'false', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -84,6 +86,7 @@ export const annualActiveSubscriptionEuro: RecurlySubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'false', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'false', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -122,6 +125,7 @@ export const annualActiveSubscriptionPro: RecurlySubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'false', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'false', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -161,6 +165,7 @@ export const pastDueExpiredSubscription: RecurlySubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'false', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'true', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -200,6 +205,7 @@ export const canceledSubscription: RecurlySubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'true', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'false', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -239,6 +245,7 @@ export const pendingSubscriptionChange: RecurlySubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'false', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'false', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -289,6 +296,7 @@ export const groupActiveSubscription: GroupSubscription = {
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: { _: 'false', $: { type: 'boolean' } },
|
||||
has_past_due_invoice: { _: 'false', $: { type: 'boolean' } },
|
||||
},
|
||||
|
@ -333,6 +341,7 @@ export const groupActiveSubscriptionWithPendingLicenseChange: GroupSubscription
|
|||
trial_ends_at: null,
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: {
|
||||
_: 'false',
|
||||
$: {
|
||||
|
@ -395,6 +404,7 @@ export const trialSubscription: RecurlySubscription = {
|
|||
trial_ends_at: new Date(sevenDaysFromToday).toString(),
|
||||
activeCoupons: [],
|
||||
account: {
|
||||
email: 'fake@example.com',
|
||||
has_canceled_subscription: {
|
||||
_: 'false',
|
||||
$: {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { render } from '@testing-library/react'
|
|||
import _ from 'lodash'
|
||||
import { SubscriptionDashboardProvider } from '../../../../../frontend/js/features/subscription/context/subscription-dashboard-context'
|
||||
import { groupPriceByUsageTypeAndSize, plans } from '../fixtures/plans'
|
||||
import fetchMock from 'fetch-mock'
|
||||
|
||||
export function renderWithSubscriptionDashContext(
|
||||
component: React.ReactElement,
|
||||
|
@ -89,4 +90,5 @@ export function cleanUpContext() {
|
|||
// @ts-ignore
|
||||
delete global.recurly
|
||||
window.metaAttributesCache = new Map()
|
||||
fetchMock.reset()
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ type Recurly = {
|
|||
trial_ends_at: Nullable<string>
|
||||
activeCoupons: any[] // TODO: confirm type in array
|
||||
account: {
|
||||
email: string
|
||||
// data via Recurly API
|
||||
has_canceled_subscription: {
|
||||
_: 'false' | 'true'
|
||||
|
|
Loading…
Add table
Reference in a new issue