From cf13cfd4076476eb5cbf630a30bc5ce13e0e8576 Mon Sep 17 00:00:00 2001 From: hasibsahibzada Date: Sun, 9 Apr 2017 10:52:08 +0200 Subject: [PATCH 1/4] customPorpTypes.js file added that would hold all propType validations --- src/components/Verse/index.js | 64 ++++++++++++++--------------------- src/customPropTypes.js | 49 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 38 deletions(-) create mode 100644 src/customPropTypes.js diff --git a/src/components/Verse/index.js b/src/components/Verse/index.js index db93f90a8..d238de90c 100644 --- a/src/components/Verse/index.js +++ b/src/components/Verse/index.js @@ -1,4 +1,5 @@ import React, { Component, PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import Link from 'react-router/lib/Link'; import Element from 'react-scroll/lib/components/Element'; import { connect } from 'react-redux'; @@ -25,44 +26,6 @@ const Share = Loadable({ }); class Verse extends Component { - static propTypes = { - isSearched: PropTypes.bool, - verse: verseType.isRequired, - chapter: surahType.isRequired, - bookmarked: PropTypes.bool, // TODO: Add this for search - bookmarkActions: PropTypes.shape({ - isLoaded: PropTypes.func.isRequired, - load: PropTypes.func.isRequired, - addBookmark: PropTypes.func.isRequired, - removeBookmark: PropTypes.func.isRequired, - }), - mediaActions: PropTypes.shape({ - setMedia: PropTypes.func.isRequired, - removeMedia: PropTypes.func.isRequired, - }), - audioActions: PropTypes.shape({ - pause: PropTypes.func.isRequired, - setAyah: PropTypes.func.isRequired, - play: PropTypes.func.isRequired, - setCurrentWord: PropTypes.func.isRequired, - }), // not required because in search it is not. - match: PropTypes.arrayOf(matchType), - isPlaying: PropTypes.bool, - isAuthenticated: PropTypes.bool, - tooltip: PropTypes.string, - currentWord: PropTypes.number, // gets passed in an integer, null by default - iscurrentVerse: PropTypes.bool, - currentVerse: PropTypes.string, - userAgent: PropTypes.func, - audio: PropTypes.number.isRequired, - loadAudio: PropTypes.func.isRequired - }; - - - static defaultProps = { - currentWord: null, - isSearched: false - }; // TODO: Should this belong here? componentDidMount() { @@ -340,4 +303,29 @@ class Verse extends Component { } } +Verse.propTypes = { + isSearched: PropTypes.bool, + verse: verseType.isRequired, + chapter: surahType.isRequired, + bookmarked: PropTypes.bool, // TODO: Add this for search + bookmarkActions: customPropTypes.bookmarkActions, + mediaActions: customPropTypes.mediaActions, + audioActions: customPropTypes.audioActions, + match: customPropTypes.match, + isPlaying: PropTypes.bool, + isAuthenticated: PropTypes.bool, + tooltip: PropTypes.string, + currentWord: PropTypes.number, // gets passed in an integer, null by default + iscurrentVerse: PropTypes.bool, + currentVerse: PropTypes.string, + userAgent: PropTypes.func, + audio: PropTypes.number.isRequired, + loadAudio: PropTypes.func.isRequired +}; + +Verse.defaultProps = { + currentWord: null, + isSearched: false +}; + export default connect(() => ({}), { loadAudio })(Verse); diff --git a/src/customPropTypes.js b/src/customPropTypes.js new file mode 100644 index 000000000..008c95975 --- /dev/null +++ b/src/customPropTypes.js @@ -0,0 +1,49 @@ +import { PropTypes } from 'react'; + +export const bookmarkActions = PropTypes.shape({ + isLoaded: PropTypes.func.isRequired, + load: PropTypes.func.isRequired, + addBookmark: PropTypes.func.isRequired, + removeBookmark: PropTypes.func.isRequired +}); + +export const mediaActions = PropTypes.shape({ + setMedia: PropTypes.func.isRequired, + removeMedia: PropTypes.func.isRequired +}); + +export const audioActions = PropTypes.shape({ + pause: PropTypes.func.isRequired, + setAyah: PropTypes.func.isRequired, + play: PropTypes.func.isRequired, + setCurrentWord: PropTypes.func.isRequired, +}); + +export const language = PropTypes.shape({ + beta: PropTypes.bool, + direction: PropTypes.string.isRequired, + english: PropTypes.string.isRequired, + esAnalyzerDefault: PropTypes.string, + languageCode: PropTypes.string.isRequired, + priority: PropTypes.number.isRequired, + unicode: PropTypes.string, +}); + +export const matchType = PropTypes.shape({ + score: PropTypes.number.isRequired, + text: PropTypes.string.isRequired, + languageCode: PropTypes.string.isRequired, + subType: PropTypes.string.isRequired, + cardinalityType: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + resourceId: PropTypes.number.isRequired, + description: PropTypes.string, + language: language.isRequired, + sourceId: PropTypes.number.isRequired, + type: PropTypes.string.isRequired, + authorId: PropTypes.number.isRequired, + slug: PropTypes.string.isRequired, + isAvailable: PropTypes.bool +}); + +export const match = PropTypes.arrayOf(matchType); From de3b1901b27633eb702380e4aeaff04397437590 Mon Sep 17 00:00:00 2001 From: hasibsahibzada Date: Sun, 9 Apr 2017 13:13:47 +0200 Subject: [PATCH 2/4] custom props added to all components --- .../Audioplayer/RepeatDropdown/index.js | 22 +-- src/components/Audioplayer/Segments/index.js | 18 +- src/components/Audioplayer/index.js | 65 +++---- src/components/Bismillah/index.js | 4 +- src/components/ContentDropdown/index.js | 15 +- src/components/Copy/index.js | 16 +- src/components/FontSizeDropdown/index.js | 18 +- src/components/FontStyles/index.js | 14 +- src/components/GlobalNav/Surah/index.js | 23 ++- src/components/GlobalNav/index.js | 34 ++-- src/components/GlobalSidebar/index.js | 24 +-- src/components/Home/LastVisit/index.js | 4 +- src/components/Home/SurahsList/index.js | 5 +- src/components/IndexHeader/index.js | 12 +- src/components/LazyLoad/index.js | 33 ++-- src/components/Line/index.js | 29 ++- src/components/LocaleSwitcher/index.js | 11 +- src/components/NightModeToggle/index.js | 9 +- src/components/PageView/index.js | 3 +- src/components/ReciterDropdown/index.js | 17 +- src/components/SearchAutocomplete/index.js | 39 ++-- src/components/SearchInput/index.js | 11 +- src/components/SettingsModal/index.js | 8 +- src/components/Share/index.js | 5 +- src/components/SmartBanner/index.js | 68 +++---- src/components/SurahInfo/index.js | 8 +- src/components/SurahsDropdown/index.js | 17 +- src/components/TopOptions/index.js | 4 +- src/components/Translation/index.js | 14 +- src/components/Verse/index.js | 1 - src/components/VersesDropdown/index.js | 31 +-- src/components/Word/index.js | 26 +-- src/containers/App/index.js | 31 ++- src/containers/Contact/index.js | 4 +- src/containers/Home/index.js | 1 - src/containers/Profile/index.js | 13 +- src/containers/Search/index.js | 48 +++-- src/containers/Surah/index.js | 46 ++--- src/customPropTypes.js | 177 ++++++++++++++++++ 39 files changed, 547 insertions(+), 381 deletions(-) diff --git a/src/components/Audioplayer/RepeatDropdown/index.js b/src/components/Audioplayer/RepeatDropdown/index.js index e3e2f5227..2c0c7ed87 100644 --- a/src/components/Audioplayer/RepeatDropdown/index.js +++ b/src/components/Audioplayer/RepeatDropdown/index.js @@ -1,30 +1,18 @@ import React, { Component, PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Popover from 'react-bootstrap/lib/Popover'; import Nav from 'react-bootstrap/lib/Nav'; import NavItem from 'react-bootstrap/lib/NavItem'; import FormControl from 'react-bootstrap/lib/FormControl'; import { intlShape, injectIntl } from 'react-intl'; - import SwitchToggle from 'components/SwitchToggle'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; - import surahType from 'types/surahType'; const style = require('../style.scss'); class RepeatButton extends Component { - static propTypes = { - chapter: surahType, - repeat: PropTypes.shape({ - from: PropTypes.number, - to: PropTypes.number, - times: PropTypes.number - }).isRequired, - setRepeat: PropTypes.func.isRequired, - current: PropTypes.number.isRequired, - intl: intlShape.isRequired - }; handleToggle = () => { const { repeat, setRepeat, current } = this.props; @@ -281,4 +269,12 @@ class RepeatButton extends Component { } } +RepeatButton.propTypes = { + chapter: surahType, + repeat: customPropTypes.timeInterval, + setRepeat: PropTypes.func.isRequired, + current: PropTypes.number.isRequired, + intl: intlShape.isRequired +}; + export default injectIntl(RepeatButton); diff --git a/src/components/Audioplayer/Segments/index.js b/src/components/Audioplayer/Segments/index.js index 91ae279db..d249fb801 100644 --- a/src/components/Audioplayer/Segments/index.js +++ b/src/components/Audioplayer/Segments/index.js @@ -1,15 +1,9 @@ import React, { Component, PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import Helmet from 'react-helmet'; -import { segmentType } from 'types'; - import debug from 'helpers/debug'; -export default class Segments extends Component { - static propTypes = { - segments: PropTypes.objectOf(segmentType).isRequired, - currentVerse: PropTypes.string, - currentTime: PropTypes.number - }; +class Segments extends Component { shouldComponentUpdate(nextProps) { return [ @@ -53,3 +47,11 @@ export default class Segments extends Component { ); } } + +Segments.propTypes = { + segments: customPropTypes.segments.isRequired, + currentVerse: PropTypes.string, + currentTime: PropTypes.number +}; + +export default Segments; \ No newline at end of file diff --git a/src/components/Audioplayer/index.js b/src/components/Audioplayer/index.js index 2d3aa554c..ec3782d38 100644 --- a/src/components/Audioplayer/index.js +++ b/src/components/Audioplayer/index.js @@ -1,18 +1,16 @@ /* global document */ // TODO: This file is too too large. import React, { Component, PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import { connect } from 'react-redux'; import { camelize } from 'humps'; import Loadable from 'react-loadable'; - import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; // Helpers import debug from 'helpers/debug'; import scroller from 'utils/scroller'; -import { surahType, segmentType, verseType } from 'types'; - // Redux import * as AudioActions from 'redux/actions/audioplayer'; @@ -29,38 +27,6 @@ const RepeatDropdown = Loadable({ }); export class Audioplayer extends Component { - static propTypes = { - className: PropTypes.string, - chapter: surahType, - onLoadAyahs: PropTypes.func.isRequired, - segments: PropTypes.objectOf(segmentType), - // NOTE: should be PropTypes.instanceOf(Audio) but not on server. - files: PropTypes.object, // eslint-disable-line - currentVerse: PropTypes.string, - buildOnClient: PropTypes.func.isRequired, - isLoadedOnClient: PropTypes.bool.isRequired, - isLoading: PropTypes.bool.isRequired, - play: PropTypes.func.isRequired, - pause: PropTypes.func.isRequired, - next: PropTypes.func.isRequired, // eslint-disable-line - previous: PropTypes.func.isRequired, // eslint-disable-line - update: PropTypes.func.isRequired, - repeat: PropTypes.shape({ - from: PropTypes.number, - to: PropTypes.number, - time: PropTypes.number, - }).isRequired, - shouldScroll: PropTypes.bool.isRequired, - setRepeat: PropTypes.func.isRequired, - setAyah: PropTypes.func.isRequired, - toggleScroll: PropTypes.func.isRequired, - isPlaying: PropTypes.bool, - currentTime: PropTypes.number, - duration: PropTypes.number, - // NOTE: should be PropTypes.instanceOf(Audio) but not on server. - currentFile: PropTypes.any, // eslint-disable-line - startVerse: verseType // eslint-disable-line - }; componentDidMount() { const { isLoadedOnClient, buildOnClient, chapter, currentFile } = this.props; // eslint-disable-line no-shadow, max-len @@ -510,4 +476,33 @@ const mapStateToProps = (state, ownProps) => { }; }; +Audioplayer.propTypes = { + className: PropTypes.string, + chapter: customPropTypes.surahType, + 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.string, + buildOnClient: PropTypes.func.isRequired, + isLoadedOnClient: PropTypes.bool.isRequired, + isLoading: PropTypes.bool.isRequired, + play: PropTypes.func.isRequired, + pause: PropTypes.func.isRequired, + next: PropTypes.func.isRequired, // eslint-disable-line + previous: PropTypes.func.isRequired, // eslint-disable-line + update: PropTypes.func.isRequired, + repeat: customPropTypes.timeInterval.isRequired, + shouldScroll: PropTypes.bool.isRequired, + setRepeat: PropTypes.func.isRequired, + setAyah: PropTypes.func.isRequired, + toggleScroll: PropTypes.func.isRequired, + isPlaying: PropTypes.bool, + currentTime: PropTypes.number, + duration: PropTypes.number, + // NOTE: should be PropTypes.instanceOf(Audio) but not on server. + currentFile: PropTypes.any, // eslint-disable-line + startVerse: customPropTypes.verseType // eslint-disable-line +}; + export default connect(mapStateToProps, AudioActions)(Audioplayer); diff --git a/src/components/Bismillah/index.js b/src/components/Bismillah/index.js index 2b8a40036..235a2d2fb 100644 --- a/src/components/Bismillah/index.js +++ b/src/components/Bismillah/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { surahType } from 'types'; +import * as customPropTypes from 'customPropTypes'; const Bismillah = ({ chapter }) => { if (chapter && chapter.bismillahPre) { @@ -19,7 +19,7 @@ const Bismillah = ({ chapter }) => { }; Bismillah.propTypes = { - chapter: surahType.isRequired + chapter: customPropTypes.surahType.isRequired }; export default Bismillah; diff --git a/src/components/ContentDropdown/index.js b/src/components/ContentDropdown/index.js index 648e227eb..43c0b80e0 100644 --- a/src/components/ContentDropdown/index.js +++ b/src/components/ContentDropdown/index.js @@ -1,8 +1,8 @@ import React, { Component, PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import { connect } from 'react-redux'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; import { loadTranslations } from 'redux/actions/options'; -import { contentType } from 'types'; import Menu, { MenuItem } from 'quran-components/lib/Menu'; import Checkbox from 'quran-components/lib/Checkbox'; import Loader from 'quran-components/lib/Loader'; @@ -28,12 +28,6 @@ const compareAlphabetically = property => class ContentDropdown extends Component { - static propTypes = { - onOptionChange: PropTypes.func.isRequired, - translations: PropTypes.arrayOf(PropTypes.number).isRequired, - translationOptions: PropTypes.arrayOf(contentType), - loadTranslations: PropTypes.func.isRequired - }; componentDidMount() { if (!this.props.translationOptions.length) { @@ -129,6 +123,13 @@ class ContentDropdown extends Component { } } +ContentDropdown.propTypes = { + onOptionChange: PropTypes.func.isRequired, + translations: PropTypes.arrayOf(PropTypes.number).isRequired, + translationOptions: customPropTypes.translationOptions, + loadTranslations: PropTypes.func.isRequired +}; + export default connect(state => ({ translationOptions: state.options.options.translations, loadingTranslations: state.options.loadingTranslations, diff --git a/src/components/Copy/index.js b/src/components/Copy/index.js index 92491f95b..8fe5cf417 100644 --- a/src/components/Copy/index.js +++ b/src/components/Copy/index.js @@ -2,11 +2,7 @@ import React, { Component, PropTypes } from 'react'; import copyToClipboard from 'copy-to-clipboard'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; -export default class Copy extends Component { - static propTypes = { - text: PropTypes.string.isRequired, - verseKey: PropTypes.string.isRequired, - } +class Copy extends Component { state = { isCopied: false @@ -17,7 +13,7 @@ export default class Copy extends Component { this.setState({ isCopied: true }); setTimeout(() => this.setState({ isCopied: false }), 1000); - } + }; render() { const { isCopied } = this.state; @@ -37,5 +33,11 @@ export default class Copy extends Component { ); } - } + +Copy.proptypes = { + text: PropTypes.string.isRequired, + verseKey: PropTypes.string.isRequired, +}; + +export default Copy; diff --git a/src/components/FontSizeDropdown/index.js b/src/components/FontSizeDropdown/index.js index 6435c63ee..ee264bcc3 100644 --- a/src/components/FontSizeDropdown/index.js +++ b/src/components/FontSizeDropdown/index.js @@ -1,17 +1,10 @@ import React, { Component, PropTypes } from 'react'; - +import * as customPropTypes from 'customPropTypes'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; const style = require('./style.scss'); -export default class FontSizeDropdown extends Component { - static propTypes = { - onOptionChange: PropTypes.func, - fontSize: PropTypes.shape({ - arabic: PropTypes.number, - translation: PropTypes.number - }).isRequired - } +class FontSizeDropdown extends Component { handleOptionSelected = (type, direction) => { const { onOptionChange, fontSize } = this.props; @@ -90,3 +83,10 @@ export default class FontSizeDropdown extends Component { ); } } + +FontSizeDropdown.propTypes = { + onOptionChange: PropTypes.func, + fontSize: customPropTypes.fontSize.isRequired +}; + +export default FontSizeDropdown; diff --git a/src/components/FontStyles/index.js b/src/components/FontStyles/index.js index c19539c46..dd22d921d 100644 --- a/src/components/FontStyles/index.js +++ b/src/components/FontStyles/index.js @@ -12,11 +12,8 @@ import selector from './selector'; }), { load } ) -export default class FontStyles extends Component { - static propTypes = { - fontFaces: PropTypes.objectOf(PropTypes.bool).isRequired, - load: PropTypes.func.isRequired - }; + +class FontStyles extends Component { shouldComponentUpdate(nextProps) { return JSON.stringify(this.props.fontFaces) !== JSON.stringify(nextProps.fontFaces); @@ -54,3 +51,10 @@ export default class FontStyles extends Component { ); } } + +FontStyles.propTypes = { + fontFaces: PropTypes.objectOf(PropTypes.bool).isRequired, + load: PropTypes.func.isRequired +}; + +export default FontStyles; diff --git a/src/components/GlobalNav/Surah/index.js b/src/components/GlobalNav/Surah/index.js index 746e47d24..41b1ab306 100644 --- a/src/components/GlobalNav/Surah/index.js +++ b/src/components/GlobalNav/Surah/index.js @@ -1,12 +1,10 @@ import React, { PropTypes, Component } from 'react'; +import * as customPropTypes from 'customPropTypes'; +import * as OptionsActions from 'redux/actions/options.js'; import { connect } from 'react-redux'; import Link from 'react-router/lib/Link'; import Drawer from 'quran-components/lib/Drawer'; import Menu from 'quran-components/lib/Menu'; - -import { surahType, optionsType } from 'types'; -import * as OptionsActions from 'redux/actions/options.js'; - import SearchInput from 'components/SearchInput'; import SurahsDropdown from 'components/SurahsDropdown'; import ReadingModeToggle from 'components/ReadingModeToggle'; @@ -26,14 +24,6 @@ import GlobalNav from '../index'; const styles = require('../style.scss'); class GlobalNavSurah extends Component { - static propTypes = { - chapter: surahType.isRequired, - chapters: PropTypes.objectOf(surahType).isRequired, - options: optionsType.isRequired, - setOption: PropTypes.func.isRequired, - versesIds: PropTypes.instanceOf(Set), - load: PropTypes.func.isRequired - }; state = { drawerOpen: false @@ -156,4 +146,13 @@ function mapStateToProps(state, ownProps) { }; } +GlobalNavSurah.propTypes = { + chapter: customPropTypes.surahType.isRequired, + chapaters: customPropTypes.chapters.isRequired, + options: customPropTypes.optionsType.isRequired, + setOption: PropTypes.func.isRequired, + versesIds: PropTypes.instanceOf(Set), + load: PropTypes.func.isRequired +}; + export default connect(mapStateToProps, { ...OptionsActions, load })(GlobalNavSurah); diff --git a/src/components/GlobalNav/index.js b/src/components/GlobalNav/index.js index 5723d105c..dbfb6c6d6 100644 --- a/src/components/GlobalNav/index.js +++ b/src/components/GlobalNav/index.js @@ -1,5 +1,6 @@ /* global window */ import React, { PropTypes, Component } from 'react'; +import * as customPropTypes from 'customPropTypes'; import { connect } from 'react-redux'; import Link from 'react-router/lib/Link'; import Navbar from 'react-bootstrap/lib/Navbar'; @@ -13,25 +14,6 @@ import { userType } from 'types'; const styles = require('./style.scss'); class GlobalNav extends Component { - static propTypes = { - // handleToggleSidebar: PropTypes.func.isRequired, - leftControls: PropTypes.arrayOf(PropTypes.element), - rightControls: PropTypes.arrayOf(PropTypes.element), - handleSidebarToggle: PropTypes.func.isRequired, - isStatic: PropTypes.bool.isRequired, - user: userType, - location: PropTypes.shape({ - action: PropTypes.string, - hash: PropTypes.string, - pathname: PropTypes.string, - search: PropTypes.string, - query: PropTypes.objectOf(PropTypes.string) - }) - }; - - static defaultProps = { - isStatic: false - }; state = { scrolled: false @@ -123,6 +105,20 @@ class GlobalNav extends Component { } } +GlobalNav.propTypes = { + // handleToggleSidebar: PropTypes.func.isRequired, + leftControls: PropTypes.arrayOf(PropTypes.element), + rightControls: PropTypes.arrayOf(PropTypes.element), + handleSidebarToggle: PropTypes.func.isRequired, + isStatic: PropTypes.bool.isRequired, + user: userType, + location: customPropTypes.location +}; + +GlobalNav.defaultProps = { + isStatic: false +}; + export default connect( state => ({ user: state.auth.user diff --git a/src/components/GlobalSidebar/index.js b/src/components/GlobalSidebar/index.js index ac3cf067d..c4ad96dc4 100644 --- a/src/components/GlobalSidebar/index.js +++ b/src/components/GlobalSidebar/index.js @@ -5,24 +5,13 @@ import Navbar from 'react-bootstrap/lib/Navbar'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; const styles = require('./style.scss'); - const NavbarHeader = Navbar.Header; class GlobalSidebar extends Component { - static propTypes = { - open: PropTypes.bool.isRequired, - handleOpen: PropTypes.func, - settingsModalProps: PropTypes.object, // eslint-disable-line - children: PropTypes.node - }; - - static defaultProps = { - open: false - }; state = { settingsModalOpen: false - } + }; componentDidMount() { document.body.addEventListener('click', this.onBodyClick.bind(this), true); @@ -116,4 +105,15 @@ class GlobalSidebar extends Component { } } +GlobalSidebar.propTypes = { + open: PropTypes.bool.isRequired, + handleOpen: PropTypes.func, + settingsModalProps: PropTypes.object, // eslint-disable-line + children: PropTypes.node +}; + +GlobalSidebar.defaultProps = { + open: false +}; + export default GlobalSidebar; diff --git a/src/components/Home/LastVisit/index.js b/src/components/Home/LastVisit/index.js index d7802ebd6..c1e74dbb0 100644 --- a/src/components/Home/LastVisit/index.js +++ b/src/components/Home/LastVisit/index.js @@ -1,7 +1,7 @@ import React, { PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import debug from 'helpers/debug'; import Link from 'react-router/lib/Link'; -import { surahType } from 'types'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; const styles = require('containers/Home/style.scss'); @@ -25,7 +25,7 @@ const LastVisit = (props) => { }; LastVisit.propTypes = { - chapter: surahType.isRequired, + chapter: customPropTypes.surahType.isRequired, verse: PropTypes.number.isRequired }; diff --git a/src/components/Home/SurahsList/index.js b/src/components/Home/SurahsList/index.js index dc197f794..a4f577c76 100644 --- a/src/components/Home/SurahsList/index.js +++ b/src/components/Home/SurahsList/index.js @@ -1,9 +1,8 @@ import React, { PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import debug from 'helpers/debug'; import Link from 'react-router/lib/Link'; -import { surahType } from 'types'; - const styles = require('./style.scss'); const SurahsList = (props) => { @@ -36,7 +35,7 @@ const SurahsList = (props) => { }; SurahsList.propTypes = { - chapters: PropTypes.arrayOf(surahType).isRequired + chapters: customPropTypes.chapters.isRequired }; export default SurahsList; diff --git a/src/components/IndexHeader/index.js b/src/components/IndexHeader/index.js index 2b67fbc7c..c363e7edf 100644 --- a/src/components/IndexHeader/index.js +++ b/src/components/IndexHeader/index.js @@ -1,6 +1,5 @@ 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'; @@ -8,10 +7,7 @@ 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) { @@ -44,3 +40,9 @@ export default class IndexHeader extends Component { ); } } + +IndexHeader.propTypes = { + noSearch: PropTypes.bool +}; + +export default IndexHeader; diff --git a/src/components/LazyLoad/index.js b/src/components/LazyLoad/index.js index 84f52cb74..8ffad3f8e 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; \ No newline at end of file diff --git a/src/components/Line/index.js b/src/components/Line/index.js index 5cd06dbac..0b1723a9a 100644 --- a/src/components/Line/index.js +++ b/src/components/Line/index.js @@ -1,25 +1,11 @@ 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('../Verse/style.scss'); -export default class Line extends React.Component { - static propTypes = { - line: PropTypes.arrayOf(wordType).isRequired, - tooltip: PropTypes.string, - currentVerse: 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, - useTextFont: PropTypes.bool - }; +class Line extends React.Component { // NOTE: this is commented out as it caused problems with 55:31 with missing text. // shouldComponentUpdate(nextProps) { @@ -73,3 +59,14 @@ export default class Line extends React.Component { ); } } + +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/LocaleSwitcher/index.js b/src/components/LocaleSwitcher/index.js index 4e4c74bbb..d2ab64639 100644 --- a/src/components/LocaleSwitcher/index.js +++ b/src/components/LocaleSwitcher/index.js @@ -7,10 +7,7 @@ import config from '../../config'; const { locales, defaultLocale } = config; -export default class LocaleSwitcher extends Component { - static propTypes = { - className: PropTypes.string - }; +class LocaleSwitcher extends Component { state = { currentLocale: defaultLocale, @@ -68,3 +65,9 @@ export default class LocaleSwitcher extends Component { ); } } + +LocaleSwitcher.propTypes = { + className: PropTypes.string +}; + +export default LocaleSwitcher; diff --git a/src/components/NightModeToggle/index.js b/src/components/NightModeToggle/index.js index 46fe461ef..9c24c731e 100644 --- a/src/components/NightModeToggle/index.js +++ b/src/components/NightModeToggle/index.js @@ -4,10 +4,6 @@ import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; import { MenuItem } from 'quran-components/lib/Menu'; class NightModeToggle extends Component { - static propTypes = { - isNightMode: PropTypes.bool.isRequired, - onToggle: PropTypes.func.isRequired - } componentDidMount() { const { isNightMode } = this.props; @@ -41,4 +37,9 @@ class NightModeToggle extends Component { } } +NightModeToggle.propTypes = { + isNightMode: PropTypes.bool.isRequired, + onToggle: PropTypes.func.isRequired +}; + export default NightModeToggle; diff --git a/src/components/PageView/index.js b/src/components/PageView/index.js index 9709cfece..5a6f784c9 100644 --- a/src/components/PageView/index.js +++ b/src/components/PageView/index.js @@ -1,4 +1,5 @@ import React, { PropTypes } from 'react'; +import * as customPropTypes from 'customPropTypes'; import { connect } from 'react-redux'; import Line from 'components/Line'; @@ -47,7 +48,7 @@ const PageView = ({ lines, keys, currentVerse, options, isPlaying, audioActions, PageView.propTypes = { keys: PropTypes.array, // eslint-disable-line lines: PropTypes.object.isRequired, // eslint-disable-line - audioActions: 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 diff --git a/src/components/ReciterDropdown/index.js b/src/components/ReciterDropdown/index.js index 16d24735a..b3871cc81 100644 --- a/src/components/ReciterDropdown/index.js +++ b/src/components/ReciterDropdown/index.js @@ -1,22 +1,14 @@ import React, { Component, PropTypes } from 'react'; +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'; -import { recitationType } from 'types'; class ReciterDropdown extends Component { - static propTypes = { - onOptionChange: PropTypes.func, - audio: PropTypes.number, - loadRecitations: PropTypes.func.isRequired, - recitations: PropTypes.arrayOf(recitationType) - }; componentDidMount() { if (!this.props.recitations.length) { @@ -61,6 +53,13 @@ class ReciterDropdown extends Component { } } +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, diff --git a/src/components/SearchAutocomplete/index.js b/src/components/SearchAutocomplete/index.js index b7f2ea6f3..7e8a26040 100644 --- a/src/components/SearchAutocomplete/index.js +++ b/src/components/SearchAutocomplete/index.js @@ -1,35 +1,14 @@ // 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'); - const ayahRegex = /^(\d+)(?::(\d+))?$/; class SearchAutocomplete extends Component { - static propTypes = { - chapters: 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)); @@ -220,4 +199,20 @@ function mapStateToProps(state, ownProps) { }; } +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..6d20f46be 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 b137cbad3..2b8114410 100644 --- a/src/components/SettingsModal/index.js +++ b/src/components/SettingsModal/index.js @@ -1,15 +1,13 @@ 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/verses.js'; -import { optionsType, surahType } from 'types'; const ModalHeader = Modal.Header; const ModalTitle = Modal.Title; @@ -73,11 +71,11 @@ const SettingsModal = ({ }; SettingsModal.propTypes = { - chapter: 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 eadf66bb7..f1b1ed873 100644 --- a/src/components/Share/index.js +++ b/src/components/Share/index.js @@ -1,9 +1,8 @@ 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'); - const { FacebookShareButton, TwitterShareButton } = ShareButtons; const FacebookIcon = generateShareIcon('facebook'); const TwitterIcon = generateShareIcon('twitter'); @@ -39,7 +38,7 @@ const Share = ({ chapter, verseKey }) => { Share.propTypes = { verseKey: PropTypes.string, - chapter: surahType.isRequired + chapter: customPropTypes.surahType.isRequired }; export default Share; diff --git a/src/components/SmartBanner/index.js b/src/components/SmartBanner/index.js index 2d0dd362e..7514aacb8 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: {}, @@ -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 6aff87295..237f5182f 100644 --- a/src/components/SurahInfo/index.js +++ b/src/components/SurahInfo/index.js @@ -1,10 +1,8 @@ import React, { PropTypes } from 'react'; - -import { surahType, infoType } from 'types'; +import * as customPropTypes from 'customPropTypes'; import Loader from 'quran-components/lib/Loader'; const style = require('./style.scss'); - const SurahInfo = ({ chapter, info, isShowingSurahInfo, onClose }) => { // So we don't need to load images and files unless needed if (!isShowingSurahInfo) return