diff --git a/.babelrc b/.babelrc index aef13b0f4..1a025a840 100644 --- a/.babelrc +++ b/.babelrc @@ -3,8 +3,9 @@ "plugins": [ "transform-runtime", "transform-decorators-legacy", - "transform-react-display-name", - ["system-import-transformer", {"modules": "common"}] + "transform-react-display-name", ["system-import-transformer", { + "modules": "common" + }] ], "env": { "development": { diff --git a/bin/server.js b/bin/server.js index 1425cd949..1f0a83989 100644 --- a/bin/server.js +++ b/bin/server.js @@ -1,6 +1,7 @@ require('dotenv').load(); require('app-module-path').addPath(__dirname); require('app-module-path').addPath('../src'); +require('isomorphic-fetch'); var fs = require('fs'); var path = require('path'); diff --git a/package.json b/package.json index e1d3cfdd4..5567f5d07 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,12 @@ "build:server": "babel ./src -d ./dist -D", "build:client": "webpack --config ./webpack/prod.config.js", "validate": "npm ls", - "analyze:build": "env NODE_ENV=production webpack --json --config ./webpack/prod.config.js > bundle-stats.json", - "analyze:json": "webpack-bundle-size-analyzer bundle-stats.json", + "analyze:build": "env NODE_ENV=production webpack --profile --json --config ./webpack/prod.config.js > bundle-stats.json", + "analyze:json": "webpack-bundle-analyzer bundle-stats.json", "lint:fix": "npm run test:dev:lint -- --fix", "prettier": "prettier --single-quote --write", - "precommit": "lint-staged" + "precommit": "lint-staged", + "postinstall": "rm -rf node_modules/react-apollo/node_modules/react-dom" }, "pre-commit": [ "test:stylelint", @@ -42,6 +43,7 @@ "node": ">= 6.3.0" }, "dependencies": { + "apollo-client": "^1.9.0-0", "app-module-path": "1.0.2", "autoprefixer": "6.6.1", "autoprefixer-loader": "3.2.0", @@ -49,6 +51,7 @@ "babel-core": "^6.24.0", "babel-loader": "^7.0.0", "babel-plugin-add-module-exports": "0.1.4", + "babel-plugin-import-inspector": "^2.0.0", "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-system-import-transformer": "^3.1.0", "babel-plugin-transform-decorators-legacy": "1.3.4", @@ -90,6 +93,7 @@ "extract-text-webpack-plugin": "^2.1.0", "file-loader": "0.8.5", "fontfaceobserver": "1.7.3", + "graphql-tag": "^2.4.2", "history": "^3.0.0", "html-pdf": "^2.1.0", "html-webpack-plugin": "1.7.0", @@ -97,42 +101,46 @@ "humps": "2.0.0", "image-webpack-loader": "3.1.0", "imports-loader": "0.6.5", + "isomorphic-fetch": "^2.2.1", "json-loader": "0.5.4", + "loadable-components": "^0.2.0", "morgan": "1.7.0", - "node-sass": "4.1.1", + "node-sass": "^4.5.3", "normalizr": "3.0.2", "postcss-loader": "0.9.1", "precss": "1.4.0", "pretty-error": "2.0.0", "promise": "7.1.1", + "prop-types": "^15.5.10", "proxy-middleware": "0.14.0", - "qs": "6.2.1", + "qs": "^6.5.0", "quran-components": "^0.0.80", "raven": "1.1.1", "raw-loader": "0.5.1", - "react": "15.4.1", + "react": "^15.6.1", "react-a11y": "0.3.3", "react-addons-create-fragment": "15.4.1", + "react-apollo": "^1.4.3", "react-bootstrap": "0.30.7", "react-cookie": "1.0.4", - "react-dom": "15.4.1", + "react-dom": "^15.6.1", "react-helmet": "3.1.0", "react-hot-loader": "next", "react-inlinesvg": "0.5.4", "react-intl": "2.1.5", - "react-loadable": "^3.3.1", + "react-loadable": "^4.0.3", "react-metrics": "1.2.1", "react-paginate": "4.1.0", "react-redux": "5.0.1", - "react-router": "3.0.0", - "react-router-bootstrap": "0.20.1", + "react-router": "^4.1.1", + "react-router-bootstrap": "^0.24.2", + "react-router-dom": "^4.1.1", "react-router-redux": "4.0.7", - "react-router-scroll": "0.2.1", "react-scroll": "1.2.0", "react-share": "1.11.0", "react-sidebar": "2.2.1", + "react-virtualized": "^9.9.0", "redux": "3.5.2", - "redux-connect": "5.0.0", "reselect": "2.5.3", "resolve-url": "0.2.1", "resolve-url-loader": "1.6.1", @@ -148,7 +156,6 @@ "url-loader": "0.5.7", "webpack": "^2.5.1", "webpack-dev-middleware": "^1.10.2", - "webpack-dev-server": "^2.4.5", "webpack-isomorphic-tools": "2.5.7", "winston": "1.1.2" }, @@ -202,7 +209,7 @@ "stylelint-webpack-plugin": "0.2.0", "webpack-bundle-analyzer": "2.2.1", "webpack-dashboard": "^0.4.0", - "webpack-dev-server": "2.1.0-beta.0", + "webpack-dev-server": "^2.4.5", "webpack-hot-middleware": "2.12.2" } } diff --git a/src/client.js b/src/client.js index 1ef5ec61a..65994190f 100644 --- a/src/client.js +++ b/src/client.js @@ -2,28 +2,22 @@ import React from 'react'; import ReactDOM from 'react-dom'; import reactCookie from 'react-cookie'; -import Router from 'react-router/lib/Router'; -import match from 'react-router/lib/match'; -import browserHistory from 'react-router/lib/browserHistory'; -import applyRouterMiddleware from 'react-router/lib/applyRouterMiddleware'; -import useScroll from 'react-router-scroll'; -import { ReduxAsyncConnect } from 'redux-connect'; -import { syncHistoryWithStore } from 'react-router-redux'; + import { AppContainer } from 'react-hot-loader'; -import { ThemeProvider } from 'styled-components'; +import { loadComponents } from 'loadable-components'; -import debug from 'debug'; +import debug from './helpers/debug'; import config from './config'; -import theme from './theme'; import ApiClient from './helpers/ApiClient'; import createStore from './redux/create'; -import routes from './routes'; import Root from './containers/Root'; +import createClient from './graphql/client'; -const client = new ApiClient(); -const store = createStore(browserHistory, client, window.reduxData); -const history = syncHistoryWithStore(browserHistory, store); +const api = new ApiClient(); +// eslint-disable-next-line +const client = createClient({ initialState: window.__APOLLO_STATE__ }); +const store = createStore(client, api, window.reduxData); try { Raven.config(config.sentryClient).install(); @@ -45,49 +39,23 @@ window.clearCookies = () => { reactCookie.remove('smartbanner-installed'); }; -match( - { history, routes: routes(store) }, - (error, redirectLocation, renderProps) => { - const component = ( - - ( - - )} - /> - - ); - - const mountNode = document.getElementById('app'); +const mountNode = document.getElementById('app'); - debug('client', 'React Rendering'); +loadComponents().then(() => { + const render = (component, time) => { + ReactDOM.render({component}, mountNode, () => { + debug('client', `React Rendered ${time} time`); + }); + }; - ReactDOM.render( - - - , - mountNode, - () => { - debug('client', 'React Rendered'); - } - ); + render(, 'first'); - if (module.hot) { - module.hot.accept('./containers/Root', () => { - const NextRoot = require('./containers/Root'); // eslint-disable-line global-require + if (module.hot) { + debug('client:hot', 'Activated'); - ReactDOM.render( - - - , - document.getElementById('root') - ); - }); - } + module.hot.accept('./containers/Root', () => { + debug('client:hot', 'Reload'); + render(, 'second'); + }); } -); +}); diff --git a/src/components/Audioplayer/RepeatDropdown/index.js b/src/components/Audioplayer/RepeatDropdown/index.js index 064b2f7ec..7e4e622ff 100644 --- a/src/components/Audioplayer/RepeatDropdown/index.js +++ b/src/components/Audioplayer/RepeatDropdown/index.js @@ -1,4 +1,5 @@ -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import * as customPropTypes from 'customPropTypes'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Popover from 'react-bootstrap/lib/Popover'; @@ -44,7 +45,9 @@ class RepeatButton extends Component { renderRangeAyahs() { const { chapter, repeat, setRepeat } = this.props; - const array = Array(chapter.versesCount).join().split(','); + const array = Array(chapter.versesCount) + .join() + .split(','); return (
@@ -53,8 +56,7 @@ class RepeatButton extends Component { - {' '} + />{' '} :
- { - array.reduce((options, ayah, index) => { - if (index + 1 < chapter.versesCount) { // Exclude last verse - options.push( - - ); - } - return options; - }, []) - } + {array.reduce((options, ayah, index) => { + if (index + 1 < chapter.versesCount) { + // Exclude last verse + options.push( + + ); + } + return options; + }, [])}
  • -
  • @@ -89,8 +90,7 @@ class RepeatButton extends Component { - {' '} + />{' '} :
    setRepeat({ ...repeat, to: parseInt(event.target.value, 10) })} > - { - array.reduce((options, ayah, index) => { - if ((repeat.from ? repeat.from : 1) < index + 1 && index + 1 <= chapter.versesCount) { // eslint-disable-line max-len - options.push( - - ); - } - return options; - }, []) - } + {array.reduce((options, ayah, index) => { + if ( + (repeat.from ? repeat.from : 1) < index + 1 && + index + 1 <= chapter.versesCount + ) { + // eslint-disable-line max-len + options.push( + + ); + } + return options; + }, [])} @@ -120,18 +122,17 @@ class RepeatButton extends Component { renderSingleAyah() { const { repeat, setRepeat, chapter } = this.props; - const array = Array(chapter.versesCount).join().split(','); + const array = Array(chapter.versesCount) + .join() + .split(','); return (
    - {' '} - : - {' '} -
    + />{' '} + :
    @@ -204,9 +207,7 @@ class RepeatButton extends Component { id="player.repeat.title" defaultMessage="Repeat" /> - : - {' '} -
    + :
    @@ -282,7 +284,7 @@ class RepeatButton extends Component { } RepeatButton.propTypes = { - chapter: customPropTypes.surahType, + chapter: customPropTypes.chapterType, repeat: customPropTypes.timeInterval, setRepeat: PropTypes.func.isRequired, current: PropTypes.number.isRequired, diff --git a/src/components/Audioplayer/ScrollButton/index.js b/src/components/Audioplayer/ScrollButton/index.js index 5b72b8411..a4c0a5507 100644 --- a/src/components/Audioplayer/ScrollButton/index.js +++ b/src/components/Audioplayer/ScrollButton/index.js @@ -1,5 +1,6 @@ -import React, { PropTypes } from 'react'; import styled from 'styled-components'; +import React from 'react'; +import PropTypes from 'prop-types'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; diff --git a/src/components/Audioplayer/Segments/index.js b/src/components/Audioplayer/Segments/index.js index 80a4c0139..237d666d8 100644 --- a/src/components/Audioplayer/Segments/index.js +++ b/src/components/Audioplayer/Segments/index.js @@ -1,4 +1,5 @@ -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import * as customPropTypes from 'customPropTypes'; import Helmet from 'react-helmet'; import debug from 'helpers/debug'; @@ -7,7 +8,7 @@ class Segments extends Component { shouldComponentUpdate(nextProps) { return [ this.props.currentVerse !== nextProps.currentVerse, - this.props.currentTime !== nextProps.currentTime, + this.props.currentTime !== nextProps.currentTime ].some(test => test); } @@ -39,11 +40,7 @@ class Segments extends Component { debug('component:Segments', 'render without currentWord'); } - return ( - - ); + return ; } } diff --git a/src/components/Audioplayer/Track/index.js b/src/components/Audioplayer/Track/index.js index 9c1e8d300..8044d75d4 100644 --- a/src/components/Audioplayer/Track/index.js +++ b/src/components/Audioplayer/Track/index.js @@ -1,6 +1,8 @@ /* eslint-disable jsx-a11y/no-static-element-interactions */ -import React, { Component, PropTypes } from 'react'; + import styled from 'styled-components'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; const Container = styled.div` height: 6px; @@ -37,6 +39,14 @@ export default class Track extends Component { onTrackChange: PropTypes.func.isRequired }; + constructor(props) { + super(props); + + this.setContainer = (container) => { + this.container = container; + }; + } + handleClick = (event) => { const { onTrackChange } = this.props; @@ -50,12 +60,7 @@ export default class Track extends Component { const { progress } = this.props; return ( - { - this.container = container; - }} - onClick={this.handleClick} - > + ); diff --git a/src/components/Audioplayer/index.js b/src/components/Audioplayer/index.js index c001f8467..14d291cde 100644 --- a/src/components/Audioplayer/index.js +++ b/src/components/Audioplayer/index.js @@ -1,10 +1,10 @@ /* global document */ // TODO: This file is too too large. -import React, { Component, PropTypes } from 'react'; import styled from 'styled-components'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import * as customPropTypes from 'customPropTypes'; import { connect } from 'react-redux'; -import { camelize } from 'humps'; import Loadable from 'react-loadable'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; @@ -24,10 +24,27 @@ const style = require('./style.scss'); const RepeatDropdown = Loadable({ loader: () => - import(/* webpackChunkName: "repeatdropdown" */ './RepeatDropdown'), - LoadingComponent: ComponentLoader + import(/* webpackChunkName: "RepeatDropdown" */ './RepeatDropdown'), + loading: ComponentLoader }); +const Container = styled.div` + position: fixed; + bottom: 15px; + display: block; + user-select: none; + height: auto; + z-index: 1; + padding: 10px 20px 5px; + background: #fff; + box-shadow: 0 0 0.5rem 0 rgba(0, 0, 0, 0.2); + min-width: 340px; + @media (max-width: $screen-sm) { + bottom: 0; + width: 100%; + } +`; + const Wrapper = styled.div` width: 100%; position: absolute; @@ -36,9 +53,14 @@ const Wrapper = styled.div` height: 10%; `; -const ControlItem = styled.li` +const ControlsContainer = styled.div` + display: table; + width: 100%; +`; + +const ControlItem = styled.div` + display: table-cell; vertical-align: middle; - padding-right: 20px; color: #939598; `; @@ -48,8 +70,7 @@ export class Audioplayer extends Component { }; componentDidMount() { - const { currentFile, currentVerse, audio, verses, load } = this.props; // eslint-disable-line no-shadow, max-len - const nextVerse = verses[this.getNext()]; + const { currentFile } = this.props; // eslint-disable-line no-shadow, max-len debug('component:Audioplayer', 'componentDidMount'); @@ -57,108 +78,62 @@ export class Audioplayer extends Component { return this.handleAddFileListeners(currentFile); } - load({ - chapterId: currentVerse.chapterId, - verseId: currentVerse.id, - verseKey: currentVerse.verseKey, - audio - }); - - if (nextVerse) { - load({ - chapterId: nextVerse.chapterId, - verseId: nextVerse.id, - verseKey: nextVerse.verseKey, - audio - }); - } - return false; } - componentWillReceiveProps(nextProps) { - // Make sure we have a current ayah to mount it to Audio - if (!this.props.currentVerse && !nextProps.currentFile) { - return false; - } - - // First load - if (this.props.currentFile !== nextProps.currentFile) { - if (this.props.currentFile) { - this.handleRemoveFileListeners(this.props.currentFile); - } - - return this.handleAddFileListeners(nextProps.currentFile); - } - - // Change verse - if (this.props.currentVerse.verseKey !== nextProps.currentVerse.verseKey) { - if (this.props.currentFile) { - this.handleRemoveFileListeners(this.props.currentFile); - } + componentWillReceiveProps({ currentFile: nextFile }) { + const { currentFile } = this.props; - return this.handleAddFileListeners(nextProps.currentFile); + if (!currentFile && nextFile) { + this.handleAddFileListeners(nextFile); } - if (this.props.audio !== nextProps.audio) { - Object.keys(this.props.files).forEach(key => - this.props.load({ - chapterId: this.props.verses[key].chapterId, - verseId: this.props.verses[key].id, - verseKey: this.props.verses[key].verseKey, - audio: nextProps.audio - }) - ); + if (currentFile !== nextFile) { + this.handleAddFileListeners(nextFile); } - - return false; } - componentDidUpdate(previousProps) { - const { - currentFile, - isPlaying, - verses, - audio, - currentVerse, - load - } = this.props; - - if ( - currentVerse.verseKey !== previousProps.currentVerse.verseKey && - verses[this.getNext()] - ) { - const verse = verses[this.getNext()]; - load({ - chapterId: verse.chapterId, - verseId: verse.id, - verseKey: verse.verseKey, - audio - }); - } + componentDidUpdate({ + isPlaying: previousPlaying, + currentFile: previousFile + }) { + const { currentFile, isPlaying } = this.props; if (!currentFile) return false; - if (isPlaying) { - const playPromise = currentFile.play(); - // Catch/silence error when a pause interrupts a play request - // on browsers which return a promise - if (playPromise !== undefined && typeof playPromise.then === 'function') { - playPromise.then(null, () => {}); + if (isPlaying !== previousPlaying) { + if (isPlaying) { + debug('component:Audioplayer', 'play'); + const playPromise = currentFile.play(); + // Catch/silence error when a pause interrupts a play request + // on browsers which return a promise + if ( + playPromise !== undefined && + typeof playPromise.then === 'function' + ) { + playPromise.then(null, () => {}); + } } - } else { - currentFile.pause(); - } - - return false; - } - componentWillUnmount() { - const { files, currentFile } = this.props; - debug('component:Audioplayer', 'componentWillUnmount'); + if (!isPlaying) { + debug('component:Audioplayer', 'pause'); + return currentFile.pause(); + } + } - if (files[currentFile]) { - return this.handleRemoveFileListeners(files[currentFile]); + if (currentFile !== previousFile) { + if (isPlaying) { + debug('component:Audioplayer', 'play'); + const playPromise = currentFile.play(); + // Catch/silence error when a pause interrupts a play request + // on browsers which return a promise + if ( + playPromise !== undefined && + typeof playPromise.then === 'function' + ) { + playPromise.then(null, () => {}); + } + } } return false; @@ -173,7 +148,7 @@ export class Audioplayer extends Component { getNext() { const { currentVerse, chapter, onLoadAyahs, verseIds } = this.props; - const ayahNum = currentVerse.verseKey.split(':')[1]; + const ayahNum = currentVerse.verseNumber; const index = verseIds.findIndex(id => id === currentVerse.verseKey); if (chapter.versesCount === ayahNum + 1) { @@ -189,35 +164,32 @@ export class Audioplayer extends Component { return verseIds[index + 1]; } - handleAyahChange = (direction = 'next') => { - const { isPlaying, play, pause, currentVerse } = this.props; // eslint-disable-line no-shadow, max-len - const previouslyPlaying = isPlaying; - - if (isPlaying) pause(); + handleVerseChange = (direction = 'next') => { + const { pause, currentVerse } = this.props; // eslint-disable-line no-shadow, max-len + const directions = { + next: 'getNext', + previous: 'getPrevious' + }; - const nextVerse = this[camelize(`get_${direction}`)](); + const nextVerse = this[directions[direction]](); if (!nextVerse) return pause(); this.props[direction](currentVerse.verseKey); this.handleScrollTo(nextVerse); - this.preloadNext(); - - if (previouslyPlaying) play(); - return false; }; - scrollToVerse = (ayahNum = this.props.currentVerse.verseKey) => { - scroller.scrollTo(`verse:${ayahNum}`, -45); + scrollToVerse = (verseNumber = this.props.currentVerse.verseKey) => { + scroller.scrollTo(`verse:${verseNumber}`, -45); }; - handleScrollTo = (ayahNum) => { + handleScrollTo = (verseNumber) => { const { shouldScroll } = this.props; if (shouldScroll) { - this.scrollToVerse(ayahNum); + this.scrollToVerse(verseNumber); } }; @@ -225,25 +197,8 @@ export class Audioplayer extends Component { this.handleScrollTo(); this.props.play(); - this.preloadNext(); }; - preloadNext() { - const { currentVerse, files } = this.props; - const ayahIds = Object.keys(files); - const index = ayahIds.findIndex(id => id === currentVerse.verseKey) + 1; - - for (let id = index; id <= index + 2; id += 1) { - if (ayahIds[id]) { - const verseKey = ayahIds[id]; - - if (files[verseKey]) { - files[verseKey].setAttribute('preload', 'auto'); - } - } - } - } - handleRepeat = (file) => { const { repeat, @@ -259,18 +214,18 @@ export class Audioplayer extends Component { if (repeat.from > ayah && repeat.to < ayah) { // user selected a range where current ayah is outside - return this.handleAyahChange(); + return this.handleVerseChange(); } if (repeat.from === repeat.to) { // user selected single ayah repeat - if (ayah !== repeat.from) return this.handleAyahChange(); + if (ayah !== repeat.from) return this.handleVerseChange(); if (repeat.times === 1) { // end of times setRepeat({}); - return this.handleAyahChange(); + return this.handleVerseChange(); } setRepeat({ ...repeat, times: repeat.times - 1 }); @@ -283,7 +238,7 @@ export class Audioplayer extends Component { // user selected a range if (ayah < repeat.to) { // still in range - return this.handleAyahChange(); + return this.handleVerseChange(); } if (ayah === repeat.to) { @@ -292,7 +247,7 @@ export class Audioplayer extends Component { // end of times setRepeat({}); - return this.handleAyahChange(); + return this.handleVerseChange(); } setRepeat({ ...repeat, times: repeat.times - 1 }); @@ -327,17 +282,13 @@ export class Audioplayer extends Component { // Preload file file.setAttribute('preload', 'auto'); + file.currentTime = 0; // eslint-disable-line - const onLoadeddata = () => { - // Default current time to zero. This will change - file.currentTime = 0; // eslint-disable-line - // file.currentTime || currentTime || 0; - - return update({ + const onLoadeddata = () => + update({ duration: file.duration, isLoading: false }); - }; const onTimeupdate = () => update({ @@ -352,11 +303,7 @@ export class Audioplayer extends Component { return this.handleRepeat(file); } - if (file.readyState >= 3 && file.paused) { - file.pause(); - } - - return this.handleAyahChange(); + return this.handleVerseChange(); }; const onPlay = () => { @@ -375,23 +322,8 @@ export class Audioplayer extends Component { return file; } - handleRemoveFileListeners = (file) => { - file.pause(); - file.currentTime = 0; // eslint-disable-line no-param-reassign - file.onloadeddata = null; // eslint-disable-line no-param-reassign - file.ontimeupdate = null; // eslint-disable-line no-param-reassign - file.onplay = null; // eslint-disable-line no-param-reassign - file.onpause = null; // eslint-disable-line no-param-reassign - file.onended = null; // eslint-disable-line no-param-reassign - file.onprogress = null; // eslint-disable-line no-param-reassign - }; - handleTrackChange = (fraction) => { - const { currentFile, update } = this.props; // eslint-disable-line no-shadow - - update({ - currentTime: fraction * currentFile.duration - }); + const { currentFile } = this.props; currentFile.currentTime = fraction * currentFile.duration; }; @@ -411,17 +343,16 @@ export class Audioplayer extends Component { } renderPreviousButton() { - const { currentVerse, files } = this.props; - if (!files) return false; - const index = Object.keys(files).findIndex( - id => id === currentVerse.verseKey - ); + const { chapter, currentVerse } = this.props; + if (!chapter) return null; + + const isBeginning = parseInt(currentVerse.verseNumber, 10) === 1; return ( index && this.handleAyahChange('previous')} + className={`pointer ${style.buttons} ${!isBeginning ? style.disabled : ''}`} + onClick={() => isBeginning && this.handleVerseChange('previous')} > @@ -430,15 +361,16 @@ export class Audioplayer extends Component { renderNextButton() { const { chapter, currentVerse } = this.props; - if (!chapter) return false; + if (!chapter) return null; + const isEnd = - chapter.versesCount === parseInt(currentVerse.verseKey.split(':')[1], 10); + chapter.versesCount === parseInt(currentVerse.verseNumber, 10); return ( !isEnd && this.handleAyahChange()} + onClick={() => !isEnd && this.handleVerseChange()} > @@ -446,18 +378,13 @@ export class Audioplayer extends Component { } render() { - debug('component:Audioplayer', 'render'); - const { className, segments, isLoading, currentVerse, currentFile, - currentTime, - duration, chapter, - isPlaying, repeat, // eslint-disable-line no-shadow shouldScroll, // eslint-disable-line no-shadow setRepeat // eslint-disable-line no-shadow @@ -465,45 +392,40 @@ export class Audioplayer extends Component { if (isLoading || !currentFile) { return ( -
  • +
    -
  • +
    ); } return ( -
    + - {currentFile && ( + {currentFile && - )} + />} {segments && - segments[currentVerse.verseKey] && ( - - )} + segments[currentVerse.verseKey] && + } -
      + - : {currentVerse.verseKey.split(':')[1]} + : {currentVerse.verseNumber} {this.renderPreviousButton()} {this.renderPlayStopButtons()} @@ -512,7 +434,7 @@ export class Audioplayer extends Component { @@ -522,8 +444,8 @@ export class Audioplayer extends Component { onScrollToggle={this.handleScrollToggle} /> -
    -
    + + ); } } @@ -535,8 +457,6 @@ const mapStateToProps = (state, ownProps) => { return { files, verseIds, - segments: state.audioplayer.segments[ownProps.chapter.id], - currentFile: files[ownProps.currentVerse.verseKey], chapterId: ownProps.chapter.id, isPlaying: state.audioplayer.isPlaying, isLoading: state.audioplayer.isLoading, @@ -550,12 +470,12 @@ const mapStateToProps = (state, ownProps) => { Audioplayer.propTypes = { className: PropTypes.string, - chapter: customPropTypes.surahType, + chapter: customPropTypes.chapterType, onLoadAyahs: PropTypes.func.isRequired, segments: customPropTypes.segments, // NOTE: should be PropTypes.instanceOf(Audio) but not on server. files: PropTypes.object, // eslint-disable-line - currentVerse: PropTypes.verseType, + currentVerse: customPropTypes.verseType, isLoading: PropTypes.bool.isRequired, play: PropTypes.func.isRequired, pause: PropTypes.func.isRequired, @@ -568,14 +488,9 @@ Audioplayer.propTypes = { setAyah: PropTypes.func.isRequired, toggleScroll: PropTypes.func.isRequired, isPlaying: PropTypes.bool, - currentTime: PropTypes.number, - duration: PropTypes.number, - load: PropTypes.func.isRequired, // NOTE: should be PropTypes.instanceOf(Audio) but not on server. currentFile: PropTypes.any, // eslint-disable-line - audio: PropTypes.number.isRequired, - verses: customPropTypes.verses, - verseIds: PropTypes.object // eslint-disable-line + verseIds: PropTypes.array // eslint-disable-line }; export default connect(mapStateToProps, AudioActions)(Audioplayer); diff --git a/src/components/Audioplayer/style.scss b/src/components/Audioplayer/style.scss index 99ff2a972..07e694f77 100644 --- a/src/components/Audioplayer/style.scss +++ b/src/components/Audioplayer/style.scss @@ -1,21 +1,4 @@ @import '../../styles/variables.scss'; -.container { - position: fixed; - bottom: 15px; - display: block; - user-select: none; - height: auto; - z-index: 1; - padding: 10px 20px 5px; - background: #fff; - box-shadow: 0 0 0.5rem 0 rgba(0, 0, 0, 0.2); - min-width: 340px; - @media (max-width: $screen-sm) { - bottom: 0; - width: 100%; - } // border: 0.08333rem solid transparent !important; -} - .buttons { width: 100%; display: inline-block; @@ -53,7 +36,7 @@ } .popover { - :global(.popover-title) { + :global(.popover-title) { font-family: $font-montserrat; text-transform: uppercase; color: $cream; @@ -61,13 +44,13 @@ padding-bottom: 15px; font-size: 0.75em; } - :global(.popover-content) { - :global(a) { + :global(.popover-content) { + :global(a) { font-size: 0.8em; } } .pill { - :global(a) { + :global(a) { padding: 10px 15px; } } diff --git a/src/components/Bismillah/index.js b/src/components/Bismillah/index.js index 235a2d2fb..f8ce74e13 100644 --- a/src/components/Bismillah/index.js +++ b/src/components/Bismillah/index.js @@ -19,7 +19,7 @@ const Bismillah = ({ chapter }) => { }; Bismillah.propTypes = { - chapter: customPropTypes.surahType.isRequired + chapter: customPropTypes.chapterType.isRequired }; export default Bismillah; diff --git a/src/components/ComponentLoader/index.js b/src/components/ComponentLoader/index.js index 8adb23c1b..cbbc9ef66 100644 --- a/src/components/ComponentLoader/index.js +++ b/src/components/ComponentLoader/index.js @@ -1,4 +1,5 @@ -import React, { PropTypes } from 'react'; +import React from 'react'; +import PropTypes from 'prop-types'; const ComponentLoader = ({ isLoading, error, pastDelay }) => { if (isLoading) { diff --git a/src/components/Copy/index.js b/src/components/Copy/index.js index 6f8882917..e4f71a9b7 100644 --- a/src/components/Copy/index.js +++ b/src/components/Copy/index.js @@ -1,9 +1,9 @@ -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import copyToClipboard from 'copy-to-clipboard'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; class Copy extends Component { - state = { isCopied: false }; @@ -37,7 +37,7 @@ class Copy extends Component { Copy.propTypes = { text: PropTypes.string.isRequired, - verseKey: PropTypes.string.isRequired, + verseKey: PropTypes.string.isRequired }; export default Copy; diff --git a/src/components/FacebookTokenButton/index.js b/src/components/FacebookTokenButton/index.js index 6bf9c7a8e..cb4842903 100644 --- a/src/components/FacebookTokenButton/index.js +++ b/src/components/FacebookTokenButton/index.js @@ -1,36 +1,65 @@ import React from 'react'; +import styled from 'styled-components'; import { connect } from 'react-redux'; import { generateShareIcon } from 'react-share'; import { save } from 'redux/actions/auth'; import { push } from 'react-router-redux'; -const styles = require('./style.scss'); - const FacebookIcon = generateShareIcon('facebook'); -const FacebookTokenButton = ({ save, push }) => { // eslint-disable-line +const Button = styled.button` + background: #3b5998; + border-color: #3b5998; + color: #fff; + font-weight: 300; + + & > div { + display: inline-block; + vertical-align: text-top; + } +`; + +// eslint-disable-next-line +const FacebookTokenButton = ({ save, push }) => { let popup = null; let interval = null; const handleClick = () => { - popup = window.open('/onequran/omniauth/facebook?omniauth_window_type=newWindow&resource_class=User', '_blank'); // eslint-disable-line - interval = setInterval(() => popup.postMessage('requestCredentials', '*'), 1000); + popup = window.open( + '/onequran/omniauth/facebook?omniauth_window_type=newWindow&resource_class=User', + '_blank' + ); // eslint-disable-line + interval = setInterval( + () => popup.postMessage('requestCredentials', '*'), + 1000 + ); + + window.addEventListener( + 'message', + (event) => { + // eslint-disable-line + if (event.data.uid) { + save(event.data); + clearInterval(interval); - window.addEventListener('message', (event) => { // eslint-disable-line - if (event.data.uid) { - save(event.data); - clearInterval(interval); + return push('/'); + } - return push('/'); - } - }, false); + return false; + }, + false + ); }; return ( - + ); }; diff --git a/src/components/FacebookTokenButton/style.scss b/src/components/FacebookTokenButton/style.scss deleted file mode 100644 index f4ef01948..000000000 --- a/src/components/FacebookTokenButton/style.scss +++ /dev/null @@ -1,11 +0,0 @@ -.button{ - background: #3B5998; - border-color: #3B5998; - color: #fff; - font-weight: 300; - - & > :global(div){ - display: inline-block; - vertical-align: text-top; - } -} diff --git a/src/components/FontStyles/index.js b/src/components/FontStyles/index.js index c97646357..091662782 100644 --- a/src/components/FontStyles/index.js +++ b/src/components/FontStyles/index.js @@ -1,4 +1,5 @@ -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { fontFaceStyle, fontFaceStyleLoaded } from 'helpers/buildFontFaces'; import load from 'redux/actions/fontFace.js'; diff --git a/src/components/Footer/PdfFooter/index.js b/src/components/Footer/PdfFooter/index.js index 80a07901c..f421338b7 100644 --- a/src/components/Footer/PdfFooter/index.js +++ b/src/components/Footer/PdfFooter/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import Link from 'react-router/lib/Link'; +import { Link } from 'react-router-dom'; const PdfFooter = () => (