Sidebar.jsx 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import React from 'react'
  2. import { connect } from 'react-redux'
  3. import { withRouter } from 'react-router'
  4. import classnames from 'classnames'
  5. import { translate } from 'react-i18next'
  6. import appFactory from '../appFactory.js'
  7. import WorkspaceListItem from '../component/Sidebar/WorkspaceListItem.jsx'
  8. import {
  9. setAppList,
  10. setContentTypeList,
  11. setWorkspaceListIsOpenInSidebar,
  12. updateWorkspaceFilter,
  13. updateWorkspaceListData
  14. } from '../action-creator.sync.js'
  15. import {
  16. getAppList, getContentTypeList,
  17. getWorkspaceList
  18. } from '../action-creator.async.js'
  19. import { PAGE, workspaceConfig } from '../helper.js'
  20. const qs = require('query-string')
  21. class Sidebar extends React.Component {
  22. constructor (props) {
  23. super(props)
  24. this.state = {
  25. sidebarClose: false,
  26. workspaceIdInUrl: props.match && props.match.params.idws ? parseInt(props.match.params.idws) : null
  27. }
  28. document.addEventListener('appCustomEvent', this.customEventReducer)
  29. }
  30. customEventReducer = async ({ detail: { type, data } }) => {
  31. switch (type) {
  32. case 'refreshWorkspaceList':
  33. console.log('%c<Sidebar> Custom event', 'color: #28a745', type, data)
  34. this.loadAppConfigAndWorkspaceList()
  35. break
  36. }
  37. }
  38. componentDidMount () {
  39. // console.log('Sidebar Did Mount', this.props)
  40. this.loadAppConfigAndWorkspaceList()
  41. }
  42. componentDidUpdate (prevProps, prevState) {
  43. const { props } = this
  44. // console.log('%c<Sidebar> Did Update', 'color: #c17838')
  45. if (!props.match || props.match.params.idws === undefined || isNaN(props.match.params.idws)) return
  46. const newWorkspaceId = parseInt(props.match.params.idws)
  47. if (prevState.workspaceIdInUrl !== newWorkspaceId) this.setState({workspaceIdInUrl: newWorkspaceId})
  48. }
  49. loadAppConfigAndWorkspaceList = async () => {
  50. const { workspaceIdInUrl } = this.state
  51. const { user, dispatch } = this.props
  52. if (user.user_id !== -1) {
  53. const fetchGetAppList = await dispatch(getAppList(user))
  54. if (fetchGetAppList.status === 200) dispatch(setAppList(fetchGetAppList.json))
  55. const fetchGetContentTypeList = await dispatch(getContentTypeList(user))
  56. if (fetchGetContentTypeList.status === 200) dispatch(setContentTypeList(fetchGetContentTypeList.json))
  57. const fetchGetWorkspaceList = await dispatch(getWorkspaceList(user))
  58. if (fetchGetWorkspaceList.status === 200) {
  59. dispatch(updateWorkspaceListData(fetchGetWorkspaceList.json))
  60. dispatch(setWorkspaceListIsOpenInSidebar(workspaceIdInUrl || fetchGetWorkspaceList.json[0].workspace_id, true))
  61. }
  62. }
  63. }
  64. handleClickWorkspace = (idWs, newIsOpenInSidebar) => this.props.dispatch(setWorkspaceListIsOpenInSidebar(idWs, newIsOpenInSidebar))
  65. handleClickAllContent = idWs => {
  66. this.props.dispatch(updateWorkspaceFilter([]))
  67. this.props.history.push(PAGE.WORKSPACE.CONTENT_LIST(idWs))
  68. }
  69. // @DEPRECATED
  70. // not used, right now, link on sidebar filters is a <Link>
  71. handleClickContentFilter = (idWs, filter) => {
  72. const { workspace, history } = this.props
  73. const newFilter = workspace.filter.includes(filter) ? [] : [filter] // use an array to allow multiple filters (NYI)
  74. history.push(`${PAGE.WORKSPACE.CONTENT_LIST(idWs)}?type=${newFilter.join(';')}`) // workspace.filter gets updated on react redraw from match.params
  75. // obviously, it's ugly to use custom event to tell WorkspaceContentList to refresh, but since WorkspaceContentList
  76. // will end up being an App, it'll have to be that way. So it's fine
  77. GLOBAL_dispatchEvent({ type: 'refreshContentList', data: {} })
  78. }
  79. handleClickToggleSidebar = () => this.setState(prev => ({sidebarClose: !prev.sidebarClose}))
  80. handleClickNewWorkspace = () => this.props.renderAppPopupCreation(workspaceConfig, this.props.user, null, null)
  81. render () {
  82. const { sidebarClose, workspaceIdInUrl } = this.state
  83. const { activeLang, workspaceList, t } = this.props
  84. return (
  85. <div className={classnames('sidebar primaryColorBgDarken', {'sidebarclose': sidebarClose})}>
  86. <div className='sidebar__expand primaryColorBg' onClick={this.handleClickToggleSidebar}>
  87. <i className={classnames('fa fa-chevron-left', {'fa-chevron-right': sidebarClose, 'fa-chevron-left': !sidebarClose})} />
  88. </div>
  89. <div className='sidebar__content'>
  90. <nav className={classnames('sidebar__content__navigation', {'sidebarclose': sidebarClose})}>
  91. <ul className='sidebar__content__navigation__workspace'>
  92. { workspaceList.map(ws =>
  93. <WorkspaceListItem
  94. idWs={ws.id}
  95. label={ws.label}
  96. allowedApp={ws.sidebarEntry}
  97. lang={activeLang}
  98. activeFilterList={ws.id === workspaceIdInUrl ? [qs.parse(this.props.location.search).type] : []}
  99. isOpenInSidebar={ws.isOpenInSidebar}
  100. onClickTitle={() => this.handleClickWorkspace(ws.id, !ws.isOpenInSidebar)}
  101. onClickAllContent={this.handleClickAllContent}
  102. // onClickContentFilter={this.handleClickContentFilter}
  103. key={ws.id}
  104. />
  105. )}
  106. </ul>
  107. </nav>
  108. <div className='sidebar__content__btnnewworkspace'>
  109. <button
  110. className='sidebar__content__btnnewworkspace__btn btn btn-primary primaryColorBg primaryColorBorder primaryColorBorderDarkenHover mb-5'
  111. onClick={this.handleClickNewWorkspace}
  112. >
  113. {t('Create a workspace')}
  114. </button>
  115. </div>
  116. </div>
  117. <div className='sidebar__footer mb-2'>
  118. <div className='sidebar__footer__text whiteFontColor d-flex align-items-end justify-content-center'>
  119. Copyright - 2013 - 2018
  120. <div className='sidebar__footer__text__link'>
  121. <a href='http://www.tracim.fr/' target='_blank' className='ml-3'>tracim.fr</a>
  122. </div>
  123. </div>
  124. </div>
  125. </div>
  126. )
  127. }
  128. }
  129. const mapStateToProps = ({ lang, user, workspace, workspaceList }) => ({
  130. activeLang: lang.find(l => l.active) || {id: 'en'},
  131. user,
  132. workspace,
  133. workspaceList
  134. })
  135. export default withRouter(connect(mapStateToProps)(appFactory(translate()(Sidebar))))