project-list-root.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import {
  2. ProjectListProvider,
  3. useProjectListContext,
  4. } from '../context/project-list-context'
  5. import { ColorPickerProvider } from '../context/color-picker-context'
  6. import * as eventTracking from '../../../infrastructure/event-tracking'
  7. import { Col, Row } from 'react-bootstrap'
  8. import { useTranslation } from 'react-i18next'
  9. import useWaitForI18n from '../../../shared/hooks/use-wait-for-i18n'
  10. import CurrentPlanWidget from './current-plan-widget/current-plan-widget'
  11. import NewProjectButton from './new-project-button'
  12. import ProjectListTable from './table/project-list-table'
  13. import SurveyWidget from './survey-widget'
  14. import WelcomeMessage from './welcome-message'
  15. import LoadingBranded from '../../../shared/components/loading-branded'
  16. import SystemMessages from '../../../shared/components/system-messages'
  17. import UserNotifications from './notifications/user-notifications'
  18. import SearchForm from './search-form'
  19. import ProjectsDropdown from './dropdown/projects-dropdown'
  20. import SortByDropdown from './dropdown/sort-by-dropdown'
  21. import ProjectTools from './table/project-tools/project-tools'
  22. import ProjectListTitle from './title/project-list-title'
  23. import Sidebar from './sidebar/sidebar'
  24. import LoadMore from './load-more'
  25. import { useEffect } from 'react'
  26. import getMeta from '../../../utils/meta'
  27. import WelcomeMessageNew from './welcome-message-new'
  28. import withErrorBoundary from '../../../infrastructure/error-boundary'
  29. import { GenericErrorBoundaryFallback } from '../../../shared/components/generic-error-boundary-fallback'
  30. function ProjectListRoot() {
  31. const { isReady } = useWaitForI18n()
  32. if (!isReady) {
  33. return null
  34. }
  35. return <ProjectListRootInner />
  36. }
  37. export function ProjectListRootInner() {
  38. return (
  39. <ProjectListProvider>
  40. <ColorPickerProvider>
  41. <ProjectListPageContent />
  42. </ColorPickerProvider>
  43. </ProjectListProvider>
  44. )
  45. }
  46. function ProjectListPageContent() {
  47. const {
  48. totalProjectsCount,
  49. error,
  50. isLoading,
  51. loadProgress,
  52. searchText,
  53. setSearchText,
  54. selectedProjects,
  55. filter,
  56. tags,
  57. selectedTagId,
  58. } = useProjectListContext()
  59. const selectedTag = tags.find(tag => tag._id === selectedTagId)
  60. const welcomePageRedesignVariant = getMeta(
  61. 'ol-welcomePageRedesignVariant'
  62. ) as 'enabled' | 'default'
  63. useEffect(() => {
  64. eventTracking.sendMB('loads_v2_dash', {})
  65. }, [])
  66. return isLoading ? (
  67. <div className="loading-container">
  68. <LoadingBranded loadProgress={loadProgress} />
  69. </div>
  70. ) : (
  71. <>
  72. <SystemMessages />
  73. <div className="project-list-wrapper clearfix">
  74. {totalProjectsCount > 0 ? (
  75. <>
  76. <Sidebar />
  77. <div className="project-list-main-react">
  78. {error ? <DashApiError /> : ''}
  79. <Row>
  80. <Col xs={12}>
  81. <UserNotifications />
  82. </Col>
  83. </Row>
  84. <div className="project-list-header-row">
  85. <ProjectListTitle
  86. filter={filter}
  87. selectedTag={selectedTag}
  88. className="hidden-xs text-truncate"
  89. />
  90. <div className="project-tools">
  91. <div className="hidden-xs">
  92. {selectedProjects.length === 0 ? (
  93. <CurrentPlanWidget />
  94. ) : (
  95. <ProjectTools />
  96. )}
  97. </div>
  98. <div className="visible-xs">
  99. <CurrentPlanWidget />
  100. </div>
  101. </div>
  102. </div>
  103. <Row className="hidden-xs">
  104. <Col md={7}>
  105. <SearchForm
  106. inputValue={searchText}
  107. setInputValue={setSearchText}
  108. filter={filter}
  109. selectedTag={selectedTag}
  110. />
  111. </Col>
  112. </Row>
  113. <div className="project-list-sidebar-survey-wrapper visible-xs">
  114. <SurveyWidget />
  115. </div>
  116. <div className="visible-xs mt-1">
  117. <div role="toolbar" className="projects-toolbar">
  118. <ProjectsDropdown />
  119. <SortByDropdown />
  120. </div>
  121. </div>
  122. <Row className="row-spaced">
  123. <Col xs={12}>
  124. <div className="card project-list-card">
  125. <div className="visible-xs pt-2 pb-3">
  126. <div className="clearfix">
  127. <NewProjectButton
  128. id="new-project-button-projects-table"
  129. className="pull-left me-2"
  130. showAddAffiliationWidget
  131. />
  132. <SearchForm
  133. inputValue={searchText}
  134. setInputValue={setSearchText}
  135. filter={filter}
  136. selectedTag={selectedTag}
  137. className="overflow-hidden"
  138. formGroupProps={{ className: 'mb-0' }}
  139. />
  140. </div>
  141. </div>
  142. <ProjectListTable />
  143. </div>
  144. </Col>
  145. </Row>
  146. <Row className="row-spaced">
  147. <Col xs={12}>
  148. <LoadMore />
  149. </Col>
  150. </Row>
  151. </div>
  152. </>
  153. ) : (
  154. <div className="project-list-welcome-wrapper">
  155. {error ? <DashApiError /> : ''}
  156. <Row className="row-spaced">
  157. <Col
  158. sm={10}
  159. smOffset={1}
  160. md={8}
  161. mdOffset={2}
  162. className="project-list-empty-col"
  163. >
  164. <Row>
  165. <Col xs={12}>
  166. <UserNotifications />
  167. </Col>
  168. </Row>
  169. {welcomePageRedesignVariant === 'enabled' ? (
  170. <WelcomeMessageNew />
  171. ) : (
  172. <WelcomeMessage />
  173. )}
  174. </Col>
  175. </Row>
  176. </div>
  177. )}
  178. </div>
  179. </>
  180. )
  181. }
  182. function DashApiError() {
  183. const { t } = useTranslation()
  184. return (
  185. <Row className="row-spaced">
  186. <Col xs={8} xsOffset={2} aria-live="polite" className="text-center">
  187. <div className="alert alert-danger">
  188. {t('generic_something_went_wrong')}
  189. </div>
  190. </Col>
  191. </Row>
  192. )
  193. }
  194. export default withErrorBoundary(ProjectListRoot, GenericErrorBoundaryFallback)