linking-section.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { useState } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
  4. import { useSSOContext, SSOSubscription } from '../context/sso-context'
  5. import { SSOLinkingWidget } from './linking/sso-widget'
  6. import getMeta from '../../../utils/meta'
  7. function LinkingSection() {
  8. const { t } = useTranslation()
  9. const { subscriptions } = useSSOContext()
  10. const [integrationLinkingWidgets] = useState(
  11. () =>
  12. getMeta('integrationLinkingWidgets') ||
  13. importOverleafModules('integrationLinkingWidgets')
  14. )
  15. const [referenceLinkingWidgets] = useState(
  16. () =>
  17. getMeta('referenceLinkingWidgets') ||
  18. importOverleafModules('referenceLinkingWidgets')
  19. )
  20. const hasIntegrationLinkingSection = integrationLinkingWidgets.length
  21. const hasReferencesLinkingSection = referenceLinkingWidgets.length
  22. const hasSSOLinkingSection = Object.keys(subscriptions).length > 0
  23. if (
  24. !hasIntegrationLinkingSection &&
  25. !hasReferencesLinkingSection &&
  26. !hasSSOLinkingSection
  27. ) {
  28. return null
  29. }
  30. return (
  31. <>
  32. <h3>{t('integrations')}</h3>
  33. <p className="small">{t('linked_accounts_explained')}</p>
  34. {hasIntegrationLinkingSection ? (
  35. <>
  36. <h3 id="project-sync" className="text-capitalize">
  37. {t('sync_dropbox_github')}
  38. </h3>
  39. <div className="settings-widgets-container">
  40. {integrationLinkingWidgets.map(
  41. ({ import: importObject, path }, widgetIndex) => (
  42. <ModuleLinkingWidget
  43. key={Object.keys(importObject)[0]}
  44. ModuleComponent={Object.values(importObject)[0]}
  45. isLast={widgetIndex === integrationLinkingWidgets.length - 1}
  46. />
  47. )
  48. )}
  49. </div>
  50. </>
  51. ) : null}
  52. {hasReferencesLinkingSection ? (
  53. <>
  54. <h3 id="references" className="text-capitalize">
  55. {t('reference_sync')}
  56. </h3>
  57. <div className="settings-widgets-container">
  58. {referenceLinkingWidgets.map(
  59. ({ import: importObject, path }, widgetIndex) => (
  60. <ModuleLinkingWidget
  61. key={Object.keys(importObject)[0]}
  62. ModuleComponent={Object.values(importObject)[0]}
  63. isLast={widgetIndex === referenceLinkingWidgets.length - 1}
  64. />
  65. )
  66. )}
  67. </div>
  68. </>
  69. ) : null}
  70. {hasSSOLinkingSection ? (
  71. <>
  72. <h3 id="linked-accounts" className="text-capitalize">
  73. {t('linked_accounts')}
  74. </h3>
  75. <div className="settings-widgets-container">
  76. {Object.values(subscriptions).map(
  77. (subscription, subscriptionIndex) => (
  78. <SSOLinkingWidgetContainer
  79. key={subscription.providerId}
  80. subscription={subscription}
  81. isLast={
  82. subscriptionIndex === Object.keys(subscriptions).length - 1
  83. }
  84. />
  85. )
  86. )}
  87. </div>
  88. </>
  89. ) : null}
  90. {hasIntegrationLinkingSection ||
  91. hasReferencesLinkingSection ||
  92. hasSSOLinkingSection ? (
  93. <hr />
  94. ) : null}
  95. </>
  96. )
  97. }
  98. type LinkingWidgetProps = {
  99. ModuleComponent: any
  100. isLast: boolean
  101. }
  102. function ModuleLinkingWidget({ ModuleComponent, isLast }: LinkingWidgetProps) {
  103. return (
  104. <>
  105. <ModuleComponent />
  106. {isLast ? null : <hr />}
  107. </>
  108. )
  109. }
  110. type SSOLinkingWidgetContainerProps = {
  111. subscription: SSOSubscription
  112. isLast: boolean
  113. }
  114. function SSOLinkingWidgetContainer({
  115. subscription,
  116. isLast,
  117. }: SSOLinkingWidgetContainerProps) {
  118. const { t } = useTranslation()
  119. const { unlink } = useSSOContext()
  120. let description = null
  121. switch (subscription.providerId) {
  122. case 'collabratec':
  123. description = t('linked_collabratec_description')
  124. break
  125. case 'google':
  126. case 'twitter':
  127. description = t('login_with_service', {
  128. service: subscription.provider.name,
  129. })
  130. break
  131. case 'orcid':
  132. description = t('oauth_orcid_description')
  133. break
  134. }
  135. return (
  136. <>
  137. <SSOLinkingWidget
  138. providerId={subscription.providerId}
  139. title={subscription.provider.name}
  140. description={description}
  141. helpPath={subscription.provider.descriptionOptions?.link}
  142. linked={subscription.linked}
  143. linkPath={subscription.provider.linkPath}
  144. onUnlink={() => unlink(subscription.providerId)}
  145. />
  146. {isLast ? null : <hr />}
  147. </>
  148. )
  149. }
  150. export default LinkingSection