Home Reference Source

src/store/lib/mixins.js

import _ from 'lodash'

// // // //
// Adds a Collection to a Vuex module

export const COLLECTION_GETTERS = {
  collection: state => {
    return state.collection
  },
  fetching: state => {
    return state.fetching
  }
}

export const COLLECTION_MUTATIONS = {
  collection (state, collection) {
    state.collection = collection
  },
  fetching (state, isFetching) {
    state.fetching = isFetching
  }
}

export const COLLECTION_STATE = {
  collection: [],
  fetching: false
}

// // // //
// Adds a Model definition to a Vuex module
export const MODEL_GETTERS = {
  model: state => {
    return state.model
  }
}

export const MODEL_MUTATIONS = {
  model (state, model) {
    state.model = model
  }
}

export const MODEL_STATE = {
  model: {}
}

// // // //
// Adds Collection filtering to a Vuex module
// TODO - abstract `showingInactive` into a separate mixin

export const FILTER_GETTERS = {
  filteredCollection: state => {
    return state.filteredCollection
  },
  filter: state => {
    return state.filter
  },
  showingInactive: state => {
    return state.showingInactive
  },
  orderBy: state => {
    return state.orderBy
  }
}

export const FILTER_MUTATIONS = {
  filteredCollection (state, filteredCollection) {
    state.filteredCollection = filteredCollection
  },
  filter (state, filter) {
    state.filter = filter
  },
  showingInactive (state, show) {
    state.showingInactive = show
  },
  orderBy (state, orderBy) {
    state.orderBy = orderBy
  }
}

export const FILTER_STATE = {
  filteredCollection: [],
  filter: '',
  showingInactive: false,
  orderBy: 'asc' // 'asc' or 'desc'
}

export const FILTER_ACTIONS = {
  // module/toggleOrderBy
  toggleOrderBy ({ state, commit, dispatch }) {
    const ORDER_ASC = 'asc'
    const ORDER_DESC = 'desc'
    if (state.orderBy === ORDER_ASC) {
      commit('orderBy', ORDER_DESC)
    } else {
      commit('orderBy', ORDER_ASC)
    }
    dispatch('filteredCollection')
  },

  // module/toggleInactive
  toggleInactive ({ state, commit, dispatch }) {
    if (state.showingInactive) {
      commit('showingInactive', false)
    } else {
      commit('showingInactive', true)
    }
    // Re-fetches the collection
    dispatch('fetchCollection')
  },

  // module/setFilter
  // Updates the current search query, invokes the module/filter mutation
  setFilter ({ commit, dispatch }, filter) {
    commit('filter', filter)
    dispatch('filteredCollection')
  }
}

// // // //
// Pagination Mixins

export const PAGINATION_STATE = {
  start: 0,
  pageSize: 3,
  currentPage: 1,
  paginatedCollection: []
}

export const PAGINATION_ACTIONS = {
  paginatedCollection ({ state, commit }) {
    let collection = state.filteredCollection || state.collection

    function paginate () {
      return _.chain(collection)
      .drop(state.start)
      .take(state.pageSize)
      .value()
    }

    let paginatedCollection = paginate()

    if (paginatedCollection.length === 0 && state.currentPage > 1) {
      commit('currentPage', 1)
      commit('paginatedCollection', paginate())
    } else {
      commit('paginatedCollection', paginatedCollection)
    }
  },
  pageSize ({ dispatch, commit }, newSize) {
    commit('pageSize', newSize)
    dispatch('paginatedCollection')
  },
  goToPage ({ dispatch, commit }, page) {
    commit('currentPage', page)
    dispatch('paginatedCollection')
  },
  prevPage ({ dispatch, state, commit }) {
    commit('currentPage', state.currentPage - 1)
    dispatch('paginatedCollection')
  },
  nextPage ({ dispatch, state, commit }) {
    commit('currentPage', state.currentPage + 1)
    dispatch('paginatedCollection')
  },
  firstPage ({ dispatch, commit }) {
    commit('currentPage', 1)
    dispatch('paginatedCollection')
  },
  lastPage ({ dispatch, state, commit }) {
    let collection = state.filteredCollection || state.collection
    commit('currentPage', Math.ceil(collection.length / state.pageSize))
    dispatch('paginatedCollection')
  }
}

export const PAGINATION_MUTATIONS = {
  currentPage (state, page) {
    state.currentPage = page
    state.start = (page - 1) * state.pageSize
  },
  pageSize (state, newSize) {
    state.pageSize = newSize
    state.start = (state.currentPage - 1) * state.pageSize
  },
  start (state, start) {
    state.start = start
  },
  paginatedCollection (state, paginatedCollection) {
    state.paginatedCollection = paginatedCollection
  }
}

export const PAGINATION_GETTERS = {
  pages: state => {
    let collection = state.filteredCollection || state.collection
    let total = Math.ceil(collection.length / state.pageSize)
    let current = Math.ceil(state.start / state.pageSize) + 1
    let pages = _.times(total, index => {
      return {
        current: index + 1 === current,
        page: index + 1
      }
    })

    return pages
  },
  currentPage: state => {
    return state.currentPage
  },
  totalPages: state => {
    let collection = state.filteredCollection || state.collection
    return Math.ceil(collection.length / state.pageSize)
  },
  prevPage: state => {
    return state.currentPage - 1 > 0 ? state.currentPage - 1 : false
  },
  nextPage: state => {
    let collection = state.filteredCollection || state.collection
    let total = Math.ceil(collection.length / state.pageSize)
    return state.currentPage < total ? state.currentPage + 1 : false
  },
  paginatedCollection: state => {
    return state.paginatedCollection
  }
}