diff options
Diffstat (limited to 'frontend/site/viewer/viewer.container.js')
| -rw-r--r-- | frontend/site/viewer/viewer.container.js | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/frontend/site/viewer/viewer.container.js b/frontend/site/viewer/viewer.container.js new file mode 100644 index 0000000..9bf4442 --- /dev/null +++ b/frontend/site/viewer/viewer.container.js @@ -0,0 +1,223 @@ +import React, { Component } from 'react' +import { Route } from 'react-router-dom' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +import { history } from 'site/store' +import actions from 'site/actions' +import { Loader } from 'app/common/loader.component' +import TileHandle from 'app/views/tile/components/tile.handle' + +import 'app/views/page/page.css' + +class ViewerContainer extends Component { + state = { + page: {}, + bounds: { width: window.innerWidth, height: window.innerHeight }, + roadblock: false, + popups: {}, + hidden: {}, + time: 0, + maxDeferTime: 0, + } + + constructor(props) { + super(props) + this.pageRef = React.createRef() + this.handleMouseDown = this.handleMouseDown.bind(this) + this.handleResize = this.handleResize.bind(this) + this.removeRoadblock = this.removeRoadblock.bind(this) + this.updateTimer = this.updateTimer.bind(this) + window.addEventListener('resize', this.handleResize) + } + + componentDidUpdate(prevProps) { + // console.log('didUpdate', this.props.graph !== prevProps.graph, this.props.location.pathname !== prevProps.location.pathname) + if (this.props.graph !== prevProps.graph || this.props.location.pathname !== prevProps.location.pathname) { + this.load() + } + } + + componentWillUnmount() { + window.removeEventListener('resize', this.handleResize) + actions.site.interact() + } + + load() { + const { graph_name, page_name } = this.props.match.params + const page_path = ["", graph_name, page_name].join('/') + const { pages, home_page } = this.props.graph + const page = pages[page_path] || pages[home_page] + if (!this.props.interactive && hasAutoplay(page)) { + this.setState({ page, popups: {}, hidden: {}, roadblock: true }) + } else { + this.setState({ page, popups: {}, hidden: {}, roadblock: false }) + actions.site.interact() + this.props.audio.player.playPage(page) + this.resetTimer(page) + } + } + + resetTimer(page) { + clearTimeout(this.timeout) + const maxDeferTime = page.tiles.reduce((max_time, tile) => Math.max(tile.settings.appear_after || 0, max_time), 0) + if (maxDeferTime) { + this.setState({ time: 0, maxDeferTime }) + this.timeout = setTimeout(this.updateTimer, 500) + } + } + + updateTimer() { + clearTimeout(this.timeout) + this.setState({ time: this.state.time + 0.500 }) + if (this.state.time < this.state.maxDeferTime) { + this.timeout = setTimeout(this.updateTimer, 500) + } + } + + handleResize() { + this.setState({ + bounds: { + width: window.innerWidth, + height: window.innerHeight, + } + }) + } + + handleMouseDown(e, tile) { + if (tile.href) { + if (tile.href.indexOf('http') === 0) { + window.location.href = tile.href + return + } + else if (tile.href === '__open_popup') { + this.setState({ + popups: { + ...this.state.popups, + [tile.settings.target_popup]: true, + }, + }) + } + else if (tile.href === '__close_popup') { + this.setState({ + popups: { + ...this.state.popups, + [tile.settings.target_popup]: false, + }, + }) + } + else if (!tile.settings.navigate_when_audio_finishes) { + history.push(tile.href) + } + } + if (tile.settings.audio_on_click_id > 0) { + this.props.audio.player.playTile({ + type: "click", + tile, + }) + } + if (tile.settings.hide_on_click) { + this.setState({ + hidden: { + ...this.state.hidden, + [tile.id]: true, + } + }) + } + } + + handlePlaybackEnded(tile) { + if (tile.href && tile.settings.autoadvance) { + history.push(tile.href) + } + } + + render() { + const { page, audio, popups, hidden, time } = this.state + if (this.state.roadblock) { + return this.renderRoadblock() + } + if (this.props.graph.loading || !page.id) { + return ( + <div> + <div className='body'> + <div className='page loading'> + <Loader /> + </div> + </div> + </div> + ) + } + const { settings } = page + const pageStyle = { backgroundColor: settings ? settings.background_color : '#000000' } + const videoBounds = (page.tiles.length && page.tiles[0].type === 'video') ? { + width: page.tiles[0].settings.width, + height: page.tiles[0].settings.height, + } : this.state.bounds + // console.log(page) + return ( + <div className='body'> + <div className='page' ref={this.pageRef} style={pageStyle}> + {page.tiles.map(tile => { + if (tile.settings.is_popup && !popups[tile.settings.popup_group]) return + if (tile.settings.appear_after && time < tile.settings.appear_after) return + if (tile.settings.hide_on_click && hidden[tile.id]) return + return ( + <TileHandle + viewing + key={tile.id} + tile={tile} + audio={audio} + bounds={this.state.bounds} + videoBounds={videoBounds} + onMouseDown={e => this.handleMouseDown(e, tile)} + onPlaybackEnded={e => this.handlePlaybackEnded(e, tile)} + onDoubleClick={e => {}} + /> + ) + })} + </div> + </div> + ) + } + + removeRoadblock() { + console.log("remove roadblock") + actions.site.interact() + this.setState({ roadblock: false }) + this.props.audio.player.playPage(this.state.page) + this.resetTimer(this.state.page) + } + + renderRoadblock() { + const { title } = this.props.graph + return ( + <div className='roadblock' onClick={this.removeRoadblock}> + <div> + <h2>{title}</h2> + <button>Enter</button> + </div> + </div> + ) + } +} + +const hasAutoplay = page => { + const hasAutoplayVideo = page.tiles.some(tile => { + return tile.type === 'video' && !tile.settings.muted + }) + const hasAutoplayAudio = page.settings.background_audio_id > 0 + return hasAutoplayAudio || hasAutoplayVideo +} + +const mapStateToProps = state => ({ + site: state.site, + audio: state.audio, + graph: state.site.graph, + interactive: state.site.interactive, +}) + +const mapDispatchToProps = dispatch => ({ +}) + +export default connect(mapStateToProps, mapDispatchToProps)(ViewerContainer) |
