mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[Settings] "Start by adding your email address" hint (#8173)
* [Settings] "Start by adding your email address" hint GitOrigin-RevId: 19d432c70b173752ee7c6d8978dd6be16b042921
This commit is contained in:
parent
bce645b0f1
commit
0e782d3fb6
5 changed files with 143 additions and 11 deletions
|
@ -424,6 +424,7 @@
|
|||
"somthing_went_wrong_compiling": "",
|
||||
"split_screen": "",
|
||||
"sso_link_error": "",
|
||||
"start_by_adding_your_email": "",
|
||||
"start_free_trial": "",
|
||||
"stop_compile": "",
|
||||
"stop_on_validation_error": "",
|
||||
|
|
|
@ -14,6 +14,7 @@ import { ssoAvailableForDomain } from '../../utils/sso'
|
|||
import { postJSON } from '../../../../infrastructure/fetch-json'
|
||||
import { University } from '../../../../../../types/university'
|
||||
import { CountryCode } from '../../data/countries-list'
|
||||
import { isValidEmail } from '../../../../shared/utils/email'
|
||||
|
||||
function AddEmail() {
|
||||
const { t } = useTranslation()
|
||||
|
@ -106,20 +107,44 @@ function AddEmail() {
|
|||
)
|
||||
}
|
||||
|
||||
const InputCol = (
|
||||
<Col md={4}>
|
||||
<Cell>
|
||||
<label htmlFor="affiliations-email" className="sr-only">
|
||||
{t('email')}
|
||||
</label>
|
||||
<Input
|
||||
onChange={handleEmailChange}
|
||||
handleAddNewEmail={handleAddNewEmail}
|
||||
/>
|
||||
</Cell>
|
||||
</Col>
|
||||
)
|
||||
|
||||
if (!isValidEmail(newEmail)) {
|
||||
return (
|
||||
<Layout isError={isError} error={error}>
|
||||
<form>
|
||||
{InputCol}
|
||||
<Col md={5}>
|
||||
<Cell>
|
||||
<div>{t('start_by_adding_your_email')}</div>
|
||||
</Cell>
|
||||
</Col>
|
||||
<Col md={3}>
|
||||
<Cell className="text-md-right">
|
||||
<AddNewEmailBtn email={newEmail} disabled />
|
||||
</Cell>
|
||||
</Col>
|
||||
</form>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout isError={isError} error={error}>
|
||||
<form>
|
||||
<Col md={4}>
|
||||
<Cell>
|
||||
<label htmlFor="affiliations-email" className="sr-only">
|
||||
{t('email')}
|
||||
</label>
|
||||
<Input
|
||||
onChange={handleEmailChange}
|
||||
handleAddNewEmail={handleAddNewEmail}
|
||||
/>
|
||||
</Cell>
|
||||
</Col>
|
||||
{InputCol}
|
||||
{newEmailMatchedDomain &&
|
||||
ssoAvailableForDomain(newEmailMatchedDomain) ? (
|
||||
<Col md={8}>
|
||||
|
|
12
services/web/frontend/js/shared/utils/email.tsx
Normal file
12
services/web/frontend/js/shared/utils/email.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copied from backend code: https://github.com/overleaf/internal/blob/6af8ae850bd8075e6bf0ebcafd2731177cdf49ad/services/web/app/src/Features/Helpers/EmailHelper.js#L4
|
||||
const EMAIL_REGEXP =
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
/^([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
|
||||
export function isValidEmail(email: string | undefined | null) {
|
||||
if (!email) {
|
||||
return false
|
||||
} else {
|
||||
return EMAIL_REGEXP.test(email)
|
||||
}
|
||||
}
|
|
@ -92,6 +92,54 @@ describe('<EmailsSection />', function () {
|
|||
screen.getByLabelText(/email/i)
|
||||
})
|
||||
|
||||
it('renders "Start adding your address" until a valid email is typed', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
|
||||
const addAnotherEmailBtn = (await screen.findByRole('button', {
|
||||
name: /add another email/i,
|
||||
})) as HTMLButtonElement
|
||||
fireEvent.click(addAnotherEmailBtn)
|
||||
|
||||
const input = screen.getByLabelText(/email/i)
|
||||
|
||||
// initially the text is displayed and the "add email" button disabled
|
||||
screen.getByText('Start by adding your email address.')
|
||||
expect(
|
||||
(
|
||||
screen.getByRole('button', {
|
||||
name: /add new email/i,
|
||||
}) as HTMLButtonElement
|
||||
).disabled
|
||||
).to.be.true
|
||||
|
||||
// no changes while writing the email address
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'partial@email' },
|
||||
})
|
||||
screen.getByText('Start by adding your email address.')
|
||||
expect(
|
||||
(
|
||||
screen.getByRole('button', {
|
||||
name: /add new email/i,
|
||||
}) as HTMLButtonElement
|
||||
).disabled
|
||||
).to.be.true
|
||||
|
||||
// the text is removed when the complete email address is typed, and the "add button" is reenabled
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'valid@email.com' },
|
||||
})
|
||||
expect(screen.queryByText('Start by adding your email address.')).to.be.null
|
||||
expect(
|
||||
(
|
||||
screen.getByRole('button', {
|
||||
name: /add new email/i,
|
||||
}) as HTMLButtonElement
|
||||
).disabled
|
||||
).to.be.false
|
||||
})
|
||||
|
||||
it('renders "add new email" button', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
|
|
46
services/web/test/frontend/shared/utils/email.test.tsx
Normal file
46
services/web/test/frontend/shared/utils/email.test.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { expect } from 'chai'
|
||||
import { isValidEmail } from '../../../../frontend/js/shared/utils/email'
|
||||
|
||||
const validEmailAddresses = [
|
||||
'email@example.com',
|
||||
'firstname.lastname@example.com',
|
||||
'firstname-lastname@example.com',
|
||||
'email@subdomain.example.com',
|
||||
'firstname+lastname@example.com',
|
||||
'1234567890@example.com',
|
||||
'email@example-one.com',
|
||||
'_@example.com',
|
||||
'email@example.name',
|
||||
'email@example.co.jp',
|
||||
]
|
||||
|
||||
const invalidEmailAddresses = [
|
||||
'plaintext',
|
||||
'#@%^%#$@#$@#.com',
|
||||
'@example.com',
|
||||
'email.example.com',
|
||||
'.email@example.com',
|
||||
'email.@example.com',
|
||||
'email..email@example.com',
|
||||
'email@example.com (Joe Smith)',
|
||||
'email@example',
|
||||
'email@111.222.333.44444',
|
||||
'email@example..com',
|
||||
]
|
||||
|
||||
describe('isValidEmail', function () {
|
||||
it('should return true for valid email addresses', function () {
|
||||
validEmailAddresses.forEach(email =>
|
||||
expect(isValidEmail(email)).to.equal(true, email + ' should be valid ')
|
||||
)
|
||||
})
|
||||
|
||||
it('should return false for invalid email addresses', function () {
|
||||
invalidEmailAddresses.forEach(email =>
|
||||
expect(isValidEmail(email)).to.equal(
|
||||
false,
|
||||
email + ' should not be valid '
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue