project-list-ds-nav.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { useProjectListContext } from '../context/project-list-context'
  2. import { useTranslation } from 'react-i18next'
  3. import CurrentPlanWidget from './current-plan-widget/current-plan-widget'
  4. import NewProjectButton from './new-project-button'
  5. import ProjectListTable from './table/project-list-table'
  6. import UserNotifications from './notifications/user-notifications'
  7. import SearchForm from './search-form'
  8. import ProjectsDropdown from './dropdown/projects-dropdown'
  9. import SortByDropdown from './dropdown/sort-by-dropdown'
  10. import ProjectTools from './table/project-tools/project-tools'
  11. import ProjectListTitle from './title/project-list-title'
  12. import LoadMore from './load-more'
  13. import OLCol from '@/shared/components/ol/ol-col'
  14. import OLRow from '@/shared/components/ol/ol-row'
  15. import { TableContainer } from '@/shared/components/table'
  16. import DashApiError from '@/features/project-list/components/dash-api-error'
  17. import getMeta from '@/utils/meta'
  18. import DefaultNavbar from '@/shared/components/navbar/default-navbar'
  19. import Footer from '@/shared/components/footer/footer'
  20. import SidebarDsNav from '@/features/project-list/components/sidebar/sidebar-ds-nav'
  21. import SystemMessages from '@/shared/components/system-messages'
  22. import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg'
  23. import overleafLogoDark from '@/shared/svgs/overleaf-a-ds-solution-mallard-dark.svg'
  24. import CookieBanner from '@/shared/components/cookie-banner'
  25. import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
  26. import { isSplitTestEnabled } from '@/utils/splitTestUtils'
  27. export function ProjectListDsNav() {
  28. const navbarProps = getMeta('ol-navbar')
  29. const footerProps = getMeta('ol-footer')
  30. const { t } = useTranslation()
  31. const {
  32. error,
  33. searchText,
  34. setSearchText,
  35. selectedProjects,
  36. filter,
  37. tags,
  38. selectedTagId,
  39. } = useProjectListContext()
  40. const activeOverallTheme = useActiveOverallTheme()
  41. const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
  42. const selectedTag = tags.find(tag => tag._id === selectedTagId)
  43. const showNewProjectButton =
  44. !isLibraryEnabled ||
  45. (filter !== 'shared' && filter !== 'archived' && filter !== 'trashed')
  46. const tableTopArea = (
  47. <div className="pt-2 pb-3 d-md-none d-flex gap-2">
  48. {isLibraryEnabled ? (
  49. <>
  50. <SearchForm
  51. inputValue={searchText}
  52. setInputValue={setSearchText}
  53. filter={filter}
  54. selectedTag={selectedTag}
  55. className="overflow-hidden flex-grow-1"
  56. />
  57. {showNewProjectButton && (
  58. <NewProjectButton
  59. id="new-project-button-projects-table"
  60. showAddAffiliationWidget
  61. />
  62. )}
  63. </>
  64. ) : (
  65. <>
  66. <NewProjectButton
  67. id="new-project-button-projects-table"
  68. showAddAffiliationWidget
  69. />
  70. <SearchForm
  71. inputValue={searchText}
  72. setInputValue={setSearchText}
  73. filter={filter}
  74. selectedTag={selectedTag}
  75. className="overflow-hidden flex-grow-1"
  76. />
  77. </>
  78. )}
  79. </div>
  80. )
  81. return (
  82. <div
  83. className={`project-ds-nav-page website-redesign${isLibraryEnabled ? ' library-enabled' : ''}`}
  84. >
  85. <SystemMessages />
  86. <DefaultNavbar
  87. {...navbarProps}
  88. overleafLogo={
  89. activeOverallTheme === 'dark' ? overleafLogoDark : overleafLogo
  90. }
  91. showCloseIcon
  92. />
  93. <div className="project-list-wrapper">
  94. <SidebarDsNav />
  95. <div className="project-ds-nav-content-and-messages">
  96. <div className="project-ds-nav-content">
  97. <div className="project-ds-nav-main">
  98. {error ? <DashApiError /> : ''}
  99. <UserNotifications />
  100. <main aria-labelledby="main-content">
  101. <div className="project-list-header-row">
  102. <ProjectListTitle
  103. filter={filter}
  104. selectedTag={selectedTag}
  105. selectedTagId={selectedTagId}
  106. className="text-truncate d-none d-md-block"
  107. />
  108. <div className="project-tools">
  109. <div className="d-none d-md-block">
  110. {selectedProjects.length === 0 ? (
  111. <CurrentPlanWidget />
  112. ) : (
  113. <ProjectTools />
  114. )}
  115. </div>
  116. <div className="d-md-none">
  117. <CurrentPlanWidget />
  118. </div>
  119. </div>
  120. </div>
  121. <div className="project-ds-nav-project-list">
  122. <OLRow className="d-none d-md-flex align-items-center">
  123. <OLCol md={isLibraryEnabled ? 8 : undefined} lg={7}>
  124. <SearchForm
  125. inputValue={searchText}
  126. setInputValue={setSearchText}
  127. filter={filter}
  128. selectedTag={selectedTag}
  129. />
  130. </OLCol>
  131. {isLibraryEnabled && showNewProjectButton && (
  132. <OLCol className="ms-auto" xs="auto">
  133. <NewProjectButton
  134. id="new-project-button-projects-table"
  135. showAddAffiliationWidget
  136. align="end"
  137. />
  138. </OLCol>
  139. )}
  140. </OLRow>
  141. <div className="project-list-sidebar-survey-wrapper d-md-none">
  142. {/* Omit the survey card in mobile view for now */}
  143. </div>
  144. <div className="mt-1 d-md-none">
  145. <div
  146. role="toolbar"
  147. className="projects-toolbar"
  148. aria-label={t('projects')}
  149. >
  150. <ProjectsDropdown />
  151. <SortByDropdown />
  152. </div>
  153. </div>
  154. <div className="mt-3">
  155. <TableContainer bordered>
  156. {tableTopArea}
  157. <ProjectListTable />
  158. </TableContainer>
  159. </div>
  160. <div className="mt-3">
  161. <LoadMore />
  162. </div>
  163. </div>
  164. </main>
  165. </div>
  166. <Footer {...footerProps} />
  167. </div>
  168. <CookieBanner />
  169. </div>
  170. </div>
  171. </div>
  172. )
  173. }