diff --git a/client/package-lock.json b/client/package-lock.json index 782df3fbc2..2cac7088e5 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1740,6 +1740,15 @@ "@types/yargs": "^13.0.0" } }, + "@loadable/component": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@loadable/component/-/component-5.12.0.tgz", + "integrity": "sha512-eDG7FPZ8tCFA/mqu2IrYV6eS+UxGBo21PwtEV9QpkpYrx25xKRXzJUm36yfQPK3o7jXu43xpPkwiU4mLWcjJlw==", + "requires": { + "@babel/runtime": "^7.7.7", + "hoist-non-react-statics": "^3.3.1" + } + }, "@mdx-js/mdx": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.1.tgz", @@ -5642,6 +5651,11 @@ "array-find-index": "^1.0.1" } }, + "custom-event-polyfill": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz", + "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==" + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -11746,9 +11760,9 @@ "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -11756,9 +11770,9 @@ }, "dependencies": { "eventemitter3": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.1.tgz", - "integrity": "sha512-MnI0l35oYL2C/c80rjJN7qu50MDx39yYE7y7oYck2YA3v+y7EaAenY8IU8AP4d1RWqE8VAKWFGSh3rfP87ll3g==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" } } }, @@ -14030,6 +14044,11 @@ "resolved": "https://registry.npmjs.org/loaders.css/-/loaders.css-0.1.2.tgz", "integrity": "sha1-Op+0NybHMzSjgUKvnQYpAZtlh0M=" }, + "loadjs": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz", + "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==" + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -15953,6 +15972,33 @@ } } }, + "plyr": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/plyr/-/plyr-3.6.2.tgz", + "integrity": "sha512-CjAhRDtzyGqMRte9Phj4FsZFegS9VxW60boOhQsAnZHuiFG3yVBRcodWsGZ79GuXHHelc4DxMHO+z0QggY+9qQ==", + "requires": { + "core-js": "^3.6.5", + "custom-event-polyfill": "^1.0.7", + "loadjs": "^4.2.0", + "rangetouch": "^2.0.1", + "url-polyfill": "^1.1.8" + }, + "dependencies": { + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" + } + } + }, + "plyr-react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/plyr-react/-/plyr-react-2.2.0.tgz", + "integrity": "sha512-nA0cdJf6ER73CRc+XRy+DeXPltuuOomoVtSwrljhQW1JT0trH2w97kE+OQ+O+bXafOKDGgN10PR4BNnLNTowmQ==", + "requires": { + "plyr": "^3.5.6" + } + }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -16975,6 +17021,11 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "rangetouch": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz", + "integrity": "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==" + }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", @@ -17592,16 +17643,6 @@ } } }, - "react-youtube": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.11.2.tgz", - "integrity": "sha512-QOrk5Wr1m9/AmWMftyn1p5nPq1GMiWdB6IYn1hT+0czyy5xV9jtKVlsBqsscY6WZrokko868VUJM9yn6GhsD7g==", - "requires": { - "fast-deep-equal": "3.1.1", - "prop-types": "15.7.2", - "youtube-player": "5.5.2" - } - }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -19001,11 +19042,6 @@ } } }, - "sister": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz", - "integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==" - }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -21202,6 +21238,11 @@ "prepend-http": "^2.0.0" } }, + "url-polyfill": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.9.tgz", + "integrity": "sha512-q/R5sowGuRfKHm497swkV+s9cPYtZRkHxzpDjRhqLO58FwdWTIkt6Y/fJlznUD/exaKx/XnDzCYXz0V16ND7ow==" + }, "url-to-options": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", @@ -22198,16 +22239,6 @@ "@types/yoga-layout": "1.9.1" } }, - "youtube-player": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz", - "integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==", - "requires": { - "debug": "^2.6.6", - "load-script": "^1.0.0", - "sister": "^3.0.0" - } - }, "yurnalist": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/yurnalist/-/yurnalist-1.1.2.tgz", diff --git a/client/package.json b/client/package.json index bc382cf1df..6cf17b4282 100644 --- a/client/package.json +++ b/client/package.json @@ -17,6 +17,7 @@ "@freecodecamp/loop-protect": "^2.2.1", "@freecodecamp/react-bootstrap": "^0.32.3", "@freecodecamp/react-calendar-heatmap": "^1.0.0", + "@loadable/component": "^5.12.0", "@reach/router": "^1.2.1", "algoliasearch": "^3.35.1", "axios": "^0.19.0", @@ -46,6 +47,7 @@ "lodash": "^4.17.15", "monaco-editor": "^0.20.0", "nanoid": "^1.2.2", + "plyr-react": "^2.2.0", "prismjs": "^1.20.0", "query-string": "^6.12.1", "react": "^16.10.2", @@ -64,7 +66,6 @@ "react-stripe-elements": "^2.0.3", "react-tooltip": "^4.2.6", "react-transition-group": "^4.4.1", - "react-youtube": "^7.11.2", "redux": "^4.0.4", "redux-actions": "^2.6.5", "redux-devtools-extension": "^2.13.8", diff --git a/client/src/templates/Challenges/video/Plyr.js b/client/src/templates/Challenges/video/Plyr.js new file mode 100644 index 0000000000..895440cfd0 --- /dev/null +++ b/client/src/templates/Challenges/video/Plyr.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { PlyrComponent } from 'plyr-react'; +import PropTypes from 'prop-types'; + +const Plyr = ({ sources }) => { + return ; +}; + +Plyr.propTypes = { + sources: PropTypes.shape({ + type: PropTypes.string.isRequired, + sources: PropTypes.arrayOf( + PropTypes.shape({ + src: PropTypes.string.isRequired, + provider: PropTypes.string.isRequired + }) + ).isRequired + }) +}; + +export default Plyr; diff --git a/client/src/templates/Challenges/video/Show.js b/client/src/templates/Challenges/video/Show.js index e87a018b79..df66de5e56 100644 --- a/client/src/templates/Challenges/video/Show.js +++ b/client/src/templates/Challenges/video/Show.js @@ -6,9 +6,9 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { graphql } from 'gatsby'; import Helmet from 'react-helmet'; -import YouTube from 'react-youtube'; import { createSelector } from 'reselect'; import { ObserveKeys } from 'react-hotkeys'; +import Loadable from '@loadable/component'; // Local Utilities import PrismFormatted from '../components/PrismFormatted'; @@ -19,7 +19,6 @@ import ChallengeDescription from '../components/Challenge-Description'; import Spacer from '../../../components/helpers/Spacer'; import CompletionModal from '../components/CompletionModal'; import Hotkeys from '../components/Hotkeys'; -import Loader from '../../../components/helpers/Loader'; import { isChallengeCompletedSelector, challengeMounted, @@ -31,6 +30,9 @@ import { // Styles import './show.css'; +// Plyr uses 'document', so must be loaded dynamically to avoid breaking SSR +const LoadablePlyr = Loadable(() => import('./Plyr')); + // Redux Setup const mapStateToProps = createSelector( isChallengeCompletedSelector, @@ -74,8 +76,7 @@ export class Project extends Component { downloadURL: null, selectedOption: null, answer: 1, - showWrong: false, - videoIsLoaded: false + showWrong: false }; this.handleSubmit = this.handleSubmit.bind(this); @@ -139,12 +140,6 @@ export class Project extends Component { }); }; - videoIsReady = () => { - this.setState({ - videoIsLoaded: true - }); - }; - render() { const { data: { @@ -183,26 +178,20 @@ export class Project extends Component { {blockNameTitle} -
- {!this.state.videoIsLoaded ? ( -
- -
- ) : null} - +
+ +