UNPKG

nexshop-web-contents

Version:

Nexshop Web Contents Project

433 lines (362 loc) 15.4 kB
import React, {Component} from 'react'; import SceneTitleView from "./scene-title-view"; import {connect} from "react-redux"; import flattenDeep from 'lodash/flattenDeep'; import {bindActionCreators} from "redux"; import {sceneActions, discardConfirmActions} from 'nexshop-web-store'; import {actions as dialogActions} from 'nexshop-web-dialog'; import SceneEditorView from "./scene-editor/scene-editor-view"; import SceneResourceView from "./scene-resource/scene-resource-view"; import {createEmptySceneFromLayouts, createScene} from "../../model-factory/scene"; import ConfirmUpdateContentsItem from "../dialog/confirm-update-contents-item/confirm-update-contents-item" import {AlertDialog} from "nexshop-web-elements"; const DEFAULT_LAYOUT_ID = ''; const DEFAULT_TAB_ID = 'contents'; const MAX_PANEL_COUNT_WITH_VIDEO = 2; function getAllPanel(panels, {direction} = 'row') { const allPanels = []; for (let i = 0; i < panels.length; i++) { allPanels.push(panels[i]); panels[i].parentDirection = direction; if (panels[i].type === 'group') { allPanels.push(getAllPanel(panels[i].panels, panels[i])); } } return allPanels; } class Scene extends Component { constructor(props) { super(props); let {orientation} = this.props; let {scene} = props; let selectedTabId = DEFAULT_TAB_ID; let selectedLayoutId = DEFAULT_LAYOUT_ID; let hasFullContent = true; const isSceneDetail = !scene; if (isSceneDetail) { selectedTabId = 'layout'; selectedLayoutId = '1'; scene = createEmptySceneFromLayouts(selectedLayoutId, orientation); hasFullContent = false; } this.state = { layout: scene, selectedLayoutId, selectedTabId, hasFullContent, selectedPanelId: '', draggedOverPanelId: '', alertVisibility: false, usedInOthers: false }; this.selectLayout = this.selectLayout.bind(this); this.updatePanelWidths = this.updatePanelWidths.bind(this); this.selectTab = this.selectTab.bind(this); this.saveScene = this.saveScene.bind(this); this.checkContentsForPanel = this.checkContentsForPanel.bind(this); this.checkContentsForGroup = this.checkContentsForGroup.bind(this); this.isDraggedOverPanel = this.isDraggedOverPanel.bind(this); this.isSelectedPanel = this.isSelectedPanel.bind(this); this.setSelectedPanelId = this.setSelectedPanelId.bind(this); this.setDraggedOverPanelId = this.setDraggedOverPanelId.bind(this); this.addContentItem = this.addContentItem.bind(this); this.removeContentItem = this.removeContentItem.bind(this); this.getPanelGroupRects = this.getPanelGroupRects.bind(this); this.getPanelRects = this.getPanelRects.bind(this); this.getPanelSize = this.getPanelSize.bind(this); this.getWrapperSizeForResolution = this.getWrapperSizeForResolution.bind(this); this.moveToPreview = this.moveToPreview.bind(this); this.getCSSWrapperName = this.getCSSWrapperName.bind(this); this.getRelatedContents = this.getRelatedContents.bind(this); this.updateFitMode = this.updateFitMode.bind(this); this.isAddableContentsItem = this.isAddableContentsItem.bind(this); this.onCloseAlertMessage = this.onCloseAlertMessage.bind(this); } isDraggedOverPanel(id) { return id === this.state.draggedOverPanelId; } isSelectedPanel(id) { return id === this.state.selectedPanelId; } setSelectedPanelId(selectedPanelId) { this.setState({ selectedPanelId }); } setDraggedOverPanelId(draggedOverPanelId) { if (this.state.draggedOverPanelId !== draggedOverPanelId) { this.setState({ draggedOverPanelId }); } } selectLayout(layoutId) { this.setState({ layout: createEmptySceneFromLayouts(layoutId, this.props.orientation), selectedLayoutId: layoutId, hasFullContent: false, selectedPanelId: '', draggedOverPanelId: '', }); } addContentItem(panelId, contentItem) { const newScene = {...this.state.layout}; let panels = flattenDeep(getAllPanel(newScene.panels)); if (contentItem.type === 'video' && !this.isAddableContentsItem(panels)) { this.setState({ alertVisibility: true, }); return; } let panel = panels.find(panel => panel.id === panelId); if (!panel.contentItems) { panel.contentItems = []; } panel.contentItems.push(contentItem); this.setState({ layout: newScene, hasFullContent: this.checkContentsForGroup(newScene.panels), }); } isAddableContentsItem(panels) { let videoCount = 0; panels.forEach((panel) => { let {contentItems: [contentItem = {}] = []} = panel; if (contentItem.type === 'video') { videoCount++; } }); return videoCount < MAX_PANEL_COUNT_WITH_VIDEO; } removeContentItem(panelId) { const newScene = {...this.state.layout}; let panels = flattenDeep(getAllPanel(newScene.panels)); let panel = panels.find(panel => panel.id === panelId); delete panel.contentItems; this.setState({ layout: newScene, hasFullContent: this.checkContentsForGroup(newScene.panels), }); } checkContentsForGroup(panels) { let resultList = panels.map((panel) => { if (panel.type === 'panel') { return this.checkContentsForPanel(panel); } else { return this.checkContentsForGroup(panel.panels); } }); return resultList.reduce((accumulator, currentValue) => { return accumulator && currentValue }, true); } checkContentsForPanel(panel) { return !!panel.contentItems; } selectTab(tabId) { this.setState({ selectedTabId: tabId, }); } saveScene() { this.props.actions.unblockNavigation(); const newScene = {...this.state.layout}; const {sceneId, name, resolution, orientation, breadcrumb, actions: {saveSceneAsync, updateSceneAsync, openDialog}} = this.props; const relatedContents = this.getRelatedContents(newScene.panels); const currentFolderId = breadcrumb[breadcrumb.length - 1].id; const sceneElement = document.getElementById('scene-body'); let sceneFormat = createScene(name, newScene.panels, currentFolderId, resolution, orientation, relatedContents); if (sceneId) { updateSceneAsync(sceneFormat, sceneId, sceneElement, resolution, orientation) .then((response) => { if (response.occupied) { openDialog('update-contents-item'); } }); } else { saveSceneAsync(sceneFormat, sceneElement, resolution, orientation); } } getRelatedContents(panels) { let flatPanels = flattenDeep(getAllPanel(panels)); let relatedContentsSet = new Set(); flatPanels.forEach((panel) => { let contentItems = panel.contentItems; if (panel.type === 'panel' && contentItems) { contentItems.forEach((content) => relatedContentsSet.add(content.id)); } }); return Array.from(relatedContentsSet).map((id) => { return {id} }); } updatePanelWidths() { const newScene = {...this.state.layout}; let panels = flattenDeep(getAllPanel(newScene.panels)).reverse(); panels.forEach((panel) => { if (panel.type === 'panel') { const domRect = document.getElementById(panel.id).getClientRects()[0]; panel.domAttribute = {...panel.domAttribute, ...this.getPanelRects(panel, domRect)}; } else { panel.domAttribute = {...panel.domAttribute, ...this.getPanelGroupRects(panel)}; } }); this.setState({ layout: newScene, hasFullContent: this.checkContentsForGroup(newScene.panels), }) } getWrapperSizeForResolution(orientation) { return orientation === 'horizontal' ? {width: 960, height: 540} : {width: 432, height: 768}; } getPanelRects({parentDirection}, domRect) { const basicSize = this.getWrapperSizeForResolution(this.props.orientation); let width, height, pixelWidth, pixelHeight, size; width = (domRect.width / basicSize.width) * 100; height = (domRect.height / basicSize.height) * 100; pixelWidth = domRect.width; pixelHeight = domRect.height; size = this.getPanelSize(parentDirection, domRect); return {width, height, pixelWidth, pixelHeight, size}; } getPanelSize(parentDirection, domRect) { let size = 0; if (parentDirection === 'row') { size = domRect.width; } else { size = domRect.height; } return size; } getPanelGroupRects({direction, parentDirection, panels}) { const basicSize = this.getWrapperSizeForResolution(this.props.orientation); let pixelHeight, pixelWidth, height, width, size; if (direction === 'row') { pixelHeight = panels[0].domAttribute.pixelHeight; pixelWidth = panels.reduce( (accum, current) => { return accum + current.domAttribute.pixelWidth; }, 0); } else { pixelHeight = panels.reduce( (accum, current) => { return accum + current.domAttribute.pixelHeight; }, 0); pixelWidth = panels[0].domAttribute.pixelWidth; } size = this.getPanelSize(parentDirection, {width: pixelWidth, height: pixelHeight}); width = (pixelWidth / basicSize.width) * 100; height = (pixelHeight / basicSize.height) * 100; return {pixelHeight, pixelWidth, height, width, size}; } moveToPreview() { this.props.actions.unblockNavigation(); const newScene = {...this.state.layout}; const {name, resolution, orientation, actions: {createScenePreview}} = this.props; const previewWindowRects = document.getElementsByClassName('scene')[0].getClientRects()[0]; const previewWindowSize = {width: previewWindowRects.width, height: previewWindowRects.height}; const sceneLayoutRects = document.getElementsByClassName('layout-wrapper' + this.getCSSWrapperName(orientation))[0].getClientRects()[0]; const sceneLayoutSize = {width: sceneLayoutRects.width - 2, height: sceneLayoutRects.height - 2}; createScenePreview(createScene(name, newScene.panels, resolution, orientation), previewWindowSize, sceneLayoutSize); setTimeout(() => { this.props.history.push('/contents/scene-preview'); }); } getCSSWrapperName(orientation) { return orientation === 'horizontal' ? '--horizontal' : '--vertical'; } updateFitMode(fitMode, panelId, contentItemId) { const newScene = {...this.state.layout}; let panels = flattenDeep(getAllPanel(newScene.panels)); let panel = panels.find(panel => panel.id === panelId); let contentItem = panel.contentItems.find(contentItem => contentItem.id === contentItemId); contentItem.fitMode = fitMode; this.setState({ layout: newScene, }); } onCloseAlertMessage() { this.setState({ selectedPanelId: '', draggedOverPanelId: '', alertVisibility: false, }); } componentWillMount() { const {name, resolution, history} = this.props; if (!name || !resolution) { history.push('/contents/main'); } } componentDidMount() { this.props.actions.blockNavigation('Your work has not been saved.'); } componentWillUnmount() { this.props.actions.unblockNavigation(); } render() { const {name = 'scene', orientation = 'vertical'} = this.props; const {layout, selectedLayoutId, selectedTabId, hasFullContent, alertVisibility} = this.state; return ( <div className="scene"> <SceneTitleView title={name} saveScene={this.saveScene} hasFullContent={hasFullContent} onPreviewClick={this.moveToPreview} /> <div className="scene-body"> <SceneEditorView layout={layout} orientation={orientation} updatePanelWidths={this.updatePanelWidths} selectedTabId={selectedTabId} isDraggedOverPanel={this.isDraggedOverPanel} isSelectedPanel={this.isSelectedPanel} setSelectedPanelId={this.setSelectedPanelId} setDraggedOverPanelId={this.setDraggedOverPanelId} addContentItem={this.addContentItem} getCSSWrapperName={this.getCSSWrapperName} removeContentItem={this.removeContentItem} updateFitMode={this.updateFitMode} /> <SceneResourceView orientation={orientation} getCSSWrapperName={this.getCSSWrapperName} changeLayout={this.selectLayout} selectTab={this.selectTab} selectedTabId={selectedTabId} selectedLayoutId={selectedLayoutId} /> <AlertDialog isOpen={alertVisibility} icon={'warning'} message={'You can add up to 2 video files.'} positiveButtonText={'OK'} onPositiveClick={this.onCloseAlertMessage}/> <ConfirmUpdateContentsItem name={name}/> </div> </div> ); } } const mapStateToProps = (state) => { let {scene: {scene, sceneId, name, resolution, orientation, usedIn}, contents: {breadcrumb}} = state; return { name, resolution, orientation, scene, sceneId, breadcrumb, usedIn, }; }; const mapDispatchToProps = (dispatch) => { const {saveSceneAsync, updateSceneAsync, createScenePreview} = sceneActions; const {blockNavigation, unblockNavigation} = discardConfirmActions; const {openDialog} = dialogActions; return { actions: bindActionCreators({ saveSceneAsync, updateSceneAsync, createScenePreview, blockNavigation, unblockNavigation, openDialog }, dispatch) } }; export default connect(mapStateToProps, mapDispatchToProps)(Scene);