row.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import { useState } from 'react'
  2. import { Trans, useTranslation } from 'react-i18next'
  3. import { UserEmailData } from '../../../../../../types/user-email'
  4. import Email from './email'
  5. import InstitutionAndRole from './institution-and-role'
  6. import EmailCell from './cell'
  7. import Actions from './actions'
  8. import { institutionAlreadyLinked } from '../../utils/selectors'
  9. import { useUserEmailsContext } from '../../context/user-email-context'
  10. import getMeta from '../../../../utils/meta'
  11. import { ExposedSettings } from '../../../../../../types/exposed-settings'
  12. import { ssoAvailableForInstitution } from '../../utils/sso'
  13. import ReconfirmationInfo from './reconfirmation-info'
  14. import { useLocation } from '../../../../shared/hooks/use-location'
  15. import OLRow from '@/features/ui/components/ol/ol-row'
  16. import OLCol from '@/features/ui/components/ol/ol-col'
  17. import { bsVersion } from '@/features/utils/bootstrap-5'
  18. import OLButton from '@/features/ui/components/ol/ol-button'
  19. type EmailsRowProps = {
  20. userEmailData: UserEmailData
  21. }
  22. function EmailsRow({ userEmailData }: EmailsRowProps) {
  23. const hasSSOAffiliation = Boolean(
  24. userEmailData.affiliation &&
  25. ssoAvailableForInstitution(userEmailData.affiliation.institution)
  26. )
  27. return (
  28. <>
  29. <OLRow>
  30. <OLCol lg={4}>
  31. <EmailCell>
  32. <Email userEmailData={userEmailData} />
  33. </EmailCell>
  34. </OLCol>
  35. <OLCol lg={5}>
  36. {userEmailData.affiliation?.institution && (
  37. <EmailCell>
  38. <InstitutionAndRole userEmailData={userEmailData} />
  39. </EmailCell>
  40. )}
  41. </OLCol>
  42. <OLCol lg={3}>
  43. <EmailCell
  44. className={bsVersion({
  45. bs5: 'text-lg-end',
  46. bs3: 'text-md-right',
  47. })}
  48. >
  49. <Actions userEmailData={userEmailData} />
  50. </EmailCell>
  51. </OLCol>
  52. </OLRow>
  53. {hasSSOAffiliation && (
  54. <SSOAffiliationInfo userEmailData={userEmailData} />
  55. )}
  56. <ReconfirmationInfo userEmailData={userEmailData} />
  57. </>
  58. )
  59. }
  60. type SSOAffiliationInfoProps = {
  61. userEmailData: UserEmailData
  62. }
  63. function SSOAffiliationInfo({ userEmailData }: SSOAffiliationInfoProps) {
  64. const { samlInitPath } = getMeta('ol-ExposedSettings') as ExposedSettings
  65. const { t } = useTranslation()
  66. const { state } = useUserEmailsContext()
  67. const location = useLocation()
  68. const [linkAccountsButtonDisabled, setLinkAccountsButtonDisabled] =
  69. useState(false)
  70. function handleLinkAccountsButtonClick() {
  71. setLinkAccountsButtonDisabled(true)
  72. location.assign(
  73. `${samlInitPath}?university_id=${userEmailData.affiliation?.institution?.id}&auto=/user/settings&email=${userEmailData.email}`
  74. )
  75. }
  76. if (
  77. !userEmailData.samlProviderId &&
  78. institutionAlreadyLinked(state, userEmailData)
  79. ) {
  80. // if the email is not linked to the institution, but there's another email already linked to that institution
  81. // no SSO affiliation is displayed, since cannot have multiple emails linked to the same institution
  82. return null
  83. }
  84. if (userEmailData.samlProviderId) {
  85. return (
  86. <OLRow>
  87. <OLCol lg={{ span: 8, offset: 4 }}>
  88. <EmailCell>
  89. <p>
  90. <Trans
  91. i18nKey="acct_linked_to_institution_acct_2"
  92. components={
  93. /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
  94. [<strong />]
  95. }
  96. values={{
  97. institutionName: userEmailData.affiliation?.institution.name,
  98. }}
  99. shouldUnescape
  100. tOptions={{ interpolation: { escapeValue: true } }}
  101. />
  102. </p>
  103. </EmailCell>
  104. </OLCol>
  105. </OLRow>
  106. )
  107. }
  108. return (
  109. <OLRow>
  110. <OLCol lg={{ span: 8, offset: 4 }}>
  111. <div className="horizontal-divider" />
  112. <OLRow>
  113. <OLCol lg={9}>
  114. <EmailCell>
  115. <p className="small">
  116. <Trans
  117. i18nKey="can_link_your_institution_acct_2"
  118. values={{
  119. institutionName:
  120. userEmailData.affiliation?.institution.name,
  121. }}
  122. shouldUnescape
  123. tOptions={{ interpolation: { escapeValue: true } }}
  124. components={
  125. /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
  126. [<strong />]
  127. }
  128. />
  129. </p>
  130. <p className="small">
  131. <Trans
  132. i18nKey="doing_this_allow_log_in_through_institution_2"
  133. components={
  134. /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
  135. [<strong />]
  136. }
  137. />{' '}
  138. <a href="/learn/how-to/Institutional_Login" target="_blank">
  139. {t('find_out_more_about_institution_login')}
  140. </a>
  141. </p>
  142. </EmailCell>
  143. </OLCol>
  144. <OLCol
  145. lg={3}
  146. className={bsVersion({
  147. bs5: 'text-lg-end',
  148. bs3: 'text-md-right',
  149. })}
  150. >
  151. <EmailCell>
  152. <OLButton
  153. variant="primary"
  154. className="btn-link-accounts"
  155. disabled={linkAccountsButtonDisabled}
  156. onClick={handleLinkAccountsButtonClick}
  157. size="small"
  158. >
  159. {t('link_accounts')}
  160. </OLButton>
  161. </EmailCell>
  162. </OLCol>
  163. </OLRow>
  164. </OLCol>
  165. </OLRow>
  166. )
  167. }
  168. export default EmailsRow