WorkspaceContent.jsx 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import React from 'react'
  2. import { connect } from 'react-redux'
  3. import { withRouter } from 'react-router-dom'
  4. import appFactory from '../appFactory.js'
  5. import { PAGE } from '../helper.js'
  6. import Sidebar from './Sidebar.jsx'
  7. import Folder from '../component/Workspace/Folder.jsx'
  8. import ContentItem from '../component/Workspace/ContentItem.jsx'
  9. import ContentItemHeader from '../component/Workspace/ContentItemHeader.jsx'
  10. import PageWrapper from '../component/common/layout/PageWrapper.jsx'
  11. import PageTitle from '../component/common/layout/PageTitle.jsx'
  12. import PageContent from '../component/common/layout/PageContent.jsx'
  13. import DropdownCreateButton from '../component/common/Input/DropdownCreateButton.jsx'
  14. import OpenContentApp from './OpenContentApp.jsx'
  15. import {
  16. getAppList,
  17. getContentTypeList,
  18. getWorkspaceContentList,
  19. getFolderContent,
  20. getWorkspaceList
  21. } from '../action-creator.async.js'
  22. import {
  23. newFlashMessage,
  24. setAppList,
  25. setContentTypeList,
  26. setWorkspaceContent,
  27. setWorkspaceListIsOpenInSidebar,
  28. updateWorkspaceListData
  29. } from '../action-creator.sync.js'
  30. const qs = require('query-string')
  31. class WorkspaceContent extends React.Component {
  32. constructor (props) {
  33. super(props)
  34. this.state = {
  35. popupCreateContent: {
  36. display: false,
  37. type: undefined,
  38. folder: undefined
  39. },
  40. workspaceIdInUrl: props.match.params.idws ? parseInt(props.match.params.idws) : null, // this is used to avoid handling the parseInt everytime
  41. appOpenedType: false
  42. }
  43. document.addEventListener('appCustomEvent', this.customEventReducer)
  44. }
  45. customEventReducer = async ({ detail: { type, data } }) => {
  46. switch (type) {
  47. case 'refreshContentList':
  48. console.log('%c<WorkspaceContent> Custom event', 'color: #28a745', type, data)
  49. this.loadContentList(this.state.workspaceIdInUrl)
  50. break
  51. case 'openContentUrl':
  52. console.log('%c<WorkspaceContent> Custom event', 'color: #28a745', type, data)
  53. this.props.history.push(PAGE.WORKSPACE.CONTENT(data.idWorkspace, data.contentType, data.idContent))
  54. break
  55. case 'appClosed':
  56. console.log('%c<WorkspaceContent> Custom event', 'color: #28a745', type, data, this.state.workspaceIdInUrl)
  57. this.props.history.push(PAGE.WORKSPACE.CONTENT_LIST(this.state.workspaceIdInUrl))
  58. this.setState({appOpenedType: false})
  59. break
  60. }
  61. }
  62. async componentDidMount () {
  63. const { workspaceIdInUrl } = this.state
  64. const { user, workspaceList, app, contentType, match, dispatch } = this.props
  65. console.log('%c<WorkspaceContent> componentDidMount', 'color: #c17838')
  66. if (app.length === 0) {
  67. const fetchGetAppList = await dispatch(getAppList(user))
  68. if (fetchGetAppList.status === 200) dispatch(setAppList(fetchGetAppList.json))
  69. }
  70. if (contentType.length === 0) {
  71. const fetchGetContentTypeList = await dispatch(getContentTypeList(user))
  72. if (fetchGetContentTypeList.status === 200) dispatch(setContentTypeList(fetchGetContentTypeList.json))
  73. }
  74. let wsToLoad = null
  75. if (match.params.idws !== undefined) wsToLoad = match.params.idws
  76. if (user.user_id !== -1 && workspaceList.length === 0) {
  77. const fetchGetWorkspaceList = await dispatch(getWorkspaceList(user))
  78. if (fetchGetWorkspaceList.status === 200) {
  79. dispatch(updateWorkspaceListData(fetchGetWorkspaceList.json))
  80. dispatch(setWorkspaceListIsOpenInSidebar(workspaceIdInUrl || fetchGetWorkspaceList.json[0].workspace_id, true))
  81. if (match.params.idws === undefined && fetchGetWorkspaceList.json.length > 0) {
  82. wsToLoad = fetchGetWorkspaceList.json[0].workspace_id // load first ws if none specified
  83. }
  84. }
  85. }
  86. if (wsToLoad === null) return // ws already loaded
  87. this.loadContentList(wsToLoad)
  88. }
  89. async componentDidUpdate (prevProps, prevState) {
  90. console.log('%c<WorkspaceContent> componentDidUpdate', 'color: #c17838')
  91. if (this.state.workspaceIdInUrl === null) return
  92. const idWorkspace = parseInt(this.props.match.params.idws)
  93. if (isNaN(idWorkspace)) return
  94. if (prevState.workspaceIdInUrl !== idWorkspace) {
  95. this.setState({workspaceIdInUrl: idWorkspace})
  96. this.loadContentList(idWorkspace)
  97. }
  98. // if (user.user_id !== -1 && prevProps.user.id !== user.id) dispatch(getWorkspaceList(user.user_id, idWorkspace))
  99. }
  100. componentWillUnmount () {
  101. this.props.emitEventApp('unmount_app')
  102. document.removeEventListener('appCustomEvent', this.customEventReducer)
  103. }
  104. loadContentList = async idWorkspace => {
  105. const { user, location, dispatch } = this.props
  106. const wsContent = await dispatch(getWorkspaceContentList(user, idWorkspace, 0))
  107. if (wsContent.status === 200) dispatch(setWorkspaceContent(wsContent.json, qs.parse(location.search).type))
  108. else dispatch(newFlashMessage('Error while loading workspace', 'danger'))
  109. }
  110. handleClickContentItem = content => {
  111. console.log('%c<WorkspaceContent> content clicked', 'color: #c17838', content)
  112. this.props.history.push(`/workspaces/${content.idWorkspace}/${content.type}/${content.id}`)
  113. }
  114. handleClickEditContentItem = (e, content) => {
  115. e.stopPropagation()
  116. console.log('%c<WorkspaceContent> edit nyi', 'color: #c17838', content)
  117. }
  118. handleClickMoveContentItem = (e, content) => {
  119. e.stopPropagation()
  120. console.log('%c<WorkspaceContent> move nyi', 'color: #c17838', content)
  121. }
  122. handleClickDownloadContentItem = (e, content) => {
  123. e.stopPropagation()
  124. console.log('%c<WorkspaceContent> download nyi', 'color: #c17838', content)
  125. }
  126. handleClickArchiveContentItem = (e, content) => {
  127. e.stopPropagation()
  128. console.log('%c<WorkspaceContent> archive nyi', 'color: #c17838', content)
  129. }
  130. handleClickDeleteContentItem = (e, content) => {
  131. e.stopPropagation()
  132. console.log('%c<WorkspaceContent> delete nyi', 'color: #c17838', content)
  133. }
  134. handleClickFolder = folderId => {
  135. this.props.dispatch(getFolderContent(this.props.workspace.id, folderId))
  136. }
  137. handleClickCreateContent = (e, idFolder, contentType) => {
  138. e.stopPropagation()
  139. this.props.renderCreateContentApp(
  140. this.props.contentType.find(ct => ct.slug === contentType),
  141. this.props.user,
  142. this.props.match.params.idws,
  143. idFolder
  144. )
  145. }
  146. handleUpdateAppOpenedType = openedAppType => this.setState({appOpenedType: openedAppType})
  147. render () {
  148. const { workspaceContent, contentType } = this.props
  149. const filterWorkspaceContent = (contentList, filter) => {
  150. return filter.length === 0
  151. ? contentList
  152. : contentList.filter(c => c.type === 'folder' || filter.includes(c.type)) // keep unfiltered files and folders
  153. // @FIXME we need to filter subfolder too, but right now, we dont handle subfolder
  154. // .map(c => c.type !== 'folder' ? c : {...c, content: filterWorkspaceContent(c.content, filter)}) // recursively filter folder content
  155. }
  156. // .filter(c => c.type !== 'folder' || c.content.length > 0) // remove empty folder => 2018/05/21 - since we load only one lvl of content, don't remove empty
  157. const urlFilter = qs.parse(this.props.location.search).type
  158. const filteredWorkspaceContent = workspaceContent.length > 0
  159. ? filterWorkspaceContent(workspaceContent, urlFilter ? [urlFilter] : [])
  160. : []
  161. return (
  162. <div className='sidebarpagecontainer'>
  163. <Sidebar />
  164. <OpenContentApp
  165. idWorkspace={this.state.workspaceIdInUrl}
  166. appOpenedType={this.state.appOpenedType}
  167. updateAppOpenedType={this.handleUpdateAppOpenedType}
  168. />
  169. <PageWrapper customeClass='workspace'>
  170. <PageTitle
  171. parentClass='workspace__header'
  172. customClass='justify-content-between'
  173. title={workspaceContent.label ? workspaceContent.label : ''}
  174. >
  175. <DropdownCreateButton
  176. parentClass='workspace__header__btnaddworkspace'
  177. idFolder={null}
  178. onClickCreateContent={this.handleClickCreateContent}
  179. availableApp={contentType}
  180. />
  181. </PageTitle>
  182. <PageContent parentClass='workspace__content'>
  183. <div id='popupCreateContentContainer' />
  184. <div className='workspace__content__fileandfolder folder__content active'>
  185. <ContentItemHeader />
  186. { filteredWorkspaceContent.map((c, i) => c.type === 'folder'
  187. ? (
  188. <Folder
  189. availableApp={contentType}
  190. folderData={c}
  191. onClickItem={this.handleClickContentItem}
  192. onClickExtendedAction={{
  193. edit: this.handleClickEditContentItem,
  194. move: this.handleClickMoveContentItem,
  195. download: this.handleClickDownloadContentItem,
  196. archive: this.handleClickArchiveContentItem,
  197. delete: this.handleClickDeleteContentItem
  198. }}
  199. onClickFolder={this.handleClickFolder}
  200. onClickCreateContent={this.handleClickCreateContent}
  201. isLast={i === filteredWorkspaceContent.length - 1}
  202. key={c.id}
  203. />
  204. )
  205. : (
  206. <ContentItem
  207. label={c.label}
  208. type={c.type}
  209. faIcon={contentType.length ? contentType.find(a => a.slug === c.type).faIcon : ''}
  210. statusSlug={c.statusSlug}
  211. contentType={contentType.find(ct => ct.slug === c.type)}
  212. onClickItem={() => this.handleClickContentItem(c)}
  213. onClickExtendedAction={{
  214. edit: e => this.handleClickEditContentItem(e, c),
  215. move: e => this.handleClickMoveContentItem(e, c),
  216. download: e => this.handleClickDownloadContentItem(e, c),
  217. archive: e => this.handleClickArchiveContentItem(e, c),
  218. delete: e => this.handleClickDeleteContentItem(e, c)
  219. }}
  220. onClickCreateContent={this.handleClickCreateContent}
  221. isLast={i === filteredWorkspaceContent.length - 1}
  222. key={c.id}
  223. />
  224. )
  225. )}
  226. </div>
  227. <DropdownCreateButton
  228. customClass='workspace__content__button mb-5'
  229. idFolder={null}
  230. onClickCreateContent={this.handleClickCreateContent}
  231. availableApp={contentType}
  232. />
  233. <div id='appContainer' />
  234. </PageContent>
  235. </PageWrapper>
  236. </div>
  237. )
  238. }
  239. }
  240. const mapStateToProps = ({ user, workspaceContent, workspaceList, app, contentType }) => ({ user, workspaceContent, workspaceList, app, contentType })
  241. export default withRouter(connect(mapStateToProps)(appFactory(WorkspaceContent)))