Unverified Commit fec148ac authored by Sarah Otts's avatar Sarah Otts Committed by GitHub

Merge pull request #4682 from LLK/annual-report-video-spinner

Add loading spinner in Annual Report
parents b08ea58f 246798b6
...@@ -3,6 +3,8 @@ const PropTypes = require('prop-types'); ...@@ -3,6 +3,8 @@ const PropTypes = require('prop-types');
const React = require('react'); const React = require('react');
const Video = require('../video/video.jsx'); const Video = require('../video/video.jsx');
const Spinner = require('../spinner/spinner.jsx');
const classNames = require('classnames');
require('./video-preview.scss'); require('./video-preview.scss');
...@@ -10,16 +12,25 @@ class VideoPreview extends React.Component { ...@@ -10,16 +12,25 @@ class VideoPreview extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
bindAll(this, [ bindAll(this, [
'handleShowVideo' 'handleShowVideo',
'handleVideoLoaded'
]); ]);
this.state = { this.state = {
videoOpen: false videoOpen: false,
spinnerVisible: false
}; };
} }
handleShowVideo () { handleShowVideo () {
this.setState({videoOpen: true}); this.setState({
videoOpen: true,
spinnerVisible: true
});
}
handleVideoLoaded () {
this.setState({spinnerVisible: false});
} }
render () { render () {
...@@ -27,17 +38,26 @@ class VideoPreview extends React.Component { ...@@ -27,17 +38,26 @@ class VideoPreview extends React.Component {
<div className="video-preview"> <div className="video-preview">
{this.state.videoOpen ? {this.state.videoOpen ?
( (
<div className="spinner-video-container">
{this.state.spinnerVisible ? <Spinner className="loading-spinner" /> : null}
<Video <Video
className="video" className="video"
height={this.props.videoHeight} height={this.props.videoHeight}
videoId={this.props.videoId} videoId={this.props.videoId}
width={this.props.videoWidth} width={this.props.videoWidth}
onVideoStart={this.handleVideoLoaded}
/> />
</div>
) : ( ) : (
<div <div
className="video-thumbnail" className="video-thumbnail"
onClick={this.handleShowVideo} onClick={this.handleShowVideo}
> >
{/* Load an invisible spinner so that the image has a chance to load before it's needed */}
<img
className={classNames('loading-spinner', 'hidden-spinner')}
src="/svgs/modal/spinner-white.svg"
/>
<img <img
src={this.props.thumbnail} src={this.props.thumbnail}
style={{ style={{
......
...@@ -24,3 +24,32 @@ ...@@ -24,3 +24,32 @@
margin-top: 20px; margin-top: 20px;
} }
} }
.loading-spinner {
margin: auto;
width: 5rem;
height: 5rem;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.hidden-spinner {
visibility: hidden;
}
.spinner-video-container {
width: 100%;
height: 100%;
position: relative;
}
.iframe-video-not-started {
visibility: hidden;
}
.iframe-video-started {
visibility: visible;
}
...@@ -4,25 +4,65 @@ const classNames = require('classnames'); ...@@ -4,25 +4,65 @@ const classNames = require('classnames');
require('./video.scss'); require('./video.scss');
const Video = props => ( class Video extends React.Component {
<div className={classNames('video-player', props.className)}> constructor (props) {
super(props);
this.state = {
videoStarted: false
};
}
componentDidMount () {
/**
uses code snippets from
https://github.com/mrdavidjcole/wistia-player-react/blob/master/src/components/wistia_embed.js
**/
if (!document.getElementById('wistia_script')) {
const wistiaScript = document.createElement('script');
wistiaScript.id = 'wistia_script';
wistiaScript.type = 'text/javascript';
wistiaScript.src = 'https://fast.wistia.com/assets/external/E-v1.js';
wistiaScript.async = false;
document.body.appendChild(wistiaScript);
}
window._wq = window._wq || [];
// Use onReady in combination with the Wistia 'play' event handler so that onVideoStart()
// isn't called until the video actually starts. onReady fires before the video player is visible.
window._wq.push({
id: this.props.videoId,
onReady: video => {
video.bind('play', () => {
this.setState({videoStarted: true});
this.props.onVideoStart();
return video.unbind;
});
}
});
}
render () {
// Provide CSS classes for anything using the video component to configure what happens before and after
// the video has played for the first time. See VideoPreview for an example.
const videoStartedClass = this.state.videoStarted ? 'iframe-video-started' : 'iframe-video-not-started';
return (
<div className={classNames('video-player', this.props.className)}>
<iframe <iframe
allowFullScreen allowFullScreen
// allowFullScreen is legacy, can we start using allow='fullscreen'? className={classNames('wistia_embed', `wistia_async_${this.props.videoId}`, videoStartedClass)}
// allow="fullscreen"
frameBorder="0" // deprecated attribute frameBorder="0" // deprecated attribute
height={props.height} height={this.props.height}
scrolling="no" // deprecated attribute scrolling="no" // deprecated attribute
src={`https://fast.wistia.net/embed/iframe/${props.videoId}?seo=false&videoFoam=true`} src={`https://fast.wistia.net/embed/iframe/${this.props.videoId}?seo=false&videoFoam=true`}
title={props.title} title={this.props.title}
width={props.width} width={this.props.width}
/>
<script
async
src="https://fast.wistia.net/assets/external/E-v1.js"
/> />
</div> </div>
); );
}
}
Video.defaultProps = { Video.defaultProps = {
height: '225', height: '225',
title: '', title: '',
...@@ -32,6 +72,7 @@ Video.defaultProps = { ...@@ -32,6 +72,7 @@ Video.defaultProps = {
Video.propTypes = { Video.propTypes = {
className: PropTypes.string, className: PropTypes.string,
height: PropTypes.string.isRequired, height: PropTypes.string.isRequired,
onVideoStart: PropTypes.func,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
videoId: PropTypes.string.isRequired, videoId: PropTypes.string.isRequired,
width: PropTypes.string.isRequired width: PropTypes.string.isRequired
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment