WikiEducationFoundation/WikiEduDashboard

View on GitHub
app/assets/javascripts/reducers/articles.js

Summary

Maintainability
C
7 hrs
Test Coverage
A
90%
import { uniqWith, map, isEqual } from 'lodash-es';
import { sortByKey } from '../utils/model_utils';
import {
  RECEIVE_ARTICLES,
  SORT_ARTICLES,
  SET_PROJECT_FILTER,
  SET_NEWNESS_FILTER,
  SET_TRACKED_STATUS_FILTER,
  UPDATE_ARTICLE_TRACKED_STATUS,
  SET_ARTICLES_PAGE,
  ARTICLES_PER_PAGE,
  RESET_PAGES
} from '../constants';

const initialState = {
  articles: [],
  limit: 500,
  limitReached: false,
  sort: {
    key: null,
    sortKey: null
  },
  totalPages: 1,
  currentPage: 1,
  wikis: [],
  wikiFilter: { project: 'all' },
  newnessFilter: 'both',
  trackedStatusFilter: 'tracked',
  loading: true,
  newnessFilterEnabled: false,
  trackedStatusFilterEnabled: false,
  lastRequestTimestamp: 0 // UNIX timestamp of last request - in milliseconds
};

const SORT_DESCENDING = {
  character_sum: true,
  references_count: true,
  view_count: true
};

const isLimitReached = (revs, limit) => {
  return revs.length < limit;
};

const mapWikis = (article) => {
  return {
    language: article.language,
    project: article.project
  };
};

const getTrackedStatusFilterEnabledStatus = _articles =>
  _articles.some(a => a.tracked) && _articles.some(a => !a.tracked);

const getDefaultTrackedStatusFilter = _articles =>
  ((_articles[0] && _articles[0].tracked) ? 'tracked' : 'both');

export default function articles(state = initialState, action) {
  switch (action.type) {
    case RECEIVE_ARTICLES: {
      const wikis = uniqWith(
        map(action.data.course.articles, mapWikis),
        isEqual
      );
      const _articles = action.data.course.articles;
      const newnessFilterEnabled = _articles.some(a => a.new_article) && _articles.some(a => !a.new_article);
      const trackedStatusFilterEnabled = getTrackedStatusFilterEnabledStatus(_articles);
      let trackedStatusFilter = state.trackedStatusFilter;
      if (!trackedStatusFilterEnabled) {
        trackedStatusFilter = getDefaultTrackedStatusFilter(_articles);
      }
      return {
        ...state,
        articles: _articles,
        limit: action.limit,
        limitReached: isLimitReached(action.data.course.articles, action.limit),
        wikis,
        wikiFilter: state.wikiFilter,
        newnessFilter: state.newnessFilter,
        trackedStatusFilter,
        newnessFilterEnabled,
        trackedStatusFilterEnabled,
        loading: false,
        lastRequestTimestamp: Date.now(),
        totalPages: Math.ceil(action.data.course.articles.length / ARTICLES_PER_PAGE)
      };
    }

    case SORT_ARTICLES: {
      const sorted = sortByKey(
        state.articles,
        action.key,
        state.sort.sortKey,
        SORT_DESCENDING[action.key],
        undefined,
        action.refresh
      );
      return {
        ...state,
        articles: sorted.newModels,
        sort: {
          sortKey: sorted.newKey,
          key: action.key
        },
        wikiFilter: state.wikiFilter,
        wikis: state.wikis
      };
    }

    case SET_PROJECT_FILTER: {
      if (action.wiki.project === 'all') {
        return { ...state, wikiFilter: { project: 'all' } };
      }
      return { ...state, wikiFilter: action.wiki };
    }

    case SET_NEWNESS_FILTER: {
      return { ...state, newnessFilter: action.newness };
    }

    case SET_TRACKED_STATUS_FILTER: {
      return { ...state, trackedStatusFilter: action.trackedStatus };
    }

    case UPDATE_ARTICLE_TRACKED_STATUS: {
      // Make sure the article's tracked status is reflected in the redux state
      const updatedArticles = state.articles.map((a) => {
        if (a.id === action.articleId) {
          a.tracked = action.tracked;
        }
        return a;
      });
      let { trackedStatusFilter } = state;
      const trackedStatusFilterEnabled = getTrackedStatusFilterEnabledStatus(updatedArticles);
      if (!trackedStatusFilterEnabled) {
        trackedStatusFilter = getDefaultTrackedStatusFilter(updatedArticles);
      } else if (trackedStatusFilter === 'tracked') {
        trackedStatusFilter = 'both';
      }
      return { ...state, trackedStatusFilterEnabled, trackedStatusFilter, articles: updatedArticles };
    }

    case SET_ARTICLES_PAGE: {
      return { ...state, currentPage: action.page };
    }
    case RESET_PAGES: {
      return { ...state, currentPage: 1, totalPages: action.totalPages };
    }

    default:
      return state;
  }
}