Leverage localStorage to cache REDUX store data for slow API calls
const LIST_REQUEST_SENT = 'LIST_REQUEST_SENT'
const LIST_REQUEST_SUCCESS = 'LIST_REQUEST_SUCCESS'
const UPDATE_LIST = 'UPDATE_LIST'
const LIST_ADD_ITEM = 'LIST_ADD_ITEM'
const LOCAL_STORAGE_EXPIRATION_PERIOD = 604800000 // 7 days
const listRequestSent = () => ({
  type: LIST_REQUEST_SENT,
})
const listRequestSuccess = () => ({
  type: LIST_REQUEST_SUCCESS,
})
const updateList = list => ({
  type: UPDATE_LIST,
  list,
})
const listAddItem = (item) => ({
  type: LIST_ADD_ITEM,
  item,
})
/**
 * Handle fetching and storing of list items
 * 
 */
export const handleGetList = () => (
  (dispatch, getState) => {
    const { items } = getState().list
    // only if list is empty do we want to set the loading state
    if (items.length === 0) {
      dispatch(listRequestSent())
    }
    // api call to fetch list items
    apiGetList()
      .then((res) => {
        const items = res.data.result
        // update the localStorage list items
        setListLocalStorage(items)
        // update the list items in the store
        dispatch(updateList(items))
        dispatch(listRequestSuccess())
      })
  }
)
/**
 * Create new biller
 * 
 * @param {object} item 
 */
export const handleAddItem = (item) => (
  (dispatch, getState) => {
    dispatch(listRequestSent())
    
    apiCreateListItem()
      .then((res) => {
        const item = res.data.result
        // update the localStorage billers list
        const { items } = getState().list
        const itemsClone = items.slice()
        itemsClone.push(item)
        setListLocalStorage(itemsClone)
        // update the store
        dispatch(listAddItem(item))
        dispatch(ListRequestSuccess())
      })
  }
)
/**
 * Add the list to localStorage
 * 
 * @param {array} items 
 */
const setListLocalStorage = (items) => {
  const now = new Date().getTime()
  const listObject = { items }
  // set the expiration time for the localStorage item
  listObject.expiration = now + LOCAL_STORAGE_EXPIRATION_PERIOD
  // store the object in localStorage
  localStorage.setItem('list', JSON.stringify(list))
}
/**
 * Fetch the billers array from localStorage
 */
const getListLocalStorage = () => {
  // fetch the item from localStorage
  const listObject = JSON.parse(localStorage.getItem('list'))
  // get the current time
  const now = new Date().getTime()
  // check if localStorage item exists and it has not expired
  if (listObject && listObject.expiration > now) {
    return listObject.items
  }
  return []
}
/**
 * Set the initial state
 */
const initialState = {
  isRequesting: false,
  list: getListLocalStorage(),
}
export default function list(state = initialState, action) {
  switch (action.type) {
    case LIST_REQUEST_SENT:
      return {
        ...state,
        isRequesting: true,
      }
    case LIST_REQUEST_SUCCESS:
      return {
        ...state,
        isRequesting: false,
      }
    case UPDATE_LIST:
      return {
        ...state,
        items: action.list,
      }
    case LIST_ADD_ITEM:
      const items = state.items.slice()
      items.push(action.item)
      return {
        ...state,
        items,
      }
    default: {
      return state
    }
  }
}const LIST_REQUEST_SENT = 'LIST_REQUEST_SENT'
const LIST_REQUEST_SUCCESS = 'LIST_REQUEST_SUCCESS'
const UPDATE_LIST = 'UPDATE_LIST'
const LIST_ADD_ITEM = 'LIST_ADD_ITEM'
const listRequestSent = () => ({
  type: LIST_REQUEST_SENT,
})
const listRequestSuccess = () => ({
  type: LIST_REQUEST_SUCCESS,
})
const updateList = list => ({
  type: UPDATE_LIST,
  list,
})
const listAddItem = (item) => ({
  type: LIST_ADD_ITEM,
  item,
})
/**
 * Handle fetching and storing of list items
 * 
 */
export const handleGetList = () => (
  (dispatch, getState) => {    
    dispatch(listRequestSent())
    // api call to fetch list items
    apiGetList()
      .then((res) => {
        const items = res.data.result
        // update the list items in the store
        dispatch(updateList(items))
        dispatch(listRequestSuccess())
      })
  }
)
/**
 * Create new biller
 * 
 * @param {object} item 
 */
export const handleAddItem = (item) => (
  (dispatch, getState) => {
    dispatch(listRequestSent())
    
    apiAddListItem()
      .then((res) => {
        const item = res.data.result
        // update the store
        dispatch(listAddItem(item))
        dispatch(ListRequestSuccess())
      })
  }
)
/**
 * Set the initial state
 */
const initialState = {
  isRequesting: false,
  list: [],
}
export default function list(state = initialState, action) {
  switch (action.type) {
    case LIST_REQUEST_SENT:
      return {
        ...state,
        isRequesting: true,
      }
    case LIST_REQUEST_SUCCESS:
      return {
        ...state,
        isRequesting: false,
      }
    case UPDATE_LIST:
      return {
        ...state,
        items: action.list,
      }
    case LIST_ADD_ITEM:
      const items = state.items.slice()
      items.push(action.item)
      return {
        ...state,
        items,
      }
    default: {
      return state
    }
  }
}