shierro/territory-manager

View on GitHub
app/containers/MapPage/reducer.js

Summary

Maintainability
A
1 hr
Test Coverage
import { fromJS, List, Map } from 'immutable';
import {
  SET_INITIAL_LOCATION,
  SET_PAGE_ERROR,
  GET_INITIAL_LOCATION,
  SET_LOADING,
  ADD_PERSON_START,
  SAVE_PERSON_DATA,
  PERSON_FORM_CHANGE,
  UPDATE_NEW_MARKER_LOCATION,
  SET_STEP,
  CANCEL_ADD,
  PERSON_UPDATE,
  PERSON_CLICK,
  SAVE_VISIT,
  TOGGLE_ADDING_VISIT,
  POPUP_CLOSE,
} from './constants';

const personSchema = {
  firstName: '',
  lastName: '',
  notes: '',
  address: '',
  ageRange: {
    min: 1,
    max: 119,
  },
  visits: List([]),
};

export const initialState = fromJS({
  initialLocation: List([0, 0]),
  initialLocationLoaded: false,
  defaultAgeRange: { min: 1, max: 120 },
  loading: false,
  addingPerson: false,
  zoom: 16,
  error: Map(),
  people: Map(),
  steps: List(['Info', 'Address & Notes', 'Map Location']),
  activeStep: 0,
  completed: Map(),
  newPerson: Map(personSchema),
  personCurrentlyEditing: 0,
  personLabels: {
    firstName: 'First Name',
    lastName: 'Last Name',
    notes: 'Notes',
    address: 'Address',
    ageRange: 'Age Range',
    visits: 'Visits',
  },
  addingVisit: false,
});

function setInitialLocation(state, action) {
  return state
    .set('initialLocation', List(action.coords))
    .set('initialLocationLoaded', true)
    .set('loading', false);
}

function addPersonStart(state) {
  return state
    .set('addingPerson', true)
    .updateIn(['newPerson', 'location'], () =>
      state.get('initialLocation').toJS(),
    );
}

function savePersonData(state) {
  let newPerson = state.get('newPerson');
  const date = new Date();
  const newVisit = { found: true, note: newPerson.get('notes'), date };
  newPerson = newPerson.updateIn(['visits'], visit => visit.push(newVisit));
  return state
    .updateIn([`people`, state.get('people').size + 1], () => newPerson)
    .set('addingPerson', false)
    .set('activeStep', 0)
    .set('newPerson', Map(personSchema))
    .set('completed', Map());
}

function setStep(state, action) {
  const activeStep = state.get('activeStep');
  const steps = state.get('steps').toJS();
  let latestState = state;
  let completed = state.get('completed');
  // go next
  if (activeStep < action.step) {
    completed = completed.set(activeStep, true);
    latestState = latestState.set('completed', completed);
  }
  // go back
  if (activeStep > action.step) {
    completed = completed.set(activeStep, false);
    latestState = latestState.set('completed', completed);
  }
  steps.forEach((step, index) => {
    if (index >= action.step) {
      completed = completed.set(index, false);
    }
  });
  return latestState.set('activeStep', action.step).set('completed', completed);
}

function cancelAdd(state) {
  return state
    .set('activeStep', 0)
    .set('completed', Map())
    .set('addingPerson', false);
}

function updateNewMarkerLocation(state, action) {
  const { lat, lng } = action.data.target._latlng; // eslint-disable-line
  return state.updateIn(['newPerson', 'location'], () => [lat, lng]);
}

function personUpdate(state, action) {
  return state.updateIn(
    ['people', state.get('personCurrentlyEditing'), action.key],
    () => action.value,
  );
}

function toggleAddingVisit(state) {
  return state.set('addingVisit', !state.get('addingVisit'));
}

function addPersonVisit(state, action) {
  const date = new Date();
  return toggleAddingVisit(state).updateIn(
    ['people', state.get('personCurrentlyEditing'), 'visits'],
    visits => visits.push({ ...action.visitData, date }),
  );
}

function mapPageReducer(state = initialState, action) {
  switch (action.type) {
    case GET_INITIAL_LOCATION:
      return state.set('loading', true);
    case SET_INITIAL_LOCATION:
      return setInitialLocation(state, action);
    case SET_PAGE_ERROR:
      return state.set('error', Map(action.error));
    case SET_LOADING:
      return state.set('loading', action.value);
    case ADD_PERSON_START:
      return addPersonStart(state);
    case SAVE_PERSON_DATA:
      return savePersonData(state);
    case PERSON_FORM_CHANGE:
      return state.updateIn(['newPerson', action.key], () => action.value);
    case PERSON_UPDATE:
      return personUpdate(state, action);
    case UPDATE_NEW_MARKER_LOCATION:
      return updateNewMarkerLocation(state, action);
    case SET_STEP:
      return setStep(state, action);
    case CANCEL_ADD:
      return cancelAdd(state);
    case PERSON_CLICK:
      return state.set('personCurrentlyEditing', parseInt(action.index, 10));
    case SAVE_VISIT:
      return addPersonVisit(state, action);
    case TOGGLE_ADDING_VISIT:
      return toggleAddingVisit(state);
    case POPUP_CLOSE:
      return state.set('addingVisit', false);
    default:
      return state;
  }
}

export default mapPageReducer;