Merge pull request #25998 from overleaf/mf-update-stripe-email-from-subscription-dashboard

[web] Make user able to sync their email address in subscription dashboard for Stripe subscription

GitOrigin-RevId: 9abdc0e18ebea29b18c2041130946b9e50fa43db
This commit is contained in:
M Fahru
2025-06-03 06:40:51 -07:00
committed by Copybot
parent ef810a9f36
commit 832f9923b9
5 changed files with 34 additions and 20 deletions
@@ -538,7 +538,8 @@ function cancelPendingSubscriptionChange(req, res, next) {
async function updateAccountEmailAddress(req, res, next) {
const user = SessionManager.getSessionUser(req.session)
try {
await RecurlyWrapper.promises.updateAccountEmailAddress(
await Modules.promises.hooks.fire(
'updateAccountEmailAddress',
user._id,
user.email
)
@@ -7,23 +7,23 @@ import OLNotification from '@/features/ui/components/ol/ol-notification'
import OLButton from '@/features/ui/components/ol/ol-button'
import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
function PersonalSubscriptionRecurlySyncEmail() {
function PersonalSubscriptionSyncEmail() {
const { t } = useTranslation()
const { personalSubscription } = useSubscriptionDashboardContext()
const userEmail = getMeta('ol-usersEmail')
const { isLoading, isSuccess, runAsync } = useAsync()
if (!personalSubscription || !('payment' in personalSubscription)) return null
const accountEmail = personalSubscription.payment.accountEmail
if (!userEmail || accountEmail === userEmail) return null
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
runAsync(postJSON('/user/subscription/account/email'))
}
if (!personalSubscription || !('payment' in personalSubscription)) return null
const recurlyEmail = personalSubscription.payment.accountEmail
if (!userEmail || recurlyEmail === userEmail) return null
return (
<>
<form onSubmit={handleSubmit}>
@@ -39,7 +39,7 @@ function PersonalSubscriptionRecurlySyncEmail() {
<Trans
i18nKey="recurly_email_update_needed"
components={[<em />, <em />]} // eslint-disable-line react/jsx-key
values={{ recurlyEmail, userEmail }}
values={{ recurlyEmail: accountEmail, userEmail }}
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>
@@ -64,4 +64,4 @@ function PersonalSubscriptionRecurlySyncEmail() {
)
}
export default PersonalSubscriptionRecurlySyncEmail
export default PersonalSubscriptionSyncEmail
@@ -5,7 +5,7 @@ import { ActiveSubscriptionNew } from '@/features/subscription/components/dashbo
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'
import PersonalSubscriptionSyncEmail from './personal-subscription-sync-email'
import OLNotification from '@/features/ui/components/ol/ol-notification'
import RedirectAlerts from './redirect-alerts'
@@ -90,7 +90,7 @@ function PersonalSubscription() {
/>
)}
<hr />
<PersonalSubscriptionRecurlySyncEmail />
<PersonalSubscriptionSyncEmail />
</>
)
}
@@ -190,7 +190,9 @@ describe('<PersonalSubscription />', function () {
})
it('shows different payment email address section', async function () {
fetchMock.post('/user/subscription/account/email', 200)
fetchMock.post('/user/subscription/account/email', {
status: 200,
})
const usersEmail = 'foo@example.com'
renderWithSubscriptionDashContext(<PersonalSubscription />, {
metaTags: [
@@ -311,15 +311,25 @@ describe('SubscriptionController', function () {
})
describe('updateAccountEmailAddress via put', function () {
it('should send the user and subscriptionId to RecurlyWrapper', async function () {
beforeEach(function () {
this.req.body = {
account_email: 'current_account_email@overleaf.com',
}
})
it('should send the user and subscriptionId to "updateAccountEmailAddress" hooks', async function () {
this.res.sendStatus = sinon.spy()
await this.SubscriptionController.updateAccountEmailAddress(
this.req,
this.res
)
this.RecurlyWrapper.promises.updateAccountEmailAddress
.calledWith(this.user._id, this.user.email)
.should.equal(true)
expect(this.Modules.promises.hooks.fire).to.have.been.calledWith(
'updateAccountEmailAddress',
this.user._id,
this.user.email
)
})
it('should respond with 200', async function () {
@@ -332,9 +342,10 @@ describe('SubscriptionController', function () {
})
it('should send the error to the next handler when updating recurly account email fails', async function () {
this.RecurlyWrapper.promises.updateAccountEmailAddress.rejects(
new Error()
)
this.Modules.promises.hooks.fire
.withArgs('updateAccountEmailAddress', this.user._id, this.user.email)
.rejects(new Error())
this.next = sinon.spy(error => {
expect(error).to.be.instanceOf(Error)
})