toolbar-header.jsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import React from 'react'
  2. import PropTypes from 'prop-types'
  3. import { useTranslation } from 'react-i18next'
  4. import MenuButton from './menu-button'
  5. import CobrandingLogo from './cobranding-logo'
  6. import BackToProjectsButton from './back-to-projects-button'
  7. import UpgradePrompt from './upgrade-prompt'
  8. import ChatToggleButton from './chat-toggle-button'
  9. import LayoutDropdownButton from './layout-dropdown-button'
  10. import OnlineUsersWidget from './online-users-widget'
  11. import ProjectNameEditableLabel from './project-name-editable-label'
  12. import TrackChangesToggleButton from './track-changes-toggle-button'
  13. import HistoryToggleButton from './history-toggle-button'
  14. import ShareProjectButton from './share-project-button'
  15. import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
  16. import BackToEditorButton from './back-to-editor-button'
  17. import getMeta from '@/utils/meta'
  18. import { isSplitTestEnabled } from '@/utils/splitTestUtils'
  19. import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
  20. const [publishModalModules] = importOverleafModules('publishModal')
  21. const PublishButton = publishModalModules?.import.default
  22. const offlineModeToolbarButtons = importOverleafModules(
  23. 'offlineModeToolbarButtons'
  24. )
  25. // double opt-in
  26. const enableROMirrorOnClient =
  27. isSplitTestEnabled('ro-mirror-on-client') &&
  28. new URLSearchParams(window.location.search).get('ro-mirror-on-client') ===
  29. 'enabled'
  30. const ToolbarHeader = React.memo(function ToolbarHeader({
  31. cobranding,
  32. onShowLeftMenuClick,
  33. chatIsOpen,
  34. toggleChatOpen,
  35. reviewPanelOpen,
  36. toggleReviewPanelOpen,
  37. historyIsOpen,
  38. toggleHistoryOpen,
  39. unreadMessageCount,
  40. onlineUsers,
  41. goToUser,
  42. isRestrictedTokenMember,
  43. hasPublishPermissions,
  44. chatVisible,
  45. projectName,
  46. renameProject,
  47. hasRenamePermissions,
  48. openShareModal,
  49. trackChangesVisible,
  50. }) {
  51. const chatEnabled = getMeta('ol-chatEnabled')
  52. const { t } = useTranslation()
  53. const shouldDisplayPublishButton = hasPublishPermissions && PublishButton
  54. return (
  55. <header
  56. className="toolbar toolbar-header"
  57. role="navigation"
  58. aria-label={t('project_layout_sharing_submission')}
  59. >
  60. <div className="toolbar-left">
  61. <MenuButton onClick={onShowLeftMenuClick} />
  62. {cobranding && cobranding.logoImgUrl && (
  63. <CobrandingLogo {...cobranding} />
  64. )}
  65. <BackToProjectsButton />
  66. {enableROMirrorOnClient &&
  67. offlineModeToolbarButtons.map(
  68. ({ path, import: { default: OfflineModeToolbarButton } }) => {
  69. return <OfflineModeToolbarButton key={path} />
  70. }
  71. )}
  72. </div>
  73. {getMeta('ol-showUpgradePrompt') && (
  74. <BootstrapVersionSwitcher
  75. bs3={<UpgradePrompt />}
  76. bs5={
  77. <div className="d-flex align-items-center">
  78. <UpgradePrompt />
  79. </div>
  80. }
  81. />
  82. )}
  83. <ProjectNameEditableLabel
  84. className="toolbar-center"
  85. projectName={projectName}
  86. hasRenamePermissions={hasRenamePermissions}
  87. onChange={renameProject}
  88. />
  89. <div className="toolbar-right">
  90. <OnlineUsersWidget onlineUsers={onlineUsers} goToUser={goToUser} />
  91. {historyIsOpen ? (
  92. <BootstrapVersionSwitcher
  93. bs3={<BackToEditorButton onClick={toggleHistoryOpen} />}
  94. bs5={
  95. <div className="d-flex align-items-center">
  96. <BackToEditorButton onClick={toggleHistoryOpen} />
  97. </div>
  98. }
  99. />
  100. ) : (
  101. <>
  102. {trackChangesVisible && (
  103. <TrackChangesToggleButton
  104. onMouseDown={toggleReviewPanelOpen}
  105. disabled={historyIsOpen}
  106. trackChangesIsOpen={reviewPanelOpen}
  107. />
  108. )}
  109. <ShareProjectButton onClick={openShareModal} />
  110. {shouldDisplayPublishButton && (
  111. <PublishButton cobranding={cobranding} />
  112. )}
  113. {!isRestrictedTokenMember && (
  114. <HistoryToggleButton onClick={toggleHistoryOpen} />
  115. )}
  116. <LayoutDropdownButton />
  117. {chatEnabled && chatVisible && (
  118. <ChatToggleButton
  119. chatIsOpen={chatIsOpen}
  120. onClick={toggleChatOpen}
  121. unreadMessageCount={unreadMessageCount}
  122. />
  123. )}
  124. </>
  125. )}
  126. </div>
  127. </header>
  128. )
  129. })
  130. ToolbarHeader.propTypes = {
  131. onShowLeftMenuClick: PropTypes.func.isRequired,
  132. cobranding: PropTypes.object,
  133. chatIsOpen: PropTypes.bool,
  134. toggleChatOpen: PropTypes.func.isRequired,
  135. reviewPanelOpen: PropTypes.bool,
  136. toggleReviewPanelOpen: PropTypes.func.isRequired,
  137. historyIsOpen: PropTypes.bool,
  138. toggleHistoryOpen: PropTypes.func.isRequired,
  139. unreadMessageCount: PropTypes.number.isRequired,
  140. onlineUsers: PropTypes.array.isRequired,
  141. goToUser: PropTypes.func.isRequired,
  142. isRestrictedTokenMember: PropTypes.bool,
  143. hasPublishPermissions: PropTypes.bool,
  144. chatVisible: PropTypes.bool,
  145. projectName: PropTypes.string.isRequired,
  146. renameProject: PropTypes.func.isRequired,
  147. hasRenamePermissions: PropTypes.bool,
  148. openShareModal: PropTypes.func.isRequired,
  149. trackChangesVisible: PropTypes.bool,
  150. }
  151. export default ToolbarHeader