All files / store reducers.js

92.5% Statements 37/40
78.57% Branches 22/28
100% Functions 5/5
92.5% Lines 37/40
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                                          16x     8x             4x 26x   8x         8x 8x   8x   2x 2x         2x     2x   16x 8x   16x       4x               4x       26x       18x   18x 18x 18x 18x 18x 18x         8x                     4x 4x 4x 26x 26x   26x 26x 26x 26x     26x     26x                    
/**
* Copyright 2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
 
import actions from './actions'
 
// reducer utilities
import handleActions from './reducers/handleActions'; // similar to handleActions from redux-actions
import combineReducers from './reducers/combineReducers';
 
// import reducers
import calculateSequencesState from './reducers/calculateSequencesState';
 
// other utilities
import {ColorScheme, isColorScheme} from '../utils/ColorScheme';
 
function checkColorScheme(state) {
  if (isColorScheme(state.colorScheme)) {
      // it's already a color scheme
    } else {
      state.colorScheme = new ColorScheme(state.colorScheme);
  }
}
 
/**
 * Makes sure that a colorScheme is only recreated if it changed.
 */
const props = (state = {}, {type, payload}) => {
  switch(type){
    case actions.updateProps.key:
      state = {
        ...state,
        ...payload,
      };
      // has the colorScheme been updated?
      Eif ("colorScheme" in payload) {
        checkColorScheme(state);
      }
      return state;
    case actions.updateProp.key:
      const {key, value} = payload;
      state = {
        ...state,
        [key]: value
      };
      // has the colorScheme been updated?
      Iif (key === "colorScheme") {
        checkColorScheme(state);
      }
      return state;
    default:
      if (state.colorScheme !== undefined) {
        checkColorScheme(state);
      }
      return state;
  }
}
 
const sequences = handleActions({
  [actions.updateSequences]: calculateSequencesState,
}, []);
 
/**
 * Aggregates the state with stats if the state changed.
 */
// TODO: maybe use reselect for this?
const sequenceStats = (prevState = {
  currentViewSequence: 0,
  currentViewSequencePosition: 0,
}, action, state) => {
  switch(action.type){
    case actions.updateProp.key:
    case actions.updateProps.key:
    case actions.updateSequences.key:
      Eif (state.props && state.props.tileHeight && state.props.tileWidth &&
          state.sequences) {
        const stats = {};
        stats.nrXTiles = Math.ceil(state.props.width / state.props.tileWidth) + 1;
        stats.nrYTiles = Math.ceil(state.props.height / state.props.tileHeight) + 1;
        stats.fullWidth = state.props.tileWidth * state.sequences.maxLength;
        stats.fullHeight = state.props.tileHeight * state.sequences.length;
        return stats;
      }
      break;
    default:
  }
  return prevState;
};
 
/**
 * Takes an reducer and an object of `statReducers`.
 * The `statReducers` have the following differences to normal reducers:
 *  - they are only called when the state has changed
 *  - they receive the full state as third parameter
 *
 *  These stat reducers are meant to efficiently compute derived statistics.
 */
const statCombineReduce = (reducer, statReducers) => {
  const keys = Object.keys(statReducers);
  return function(prevState = {}, action){
    const state = reducer(prevState, action);
    Eif (prevState !== state) {
      // state object already changed, no need to copy it again
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        const nextStateForKey = statReducers[key](state[key], action, state);
        Iif (typeof nextStateForKey === 'undefined') {
          throw new Error("A reducer can't return 'undefined'");
        }
        state[key] = nextStateForKey;
      }
    }
    return state;
  }
};
 
export default statCombineReduce(combineReducers({
  props,
  sequences,
}), {
  sequenceStats,
});