project-list-root.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 './notifications/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. function ProjectListRoot() {
  27. const { isReady } = useWaitForI18n()
  28. return isReady ? (
  29. <ProjectListProvider>
  30. <ColorPickerProvider>
  31. <ProjectListPageContent />
  32. </ColorPickerProvider>
  33. </ProjectListProvider>
  34. ) : null
  35. }
  36. function ProjectListPageContent() {
  37. const {
  38. totalProjectsCount,
  39. error,
  40. isLoading,
  41. loadProgress,
  42. searchText,
  43. setSearchText,
  44. selectedProjects,
  45. filter,
  46. tags,
  47. selectedTagId,
  48. } = useProjectListContext()
  49. const selectedTag = tags.find(tag => tag._id === selectedTagId)
  50. useEffect(() => {
  51. eventTracking.sendMB('loads_v2_dash', {})
  52. }, [])
  53. return isLoading ? (
  54. <div className="loading-container">
  55. <LoadingBranded loadProgress={loadProgress} />
  56. </div>
  57. ) : (
  58. <>
  59. <SystemMessages />
  60. <div className="project-list-wrapper clearfix">
  61. {totalProjectsCount > 0 ? (
  62. <>
  63. <Sidebar />
  64. <div className="project-list-main-react">
  65. {error ? <DashApiError /> : ''}
  66. <Row>
  67. <Col xs={12}>
  68. <UserNotifications />
  69. </Col>
  70. </Row>
  71. <div className="project-list-header-row">
  72. <ProjectListTitle
  73. filter={filter}
  74. selectedTag={selectedTag}
  75. className="hidden-xs text-truncate"
  76. />
  77. <div className="project-tools">
  78. <div className="hidden-xs">
  79. {selectedProjects.length === 0 ? (
  80. <CurrentPlanWidget />
  81. ) : (
  82. <ProjectTools />
  83. )}
  84. </div>
  85. <div className="visible-xs">
  86. <CurrentPlanWidget />
  87. </div>
  88. </div>
  89. </div>
  90. <Row className="hidden-xs">
  91. <Col md={7}>
  92. <SearchForm
  93. inputValue={searchText}
  94. setInputValue={setSearchText}
  95. filter={filter}
  96. selectedTag={selectedTag}
  97. />
  98. </Col>
  99. </Row>
  100. <div className="project-list-sidebar-survey-wrapper visible-xs">
  101. <SurveyWidget />
  102. </div>
  103. <div className="visible-xs mt-1">
  104. <div role="toolbar" className="projects-toolbar">
  105. <ProjectsDropdown />
  106. <SortByDropdown />
  107. </div>
  108. </div>
  109. <Row className="row-spaced">
  110. <Col xs={12}>
  111. <div className="card project-list-card">
  112. <div className="visible-xs pt-2 pb-3">
  113. <div className="clearfix">
  114. <NewProjectButton
  115. id="new-project-button-projects-table"
  116. className="pull-left me-2"
  117. showAddAffiliationWidget
  118. />
  119. <SearchForm
  120. inputValue={searchText}
  121. setInputValue={setSearchText}
  122. filter={filter}
  123. selectedTag={selectedTag}
  124. className="overflow-hidden"
  125. formGroupProps={{ className: 'mb-0' }}
  126. />
  127. </div>
  128. </div>
  129. <ProjectListTable />
  130. </div>
  131. </Col>
  132. </Row>
  133. <Row className="row-spaced">
  134. <Col xs={12}>
  135. <LoadMore />
  136. </Col>
  137. </Row>
  138. </div>
  139. </>
  140. ) : (
  141. <div className="project-list-welcome-wrapper">
  142. {error ? <DashApiError /> : ''}
  143. <Row className="row-spaced">
  144. <Col
  145. sm={10}
  146. smOffset={1}
  147. md={8}
  148. mdOffset={2}
  149. className="project-list-empty-col"
  150. >
  151. <Row>
  152. <Col xs={12}>
  153. <UserNotifications />
  154. </Col>
  155. </Row>
  156. <WelcomeMessage />
  157. </Col>
  158. </Row>
  159. </div>
  160. )}
  161. </div>
  162. </>
  163. )
  164. }
  165. function DashApiError() {
  166. const { t } = useTranslation()
  167. return (
  168. <Row className="row-spaced">
  169. <Col xs={8} xsOffset={2} aria-live="polite" className="text-center">
  170. <div className="alert alert-danger">
  171. {t('generic_something_went_wrong')}
  172. </div>
  173. </Col>
  174. </Row>
  175. )
  176. }
  177. export default ProjectListRoot