toolbar-header.jsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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 { canUseNewEditor } from '@/features/ide-redesign/utils/new-editor-utils'
  20. import TryNewEditorButton from '../try-new-editor-button'
  21. const [publishModalModules] = importOverleafModules('publishModal')
  22. const PublishButton = publishModalModules?.import.default
  23. const offlineModeToolbarButtons = importOverleafModules(
  24. 'offlineModeToolbarButtons'
  25. )
  26. // double opt-in
  27. const enableROMirrorOnClient =
  28. isSplitTestEnabled('ro-mirror-on-client') &&
  29. new URLSearchParams(window.location.search).get('ro-mirror-on-client') ===
  30. 'enabled'
  31. const ToolbarHeader = React.memo(function ToolbarHeader({
  32. cobranding,
  33. onShowLeftMenuClick,
  34. chatIsOpen,
  35. toggleChatOpen,
  36. reviewPanelOpen,
  37. toggleReviewPanelOpen,
  38. historyIsOpen,
  39. toggleHistoryOpen,
  40. unreadMessageCount,
  41. onlineUsers,
  42. goToUser,
  43. isRestrictedTokenMember,
  44. hasPublishPermissions,
  45. chatVisible,
  46. projectName,
  47. renameProject,
  48. hasRenamePermissions,
  49. openShareModal,
  50. trackChangesVisible,
  51. }) {
  52. const chatEnabled = getMeta('ol-chatEnabled')
  53. const { t } = useTranslation()
  54. const shouldDisplayPublishButton = hasPublishPermissions && PublishButton
  55. return (
  56. <header
  57. className="toolbar toolbar-header"
  58. role="navigation"
  59. aria-label={t('project_layout_sharing_submission')}
  60. >
  61. <div className="toolbar-left">
  62. <MenuButton onClick={onShowLeftMenuClick} />
  63. {cobranding && cobranding.logoImgUrl && (
  64. <CobrandingLogo {...cobranding} />
  65. )}
  66. <BackToProjectsButton />
  67. {enableROMirrorOnClient &&
  68. offlineModeToolbarButtons.map(
  69. ({ path, import: { default: OfflineModeToolbarButton } }) => {
  70. return <OfflineModeToolbarButton key={path} />
  71. }
  72. )}
  73. </div>
  74. {getMeta('ol-showUpgradePrompt') && (
  75. <div className="d-flex align-items-center">
  76. <UpgradePrompt />
  77. </div>
  78. )}
  79. <ProjectNameEditableLabel
  80. className="toolbar-center"
  81. projectName={projectName}
  82. hasRenamePermissions={hasRenamePermissions}
  83. onChange={renameProject}
  84. />
  85. <div className="toolbar-right">
  86. {canUseNewEditor() && <TryNewEditorButton />}
  87. <OnlineUsersWidget onlineUsers={onlineUsers} goToUser={goToUser} />
  88. {historyIsOpen ? (
  89. <div className="d-flex align-items-center">
  90. <BackToEditorButton onClick={toggleHistoryOpen} />
  91. </div>
  92. ) : (
  93. <>
  94. {trackChangesVisible && (
  95. <TrackChangesToggleButton
  96. onMouseDown={toggleReviewPanelOpen}
  97. disabled={historyIsOpen}
  98. trackChangesIsOpen={reviewPanelOpen}
  99. />
  100. )}
  101. <ShareProjectButton onClick={openShareModal} />
  102. {shouldDisplayPublishButton && (
  103. <PublishButton cobranding={cobranding} />
  104. )}
  105. {!isRestrictedTokenMember && (
  106. <HistoryToggleButton onClick={toggleHistoryOpen} />
  107. )}
  108. <LayoutDropdownButton />
  109. {chatEnabled && chatVisible && (
  110. <ChatToggleButton
  111. chatIsOpen={chatIsOpen}
  112. onClick={toggleChatOpen}
  113. unreadMessageCount={unreadMessageCount}
  114. />
  115. )}
  116. </>
  117. )}
  118. </div>
  119. </header>
  120. )
  121. })
  122. ToolbarHeader.propTypes = {
  123. onShowLeftMenuClick: PropTypes.func.isRequired,
  124. cobranding: PropTypes.object,
  125. chatIsOpen: PropTypes.bool,
  126. toggleChatOpen: PropTypes.func.isRequired,
  127. reviewPanelOpen: PropTypes.bool,
  128. toggleReviewPanelOpen: PropTypes.func.isRequired,
  129. historyIsOpen: PropTypes.bool,
  130. toggleHistoryOpen: PropTypes.func.isRequired,
  131. unreadMessageCount: PropTypes.number.isRequired,
  132. onlineUsers: PropTypes.array.isRequired,
  133. goToUser: PropTypes.func.isRequired,
  134. isRestrictedTokenMember: PropTypes.bool,
  135. hasPublishPermissions: PropTypes.bool,
  136. chatVisible: PropTypes.bool,
  137. projectName: PropTypes.string.isRequired,
  138. renameProject: PropTypes.func.isRequired,
  139. hasRenamePermissions: PropTypes.bool,
  140. openShareModal: PropTypes.func.isRequired,
  141. trackChangesVisible: PropTypes.bool,
  142. }
  143. export default ToolbarHeader