Skip to content

Commit 520ded9

Browse files
committed
Overlay for loading and error states
1 parent 26b5b0d commit 520ded9

File tree

8 files changed

+177
-44
lines changed

8 files changed

+177
-44
lines changed

src/DefaultPlayer/DefaultPlayer.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Volume from './Volume/Volume';
1818
import Captions from './Captions/Captions';
1919
import PlayPause from './PlayPause/PlayPause';
2020
import Fullscreen from './Fullscreen/Fullscreen';
21-
import ErrorMessage from './ErrorMessage/ErrorMessage';
21+
import Overlay from './Overlay/Overlay';
2222

2323
export const DefaultPlayer = ({
2424
video,
@@ -41,17 +41,15 @@ export const DefaultPlayer = ({
4141
className
4242
].join(' ')}
4343
style={style}>
44-
{ video && video.error
45-
? <ErrorMessage
46-
className={styles.error}
47-
{...video} />
48-
: null }
4944
<video
5045
className={styles.video}
5146
{...restProps}>
5247
{ children }
5348
</video>
54-
{ controls && controls.length
49+
<Overlay
50+
onClick={onPlayPauseClick}
51+
{...video} />
52+
{ controls && controls.length && !video.error
5553
? <div className={styles.controls}>
5654
{ controls.map((control, i) => {
5755
switch (control) {
@@ -82,7 +80,7 @@ export const DefaultPlayer = ({
8280
onClick={onVolumeClick}
8381
{...video} />;
8482
case 'Captions':
85-
return video && video.textTracks && video.textTracks.length
83+
return video.textTracks && video.textTracks.length
8684
? <Captions
8785
key={i}
8886
onClick={onCaptionsClick}
@@ -102,18 +100,23 @@ export const DefaultPlayer = ({
102100
const controls = ['PlayPause', 'Seek', 'Time', 'Volume', 'Fullscreen', 'Captions'];
103101

104102
DefaultPlayer.defaultProps = {
103+
video: {},
105104
controls
106105
};
107106

108107
DefaultPlayer.propTypes = {
108+
video: PropTypes.object.isRequired,
109109
controls: PropTypes.arrayOf(PropTypes.oneOf(controls))
110110
};
111111

112112
export default videoConnect(
113113
DefaultPlayer,
114-
({ networkState, error, ...restState }) => ({
114+
({ networkState, readyState, error, ...restState }) => ({
115115
video: {
116+
readyState,
117+
networkState,
116118
error: error || networkState === 3,
119+
loading: readyState < 4,
117120
percentagePlayed: getPercentagePlayed(restState),
118121
percentageBuffered: getPercentageBuffered(restState),
119122
...restState

src/DefaultPlayer/DefaultPlayer.test.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Seek from './Seek/Seek';
77
import Volume from './Volume/Volume';
88
import PlayPause from './PlayPause/PlayPause';
99
import Fullscreen from './Fullscreen/Fullscreen';
10-
import ErrorMessage from './ErrorMessage/ErrorMessage';
10+
import Overlay from './Overlay/Overlay';
1111

1212
describe('DefaultPlayer', () => {
1313
let component;
@@ -45,15 +45,8 @@ describe('DefaultPlayer', () => {
4545
.toEqual(true);
4646
});
4747

48-
it('shows the error component when required', () => {
49-
expect(component.find(ErrorMessage).exists())
50-
.toBeFalsy();
51-
component.setProps({
52-
video: {
53-
error: true
54-
}
55-
});
56-
expect(component.find(ErrorMessage).exists())
48+
it('has an overlay component', () => {
49+
expect(component.find(Overlay).exists())
5750
.toBeTruthy();
5851
});
5952

@@ -93,4 +86,23 @@ describe('DefaultPlayer', () => {
9386
expect(component.find(`.${styles.controls}`).exists())
9487
.toBeFalsy();
9588
});
89+
90+
it('renders no controls when there is an error', () => {
91+
component.setProps({
92+
controls: ['PlayPause'],
93+
video: {
94+
error: false
95+
}
96+
});
97+
expect(component.find(`.${styles.controls}`).exists())
98+
.toBeTruthy();
99+
component.setProps({
100+
controls: ['PlayPause'],
101+
video: {
102+
error: true
103+
}
104+
});
105+
expect(component.find(`.${styles.controls}`).exists())
106+
.toBeFalsy();
107+
});
96108
});

src/DefaultPlayer/ErrorMessage/ErrorMessage.css

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/DefaultPlayer/ErrorMessage/ErrorMessage.js

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/DefaultPlayer/Icon/spin.svg

Lines changed: 1 addition & 0 deletions
Loading

src/DefaultPlayer/Overlay/Overlay.css

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.component {
2+
position: absolute;
3+
top: 0;
4+
right: 0;
5+
bottom: 0;
6+
left: 0;
7+
color: #fff;
8+
text-align: center;
9+
cursor: pointer;
10+
}
11+
12+
.inner {
13+
display: inline-block;
14+
position: absolute;
15+
top: 50%;
16+
right: 0;
17+
left: 50%;
18+
width: 60px;
19+
height: 60px;
20+
transform: translateY(-50%);
21+
margin-left: -30px;
22+
background-color: rgba(0,0,0,0.7);
23+
border-radius: 10px;
24+
}
25+
26+
.icon {
27+
position: absolute;
28+
top: 50%;
29+
right: 0;
30+
left: 50%;
31+
margin-left: -20px;
32+
transform: translateY(-50%);
33+
}

src/DefaultPlayer/Overlay/Overlay.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React, { Component } from 'react';
2+
import styles from './Overlay.css';
3+
import PlayArrow from './../Icon/play_arrow.svg';
4+
import Spin from './../Icon/spin.svg';
5+
import Report from './../Icon/report.svg';
6+
7+
export default class Overlay extends Component {
8+
renderContent () {
9+
const {
10+
error,
11+
paused,
12+
loading
13+
} = this.props;
14+
const iconProps = {
15+
className: styles.icon,
16+
height: 40,
17+
width: 40,
18+
fill: '#fff'
19+
};
20+
if (error) {
21+
return (
22+
<span className={styles.inner}>
23+
<Report {...iconProps} />
24+
</span>
25+
);
26+
} else if (loading) {
27+
return (
28+
<span className={styles.inner}>
29+
<Spin {...iconProps} />
30+
</span>
31+
);
32+
} else if (paused) {
33+
return (
34+
<span className={styles.inner}>
35+
<PlayArrow {...iconProps} />
36+
</span>
37+
);
38+
}
39+
}
40+
41+
render () {
42+
const { className, onClick } = this.props;
43+
return (
44+
<div className={[
45+
styles.component,
46+
className
47+
].join(' ')}
48+
onClick={onClick}>
49+
{ this.renderContent() }
50+
</div>
51+
);
52+
}
53+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from 'react';
2+
import { shallow } from 'enzyme';
3+
import Overlay from './Overlay';
4+
import styles from './Overlay.css';
5+
import PlayArrow from './../Icon/play_arrow.svg';
6+
import Spin from './../Icon/spin.svg';
7+
import Report from './../Icon/report.svg';
8+
9+
describe('Overlay', () => {
10+
let component;
11+
12+
beforeAll(() => {
13+
component = shallow(<Overlay />);
14+
});
15+
16+
it('should accept a className prop and append it to the components class', () => {
17+
const newClassNameString = 'a new className';
18+
expect(component.prop('className'))
19+
.toContain(styles.component);
20+
component.setProps({
21+
className: newClassNameString
22+
});
23+
expect(component.prop('className'))
24+
.toContain(styles.component);
25+
expect(component.prop('className'))
26+
.toContain(newClassNameString);
27+
});
28+
29+
it('shows a PlayArrow icon if paused', () => {
30+
component.setProps({
31+
paused: true
32+
});
33+
expect(component.html())
34+
.toContain(PlayArrow);
35+
});
36+
37+
it('shows Report icon if error regardless of loading or paused state', () => {
38+
component.setProps({
39+
error: true,
40+
loading: true,
41+
paused: true
42+
});
43+
expect(component.html())
44+
.toContain(Report);
45+
});
46+
47+
it('shows Spin icon if loading regardless of paused state', () => {
48+
component.setProps({
49+
loading: true,
50+
paused: true,
51+
error: false
52+
});
53+
expect(component.html())
54+
.toContain(Spin);
55+
});
56+
});

0 commit comments

Comments
 (0)