row.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 { ssoAvailableForInstitution } from '../../utils/sso'
  12. import ReconfirmationInfo from './reconfirmation-info'
  13. import { useLocation } from '../../../../shared/hooks/use-location'
  14. import OLRow from '@/shared/components/ol/ol-row'
  15. import OLCol from '@/shared/components/ol/ol-col'
  16. import OLButton from '@/shared/components/ol/ol-button'
  17. import UnlinkCommonsSSOModal from './unlink-commons-sso-modal'
  18. type EmailsRowProps = {
  19. userEmailData: UserEmailData
  20. primary?: UserEmailData
  21. }
  22. function EmailsRow({ userEmailData, primary }: EmailsRowProps) {
  23. const hasSSOAffiliation = Boolean(
  24. userEmailData.affiliation &&
  25. ssoAvailableForInstitution(userEmailData.affiliation.institution)
  26. )
  27. return (
  28. <>
  29. <OLRow data-testid="email-row">
  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 className="text-lg-end">
  44. <Actions userEmailData={userEmailData} primary={primary} />
  45. </EmailCell>
  46. </OLCol>
  47. </OLRow>
  48. {hasSSOAffiliation && (
  49. <SSOAffiliationInfo userEmailData={userEmailData} />
  50. )}
  51. <ReconfirmationInfo userEmailData={userEmailData} />
  52. </>
  53. )
  54. }
  55. type SSOAffiliationInfoProps = {
  56. userEmailData: UserEmailData
  57. }
  58. function SSOAffiliationInfo({ userEmailData }: SSOAffiliationInfoProps) {
  59. const { samlInitPath } = getMeta('ol-ExposedSettings')
  60. const { t } = useTranslation()
  61. const { state } = useUserEmailsContext()
  62. const location = useLocation()
  63. const [showUnlinkSSOModal, setShowUnlinkSSOModal] = useState(false)
  64. const [linkAccountsButtonDisabled, setLinkAccountsButtonDisabled] =
  65. useState(false)
  66. function handleLinkAccountsButtonClick() {
  67. setLinkAccountsButtonDisabled(true)
  68. location.assign(
  69. `${samlInitPath}?university_id=${userEmailData.affiliation?.institution?.id}&auto=/user/settings&email=${userEmailData.email}`
  70. )
  71. }
  72. if (
  73. !userEmailData.samlProviderId &&
  74. institutionAlreadyLinked(state, userEmailData)
  75. ) {
  76. // if the email is not linked to the institution, but there's another email already linked to that institution
  77. // no SSO affiliation is displayed, since cannot have multiple emails linked to the same institution
  78. return null
  79. }
  80. if (userEmailData.samlProviderId) {
  81. return (
  82. <OLRow>
  83. <OLCol lg={{ span: 8, offset: 4 }}>
  84. <div className="horizontal-divider" />
  85. <OLRow>
  86. <OLCol lg={9}>
  87. <EmailCell>
  88. <p>
  89. <Trans
  90. i18nKey="acct_linked_to_institution_acct_2"
  91. components={
  92. /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
  93. [<strong />]
  94. }
  95. values={{
  96. institutionName:
  97. userEmailData.affiliation?.institution.name,
  98. }}
  99. shouldUnescape
  100. tOptions={{ interpolation: { escapeValue: true } }}
  101. />
  102. </p>
  103. </EmailCell>
  104. </OLCol>
  105. <OLCol lg={3} className="text-lg-end">
  106. <EmailCell>
  107. <OLButton
  108. variant="secondary"
  109. size="sm"
  110. onClick={() => setShowUnlinkSSOModal(true)}
  111. >
  112. {t('unlink_sso')}
  113. </OLButton>
  114. <UnlinkCommonsSSOModal
  115. show={showUnlinkSSOModal}
  116. onClose={() => setShowUnlinkSSOModal(false)}
  117. institutionName={
  118. userEmailData.affiliation?.institution.name || ''
  119. }
  120. institutionEmail={userEmailData.email}
  121. hasLicence={userEmailData.emailHasInstitutionLicence || false}
  122. />
  123. </EmailCell>
  124. </OLCol>
  125. </OLRow>
  126. </OLCol>
  127. </OLRow>
  128. )
  129. }
  130. const domainAlsoForGroupWithDomainCapture =
  131. userEmailData?.affiliation?.group?.domainCaptureEnabled
  132. if (domainAlsoForGroupWithDomainCapture) {
  133. // user is not linked via Commons and should link via groups
  134. // do not show UI to link to Commons
  135. return null
  136. }
  137. return (
  138. <OLRow>
  139. <OLCol lg={{ span: 8, offset: 4 }}>
  140. <div className="horizontal-divider" />
  141. <OLRow>
  142. <OLCol lg={9}>
  143. <EmailCell>
  144. <p className="small">
  145. <Trans
  146. i18nKey="can_link_your_institution_acct_2"
  147. values={{
  148. institutionName:
  149. userEmailData.affiliation?.institution.name,
  150. }}
  151. shouldUnescape
  152. tOptions={{ interpolation: { escapeValue: true } }}
  153. components={
  154. /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
  155. [<strong />]
  156. }
  157. />
  158. </p>
  159. <p className="small">
  160. <Trans
  161. i18nKey="doing_this_allow_log_in_through_institution_2"
  162. components={
  163. /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
  164. [<strong />]
  165. }
  166. />{' '}
  167. <a href="/learn/how-to/Institutional_Login" target="_blank">
  168. {t('find_out_more_about_institution_login')}
  169. </a>
  170. </p>
  171. </EmailCell>
  172. </OLCol>
  173. <OLCol lg={3} className="text-lg-end">
  174. <EmailCell>
  175. <OLButton
  176. variant="primary"
  177. className="btn-link-accounts"
  178. disabled={linkAccountsButtonDisabled}
  179. onClick={handleLinkAccountsButtonClick}
  180. size="sm"
  181. >
  182. {t('link_accounts')}
  183. </OLButton>
  184. </EmailCell>
  185. </OLCol>
  186. </OLRow>
  187. </OLCol>
  188. </OLRow>
  189. )
  190. }
  191. export default EmailsRow