UNPKG

nexshop-web-contents

Version:

Nexshop Web Contents Project

285 lines (253 loc) 13.1 kB
import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {DropDown} from 'nexshop-web-elements'; import {formatSeconds} from "../../../helpers/time-helper"; import {leftPadZero} from "../../../helpers/string-helper"; import {EFFECT_TYPES} from "../../../constants/effect-types" import {DURATION_ITEMS} from "../../../constants/duration-items"; import {FIT_MODES} from "../../../constants/fit-modes" class PlaylistEditorView extends Component { constructor(props) { super(props); this.state = { mouseOverUUID: '', mouseOverDomType: '', isDragging: false, top: 1, left: 1, width: 1, draggingContentItem: null, selectItem: { uuid: '', selectedValue: '', } }; this.onMouseOver = this.onMouseOver.bind(this); this.onMouseLeave = this.onMouseLeave.bind(this); this.onDeleteClick = this.onDeleteClick.bind(this); this.onDragStart = this.onDragStart.bind(this); this.onDragEnd = this.onDragEnd.bind(this); this.onDragOver = this.onDragOver.bind(this); this.onTransitionEffectChange = this.onTransitionEffectChange.bind(this); this.onDurationChange = this.onDurationChange.bind(this); this.onFitModeChange = this.onFitModeChange.bind(this); } onMouseOver(uuid) { return () => { if (this.state.isDragging) return; this.setState({ mouseOverUUID: uuid }); } } onMouseLeave() { this.setState({ mouseOverUUID: '' }); } onDeleteClick(index) { const {onDeleteItem} = this.props; onDeleteItem(index); setTimeout(() => { //this will be triggered after view is rendered const {contentItems} = this.props; let mouseOverUUID = ''; if (index < contentItems.length) { mouseOverUUID = contentItems[index].uuid } this.setState({mouseOverUUID}); }, 0) } onDragStart(index) { const {onOrderChangeStart, contentItems} = this.props; return (e) => { const {currentTarget, nativeEvent: {offsetX, offsetY}} = e; this.setState({isDragging: true, draggingContentItem: {...contentItems[index]}}); //TODO: not tested this.preview.style.width = `${currentTarget.clientWidth + 5}px`; //TODO: technical dept e.dataTransfer.effectAllowed = 'copy'; e.dataTransfer.setDragImage(this.preview, offsetX, offsetY); onOrderChangeStart(index); } } onDragEnd() { const {onOrderChangeEnd} = this.props; this.setState({isDragging: false, draggingContentItem: null}); onOrderChangeEnd(); } onDragOver(index) { const {onOrderChangeProcess} = this.props; return (e) => { e.preventDefault(); onOrderChangeProcess(index); } } onTransitionEffectChange(uuid) { const {onUpdateContentItemTransition} = this.props; return ({value}) => { onUpdateContentItemTransition(uuid, value); }; } onDurationChange(uuid) { const {onUpdateContentItemDuration} = this.props; return ({value}) => { onUpdateContentItemDuration(uuid, value); }; } onFitModeChange(uuid) { const {onUpdateContentItemFitMode} = this.props; return ({value}) => { onUpdateContentItemFitMode(uuid, value); }; } render() { const { resolution: {value, orientation}, onDropDragContentsItem, contentItems, blankIndex, onOrderChangeEnd, onSelectPreviewItem, } = this.props; let hasContent = (contentItems && contentItems.length > 0); return ( <div className="playlist-editor-wrapper" onDragOver={(e) => e.preventDefault()} onDrop={onDropDragContentsItem}> <div className="playlist-editor"> <div className="playlist-top"> <div className="playlist-summary"> <span className="playlist-summary__label">Counts</span> <span className="playlist-summary__value">{leftPadZero(contentItems.length)}</span> <span className="playlist-summary__label">Total</span> <span className="playlist-summary__value">{ formatSeconds(contentItems.reduce((sum, content) => sum + content.durationSeconds, 0),'hh:mm:ss') }</span> </div> <div className="playlist-resolution"> <div className="playlist-resolution__value">{value}</div> <div className={`playlist-resolution__${orientation}`}/> </div> </div> <div className="playlist-items"> { hasContent && contentItems.map(({contents, uuid, transitionEffect, durationSeconds, fitMode}, index) => { return ( index === blankIndex ? <div key={uuid} className="playlist-placeholder" onDragEnd={this.onDragEnd} onDrop={onOrderChangeEnd}/> : <div key={uuid} data-uuid={uuid} className={`playlist-item${this.state.mouseOverUUID === uuid ? '--hovered' : ''}`} onMouseLeave={this.onMouseLeave} onMouseOver={this.onMouseOver(uuid)} onDragStart={this.onDragStart(index)} onDragEnd={this.onDragEnd} onDragOver={this.onDragOver(index)} draggable={true}> {uuid === this.state.mouseOverUUID && <div className="playlist-item-preview-link"> <div className="playlist-item-preview" onClick={() => { onSelectPreviewItem(index) }}> <div className="playlist-item-preview__play"/> </div> </div>} <div className="playlist-item__thumbnail" style={{backgroundImage: `url(${contents.thumbnailUrls.thumbnail ? contents.thumbnailUrls.thumbnail : ''})`}}/> <div className={`playlist-item__type--${contents.type}`}/> <div className="playlist-item__name">{contents.name}</div> <div className={`playlist-item__duration${contents.type === 'video' ? '__video' : ''}`}> { contents.type === 'video' ? ( formatSeconds(durationSeconds, durationSeconds >= 3600 ? 'hh:mm:ss' : 'mm:ss') ) : ( <DropDown items={DURATION_ITEMS} selected={DURATION_ITEMS.find((item) => item.value === durationSeconds)} onSelect={this.onDurationChange(uuid)}/> ) } </div> <div className='playlist-item__effect'> { contents.type === 'video' ? ( <div>No Effect</div> ) : ( <DropDown items={EFFECT_TYPES} selected={EFFECT_TYPES.find((item) => item.value === transitionEffect)} onSelect={this.onTransitionEffectChange(uuid)}/> ) } </div> <div className="playlist-item__fitMode"> <DropDown items={FIT_MODES} selected={FIT_MODES.find((item) => item.value === fitMode)} onSelect={this.onFitModeChange(uuid)} classNamePrefix={'playlist-fitMode'} /> </div> { this.state.mouseOverUUID === uuid && <div className="playlist-item__delete" onClick={() => this.onDeleteClick(index)}/> } </div> ) }) } { !hasContent && <div className="playlist-item-drag-placeholder"> Drag & drop contents </div> } </div> </div> <div className="dragging" ref={(preview) => this.preview = preview}> { this.state.draggingContentItem && <DraggingContentItem contentItem={this.state.draggingContentItem} durationSeconds={this.state.draggingContentItem.durationSeconds} transitionEffect={EFFECT_TYPES.filter((item) => item.value === this.state.draggingContentItem.transitionEffect)[0]} /> } </div> </div> ); } } const DraggingContentItem = ({contentItem: {contents}, transitionEffect, durationSeconds}) => { let formattedDurationSeconds = formatSeconds(durationSeconds, durationSeconds >= 3600 ? 'hh:mm:ss' : 'mm:ss'); return ( <div className='playlist-item playlist-item-shadow'> <div className="playlist-item__thumbnail" style={{backgroundImage: `url(${contents.thumbnailUrls.thumbnail ? contents.thumbnailUrls.thumbnail : ''})`}}/> <div className={`playlist-item__type--${contents.type}`}/> <div className="playlist-item__name">{contents.name}</div> <div className="playlist-item__duration">{formattedDurationSeconds}</div> <div className="playlist-item__effect">{transitionEffect.text}</div> </div> ) }; PlaylistEditorView.propTypes = { resolution: PropTypes.object.isRequired, contentItems: PropTypes.array.isRequired, onDropDragContentsItem: PropTypes.func.isRequired, onDeleteItem: PropTypes.func.isRequired, onOrderChangeStart: PropTypes.func.isRequired, onOrderChangeProcess: PropTypes.func.isRequired, onOrderChangeEnd: PropTypes.func.isRequired, blankIndex: PropTypes.number, onSelectPreviewItem: PropTypes.func.isRequired, onUpdateContentItemTransition: PropTypes.func.isRequired, onUpdateContentItemDuration: PropTypes.func.isRequired, onUpdateContentItemFitMode: PropTypes.func.isRequired, }; export default PlaylistEditorView;