diff --git a/server.js b/server.js index 55413f0f8..9c1a781a8 100644 --- a/server.js +++ b/server.js @@ -25,8 +25,8 @@ import debug from './src/helpers/debug'; import Html from './src/helpers/Html'; -import { setUserAgent } from './src/redux/modules/audioplayer'; -import { setOption } from './src/redux/modules/options'; +import { setUserAgent } from './src/redux/actions/audioplayer.js'; +import { setOption } from './src/redux/actions/options.js'; // Use varnish for the static routes, which will cache too server.use(raven.middleware.express.requestHandler(config.sentryServer)); diff --git a/src/components/Audioplayer/index.js b/src/components/Audioplayer/index.js index 05382fd7e..6492999bf 100644 --- a/src/components/Audioplayer/index.js +++ b/src/components/Audioplayer/index.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import { camelize } from 'humps'; // Redux -import * as AudioActions from '../../redux/modules/audioplayer'; +import * as AudioActions from '../../redux/actions/audioplayer'; // Components import Track from './Track'; diff --git a/src/components/FontStyles/index.js b/src/components/FontStyles/index.js index a887bb375..b147dbe2e 100644 --- a/src/components/FontStyles/index.js +++ b/src/components/FontStyles/index.js @@ -1,7 +1,7 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; import { fontFaceStyle, fontFaceStyleLoaded } from '../../helpers/buildFontFaces'; -import { load } from 'redux/modules/fontFaces'; +import { load } from 'redux/actions/fontFace.js'; import debug from 'helpers/debug'; import selector from './selector'; diff --git a/src/containers/Home/index.js b/src/containers/Home/index.js index 42cecc777..50fb5f230 100644 --- a/src/containers/Home/index.js +++ b/src/containers/Home/index.js @@ -7,7 +7,7 @@ import { connect } from 'react-redux'; import debug from '../../helpers/debug'; -import { isAllLoaded, loadAll } from '../../redux/modules/surahs'; +import { isAllLoaded, loadAll } from '../../redux/actions/surahs.js'; const styles = require('./style.scss'); diff --git a/src/containers/Search/index.js b/src/containers/Search/index.js index 1af7eb7b6..1d36c8b42 100644 --- a/src/containers/Search/index.js +++ b/src/containers/Search/index.js @@ -16,7 +16,7 @@ import Header from './Header'; import Ayah from '../../components/Ayah'; import CoreLoader from '../../components/Loader'; -import { search } from '../../redux/modules/searchResults'; +import { search } from '../../redux/actions/search.js'; const style = require('./style.scss'); diff --git a/src/containers/Surah/connect.js b/src/containers/Surah/connect.js index 965888db0..197910c57 100644 --- a/src/containers/Surah/connect.js +++ b/src/containers/Surah/connect.js @@ -1,7 +1,15 @@ -import { isAllLoaded, loadAll, setCurrent as setCurrentSurah } from '../../redux/modules/surahs'; -import { clearCurrent, isLoaded, load as loadAyahs } from '../../redux/modules/ayahs'; - -import debug from 'helpers/debug'; +import { + isAllLoaded, + loadAll, + setCurrent as setCurrentSurah + } from '../../redux/actions/surahs.js'; + +import { + clearCurrent, + load as loadAyahs + } from '../../redux/actions/ayahs.js'; + +import {debug, isLoaded} from 'helpers'; const ayahRangeSize = 30; diff --git a/src/containers/Surah/index.js b/src/containers/Surah/index.js index 1a39dd665..f7b73685b 100644 --- a/src/containers/Surah/index.js +++ b/src/containers/Surah/index.js @@ -42,9 +42,9 @@ import descriptions from './descriptions'; import { surahsConnect, ayahsConnect } from './connect'; -import * as AudioActions from '../../redux/modules/audioplayer'; -import * as AyahActions from '../../redux/modules/ayahs'; -import * as OptionsActions from '../../redux/modules/options'; +import * as AudioActions from '../../redux/actions/audioplayer.js'; +import * as AyahActions from '../../redux/actions/ayahs.js'; +import * as OptionsActions from '../../redux/actions/options.js'; const style = require('./style.scss'); diff --git a/src/helpers/index.js b/src/helpers/index.js new file mode 100644 index 000000000..d5c2d2955 --- /dev/null +++ b/src/helpers/index.js @@ -0,0 +1,8 @@ +export function isLoaded(globalState, surahId, from, to) { + return ( + globalState.ayahs.entities[surahId] && + globalState.ayahs.entities[surahId][`${surahId}:${from}`] && + globalState.ayahs.entities[surahId][`${surahId}:${to}`] + ); +} +export { default as debug } from './debug'; diff --git a/src/redux/actions/audioplayer.js b/src/redux/actions/audioplayer.js new file mode 100644 index 000000000..9b8205f9d --- /dev/null +++ b/src/redux/actions/audioplayer.js @@ -0,0 +1,94 @@ +import { + SET_USER_AGENT, + SET_CURRENT_FILE, + SET_CURRENT_WORD, + PLAY, + PAUSE, + NEXT, + SET_AYAH, + PREVIOUS, + SET_REPEAT, + TOGGLE_SCROLL, + BUILD_ON_CLIENT, + UPDATE } from '../constants/audioplayer.js'; + +export function setUserAgent(userAgent) { + return { + type: SET_USER_AGENT, + userAgent + }; +} + +export function setCurrentFile(file) { + return { + type: SET_CURRENT_FILE, + file + }; +} + +export function setCurrentWord(word) { + return { + type: SET_CURRENT_WORD, + word + }; +} + +export function play() { + return { + type: PLAY + }; +} + +export function pause() { + return { + type: PAUSE + }; +} + +export function next(currentAyah) { + return { + type: NEXT, + currentAyah + }; +} + +export function setAyah(currentAyah) { + return { + type: SET_AYAH, + currentAyah + }; +} + +export function previous(currentAyah) { + return { + type: PREVIOUS, + currentAyah + }; +} + +export function setRepeat(repeat) { + return { + type: SET_REPEAT, + repeat + }; +} + +export function toggleScroll() { + return { + type: TOGGLE_SCROLL + }; +} + +export function buildOnClient(surahId) { + return { + type: BUILD_ON_CLIENT, + surahId + }; +} + +export function update(payload) { + return { + type: UPDATE, + payload + }; +} diff --git a/src/redux/actions/ayahs.js b/src/redux/actions/ayahs.js new file mode 100644 index 000000000..6140559a1 --- /dev/null +++ b/src/redux/actions/ayahs.js @@ -0,0 +1,66 @@ +import { ayahsSchema } from '../schemas'; + +import { arrayOf } from 'normalizr'; + +import { + LOAD, + LOAD_SUCCESS, + LOAD_FAIL, + CLEAR_CURRENT, + SET_CURRENT_AYAH, + SET_CURRENT_WORD, + CLEAR_CURRENT_WORD + } from '../constants/ayahs.js'; + +// For safe measure +const defaultOptions = { + audio: 8, + quran: 1, + content: [19] +}; + +export function load(id, from, to, options = defaultOptions) { + const { audio, quran, content } = options; + + return { + types: [LOAD, LOAD_SUCCESS, LOAD_FAIL], + schema: arrayOf(ayahsSchema), + promise: (client) => client.get(`/v2/surahs/${id}/ayahs`, { + params: { + from, + to, + audio, + quran, + content + } + }), + surahId: id + }; +} + +export function clearCurrent(id) { + return { + type: CLEAR_CURRENT, + id + }; +} + +export function clearCurrentWord() { + return { + type: CLEAR_CURRENT_WORD + }; +} + +export function setCurrentAyah(id) { + return { + type: SET_CURRENT_AYAH, + id + }; +} + +export function setCurrentWord(id) { + return { + type: SET_CURRENT_WORD, + id + }; +} diff --git a/src/redux/actions/fontFace.js b/src/redux/actions/fontFace.js new file mode 100644 index 000000000..0fb13f699 --- /dev/null +++ b/src/redux/actions/fontFace.js @@ -0,0 +1,8 @@ +import { LOAD } from '../constants/fontFace.js'; + +export function load(className) { + return { + type: LOAD, + className + }; +} diff --git a/src/redux/actions/options.js b/src/redux/actions/options.js new file mode 100644 index 000000000..a2006d479 --- /dev/null +++ b/src/redux/actions/options.js @@ -0,0 +1,23 @@ +import cookie from 'react-cookie'; +import { TOGGLE_READING_MODE, SET_OPTION } from '../constants/options.js'; + +export function isReadingMode(globalState) { + return globalState.options.isReadingMode; +} + +export function setOption(payload) { + const options = cookie.load('options') || {}; // protect against first timers. + Object.keys(payload).forEach(option => { options[option] = payload[option]; }); + cookie.save('options', JSON.stringify(options)); + + return { + type: SET_OPTION, + payload + }; +} + +export function toggleReadingMode() { + return { + type: TOGGLE_READING_MODE + }; +} diff --git a/src/redux/actions/search.js b/src/redux/actions/search.js new file mode 100644 index 000000000..eecac3587 --- /dev/null +++ b/src/redux/actions/search.js @@ -0,0 +1,21 @@ +import { ayahsSchema } from '../schemas'; +import { arrayOf } from 'normalizr'; + +import { + SEARCH, + SEARCH_SUCCESS, + SEARCH_FAIL + } from '../constants/search.js'; + +export function search(params) { + return { + types: [SEARCH, SEARCH_SUCCESS, SEARCH_FAIL], + schema: {results: arrayOf({ayah: ayahsSchema})}, + promise: (client) => client.get('/v2/search', { params }), + params + }; +} + +export function isQueried() { + return false; +} diff --git a/src/redux/actions/spec.js b/src/redux/actions/spec.js new file mode 100644 index 000000000..9d84cc5c3 --- /dev/null +++ b/src/redux/actions/spec.js @@ -0,0 +1,43 @@ +import * as audioplayerActions from './audioplayer.js'; +import * as ayahsActions from './ayahs.js'; +import * as surahsActions from './surahs.js'; +import * as audioplayerConstant from '../constants/audioplayer.js'; +import * as ayahsConstants from '../constants/ayahs.js'; +import * as surahsConstants from '../constants/surahs.js'; + + +describe("action tests", () => { + + it("audioplayer actions", () => { + expect(audioplayerActions.setUserAgent('abc').type).to.equal(audioplayerConstant.SET_USER_AGENT); + expect(audioplayerActions.setCurrentFile('fil').type).to.equal(audioplayerConstant.SET_CURRENT_FILE); + expect(audioplayerActions.setCurrentWord('word').type).to.equal(audioplayerConstant.SET_CURRENT_WORD); + expect(audioplayerActions.play().type).to.equal(audioplayerConstant.PLAY); + expect(audioplayerActions.pause().type).to.equal(audioplayerConstant.PAUSE); + expect(audioplayerActions.next('abc').type).to.equal(audioplayerConstant.NEXT); + expect(audioplayerActions.previous('abc').type).to.equal(audioplayerConstant.PREVIOUS); + expect(audioplayerActions.setRepeat('abc').type).to.equal(audioplayerConstant.SET_REPEAT); + expect(audioplayerActions.toggleScroll().type).to.equal(audioplayerConstant.TOGGLE_SCROLL); + expect(audioplayerActions.buildOnClient('abc').type).to.equal(audioplayerConstant.BUILD_ON_CLIENT); + expect(audioplayerActions.update('abc').type).to.equal(audioplayerConstant.UPDATE); + }); + + it("ayahs actions", () => { + expect(ayahsActions.load(1, 2, 4).types.length).to.equal(3); + expect(ayahsActions.clearCurrent().type).to.equal(ayahsConstants.CLEAR_CURRENT); + expect(ayahsActions.clearCurrentWord(1).type).to.equal(ayahsConstants.CLEAR_CURRENT_WORD); + expect(ayahsActions.setCurrentAyah(1).type).to.equal(ayahsConstants.SET_CURRENT_AYAH); + expect(ayahsActions.setCurrentWord(1).type).to.equal(ayahsConstants.SET_CURRENT_WORD); + }); + + it("surahs actions", () => { + expect(surahsActions.loadAll().types.length).to.equal(3); + expect(surahsActions.load(1).types.length).to.equal(3); + expect(surahsActions.loadInfo('url').types.length).to.equal(3); + expect(surahsActions.setCurrent(1).type).to.equal(surahsConstants.SET_CURRENT); + }); + + + + +}); diff --git a/src/redux/actions/surahs.js b/src/redux/actions/surahs.js new file mode 100644 index 000000000..7ee52ae12 --- /dev/null +++ b/src/redux/actions/surahs.js @@ -0,0 +1,48 @@ +import { surahsSchema } from '../schemas'; +import { arrayOf } from 'normalizr'; +import { + LOAD, + LOAD_SUCCESS, + LOAD_FAIL, + LOAD_INFO, + LOAD_INFO_SUCCESS, + LOAD_INFO_FAIL, + SET_CURRENT } from '../constants/surahs.js'; + +export function loadAll() { + return { + types: [LOAD, LOAD_SUCCESS, LOAD_FAIL], + schema: arrayOf(surahsSchema), + promise: (client) => client.get('/v2/surahs') + }; +} + +export function load(id) { + return { + types: [LOAD, LOAD_SUCCESS, LOAD_FAIL], + schema: arrayOf(surahsSchema), + promise: (client) => client.get(`/v2/surahs/${id}`) + }; +} + +export function loadInfo(link) { + return { + types: [LOAD_INFO, LOAD_INFO_SUCCESS, LOAD_INFO_FAIL], + promise: (client) => client.get(`http://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&titles=${link}&redirects=true`) // eslint-disable-line max-len + }; +} + +export function setCurrent(id) { + return { + type: SET_CURRENT, + current: id + }; +} + +export function isSingleLoaded(globalState, id) { + return !!globalState.surahs.entities[id]; +} + +export function isAllLoaded(globalState) { + return Object.keys(globalState.surahs.entities).length === 114; +} diff --git a/src/redux/constants/audioplayer.js b/src/redux/constants/audioplayer.js new file mode 100644 index 000000000..e0d43d7a8 --- /dev/null +++ b/src/redux/constants/audioplayer.js @@ -0,0 +1,12 @@ +export const SET_USER_AGENT = '@@quran/audioplayer/SET_USER_AGENT'; +export const SET_CURRENT_FILE = '@@quran/audioplayer/SET_CURRENT_FILE'; +export const SET_CURRENT_WORD = '@@quran/audioplayer/SET_CURRENT_WORD'; +export const PLAY = '@@quran/audioplayer/PLAY'; +export const PAUSE = '@@quran/audioplayer/PAUSE'; +export const NEXT = '@@quran/audioplayer/NEXT'; +export const SET_AYAH = '@@quran/audioplayer/SET'; +export const PREVIOUS = '@@quran/audioplayer/PREVIOUS'; +export const SET_REPEAT = '@@quran/audioplayer/SET_REPEAT'; +export const TOGGLE_SCROLL = '@@quran/audioplayer/TOGGLE_SCROLL'; +export const BUILD_ON_CLIENT = '@@quran/audioplayer/BUILD_ON_CLIENT'; +export const UPDATE = '@@quran/audioplayer/UPDATE'; diff --git a/src/redux/constants/ayahs.js b/src/redux/constants/ayahs.js new file mode 100644 index 000000000..4b215a3a8 --- /dev/null +++ b/src/redux/constants/ayahs.js @@ -0,0 +1,7 @@ +export const LOAD = '@@quran/ayahs/LOAD'; +export const LOAD_SUCCESS = '@@quran/ayahs/LOAD_SUCCESS'; +export const LOAD_FAIL = '@@quran/ayahs/LOAD_FAIL'; +export const CLEAR_CURRENT = '@@quran/ayahs/CLEAR_CURRENT'; +export const SET_CURRENT_AYAH = '@@quran/ayahs/SET_CURRENT_AYAH'; +export const SET_CURRENT_WORD = '@@quran/ayahs/SET_CURRENT_WORD'; +export const CLEAR_CURRENT_WORD = '@@quran/ayahs/CLEAR_CURRENT_WORD'; diff --git a/src/redux/constants/fontFace.js b/src/redux/constants/fontFace.js new file mode 100644 index 000000000..1dc3a243b --- /dev/null +++ b/src/redux/constants/fontFace.js @@ -0,0 +1 @@ +export const LOAD = '@@quran/fontFaces/LOAD'; diff --git a/src/redux/constants/options.js b/src/redux/constants/options.js new file mode 100644 index 000000000..ffa608eeb --- /dev/null +++ b/src/redux/constants/options.js @@ -0,0 +1,2 @@ +export const TOGGLE_READING_MODE = '@@quran/options/TOGGLE_READING_MODE'; +export const SET_OPTION = '@@quran/options/SET_OPTION'; diff --git a/src/redux/constants/search.js b/src/redux/constants/search.js new file mode 100644 index 000000000..2eeaa1654 --- /dev/null +++ b/src/redux/constants/search.js @@ -0,0 +1,3 @@ +export const SEARCH = '@@quran/search/LOAD'; +export const SEARCH_SUCCESS = '@@quran/search/LOAD_SUCCESS'; +export const SEARCH_FAIL = '@@quran/search/LOAD_FAIL'; diff --git a/src/redux/constants/surahs.js b/src/redux/constants/surahs.js new file mode 100644 index 000000000..b74c0eb4e --- /dev/null +++ b/src/redux/constants/surahs.js @@ -0,0 +1,7 @@ +export const LOAD = '@@quran/surahs/LOAD'; +export const LOAD_SUCCESS = '@@quran/surahs/LOAD_SUCCESS'; +export const LOAD_FAIL = '@@quran/surahs/LOAD_FAIL'; +export const LOAD_INFO = '@@quran/surahs/LOAD_INFO'; +export const LOAD_INFO_SUCCESS = '@@quran/surahs/LOAD_INFO_SUCCESS'; +export const LOAD_INFO_FAIL = '@@quran/surahs/LOAD_INFO_FAIL'; +export const SET_CURRENT = '@@quran/surahs/SET_CURRENT'; diff --git a/src/redux/modules/audioplayer.js b/src/redux/modules/audioplayer.js index 39b5d1003..caf844e05 100644 --- a/src/redux/modules/audioplayer.js +++ b/src/redux/modules/audioplayer.js @@ -8,20 +8,24 @@ import { LOAD as AYAHS_LOAD, CLEAR_CURRENT as AYAHS_CLEAR_CURRENT, SET_CURRENT_AYAH -} from './ayahs'; + } from './ayahs'; -const SET_USER_AGENT = '@@quran/audioplayer/SET_USER_AGENT'; -const SET_CURRENT_FILE = '@@quran/audioplayer/SET_CURRENT_FILE'; -const SET_CURRENT_WORD = '@@quran/audioplayer/SET_CURRENT_WORD'; -const PLAY = '@@quran/audioplayer/PLAY'; -const PAUSE = '@@quran/audioplayer/PAUSE'; -export const NEXT = '@@quran/audioplayer/NEXT'; -export const SET_AYAH = '@@quran/audioplayer/SET'; -const PREVIOUS = '@@quran/audioplayer/PREVIOUS'; -const SET_REPEAT = '@@quran/audioplayer/SET_REPEAT'; -const TOGGLE_SCROLL = '@@quran/audioplayer/TOGGLE_SCROLL'; -const BUILD_ON_CLIENT = '@@quran/audioplayer/BUILD_ON_CLIENT'; -const UPDATE = '@@quran/audioplayer/UPDATE'; +import { + SET_USER_AGENT, + SET_CURRENT_FILE, + SET_CURRENT_WORD, + PLAY, + PAUSE, + NEXT, + SET_AYAH, + PREVIOUS, + SET_REPEAT, + TOGGLE_SCROLL, + BUILD_ON_CLIENT, + UPDATE + } from '../constants/audioplayer.js'; + +export { NEXT, SET_AYAH }; const initialState = { files: {}, @@ -43,39 +47,49 @@ const initialState = { }; export default function reducer(state = initialState, action = {}) { + switch (action.type) { case BUILD_ON_CLIENT: { debug('reducer:audioplayer', 'BUILD_ON_CLIENT init'); const audioFromHash = buildAudioFromHash(state.files[action.surahId], state.userAgent); debug('reducer:audioplayer', 'BUILD_ON_CLIENT return'); + + const stateFiles = state.files; + const filesById = stateFiles[action.surahId]; + const filesFromHash = audioFromHash.files; + return { ...state, isLoadedOnClient: true, files: { - ...state.files, + ...stateFiles, [action.surahId]: { - ...state.files[action.surahId], - ...audioFromHash.files + ...filesById, + ...filesFromHash } }, currentFile: Object.values(audioFromHash.files)[0], currentAyah: Object.keys(audioFromHash.files)[0] }; } - case AYAHS_CLEAR_CURRENT: + case AYAHS_CLEAR_CURRENT: { + const stateFilesCurrent = state.files; + return { ...state, files: { - ...state.files, + ...stateFilesCurrent, [action.id]: {} } }; - case AYAHS_LOAD: + } + case AYAHS_LOAD: { return { ...state, isLoading: false }; + } case AYAHS_LOAD_SUCCESS: { debug('reducer:audioplayer', 'AYAHS_LOAD_SUCCESS init'); let currentFile; @@ -115,6 +129,9 @@ export default function reducer(state = initialState, action = {}) { } } + const stateFiles = state.files; + const stateSegments = state.segments; + debug('reducer:audioplayer', 'AYAHS_LOAD_SUCCESS return'); return { ...state, @@ -124,50 +141,56 @@ export default function reducer(state = initialState, action = {}) { surahId: action.surahId, isLoadedOnClient: __CLIENT__, files: { - ...state.files, + ...stateFiles, [action.surahId]: files }, segments: { - ...state.segments, + ...stateSegments, [action.surahId]: extractSegments(action.result.entities.ayahs) } }; } - case UPDATE: + case UPDATE: { + const {payload} = action; return { ...state, - ...action.payload + ...payload }; - case SET_USER_AGENT: + } + case SET_USER_AGENT: { + const {userAgent} = action; return { ...state, - userAgent: action.userAgent + userAgent }; - case PLAY: + } + case PLAY: { state.currentFile.play(); - return { ...state, isPlaying: true }; - case PAUSE: + } + case PAUSE: { state.currentFile.pause(); return { ...state, isPlaying: false }; - + } case NEXT: { const [surahId, ayahNum] = action.currentAyah.split(':'); const nextId = `${surahId}:${parseInt(ayahNum, 10) + 1}`; + const stateSegments = state.segments; + const stateSegmentsId = stateSegments[surahId]; return { ...state, segments: { - ...state.segments, + ...stateSegments, [surahId]: { - ...state.segments[surahId], + ...stateSegmentsId, [nextId]: buildSegments(state.segments[surahId][nextId]) } }, @@ -176,52 +199,57 @@ export default function reducer(state = initialState, action = {}) { currentTime: 0 }; } + case PREVIOUS: { + const [surahId, ayahNum] = action.currentAyah.split(':'); + const nextId = `${surahId}:${parseInt(ayahNum, 10) - 1}`; + return { + ...state, + currentAyah: nextId, + currentFile: state.files[surahId][nextId], + currentTime: 0 + }; + } case SET_AYAH: { const [surahId, ayahNum] = action.currentAyah.split(':'); const currentAyah = `${surahId}:${parseInt(ayahNum, 10)}`; + const stateSegments = state.segments; + const stateSegmentsId = state.segments[surahId]; + const currentFile = state.files[surahId][currentAyah]; return { ...state, segments: { - ...state.segments, + ...stateSegments, [surahId]: { - ...state.segments[surahId], + ...stateSegmentsId, [currentAyah]: buildSegments(state.segments[surahId][currentAyah]) } }, currentAyah, - currentFile: state.files[surahId][currentAyah], + currentFile, currentTime: 0 }; } - - case PREVIOUS: { - const [surahId, ayahNum] = action.currentAyah.split(':'); - const nextId = `${surahId}:${parseInt(ayahNum, 10) - 1}`; - + case SET_REPEAT: { + const {repeat} = action; return { ...state, - currentAyah: nextId, - currentFile: state.files[surahId][nextId], - currentTime: 0 + repeat }; } - case SET_REPEAT: - return { - ...state, - repeat: action.repeat - }; - case TOGGLE_SCROLL: + case TOGGLE_SCROLL: { return { ...state, shouldScroll: !state.shouldScroll }; - case SET_CURRENT_FILE: + } + case SET_CURRENT_FILE: { return { ...state, currentFile: action.file }; + } case SET_CURRENT_WORD: { if (!action.word) return state; @@ -246,6 +274,8 @@ export default function reducer(state = initialState, action = {}) { const segment = buildSegments(state.segments[surahId][nextId]); currentTime = segment.words[word].startTime; currentFile.currentTime = currentTime; + const stateSegments = state.segments; + const stateSegmentsId = state.segments[surahId]; return { ...state, @@ -255,102 +285,22 @@ export default function reducer(state = initialState, action = {}) { currentTime, currentFile, segments: { - ...state.segments, + ...stateSegments, [surahId]: { - ...state.segments[surahId], + ...stateSegmentsId, [nextId]: segment } } }; - } - case SET_CURRENT_AYAH: + case SET_CURRENT_AYAH: { return { ...state, currentAyah: action.id }; - default: + } + default: { return state; + } } } - -export function setUserAgent(userAgent) { - return { - type: SET_USER_AGENT, - userAgent - }; -} - -export function setCurrentFile(file) { - return { - type: SET_CURRENT_FILE, - file - }; -} - -export function setCurrentWord(word) { - return { - type: SET_CURRENT_WORD, - word - }; -} - -export function play() { - return { - type: PLAY - }; -} - -export function pause() { - return { - type: PAUSE - }; -} - -export function next(currentAyah) { - return { - type: NEXT, - currentAyah - }; -} - -export function setAyah(currentAyah) { - return { - type: SET_AYAH, - currentAyah - }; -} - -export function previous(currentAyah) { - return { - type: PREVIOUS, - currentAyah - }; -} - -export function setRepeat(repeat) { - return { - type: SET_REPEAT, - repeat - }; -} - -export function toggleScroll() { - return { - type: TOGGLE_SCROLL - }; -} - -export function buildOnClient(surahId) { - return { - type: BUILD_ON_CLIENT, - surahId - }; -} - -export function update(payload) { - return { - type: UPDATE, - payload - }; -} diff --git a/src/redux/modules/ayahs.js b/src/redux/modules/ayahs.js index 80fd8715c..1e9f543c0 100644 --- a/src/redux/modules/ayahs.js +++ b/src/redux/modules/ayahs.js @@ -1,14 +1,19 @@ -import { ayahsSchema } from '../schemas'; +import { + LOAD, + LOAD_SUCCESS, + LOAD_FAIL, + CLEAR_CURRENT, + SET_CURRENT_AYAH, + SET_CURRENT_WORD, + CLEAR_CURRENT_WORD + } from '../constants/ayahs.js'; -import { arrayOf } from 'normalizr'; - -export const LOAD = '@@quran/ayahs/LOAD'; -export const LOAD_SUCCESS = '@@quran/ayahs/LOAD_SUCCESS'; -export const LOAD_FAIL = '@@quran/ayahs/LOAD_FAIL'; -export const CLEAR_CURRENT = '@@quran/ayahs/CLEAR_CURRENT'; -export const SET_CURRENT_AYAH = '@@quran/ayahs/SET_CURRENT_AYAH'; -export const SET_CURRENT_WORD = '@@quran/ayahs/SET_CURRENT_WORD'; -export const CLEAR_CURRENT_WORD = '@@quran/ayahs/CLEAR_CURRENT_WORD'; +export { + LOAD, + LOAD_SUCCESS, + CLEAR_CURRENT, + SET_CURRENT_AYAH, +}; const initialState = { current: null, @@ -46,12 +51,13 @@ export default function reducer(state = initialState, action = {}) { currentWord: null }; case CLEAR_CURRENT: + const entities = state.entities; return { ...state, current: null, currentWord: null, entities: { - ...state.entities, + ...entities, [action.id]: {} } }; @@ -63,6 +69,7 @@ export default function reducer(state = initialState, action = {}) { }; case LOAD_SUCCESS: const current = state.current ? state.current : action.result.result[0]; + const stateEntities = state.entities; return { ...state, @@ -71,7 +78,7 @@ export default function reducer(state = initialState, action = {}) { loading: false, errored: false, entities: { - ...state.entities, + ...stateEntities, [action.surahId]: Object.assign( {}, state.entities[action.surahId], @@ -87,64 +94,3 @@ export default function reducer(state = initialState, action = {}) { return state; } } - -// For safe measure -const defaultOptions = { - audio: 8, - quran: 1, - content: [19] -}; - -export function load(id, from, to, options = defaultOptions) { - const { audio, quran, content } = options; - - return { - types: [LOAD, LOAD_SUCCESS, LOAD_FAIL], - schema: arrayOf(ayahsSchema), - promise: (client) => client.get(`/v2/surahs/${id}/ayahs`, { - params: { - from, - to, - audio, - quran, - content - } - }), - surahId: id - }; -} - -export function clearCurrent(id) { - return { - type: CLEAR_CURRENT, - id - }; -} - -export function clearCurrentWord() { - return { - type: CLEAR_CURRENT_WORD - }; -} - -export function setCurrentAyah(id) { - return { - type: SET_CURRENT_AYAH, - id - }; -} - -export function setCurrentWord(id) { - return { - type: SET_CURRENT_WORD, - id - }; -} - -export function isLoaded(globalState, surahId, from, to) { - return ( - globalState.ayahs.entities[surahId] && - globalState.ayahs.entities[surahId][`${surahId}:${from}`] && - globalState.ayahs.entities[surahId][`${surahId}:${to}`] - ); -} diff --git a/src/redux/modules/fontFaces.js b/src/redux/modules/fontFaces.js index 6c53fe62a..6c573f848 100644 --- a/src/redux/modules/fontFaces.js +++ b/src/redux/modules/fontFaces.js @@ -1,7 +1,6 @@ -import { LOAD_SUCCESS } from './ayahs'; -import { SEARCH_SUCCESS } from './searchResults'; - -export const LOAD = '@@quran/fontFaces/LOAD'; +import { LOAD_SUCCESS } from '../constants/ayahs.js'; +import { SEARCH_SUCCESS } from '../constants/search.js'; +import { LOAD } from '../constants/fontFace.js'; export default function reducer(state = {}, action = {}) { switch (action.type) { @@ -32,10 +31,3 @@ export default function reducer(state = {}, action = {}) { return state; } } - -export function load(className) { - return { - type: LOAD, - className - }; -} diff --git a/src/redux/modules/lines.js b/src/redux/modules/lines.js index f4820b0a7..644915648 100644 --- a/src/redux/modules/lines.js +++ b/src/redux/modules/lines.js @@ -2,13 +2,13 @@ import { LOAD as AYAHS_LOAD, LOAD_SUCCESS as AYAHS_LOAD_SUCCESS, - LOAD_FAIL as AYAHS_LOAD_FAIL -} from './ayahs'; + LOAD_FAIL as AYAHS_LOAD_FAIL, + } from '../constants/ayahs.js'; -import { SET_CURRENT as SURAHS_SET_CURRENT } from './surahs'; +import { SET_CURRENT as SURAHS_SET_CURRENT } from '../constants/surahs.js'; const initialState = { - lines: {}, + lines: {} }; export default function reducer(state = initialState, action = {}) { @@ -26,7 +26,8 @@ export default function reducer(state = initialState, action = {}) { }; case AYAHS_LOAD_SUCCESS: const ayahs = action.result.entities.ayahs; - const lines = {...state.lines}; + const stateLines = state.lines; + const lines = {...stateLines}; action.result.result.forEach(ayahId => { const ayah = ayahs[ayahId]; diff --git a/src/redux/modules/options.js b/src/redux/modules/options.js index c4673bdce..2851fa49e 100644 --- a/src/redux/modules/options.js +++ b/src/redux/modules/options.js @@ -1,7 +1,5 @@ -import cookie from 'react-cookie'; -const TOGGLE_READING_MODE = '@@quran/options/TOGGLE_READING_MODE'; -const SET_OPTION = '@@quran/options/SET_OPTION'; +import { TOGGLE_READING_MODE, SET_OPTION } from '../constants/options.js'; const initialState = { isReadingMode: false, @@ -24,32 +22,12 @@ export default function reducer(state = initialState, action = {}) { isReadingMode: !state.isReadingMode }; case SET_OPTION: + const payload = action.payload; return { ...state, - ...action.payload + ...payload }; default: return state; } } - -export function isReadingMode(globalState) { - return globalState.options.isReadingMode; -} - -export function setOption(payload) { - const options = cookie.load('options') || {}; // protect against first timers. - Object.keys(payload).forEach(option => { options[option] = payload[option]; }); - cookie.save('options', JSON.stringify(options)); - - return { - type: SET_OPTION, - payload - }; -} - -export function toggleReadingMode() { - return { - type: TOGGLE_READING_MODE - }; -} diff --git a/src/redux/modules/searchResults.js b/src/redux/modules/searchResults.js index c97969b73..67a15b041 100644 --- a/src/redux/modules/searchResults.js +++ b/src/redux/modules/searchResults.js @@ -1,9 +1,8 @@ -import { ayahsSchema } from '../schemas'; -import { arrayOf } from 'normalizr'; - -export const SEARCH = '@@quran/search/LOAD'; -export const SEARCH_SUCCESS = '@@quran/search/LOAD_SUCCESS'; -export const SEARCH_FAIL = '@@quran/search/LOAD_FAIL'; +import { + SEARCH, + SEARCH_SUCCESS, + SEARCH_FAIL + } from '../constants/search.js'; const initialState = { errored: false, @@ -46,16 +45,3 @@ export default function reducer(state = initialState, action = {}) { return state; } } - -export function search(params) { - return { - types: [SEARCH, SEARCH_SUCCESS, SEARCH_FAIL], - schema: {results: arrayOf({ayah: ayahsSchema})}, - promise: (client) => client.get('/v2/search', { params }), - params - }; -} - -export function isQueried() { - return false; -} diff --git a/src/redux/modules/surahs.js b/src/redux/modules/surahs.js index 38fc516c4..dd7ddffec 100644 --- a/src/redux/modules/surahs.js +++ b/src/redux/modules/surahs.js @@ -1,13 +1,8 @@ -import { surahsSchema } from '../schemas'; -import { arrayOf } from 'normalizr'; - -export const LOAD = '@@quran/surahs/LOAD'; -export const LOAD_SUCCESS = '@@quran/surahs/LOAD_SUCCESS'; -export const LOAD_FAIL = '@@quran/surahs/LOAD_FAIL'; -export const LOAD_INFO = '@@quran/surahs/LOAD_INFO'; -export const LOAD_INFO_SUCCESS = '@@quran/surahs/LOAD_INFO_SUCCESS'; -export const LOAD_INFO_FAIL = '@@quran/surahs/LOAD_INFO_FAIL'; -export const SET_CURRENT = '@@quran/surahs/SET_CURRENT'; +import { + LOAD_SUCCESS, + LOAD_FAIL, + SET_CURRENT + } from '../constants/surahs.js'; const initialState = { errored: false, @@ -24,14 +19,16 @@ export default function reducer(state = initialState, action = {}) { current: action.current }; case LOAD_SUCCESS: + const entities = state.entities; + const {surahs} = action.result.entities; return { ...state, loaded: true, errored: false, entities: { - ...state.entities, - ...action.result.entities.surahs - }, + ...entities, + ...surahs + } }; case LOAD_FAIL: console.log(action); @@ -40,41 +37,3 @@ export default function reducer(state = initialState, action = {}) { return state; } } - -export function loadAll() { - return { - types: [LOAD, LOAD_SUCCESS, LOAD_FAIL], - schema: arrayOf(surahsSchema), - promise: (client) => client.get('/v2/surahs') - }; -} - -export function load(id) { - return { - types: [LOAD, LOAD_SUCCESS, LOAD_FAIL], - schema: arrayOf(surahsSchema), - promise: (client) => client.get(`/v2/surahs/${id}`) - }; -} - -export function loadInfo(link) { - return { - types: [LOAD_INFO, LOAD_INFO_SUCCESS, LOAD_INFO_FAIL], - promise: (client) => client.get(`http://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&titles=${link}&redirects=true`) // eslint-disable-line max-len - }; -} - -export function setCurrent(id) { - return { - type: SET_CURRENT, - current: id - }; -} - -export function isSingleLoaded(globalState, id) { - return !!globalState.surahs.entities[id]; -} - -export function isAllLoaded(globalState) { - return Object.keys(globalState.surahs.entities).length === 114; -}