Editor.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import React, { useEffect, useCallback, useState } from 'react'
  21. import Helmet from 'react-helmet'
  22. import { useDispatch, useSelector } from 'react-redux'
  23. import { makeSelectCurrentProject } from 'containers/Projects/selectors'
  24. import {
  25. makeSelectCurrentDisplay,
  26. makeSelectCurrentSlides,
  27. makeSelectCurrentSlide
  28. } from '../selectors'
  29. import { VizActions } from '../actions'
  30. import { Route } from 'react-router-dom'
  31. import { RouteComponentWithParams } from 'utils/types'
  32. import { Layout, PageHeader } from 'antd'
  33. import SplitPane from 'components/SplitPane'
  34. import SlideThumbnailList from '../components/SlideThumbnail'
  35. import DisplayHeader from 'containers/Display/Editor/Header'
  36. import { Display } from 'containers/Display/Loadable'
  37. import { ISlideFormed } from 'containers/Viz/components/types'
  38. import styles from '../Viz.less'
  39. const VizDisplayEditor: React.FC<RouteComponentWithParams> = (props) => {
  40. const dispatch = useDispatch()
  41. const { id: projectId } = useSelector(makeSelectCurrentProject())
  42. const currentDisplay = useSelector(makeSelectCurrentDisplay())
  43. const displayId = currentDisplay.id
  44. const { id: slideId } = useSelector(makeSelectCurrentSlide())
  45. const currentSlides = useSelector(makeSelectCurrentSlides())
  46. const { history } = props
  47. const [selectedSlideIds, setSelectedSlideIds] = useState([])
  48. const clearSelectedSlide = useCallback(() => {
  49. setSelectedSlideIds([])
  50. }, [])
  51. useEffect(() => {
  52. window.addEventListener('click', clearSelectedSlide, false)
  53. return () => {
  54. window.removeEventListener('click', clearSelectedSlide, false)
  55. }
  56. }, [])
  57. const goToViz = useCallback(() => {
  58. const prefix = window.localStorage.getItem('inDataService') ?? ''
  59. const prefixPath = prefix ? '/' + prefix : prefix
  60. history.replace(`/project/${projectId}${prefixPath}/vizs`)
  61. }, [projectId])
  62. const selectSlide = useCallback(
  63. (slideId: number, append: boolean) => {
  64. if (append) {
  65. setSelectedSlideIds(
  66. selectedSlideIds.includes(slideId)
  67. ? selectedSlideIds.filter((id) => id !== slideId)
  68. : selectedSlideIds.concat(slideId)
  69. )
  70. } else {
  71. setSelectedSlideIds([slideId])
  72. history.replace(
  73. `/project/${projectId}/display/${displayId}/slide/${slideId}`
  74. )
  75. }
  76. },
  77. [projectId, displayId, selectedSlideIds]
  78. )
  79. const changeDisplayAvatar = useCallback(
  80. (avatar: string) => {
  81. dispatch(
  82. VizActions.editDisplay({
  83. ...currentDisplay,
  84. avatar
  85. })
  86. )
  87. },
  88. [currentDisplay]
  89. )
  90. const editSlides = useCallback((newSlides: ISlideFormed[]) => {
  91. dispatch(VizActions.editSlides(newSlides))
  92. }, [])
  93. const deleteSlides = useCallback(
  94. (targetSlideId?: number) => {
  95. if (!targetSlideId || selectedSlideIds.includes(targetSlideId)) {
  96. dispatch(VizActions.deleteSlides(displayId, selectedSlideIds))
  97. return
  98. }
  99. if (targetSlideId) {
  100. dispatch(VizActions.deleteSlides(displayId, [targetSlideId]))
  101. }
  102. },
  103. [displayId, selectedSlideIds]
  104. )
  105. return (
  106. <>
  107. <Helmet title={`${currentDisplay.name} - Display`} />
  108. <Layout>
  109. <PageHeader
  110. ghost={false}
  111. title={currentDisplay.name}
  112. subTitle={currentDisplay.description}
  113. avatar={{
  114. src: currentDisplay.avatar,
  115. shape: 'square'
  116. }}
  117. extra={<DisplayHeader />}
  118. onBack={goToViz}
  119. />
  120. <SplitPane
  121. className="ant-layout-content"
  122. type="horizontal"
  123. initialSize={120}
  124. minSize={120}
  125. maxSize={200}
  126. >
  127. <SlideThumbnailList
  128. className={styles.slides}
  129. currentSlideId={slideId}
  130. selectedSlideIds={selectedSlideIds}
  131. slides={currentSlides}
  132. onChange={editSlides}
  133. onSelect={selectSlide}
  134. onDelete={deleteSlides}
  135. onChangeDisplayAvatar={changeDisplayAvatar}
  136. />
  137. <Route
  138. path="/project/:projectId/display/:displayId/slide/:slideId"
  139. component={Display}
  140. />
  141. </SplitPane>
  142. </Layout>
  143. </>
  144. )
  145. }
  146. export default VizDisplayEditor