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 = () => (