@@ -32,7 +35,7 @@ const SurahsList = (props) => {
};
SurahsList.propTypes = {
- surahs: PropTypes.arrayOf(surahType).isRequired
+ chapters: customPropTypes.chapters.isRequired
};
export default SurahsList;
diff --git a/src/components/Home/SurahsList/style.scss b/src/components/Home/SurahsList/style.scss
index 08aedee52..e0e170ee4 100644
--- a/src/components/Home/SurahsList/style.scss
+++ b/src/components/Home/SurahsList/style.scss
@@ -12,7 +12,7 @@
padding: 10px 10px;
}
- .english {
+ .translated_name {
font-size: 10px;
}
.arabic {
diff --git a/src/components/IndexHeader/index.js b/src/components/IndexHeader/index.js
index adbb0af15..90d01ba1b 100644
--- a/src/components/IndexHeader/index.js
+++ b/src/components/IndexHeader/index.js
@@ -1,15 +1,13 @@
import React, { Component, PropTypes } from 'react';
import Link from 'react-router/lib/Link';
-
import SearchInput from 'components/SearchInput';
import debug from 'helpers/debug';
+import Jumbotron from 'quran-components/lib/Jumbotron';
const logo = require('../../../static/images/logo-lg-w.png');
+const styles = require('./style.scss');
-export default class IndexHeader extends Component {
- static propTypes = {
- noSearch: PropTypes.bool
- };
+class IndexHeader extends Component {
renderSearch() {
if (this.props.noSearch) {
@@ -25,19 +23,26 @@ export default class IndexHeader extends Component {
debug('component:IndexHeader', 'Render');
return (
-
+
+
);
}
}
+
+IndexHeader.propTypes = {
+ noSearch: PropTypes.bool
+};
+
+export default IndexHeader;
diff --git a/src/components/IndexHeader/style.scss b/src/components/IndexHeader/style.scss
new file mode 100644
index 000000000..2211ac9df
--- /dev/null
+++ b/src/components/IndexHeader/style.scss
@@ -0,0 +1,18 @@
+@import '../../styles/variables.scss';
+
+.link{
+ display: inline-block;
+ width: 30%;
+ margin-top: 35px;
+}
+.logo{
+ padding-top: 10px;
+ padding-bottom: 10px;
+ height: auto;
+ width: 100%;
+}
+.title{
+ color: lighten($brand-primary, 30%);
+ font-size: 160%;
+ padding-bottom: 3.5%;
+}
diff --git a/src/components/InformationToggle/index.js b/src/components/InformationToggle/index.js
index 929b5cb30..74438fa9d 100644
--- a/src/components/InformationToggle/index.js
+++ b/src/components/InformationToggle/index.js
@@ -1,19 +1,14 @@
import React, { PropTypes } from 'react';
import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+import { MenuItem } from 'quran-components/lib/Menu';
const InformationToggle = ({ isToggled, onToggle }) => (
-
+
);
InformationToggle.propTypes = {
diff --git a/src/components/LazyLoad/index.js b/src/components/LazyLoad/index.js
index 84f52cb74..028c0d55c 100644
--- a/src/components/LazyLoad/index.js
+++ b/src/components/LazyLoad/index.js
@@ -4,21 +4,7 @@ import ReactDOM from 'react-dom';
import debug from 'helpers/debug';
-export default class LazyLoad extends Component {
- static propTypes = {
- isLoading: PropTypes.bool.isRequired,
- isEnd: PropTypes.bool.isRequired,
- onLazyLoad: PropTypes.func.isRequired,
- loadingComponent: PropTypes.element,
- endComponent: PropTypes.element,
- offset: PropTypes.number
- }
-
- static defaultProps = {
- loadingComponent: 'Loading...',
- endComponent: 'End.',
- offset: 1000
- }
+class LazyLoad extends Component {
componentDidMount() {
if (__CLIENT__) {
@@ -57,3 +43,20 @@ export default class LazyLoad extends Component {
return loadingComponent;
}
}
+
+LazyLoad.propTypes = {
+ isLoading: PropTypes.bool.isRequired,
+ isEnd: PropTypes.bool.isRequired,
+ onLazyLoad: PropTypes.func.isRequired,
+ loadingComponent: PropTypes.element,
+ endComponent: PropTypes.element,
+ offset: PropTypes.number
+};
+
+LazyLoad.defaultProps = {
+ loadingComponent: 'Loading...',
+ endComponent: 'End.',
+ offset: 1000
+};
+
+export default LazyLoad;
diff --git a/src/components/Line/index.js b/src/components/Line/index.js
index 585354fe1..a7a529e77 100644
--- a/src/components/Line/index.js
+++ b/src/components/Line/index.js
@@ -1,29 +1,16 @@
import React, { PropTypes } from 'react';
+import * as customPropTypes from 'customPropTypes';
import debug from 'helpers/debug';
-
-import { wordType } from 'types';
import Word from 'components/Word';
-const styles = require('../Ayah/style.scss');
+const styles = require('../Verse/style.scss');
-export default class Line extends React.Component {
- static propTypes = {
- line: PropTypes.arrayOf(wordType).isRequired,
- tooltip: PropTypes.string,
- currentAyah: PropTypes.string.isRequired,
- audioActions: PropTypes.shape({
- pause: PropTypes.func.isRequired,
- setAyah: PropTypes.func.isRequired,
- play: PropTypes.func.isRequired,
- setCurrentWord: PropTypes.func.isRequired,
- }),
- isPlaying: PropTypes.bool
- };
+class Line extends React.Component {
// NOTE: this is commented out as it caused problems with 55:31 with missing text.
// shouldComponentUpdate(nextProps) {
// const conditions = [
- // this.props.currentAyah !== nextProps.currentAyah,
+ // this.props.currentVerse !== nextProps.currentVerse,
// this.props.line !== nextProps.line,
// this.props.isPlaying !== nextProps.isPlaying
// ];
@@ -34,16 +21,17 @@ export default class Line extends React.Component {
// }
renderText() {
- const { tooltip, currentAyah, audioActions, isPlaying, line } = this.props;
+ const { tooltip, currentVerse, audioActions, isPlaying, line, useTextFont } = this.props;
const text = line.map(word => (
));
@@ -59,15 +47,26 @@ export default class Line extends React.Component {
debug(
'component:Line',
- `Page: ${line[0].pageNum} - Line: ${line[0].lineNum} - Ayah: ${line[0].ayahKey}`
+ `Page: ${line[0].pageNum} - Line: ${line[0].lineNum} - Ayah: ${line[0].verseKey}`
);
return (
-
);
}
}
+
+Line.propTypes = {
+ line: customPropTypes.line.isRequired,
+ tooltip: PropTypes.string,
+ currentVerse: PropTypes.string.isRequired,
+ audioActions: customPropTypes.audioActions,
+ isPlaying: PropTypes.bool,
+ useTextFont: PropTypes.bool
+};
+
+export default Line;
diff --git a/src/components/Loader/index.js b/src/components/Loader/index.js
deleted file mode 100644
index 57f48b889..000000000
--- a/src/components/Loader/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react';
-
-const Loader = () => (
-
-
-
-);
-
-export default Loader;
diff --git a/src/components/Loader/style.scss b/src/components/Loader/style.scss
deleted file mode 100644
index 80fded77d..000000000
--- a/src/components/Loader/style.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-@import '../../styles/variables.scss';
-
-$timing: 1s;
-$size: 4px;
-$border-size: $size * 1.25;
-
-.loader,
-.loader:after {
- border-radius: 50%;
- width: 10em;
- height: 10em;
-}
-
-.loader {
- margin: 30px auto;
- font-size: $size;
- position: relative;
- text-indent: -9999em;
- border-top: $border-size solid $brand-primary;
- border-right: $border-size solid $brand-primary;
- border-bottom: $border-size solid $brand-primary;
- border-left: $border-size solid #ffffff;
- -webkit-transform: translateZ(0);
- -ms-transform: translateZ(0);
- transform: translateZ(0);
- -webkit-animation: load $timing infinite linear;
- animation: load $timing infinite linear;
-}
-
-@-webkit-keyframes load {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
-@keyframes load {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
diff --git a/src/components/LocaleSwitcher/index.js b/src/components/LocaleSwitcher/index.js
index 12ce4f84e..863dd4118 100644
--- a/src/components/LocaleSwitcher/index.js
+++ b/src/components/LocaleSwitcher/index.js
@@ -3,12 +3,11 @@ import React, { PropTypes, Component } from 'react';
import cookie from 'react-cookie';
import NavDropdown from 'react-bootstrap/lib/NavDropdown';
import MenuItem from 'react-bootstrap/lib/MenuItem';
-import { locales, defaultLocale } from '../../config';
+import config from '../../config';
-export default class LocaleSwitcher extends Component {
- static propTypes = {
- className: PropTypes.string
- };
+const { locales, defaultLocale } = config;
+
+class LocaleSwitcher extends Component {
state = {
currentLocale: defaultLocale,
@@ -43,7 +42,7 @@ export default class LocaleSwitcher extends Component {
);
}
}
+NightModeToggle.propTypes = {
+ isNightMode: PropTypes.bool.isRequired,
+ onToggle: PropTypes.func.isRequired
+};
+
export default NightModeToggle;
diff --git a/src/components/PageBreak/index.js b/src/components/PageBreak/index.js
index 209293af2..634dde62f 100644
--- a/src/components/PageBreak/index.js
+++ b/src/components/PageBreak/index.js
@@ -1,12 +1,11 @@
import React, { PropTypes } from 'react';
-import Col from 'react-bootstrap/lib/Col';
const PageBreak = ({ pageNum }) => (
);
diff --git a/src/components/PageView/index.js b/src/components/PageView/index.js
new file mode 100644
index 000000000..64e679c70
--- /dev/null
+++ b/src/components/PageView/index.js
@@ -0,0 +1,61 @@
+import React, { PropTypes } from 'react';
+import * as customPropTypes from 'customPropTypes';
+import { connect } from 'react-redux';
+
+import Line from 'components/Line';
+import PageBreak from 'components/PageBreak';
+
+const PageView = ({ lines, keys, currentVerse, options, isPlaying, audioActions, userAgent }) => { // eslint-disable-line
+ const elements = keys.map((lineNum, index) => {
+ const nextNum = keys[index + 1];
+ const pageNum = lineNum.split('-')[0];
+ const line = lines[lineNum];
+ const renderText = false; // userAgent.isBot;
+
+ if (index + 1 !== keys.length && pageNum !== nextNum.split('-')[0]) {
+ return [
+
,
+
+ ];
+ }
+
+ return (
+
+ );
+ });
+
+ return (
+
{elements}
+ );
+};
+
+PageView.propTypes = {
+ keys: PropTypes.array, // eslint-disable-line
+ lines: PropTypes.object.isRequired, // eslint-disable-line
+ audioActions: customPropTypes.audioActions.isRequired, // eslint-disable-line
+ currentVerse: PropTypes.string,
+ bookmarks: PropTypes.object.isRequired, // eslint-disable-line
+ options: PropTypes.object.isRequired, // eslint-disable-line
+ isPlaying: PropTypes.bool,
+ userAgent: PropTypes.func
+};
+
+export default connect(state => ({
+ userAgent: state.options.userAgent
+}))(PageView);
diff --git a/src/components/Radio/index.js b/src/components/Radio/index.js
deleted file mode 100644
index 1d94fb551..000000000
--- a/src/components/Radio/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React, { PropTypes } from 'react';
-
-const styles = require('./style.scss');
-
-const Radio = ({ id, name, checked, handleChange, children }) => (
-
-);
-
-Radio.propTypes = {
- id: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- checked: PropTypes.bool.isRequired,
- handleChange: PropTypes.func.isRequired,
- children: PropTypes.element.isRequired,
-};
-
-export default Radio;
diff --git a/src/components/Radio/style.scss b/src/components/Radio/style.scss
deleted file mode 100644
index a00b1fdee..000000000
--- a/src/components/Radio/style.scss
+++ /dev/null
@@ -1,130 +0,0 @@
-@import '../../styles/variables.scss';
-
-@-webkit-keyframes cardEnter {
- 0%, 20%, 40%, 60%, 80%, 100% {
- -webkit-transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- }
- 0% {
- opacity: 0;
- -webkit-transform: scale3d(0.3, 0.3, 0.3);
- }
- 20% {
- -webkit-transform: scale3d(1.1, 1.1, 1.1);
- }
- 40% {
- -webkit-transform: scale3d(0.9, 0.9, 0.9);
- }
- 60% {
- opacity: 1;
- -webkit-transform: scale3d(1.03, 1.03, 1.03);
- }
- 80% {
- -webkit-transform: scale3d(0.97, 0.97, 0.97);
- }
- 100% {
- opacity: 1;
- -webkit-transform: scale3d(1, 1, 1);
- }
-}
-
-@keyframes cardEnter {
- 0%, 20%, 40%, 60%, 80%, 100% {
- -webkit-transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- }
- 0% {
- opacity: 0;
- -webkit-transform: scale3d(0.3, 0.3, 0.3);
- transform: scale3d(0.3, 0.3, 0.3);
- }
- 20% {
- -webkit-transform: scale3d(1.1, 1.1, 1.1);
- transform: scale3d(1.1, 1.1, 1.1);
- }
- 40% {
- -webkit-transform: scale3d(0.9, 0.9, 0.9);
- transform: scale3d(0.9, 0.9, 0.9);
- }
- 60% {
- opacity: 1;
- -webkit-transform: scale3d(1.03, 1.03, 1.03);
- transform: scale3d(1.03, 1.03, 1.03);
- }
- 80% {
- -webkit-transform: scale3d(0.97, 0.97, 0.97);
- transform: scale3d(0.97, 0.97, 0.97);
- }
- 100% {
- opacity: 1;
- -webkit-transform: scale3d(1, 1, 1);
- transform: scale3d(1, 1, 1);
- }
-}
-
-.radio {
- display: inline-block;
- padding-right: 20px;
- font-weight: 500;
- color: #777;
- line-height: 40px;
- cursor: pointer;
-}
-
-.radio:hover .inner {
- -webkit-transform: scale(0.5);
- -ms-transform: scale(0.5);
- transform: scale(0.5);
- opacity: .5;
-}
-
-.radio .input {
- width: 1px;
- height: 1px;
- opacity: 0;
-}
-
-.radio .input:checked + .outer .inner {
- -webkit-transform: scale(1);
- -ms-transform: scale(1);
- transform: scale(1);
- opacity: 1;
-}
-
-.radio .input:checked + .outer {
- border: 2px solid $brand-primary;
-}
-
-.radio .input:focus + .outer .inner {
- -webkit-transform: scale(1);
- -ms-transform: scale(1);
- transform: scale(1);
- opacity: 1;
- background-color: $brand-primary;
-}
-
-.radio .outer {
- width: 20px;
- height: 20px;
- display: block;
- float: left;
- margin: 10px 9px 10px 10px;
- border: 2px solid $brand-primary;
- border-radius: 50%;
- background-color: #fff;
-}
-
-.radio .inner {
- -webkit-transition: all 0.25s ease-in-out;
- transition: all 0.25s ease-in-out;
- width: 10px;
- height: 10px;
- -webkit-transform: scale(0);
- -ms-transform: scale(0);
- transform: scale(0);
- display: block;
- margin: 3px;
- border-radius: 50%;
- background-color: $brand-primary;
- opacity: 0;
-}
diff --git a/src/components/ReadingModeToggle/index.js b/src/components/ReadingModeToggle/index.js
index ff75185c0..76146bdaa 100644
--- a/src/components/ReadingModeToggle/index.js
+++ b/src/components/ReadingModeToggle/index.js
@@ -1,19 +1,14 @@
import React, { PropTypes } from 'react';
import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+import { MenuItem } from 'quran-components/lib/Menu';
const ReadingModeToggle = ({ onToggle, isToggled }) => (
-
- onToggle({ isReadingMode: !isToggled })}
- >
-
- {' '}
-
-
+
}
+ onClick={() => onToggle({ isReadingMode: !isToggled })}
+ >
+
+
);
ReadingModeToggle.propTypes = {
diff --git a/src/components/ReciterDropdown/index.js b/src/components/ReciterDropdown/index.js
index 3f11060ff..b6e407407 100644
--- a/src/components/ReciterDropdown/index.js
+++ b/src/components/ReciterDropdown/index.js
@@ -1,229 +1,69 @@
import React, { Component, PropTypes } from 'react';
-import ButtonToolbar from 'react-bootstrap/lib/ButtonToolbar';
-import DropdownButton from 'react-bootstrap/lib/DropdownButton';
-import MenuItem from 'react-bootstrap/lib/MenuItem';
+import * as customPropTypes from 'customPropTypes';
+import { connect } from 'react-redux';
+import Menu, { MenuItem } from 'quran-components/lib/Menu';
+import Radio from 'quran-components/lib/Radio';
+import Loader from 'quran-components/lib/Loader';
+import Icon from 'quran-components/lib/Icon';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+import { loadRecitations } from 'redux/actions/options';
-const style = require('./style.scss');
+class ReciterDropdown extends Component {
-// To save API calls.
-export const slugs = [
- {
- reciter: {
- slug: 'abdulbaset',
- id: 1
- },
- name: {
- english: 'AbdulBaset AbdulSamad (Mujawwad)',
- arabic: 'عبد الباسط عبد الصمد (مجود)'
- },
- style: {
- slug: 'mujawwad',
- id: 1
- },
- id: 1
- },
- {
- reciter: {
- slug: 'abdulbaset',
- id: 1
- },
- name: {
- english: 'AbdulBaset AbdulSamad (Murattal)',
- arabic: 'عبد الباسط عبد الصمد (مرتل)'
- },
- style: {
- slug: 'murattal',
- id: 2
- },
- id: 2
- },
- {
- reciter: {
- slug: 'sudais',
- id: 2
- },
- name: {
- english: 'Abdur-Rahman as-Sudais',
- arabic: 'عبدالرحمن السديس'
- },
- style: {
- slug: null,
- id: null
- },
- id: 3
- },
- {
- reciter: {
- slug: 'shatri',
- id: 3
- },
- name: {
- english: 'Abu Bakr al-Shatri',
- arabic: 'أبو بكر الشاطرى'
- },
- style: {
- slug: null,
- id: null
- },
- id: 4
- },
- {
- reciter: {
- slug: 'rifai',
- id: 4
- },
- name: {
- english: 'Hani ar-Rifai',
- arabic: 'هاني الرفاعي'
- },
- style: {
- slug: null,
- id: null
- },
- id: 5
- },
- {
- reciter: {
- slug: 'alafasy',
- id: 6
- },
- name: {
- english: 'Mishari Rashid al-`Afasy',
- arabic: 'مشاري راشد العفاسي'
- },
- style: {
- slug: null,
- id: null
- },
- id: 8
- },
- {
- reciter: {
- slug: 'minshawi',
- id: 7
- },
- name: {
- english: 'Mohamed Siddiq al-Minshawi (Mujawwad)',
- arabic: 'محمد صديق المنشاوي (مجود)'
- },
- style: {
- slug: 'mujawwad',
- id: 1
- },
- id: 9
- },
- {
- reciter: {
- slug: 'minshawi',
- id: 7
- },
- name: {
- english: 'Mohamed Siddiq al-Minshawi (Murattal)',
- arabic: 'محمد صديق المنشاوي (مرتل)'
- },
- style: {
- slug: 'murattal',
- id: 2
- },
- id: 10
- },
- {
- reciter: {
- slug: 'altablawi',
- id: 9
- },
- name: {
- english: 'Mohamed al-Tablawi',
- arabic: 'محمد الطبلاوي'
- },
- style: {
- slug: null,
- id: null
- },
- id: 12
- },
- {
- reciter: {
- slug: 'alhusary',
- id: 5
- },
- name: {
- english: 'Mahmoud Khalil Al-Husary',
- arabic: 'محمود خليل الحصري'
- },
- style: {
- slug: null,
- id: null
- },
- id: 7
- },
- {
- reciter: {
- slug: 'muallim', // i'm just making up values for slug, i dont think we need this at all
- id: 5
- },
- name: {
- english: 'Mahmoud Khalil Al-Husary (Muallim)',
- arabic: 'محمود خليل الحصري'
- },
- style: {
- slug: 'muallim',
- id: 3
- },
- id: 13
- },
- {
- reciter: {
- slug: 'shuraym',
- id: 8
- },
- name: {
- english: 'Sa`ud ash-Shuraym',
- arabic: 'سعود الشريم'
- },
- style: {
- slug: null,
- id: null
- },
- id: 11
- }
-];
+ componentDidMount() {
+ if (!this.props.recitations.length) {
+ return this.props.loadRecitations();
+ }
-export default class ReciterDropdown extends Component {
- static propTypes = {
- onOptionChange: PropTypes.func,
- audio: PropTypes.number,
- className: PropTypes.string
- };
+ return false;
+ }
renderMenu() {
- const { audio, onOptionChange } = this.props;
+ const { audio, onOptionChange, recitations } = this.props;
- return slugs.map(slug => (
+ return recitations.map(slug => (
onOptionChange({ audio: slug.id })}
+ key={slug.id}
>
- {slug.name.english}
+ onOptionChange({ audio: slug.id })}
+ >
+
+ {slug.reciterNameEng} {slug.style ? `(${slug.style})` : ''}
+
+
));
}
render() {
- const { className, audio } = this.props;
+ const { recitations } = this.props;
return (
-
- slug.id === audio).name.english}
- >
- {this.renderMenu()}
-
-
+
}
+ menu={
+ recitations.length ?
:
+ }
+ >
+
+
);
}
}
+
+ReciterDropdown.propTypes = {
+ onOptionChange: PropTypes.func,
+ audio: PropTypes.number,
+ loadRecitations: PropTypes.func.isRequired,
+ recitations: customPropTypes.recitations
+};
+
+export default connect(state => ({
+ recitations: state.options.options.recitations,
+ loadingRecitations: state.options.loadingRecitations,
+ audio: state.options.audio
+}), { loadRecitations })(ReciterDropdown);
diff --git a/src/components/SearchAutocomplete/index.js b/src/components/SearchAutocomplete/index.js
index 7f34aa059..1392cf8b1 100644
--- a/src/components/SearchAutocomplete/index.js
+++ b/src/components/SearchAutocomplete/index.js
@@ -1,9 +1,8 @@
// TODO: Should be handled by redux and not component states.
import React, { Component, PropTypes } from 'react';
+import * as customPropTypes from 'customPropTypes';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
-import { surahType } from 'types';
-
import { suggest } from 'redux/actions/suggest';
const styles = require('./style.scss');
@@ -11,25 +10,6 @@ const styles = require('./style.scss');
const ayahRegex = /^(\d+)(?::(\d+))?$/;
class SearchAutocomplete extends Component {
- static propTypes = {
- surahs: PropTypes.objectOf(surahType).isRequired,
- value: PropTypes.string,
- // TODO: This should not be doing html stuff. Should use react onKeydown.
- input: PropTypes.any, // eslint-disable-line
- push: PropTypes.func.isRequired,
- suggest: PropTypes.func.isRequired,
- suggestions: PropTypes.arrayOf(PropTypes.shape({
- ayah: PropTypes.string,
- href: PropTypes.string.isRequired,
- text: PropTypes.string.isRequired
- })),
- lang: PropTypes.string,
- delay: PropTypes.number,
- };
-
- static defaultProps = {
- delay: 200
- }
componentDidMount() {
this.props.input.addEventListener('keydown', this.handleInputKeyDown.bind(this));
@@ -64,23 +44,23 @@ class SearchAutocomplete extends Component {
if (!value) return matches;
- const isAyahKeySearch = ayahRegex.test(value);
+ const isverseKeySearch = ayahRegex.test(value);
- if (isAyahKeySearch) {
+ if (isverseKeySearch) {
const captures = value.match(ayahRegex);
- const surahId = captures[1];
+ const chapterId = captures[1];
const ayahNum = captures[2];
- const surah = this.props.surahs[surahId];
- matches.push([surah.name.simple, surah.id + (ayahNum ? `/${ayahNum}` : '')]);
+ const chapter = this.props.chapters[chapterId];
+ matches.push([chapter.nameSimple, chapter.chapterNumber + (ayahNum ? `/${ayahNum}` : '')]);
} else if (value.length >= 2) {
const escaped = value.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
- Object.keys(this.props.surahs).forEach((surahId) => {
- const surah = this.props.surahs[surahId];
- if (RegExp(escaped, 'i').test(surah.name.simple.replace(/['-]/g, ''))) {
- matches.push([surah.name.simple, surah.id]);
- } else if (RegExp(escaped, 'i').test(surah.name.arabic)) {
- matches.push([surah.name.arabic, surah.id]);
+ Object.keys(this.props.chapters).forEach((chapterId) => {
+ const chapter = this.props.chapters[chapterId];
+ if (RegExp(escaped, 'i').test(chapter.nameSimple.replace(/['-]/g, ''))) {
+ matches.push([chapter.nameSimple, chapter.chapterNumber]);
+ } else if (RegExp(escaped, 'i').test(chapter.nameArabic)) {
+ matches.push([chapter.nameArabic, chapter.chapterNumber]);
}
});
}
@@ -174,7 +154,7 @@ class SearchAutocomplete extends Component {
onKeyDown={event => this.handleItemKeyDown(event, item)}
>
@@ -195,17 +175,17 @@ class SearchAutocomplete extends Component {
}
function mapStateToProps(state, ownProps) {
- const surahs = state.surahs.entities;
- const surahId = state.surahs.current;
+ const chapters = state.chapters.entities;
+ const chapterId = state.chapters.current;
const suggestions = state.suggestResults.results[ownProps.value];
let lang = 'en';
- if (state.ayahs && state.ayahs.entities && state.ayahs.entities[surahId]) {
- const ayahs = state.ayahs.entities[surahId];
- const ayahKey = Object.keys(ayahs)[0];
+ if (state.verses && state.verses.entities && state.verses.entities[chapterId]) {
+ const ayahs = state.verses.entities[chapterId];
+ const verseKey = Object.keys(ayahs)[0];
- if (ayahKey) {
- const ayah = ayahs[ayahKey];
+ if (verseKey) {
+ const ayah = ayahs[verseKey];
if (ayah.content && ayah.content[0] && ayah.content[0].lang) {
lang = ayah.content[0].lang;
@@ -214,10 +194,26 @@ function mapStateToProps(state, ownProps) {
}
return {
- surahs,
+ chapters,
suggestions,
lang
};
}
+SearchAutocomplete.propTypes = {
+ chapters: customPropTypes.chapters.isRequired,
+ value: PropTypes.string,
+ // TODO: This should not be doing html stuff. Should use react onKeydown.
+ input: PropTypes.any, // eslint-disable-line
+ push: PropTypes.func.isRequired,
+ suggest: PropTypes.func.isRequired,
+ suggestions: customPropTypes.suggestions,
+ lang: PropTypes.string,
+ delay: PropTypes.number,
+};
+
+SearchAutocomplete.defaultProps = {
+ delay: 200
+};
+
export default connect(mapStateToProps, { push, suggest })(SearchAutocomplete);
diff --git a/src/components/SearchInput/index.js b/src/components/SearchInput/index.js
index a500c8d60..df9885d4a 100644
--- a/src/components/SearchInput/index.js
+++ b/src/components/SearchInput/index.js
@@ -9,11 +9,6 @@ import SearchAutocomplete from 'components/SearchAutocomplete';
import debug from 'helpers/debug';
class SearchInput extends Component {
- static propTypes = {
- push: PropTypes.func.isRequired,
- className: PropTypes.string,
- intl: intlShape.isRequired
- };
static contextTypes = {
metrics: MetricsPropTypes.metrics
@@ -116,4 +111,10 @@ class SearchInput extends Component {
}
}
+SearchInput.propTypes = {
+ push: PropTypes.func.isRequired,
+ className: PropTypes.string,
+ intl: intlShape.isRequired
+};
+
export default injectIntl(connect(null, { push })(SearchInput));
diff --git a/src/components/SettingsModal/index.js b/src/components/SettingsModal/index.js
index 2c46faca4..2b8114410 100644
--- a/src/components/SettingsModal/index.js
+++ b/src/components/SettingsModal/index.js
@@ -1,22 +1,20 @@
import React, { PropTypes } from 'react';
+import * as customProptypes from 'customPropTypes';
import { connect } from 'react-redux';
import Modal from 'react-bootstrap/lib/Modal';
-
import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
import ReciterDropdown from 'components/ReciterDropdown';
import ContentDropdown from 'components/ContentDropdown';
import TooltipDropdown from 'components/TooltipDropdown';
-
import { setOption } from 'redux/actions/options.js';
-import { load } from 'redux/actions/ayahs.js';
-import { optionsType, surahType } from 'types';
+import { load } from 'redux/actions/verses.js';
const ModalHeader = Modal.Header;
const ModalTitle = Modal.Title;
const ModalBody = Modal.Body;
const SettingsModal = ({
- surah,
+ chapter,
ayahIds,
open,
handleHide,
@@ -27,10 +25,10 @@ const SettingsModal = ({
const handleOptionChange = (payload) => {
setOption(payload);
- if (surah) {
+ if (chapter) {
const first = [...ayahIds][0];
const last = [...ayahIds][[...ayahIds].length - 1];
- load(surah.id, first, last, { ...options, ...payload });
+ load(chapter.chapterNumber, first, last, { ...options, ...payload });
}
};
@@ -48,7 +46,6 @@ const SettingsModal = ({
@@ -57,7 +54,6 @@ const SettingsModal = ({
@@ -75,11 +71,11 @@ const SettingsModal = ({
};
SettingsModal.propTypes = {
- surah: surahType,
+ chapter: customProptypes.surahType,
ayahIds: PropTypes.instanceOf(Set),
open: PropTypes.bool,
handleHide: PropTypes.func.isRequired,
- options: optionsType,
+ options: customProptypes.optionsType,
setOption: PropTypes.func.isRequired,
load: PropTypes.func.isRequired,
};
diff --git a/src/components/Share/index.js b/src/components/Share/index.js
index 7385f5f5a..f3b8699ba 100644
--- a/src/components/Share/index.js
+++ b/src/components/Share/index.js
@@ -1,7 +1,6 @@
-/* global window */
-import React, { Component } from 'react';
+import React, { PropTypes } from 'react';
import { ShareButtons, generateShareIcon } from 'react-share';
-import { surahType } from 'types';
+import * as customPropTypes from 'customPropTypes';
const styles = require('./style.scss');
@@ -9,38 +8,38 @@ const { FacebookShareButton, TwitterShareButton } = ShareButtons;
const FacebookIcon = generateShareIcon('facebook');
const TwitterIcon = generateShareIcon('twitter');
-export default class Share extends Component {
- static propTypes = {
- surah: surahType.isRequired
- };
+const Share = ({ chapter, verseKey }) => {
+ // Fallback to Surah Id
+ const path = verseKey ? verseKey.replace(':', '/') : chapter.chapterNumber;
+ const shareUrl = `https://quran.com/${path}`;
+ const title = verseKey ? `Surah ${chapter.nameSimple} [${verseKey}]` : `Surah ${chapter.nameSimple}`;
+ const iconProps = verseKey ? { iconBgStyle: { fill: '#d1d0d0' } } : {};
- onClickPopup = (url, title) => {
- window.open(url, title, 'width=670,height=540,scrollbars=no,toolbar=0');
- }
+ return (
+
+
+
+
+
+
+
+
+ );
+};
- render() {
- const { surahId, name } = this.props.surah;
- const surahUrl = `https://quran.com/${surahId}`;
+Share.propTypes = {
+ verseKey: PropTypes.string,
+ chapter: customPropTypes.surahType.isRequired
+};
- return (
-
-
-
-
-
-
-
-
- );
- }
-}
+export default Share;
diff --git a/src/components/Share/style.scss b/src/components/Share/style.scss
index 11025dba5..92b6684bb 100644
--- a/src/components/Share/style.scss
+++ b/src/components/Share/style.scss
@@ -3,13 +3,14 @@
.shareContainer {
position: relative;
top: 7px;
- display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6, BB7 */
- display: -ms-flexbox; /* TWEENER - IE 10 */
- display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
- display: flex; /* NEW, Spec - Firefox, Chrome, Opera */
+ display: inline-block;
.iconContainer {
- padding: 0 5px;
+ display: inline-block;
+
+ &:last-child{
+ padding-left: 5px;
+ }
&:hover {
cursor: pointer;
diff --git a/src/components/SmartBanner/index.js b/src/components/SmartBanner/index.js
index 444949c51..3dd954306 100644
--- a/src/components/SmartBanner/index.js
+++ b/src/components/SmartBanner/index.js
@@ -1,42 +1,10 @@
/* global window */
import React, { Component, PropTypes } from 'react';
+import * as customPropTypes from 'customPropTypes';
import useragent from 'express-useragent';
import cookie from 'react-cookie';
class SmartBanner extends Component {
- static propTypes = {
- daysHidden: PropTypes.number,
- daysReminder: PropTypes.number,
- appStoreLanguage: PropTypes.string,
- button: PropTypes.string,
- storeText: PropTypes.objectOf(PropTypes.string),
- price: PropTypes.objectOf(PropTypes.string),
- force: PropTypes.string,
- title: PropTypes.string,
- author: PropTypes.string,
- };
-
- static defaultProps = {
- daysHidden: 15,
- daysReminder: 90,
- appStoreLanguage: 'us',
- button: 'View',
- storeText: {
- ios: 'On the App Store',
- android: 'In Google Play',
- windows: 'In Windows Store',
- kindle: 'In the Amazon Appstore',
- },
- price: {
- ios: 'Free',
- android: 'Free',
- windows: 'Free',
- kindle: 'Free',
- },
- force: '',
- title: '',
- author: '',
- };
state = {
settings: {},
@@ -76,13 +44,13 @@ class SmartBanner extends Component {
const mixins = {
ios: {
icon: 'app-banner-ios.jpg',
- appMeta: 'google-play-app',
+ appMeta: 'apple-itunes-app',
getStoreLink: () =>
`https://itunes.apple.com/${this.props.appStoreLanguage}/app/id`,
},
android: {
icon: 'app-banner-android.png',
- appMeta: 'apple-itunes-app',
+ appMeta: 'google-play-app',
getStoreLink: () =>
'http://play.google.com/store/apps/details?id=',
}
@@ -178,7 +146,7 @@ class SmartBanner extends Component {
this.close()}
data-metrics-event-name="SmartBanner:close"
>
@@ -190,7 +158,7 @@ class SmartBanner extends Component {
{inStore}
-
+ this.install()} className="smartbanner-button" data-metrics-event-name="SmartBanner:InstallAapp">
{this.props.button}
@@ -199,4 +167,38 @@ class SmartBanner extends Component {
}
}
+SmartBanner.propTypes = {
+ daysHidden: PropTypes.number,
+ daysReminder: PropTypes.number,
+ appStoreLanguage: PropTypes.string,
+ button: PropTypes.string,
+ storeText: customPropTypes.storeText,
+ price: customPropTypes.storeText,
+ force: PropTypes.string,
+ title: PropTypes.string,
+ author: PropTypes.string,
+};
+
+SmartBanner.defaultProps = {
+ daysHidden: 15,
+ daysReminder: 90,
+ appStoreLanguage: 'us',
+ button: 'View',
+ storeText: {
+ ios: 'On the App Store',
+ android: 'In Google Play',
+ windows: 'In Windows Store',
+ kindle: 'In the Amazon Appstore',
+ },
+ price: {
+ ios: 'Free',
+ android: 'Free',
+ windows: 'Free',
+ kindle: 'Free',
+ },
+ force: '',
+ title: '',
+ author: '',
+};
+
export default SmartBanner;
diff --git a/src/components/SurahInfo/index.js b/src/components/SurahInfo/index.js
index 0ea4aece1..16d13b1b4 100644
--- a/src/components/SurahInfo/index.js
+++ b/src/components/SurahInfo/index.js
@@ -1,58 +1,58 @@
import React, { PropTypes } from 'react';
-
-import Col from 'react-bootstrap/lib/Col';
-import { surahType } from 'types';
-import Loader from 'components/Loader';
+import * as customPropTypes from 'customPropTypes';
+import Loader from 'quran-components/lib/Loader';
const style = require('./style.scss');
-const SurahInfo = ({ surah, isShowingSurahInfo, onClose }) => {
+const SurahInfo = ({ chapter, info, isShowingSurahInfo, onClose }) => {
// So we don't need to load images and files unless needed
if (!isShowingSurahInfo) return