widget.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { useCallback, useState } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { Button, Modal } from 'react-bootstrap'
  4. import AccessibleModal from '../../../../shared/components/accessible-modal'
  5. import IEEELogo from '../../../../shared/svgs/ieee-logo'
  6. import GoogleLogo from '../../../../shared/svgs/google-logo'
  7. import OrcidLogo from '../../../../shared/svgs/orcid-logo'
  8. const providerLogos = {
  9. collabratec: <IEEELogo />,
  10. google: <GoogleLogo />,
  11. orcid: <OrcidLogo />,
  12. }
  13. type SSOLinkingWidgetProps = {
  14. providerId: string
  15. title: string
  16. description: string
  17. helpPath?: string
  18. linked?: boolean
  19. linkPath: string
  20. onUnlink: () => Promise<void>
  21. }
  22. export function SSOLinkingWidget({
  23. providerId,
  24. title,
  25. description,
  26. helpPath,
  27. linked,
  28. linkPath,
  29. onUnlink,
  30. }: SSOLinkingWidgetProps) {
  31. const { t } = useTranslation()
  32. const [showModal, setShowModal] = useState(false)
  33. const [unlinkRequestInflight, setUnlinkRequestInflight] = useState(false)
  34. const [errorMessage, setErrorMessage] = useState('')
  35. const handleUnlinkClick = useCallback(() => {
  36. setShowModal(true)
  37. }, [])
  38. const handleUnlinkConfirmationClick = useCallback(() => {
  39. setShowModal(false)
  40. setUnlinkRequestInflight(true)
  41. onUnlink()
  42. .catch((error: Error) => {
  43. setErrorMessage(error.message)
  44. })
  45. .finally(() => {
  46. setUnlinkRequestInflight(false)
  47. })
  48. }, [onUnlink])
  49. const handleModalHide = useCallback(() => {
  50. setShowModal(false)
  51. }, [])
  52. return (
  53. <div className="settings-widget-container">
  54. <div>{providerLogos[providerId]}</div>
  55. <div className="description-container">
  56. <div className="title-row">
  57. <h4>{title}</h4>
  58. </div>
  59. <p>
  60. {description?.replace(/<[^>]+>/g, '')}{' '}
  61. {helpPath ? (
  62. <a href={helpPath} target="_blank" rel="noreferrer">
  63. {t('learn_more')}
  64. </a>
  65. ) : null}
  66. </p>
  67. {errorMessage && <div>{errorMessage} </div>}
  68. </div>
  69. <div>
  70. <ActionButton
  71. unlinkRequestInflight={unlinkRequestInflight}
  72. accountIsLinked={linked}
  73. linkPath={linkPath}
  74. onUnlinkClick={handleUnlinkClick}
  75. />
  76. </div>
  77. <UnlinkConfirmModal
  78. title={title}
  79. show={showModal}
  80. handleConfirmation={handleUnlinkConfirmationClick}
  81. handleHide={handleModalHide}
  82. />
  83. </div>
  84. )
  85. }
  86. type ActionButtonProps = {
  87. unlinkRequestInflight: boolean
  88. accountIsLinked?: boolean
  89. linkPath: string
  90. onUnlinkClick: () => void
  91. }
  92. function ActionButton({
  93. unlinkRequestInflight,
  94. accountIsLinked,
  95. linkPath,
  96. onUnlinkClick,
  97. }: ActionButtonProps) {
  98. const { t } = useTranslation()
  99. if (unlinkRequestInflight) {
  100. return (
  101. <Button bsStyle="danger" disabled>
  102. {t('unlinking')}
  103. </Button>
  104. )
  105. } else if (accountIsLinked) {
  106. return (
  107. <Button bsStyle="danger" onClick={onUnlinkClick}>
  108. {t('unlink')}
  109. </Button>
  110. )
  111. } else {
  112. return (
  113. <a href={linkPath} className="btn btn-primary text-capitalize">
  114. {t('link')}
  115. </a>
  116. )
  117. }
  118. }
  119. type UnlinkConfirmModalProps = {
  120. title: string
  121. show: boolean
  122. handleConfirmation: () => void
  123. handleHide: () => void
  124. }
  125. function UnlinkConfirmModal({
  126. title,
  127. show,
  128. handleConfirmation,
  129. handleHide,
  130. }: UnlinkConfirmModalProps) {
  131. const { t } = useTranslation()
  132. return (
  133. <AccessibleModal show={show} onHide={handleHide}>
  134. <Modal.Header closeButton>
  135. <Modal.Title>
  136. {t('unlink_provider_account_title', { provider: title })}
  137. </Modal.Title>
  138. </Modal.Header>
  139. <Modal.Body className="modal-body-share">
  140. <p>{t('unlink_provider_account_warning', { provider: title })}</p>
  141. </Modal.Body>
  142. <Modal.Footer>
  143. <Button bsStyle="default" onClick={handleHide}>
  144. {t('cancel')}
  145. </Button>
  146. <Button bsStyle="danger" onClick={handleConfirmation}>
  147. {t('unlink')}
  148. </Button>
  149. </Modal.Footer>
  150. </AccessibleModal>
  151. )
  152. }