add-email.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { useState, useEffect } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { Col } from 'react-bootstrap'
  4. import Cell from './cell'
  5. import Layout from './add-email/layout'
  6. import Input, { DomainInfo } from './add-email/input'
  7. import AddAnotherEmailBtn from './add-email/add-another-email-btn'
  8. import InstitutionFields from './add-email/institution-fields'
  9. import SsoLinkingInfo from './add-email/sso-linking-info'
  10. import AddNewEmailBtn from './add-email/add-new-email-btn'
  11. import useAsync from '../../../../shared/hooks/use-async'
  12. import { useUserEmailsContext } from '../../context/user-email-context'
  13. import { ssoAvailableForDomain } from '../../utils/sso'
  14. import { postJSON } from '../../../../infrastructure/fetch-json'
  15. import { University } from '../../../../../../types/university'
  16. import { CountryCode } from '../../data/countries-list'
  17. import { isValidEmail } from '../../../../shared/utils/email'
  18. function AddEmail() {
  19. const { t } = useTranslation()
  20. const [isFormVisible, setIsFormVisible] = useState(
  21. () => window.location.hash === '#add-email'
  22. )
  23. const [newEmail, setNewEmail] = useState('')
  24. const [newEmailMatchedDomain, setNewEmailMatchedDomain] =
  25. useState<DomainInfo | null>(null)
  26. const [countryCode, setCountryCode] = useState<CountryCode | null>(null)
  27. const [universities, setUniversities] = useState<
  28. Partial<Record<CountryCode, University[]>>
  29. >({})
  30. const [universityName, setUniversityName] = useState('')
  31. const [role, setRole] = useState('')
  32. const [department, setDepartment] = useState('')
  33. const { isLoading, isError, error, runAsync } = useAsync()
  34. const {
  35. state,
  36. setLoading: setUserEmailsContextLoading,
  37. getEmails,
  38. } = useUserEmailsContext()
  39. useEffect(() => {
  40. setUserEmailsContextLoading(isLoading)
  41. }, [setUserEmailsContextLoading, isLoading])
  42. const handleShowAddEmailForm = () => {
  43. setIsFormVisible(true)
  44. }
  45. const handleEmailChange = (value: string, domain?: DomainInfo) => {
  46. setNewEmail(value)
  47. setNewEmailMatchedDomain(domain || null)
  48. }
  49. const getSelectedKnownUniversityId = (): number | undefined => {
  50. if (countryCode) {
  51. return universities[countryCode]?.find(
  52. ({ name }) => name === universityName
  53. )?.id
  54. }
  55. return newEmailMatchedDomain?.university.id
  56. }
  57. const handleAddNewEmail = () => {
  58. const selectedKnownUniversityId = getSelectedKnownUniversityId()
  59. const knownUniversityData = selectedKnownUniversityId && {
  60. university: {
  61. id: selectedKnownUniversityId,
  62. },
  63. role,
  64. department,
  65. }
  66. const unknownUniversityData = universityName &&
  67. !selectedKnownUniversityId && {
  68. university: {
  69. name: universityName,
  70. country_code: countryCode,
  71. },
  72. role,
  73. department,
  74. }
  75. runAsync(
  76. postJSON('/user/emails', {
  77. body: {
  78. email: newEmail,
  79. ...knownUniversityData,
  80. ...unknownUniversityData,
  81. },
  82. })
  83. )
  84. .then(() => {
  85. getEmails()
  86. })
  87. .catch(() => {})
  88. }
  89. if (!isFormVisible) {
  90. return (
  91. <Layout isError={isError} error={error}>
  92. <Col md={4}>
  93. <Cell>
  94. <AddAnotherEmailBtn onClick={handleShowAddEmailForm} />
  95. </Cell>
  96. </Col>
  97. </Layout>
  98. )
  99. }
  100. const InputComponent = (
  101. <>
  102. <label htmlFor="affiliations-email" className="sr-only">
  103. {t('email')}
  104. </label>
  105. <Input
  106. onChange={handleEmailChange}
  107. handleAddNewEmail={handleAddNewEmail}
  108. />
  109. </>
  110. )
  111. if (!isValidEmail(newEmail)) {
  112. return (
  113. <Layout isError={isError} error={error}>
  114. <form>
  115. <Col md={8}>
  116. <Cell>
  117. {InputComponent}
  118. <div className="affiliations-table-cell-tabbed">
  119. <div>{t('start_by_adding_your_email')}</div>
  120. </div>
  121. </Cell>
  122. </Col>
  123. <Col md={4}>
  124. <Cell className="text-md-right">
  125. <AddNewEmailBtn email={newEmail} disabled />
  126. </Cell>
  127. </Col>
  128. </form>
  129. </Layout>
  130. )
  131. }
  132. const isSsoAvailableForDomain =
  133. newEmailMatchedDomain && ssoAvailableForDomain(newEmailMatchedDomain)
  134. return (
  135. <Layout isError={isError} error={error}>
  136. <form>
  137. <Col md={8}>
  138. <Cell>
  139. {InputComponent}
  140. {!isSsoAvailableForDomain ? (
  141. <div className="affiliations-table-cell-tabbed">
  142. <InstitutionFields
  143. countryCode={countryCode}
  144. setCountryCode={setCountryCode}
  145. universities={universities}
  146. setUniversities={setUniversities}
  147. universityName={universityName}
  148. setUniversityName={setUniversityName}
  149. role={role}
  150. setRole={setRole}
  151. department={department}
  152. setDepartment={setDepartment}
  153. newEmailMatchedDomain={newEmailMatchedDomain}
  154. />
  155. </div>
  156. ) : null}
  157. </Cell>
  158. </Col>
  159. {!isSsoAvailableForDomain ? (
  160. <Col md={4}>
  161. <Cell className="text-md-right">
  162. <AddNewEmailBtn
  163. email={newEmail}
  164. disabled={isLoading || state.isLoading}
  165. onClick={handleAddNewEmail}
  166. />
  167. </Cell>
  168. </Col>
  169. ) : (
  170. <Col md={12}>
  171. <Cell>
  172. <div className="affiliations-table-cell-tabbed">
  173. <SsoLinkingInfo
  174. email={newEmail}
  175. domainInfo={newEmailMatchedDomain as DomainInfo}
  176. />
  177. </div>
  178. </Cell>
  179. </Col>
  180. )}
  181. </form>
  182. </Layout>
  183. )
  184. }
  185. export default AddEmail