overleaf/services/web/frontend/js/features/settings/components/emails/add-email.tsx
Timothée Alby e5051bcd1d Merge pull request #7765 from overleaf/ii-add-email-ui-affiliating-with-existing-institution
Add email with existing and non existing institution

GitOrigin-RevId: 331bc06f0ea289a82b403a910491e233f4eda4bb
2022-04-28 08:03:16 +00:00

247 lines
7.6 KiB
TypeScript

import { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { Button, Row, Col } from 'react-bootstrap'
import Cell from './cell'
import Icon from '../../../../shared/components/icon'
import DownshiftInput from './downshift-input'
import CountryInput from './country-input'
import { AddEmailInput } from './add-email-input'
import useAsync from '../../../../shared/hooks/use-async'
import { useUserEmailsContext } from '../../context/user-email-context'
import { getJSON, postJSON } from '../../../../infrastructure/fetch-json'
import { defaults as roles } from '../../roles'
import { defaults as departments } from '../../departments'
import { University } from '../../../../../../types/university'
import { CountryCode } from '../../../../../../types/country'
const isValidEmail = (email: string) => {
return Boolean(email)
}
function AddEmail() {
const { t } = useTranslation()
const [isFormVisible, setIsFormVisible] = useState(
() => window.location.hash === '#add-email'
)
const [newEmail, setNewEmail] = useState('')
const [countryCode, setCountryCode] = useState<CountryCode | null>(null)
const [universities, setUniversities] = useState<
Partial<Record<CountryCode, University[]>>
>({})
const [university, setUniversity] = useState('')
const [role, setRole] = useState('')
const [department, setDepartment] = useState('')
const [isInstitutionFieldsVisible, setIsInstitutionFieldsVisible] =
useState(false)
const [isUniversityDirty, setIsUniversityDirty] = useState(false)
const { isLoading, isError, runAsync } = useAsync()
const { runAsync: institutionRunAsync } = useAsync()
const {
state,
setLoading: setUserEmailsContextLoading,
getEmails,
} = useUserEmailsContext()
useEffect(() => {
setUserEmailsContextLoading(isLoading)
}, [setUserEmailsContextLoading, isLoading])
useEffect(() => {
if (university) {
setIsUniversityDirty(true)
}
}, [setIsUniversityDirty, university])
// Fetch country institution
useEffect(() => {
// Skip if country not selected or universities for
// that country are already fetched
if (!countryCode || universities[countryCode]) {
return
}
institutionRunAsync<University[]>(
getJSON(`/institutions/list?country_code=${countryCode}`)
)
.then(data => {
setUniversities(state => ({ ...state, [countryCode]: data }))
})
.catch(() => {})
}, [countryCode, universities, setUniversities, institutionRunAsync])
const handleShowAddEmailForm = () => {
setIsFormVisible(true)
}
const handleShowInstitutionFields = () => {
setIsInstitutionFieldsVisible(true)
}
const handleEmailChange = (value: string) => {
setNewEmail(value)
}
const handleAddNewEmail = () => {
const selectedKnownUniversity = countryCode
? universities[countryCode]?.find(({ name }) => name === university)
: undefined
const knownUniversityData = university &&
selectedKnownUniversity && {
university: {
id: selectedKnownUniversity.id,
},
role,
department,
}
const unknownUniversityData = university &&
!selectedKnownUniversity && {
university: {
name: university,
country_code: countryCode,
},
role,
department,
}
runAsync(
postJSON('/user/emails', {
body: {
email: newEmail,
...knownUniversityData,
...unknownUniversityData,
},
})
)
.then(() => {
getEmails()
setIsFormVisible(false)
setNewEmail('')
setCountryCode(null)
setIsUniversityDirty(false)
setUniversity('')
setRole('')
setDepartment('')
setIsInstitutionFieldsVisible(false)
})
.catch(() => {})
}
const getUniversityItems = () => {
if (!countryCode) {
return []
}
return universities[countryCode]?.map(({ name }) => name) ?? []
}
return (
<div className="affiliations-table-row--highlighted">
<Row>
{!isFormVisible ? (
<Col md={4}>
<Cell>
<Button
className="btn-inline-link"
onClick={handleShowAddEmailForm}
>
{t('add_another_email')}
</Button>
</Cell>
</Col>
) : (
<form>
<Col md={4}>
<Cell>
<label htmlFor="affiliations-email" className="sr-only">
{t('email')}
</label>
<AddEmailInput onChange={handleEmailChange} />
</Cell>
</Col>
<Col md={4}>
<Cell>
{isInstitutionFieldsVisible ? (
<>
<div className="form-group mb-2">
<CountryInput
id="new-email-country-input"
setValue={setCountryCode}
/>
</div>
<div className="form-group mb-2">
<DownshiftInput
items={getUniversityItems()}
inputValue={university}
placeholder={t('university')}
label={t('university')}
setValue={setUniversity}
disabled={!countryCode}
/>
</div>
{isUniversityDirty && (
<>
<div className="form-group mb-2">
<DownshiftInput
items={roles}
inputValue={role}
placeholder={t('role')}
label={t('role')}
setValue={setRole}
/>
</div>
<div className="form-group mb-0">
<DownshiftInput
items={departments}
inputValue={department}
placeholder={t('department')}
label={t('department')}
setValue={setDepartment}
/>
</div>
</>
)}
</>
) : (
<div className="mt-1">
{t('is_email_affiliated')}
<br />
<Button
className="btn-inline-link"
onClick={handleShowInstitutionFields}
>
{t('let_us_know')}
</Button>
</div>
)}
</Cell>
</Col>
<Col md={4}>
<Cell className="text-md-right">
<Button
bsSize="small"
bsStyle="success"
disabled={
!isValidEmail(newEmail) || isLoading || state.isLoading
}
onClick={handleAddNewEmail}
>
{t('add_new_email')}
</Button>
{isError && (
<div className="text-danger small">
<Icon type="exclamation-triangle" fw />{' '}
{t('error_performing_request')}
</div>
)}
</Cell>
</Col>
</form>
)}
</Row>
</div>
)
}
export default AddEmail