saarnilauri/fida-imu

View on GitHub
src/reducers/curriedFirebase.js

Summary

Maintainability
B
4 hrs
Test Coverage
import forEach from 'lodash/forEach'
import { sendNotification } from './notifications'
import { getWordForms } from '../constants/utils'

export function getInitialState(entity) {
  const wordForms = getWordForms(entity)
  const INITIAL_STATE = { collectionReady: false }
  INITIAL_STATE[entity] = null
  INITIAL_STATE[`${wordForms.prular}Collection`] = []
  return INITIAL_STATE
}

export const getAddEntityActionCreator = entity => payload => {
  const wordForms = getWordForms(entity)
  return {
    type: `ADD_${wordForms.allCaps}`,
    payload,
  }
}

export const getAddEntitiesActionCreator = entity => payload => {
  const wordForms = getWordForms(entity)
  return {
    type: `ADD_${wordForms.allCapsPrular}`,
    payload,
  }
}

export const getEntityCollectionNotReadyActionCreator = entity => () => {
  const wordForms = getWordForms(entity)
  return {
    type: `${wordForms.allCapsPrular}_COLLECTION_NOT_READY`,
  }
}

export const getEntityCollectionIsReadyActionCreator = entity => () => {
  const wordForms = getWordForms(entity)
  return {
    type: `${wordForms.allCapsPrular}_COLLECTION_IS_READY`,
  }
}

export const getLoadOneEntityActionCreator = entity => (
  uid,
  message,
  addToStore = true,
) => (dispatch, getState, getFirebase) => {
  const wordForms = getWordForms(entity)
  const firebase = getFirebase()
  const prom = new Promise((resolve, reject) => {
    firebase
      .ref(`${wordForms.prular}/${uid}`)
      .once('value')
      .then(snap => {
        if (addToStore) {
          dispatch(getAddEntityActionCreator(entity)(snap.val()))
        }
        dispatch(sendNotification(message))
        resolve({ ...snap.val(), uid: snap.key })
      })
      .catch(error => reject(error))
  })
  return prom
}

export const getLoadEntityCollectionActionCreator = entity => (
  message = `${entity} loaded...`,
) => (dispatch, getState, getFirebase) => {
  const wordForms = getWordForms(entity)
  const notReady = getEntityCollectionNotReadyActionCreator(entity)
  dispatch(notReady())
  const firebase = getFirebase()
  firebase
    .ref(wordForms.prular)
    .once('value')
    .then(snap => {
      const addEntities = getAddEntitiesActionCreator(entity)
      const isReady = getEntityCollectionIsReadyActionCreator(entity)
      dispatch(addEntities(snap.val()))
      dispatch(isReady())
      dispatch(sendNotification(message))
    })
}

export const getAddEntityToFirebaseActionCreator = entity => (
  newEntity,
  message,
) => (dispatch, getState, getFirebase) => {
  const wordForms = getWordForms(entity)
  const firebase = getFirebase()
  firebase.push(wordForms.prular, newEntity).then(snap => {
    dispatch(getAddEntityActionCreator(entity)({ ...newEntity, uid: snap.key }))
    dispatch(getLoadEntityCollectionActionCreator(entity)(message))
  })
}

export const getUpdateEntityToFirebaseActionCreator = entity => (
  uid,
  updatedEntity,
  message,
) => (dispatch, getState, getFirebase) => {
  const wordForms = getWordForms(entity)
  const firebase = getFirebase()
  firebase.set(`${wordForms.prular}/${uid}`, updatedEntity).then(() => {
    if (entity === 'user') {
      firebase.set(`userProfiles/${uid}`, updatedEntity).then(() => {})
    }
    dispatch(getLoadEntityCollectionActionCreator(entity)(message))
  })
}

export const getRemoveEntityFromFirebaseActionCreator = entity => (
  uid,
  message,
) => (dispatch, getState, getFirebase) => {
  const wordForms = getWordForms(entity)
  const firebase = getFirebase()
  firebase
    .ref(wordForms.prular)
    .child(uid)
    .remove()
    .then(() => {
      dispatch(getLoadEntityCollectionActionCreator(entity)(message))
    })
}

export const getApplyEntityToState = entity => (state, action) => {
  const newState = {
    ...state,
  }
  newState[entity] = action.payload
  return newState
}

export const getApplyEntityCollectionToState = entity => (state, action) => {
  const wordForms = getWordForms(entity)
  const newState = {
    ...state,
  }
  newState[`${wordForms.prular}Collection`] = action.payload
  return newState
}

export const applyReady = (state, action) => ({
  ...state,
  collectionReady: action.payload,
})

export const getMapDispatchToProps = (entity, sources = {}) => dispatch => {
  const addEntity = getAddEntityToFirebaseActionCreator(entity)
  const loadEntity = getLoadOneEntityActionCreator(entity)
  const loadEntities = getLoadEntityCollectionActionCreator(entity)
  const removeEntity = getRemoveEntityFromFirebaseActionCreator(entity)
  const updateEntity = getUpdateEntityToFirebaseActionCreator(entity)
  const wordForms = getWordForms(entity)

  const map = {}
  map[`add${wordForms.capitalized}`] = item =>
    dispatch(addEntity(item, `${wordForms.capitalizedPrular} added...`))
  // eslint-disable-next-line max-len
  map[`update${wordForms.capitalized}`] = (uid, item) =>
    dispatch(updateEntity(uid, item, `${wordForms.capitalized} updated...`))
  map[`remove${wordForms.capitalized}`] = uid =>
    dispatch(removeEntity(uid, `${wordForms.capitalized} removed...`))
  map[`load${wordForms.capitalizedPrular}`] = () =>
    dispatch(loadEntities(`${wordForms.capitalizedPrular} loaded...`))
  // eslint-disable-next-line max-len
  map[`load${wordForms.capitalized}`] = (uid, addToStore) =>
    dispatch(loadEntity(uid, `${wordForms.capitalized} loaded...`, addToStore))
  forEach(sources, source => {
    const sourceWordForms = getWordForms(source)
    const loadSource = getLoadEntityCollectionActionCreator(source)
    // eslint-disable-next-line max-len
    map[`load${sourceWordForms.capitalizedPrular}`] = () =>
      dispatch(loadSource(`${sourceWordForms.capitalizedPrular} loaded...`))
  })
  return map
}

const getEntityReducer = entity => (
  state = getInitialState(entity),
  action,
) => {
  const wordForms = getWordForms(entity)
  switch (action.type) {
    case `ADD_${wordForms.allCaps}`: {
      return getApplyEntityToState(entity)(state, action)
    }
    case `ADD_${wordForms.allCapsPrular}`: {
      return getApplyEntityCollectionToState(entity)(state, action)
    }
    case `${wordForms.allCapsPrular}_COLLECTION_NOT_READY`: {
      return applyReady(state, { payload: false })
    }
    case `${wordForms.allCapsPrular}_COLLECTION_IS_READY`: {
      return applyReady(state, { payload: true })
    }
    default:
      return state
  }
}

export default getEntityReducer