client/src/modules/index/redux.js
import _ from 'lodash';
import { combineReducers } from 'redux';
import reduceReducers from 'reduce-reducers';
import {
combineActions,
createAction,
handleAction,
handleActions
} from 'redux-actions';
import { EventsAPI, ServiceInfoAPI } from 'apis';
import store from 'store';
import moment from 'moment';
import dotProp from 'dot-prop-immutable';
//===========
// Constants
//===========
export const PREFIX = 'index';
//=================
// Action Creators
//=================
export const receiveRetrieveEvents = createAction(
`${PREFIX}/RECEIVE_RETRIEVE_EVENTS`
);
export const requestRetrieveEvents = createAction(
`${PREFIX}/REQUEST_RETRIEVE_EVENTS`,
payload => {
EventsAPI.retrieve(payload).then(({ data }) =>
store.dispatch(receiveRetrieveEvents(data))
);
return payload;
}
);
export const receiveModifyIdEvents = createAction(
`${PREFIX}/RECEIVE_MODIFY_ID_EVENTS`
);
export const requestModifyIdEvents = createAction(
`${PREFIX}/REQUEST_MODIFY_ID_EVENTS`,
payload => {
EventsAPI.modify(payload).then(({ data }) => {
store.dispatch(receiveModifyIdEvents(data));
});
return payload;
}
);
export const receiveModifyServiceInfo = createAction(
`${PREFIX}/RECEIVE_MODIFY_SERVICE_INFO`
);
export const requestModifyServiceInfo = createAction(
`${PREFIX}/REQUEST_MODIFY_SERVICE_INFO`,
payload => {
let { id, ...body } = payload;
if (id) {
ServiceInfoAPI.modify({ id, ...body }).then(() =>
store.dispatch(
receiveModifyServiceInfo({ id, serviceInfo: { id, ...body } })
)
);
} else {
ServiceInfoAPI.create(body).then(({ data }) => {
const id = data.id;
store.dispatch(
receiveModifyServiceInfo({ id, serviceInfo: { id, ...body } })
);
});
}
return payload;
}
);
export const setEvent = createAction(`${PREFIX}/SET_EVENT`);
export const setSelectedData = createAction(`${PREFIX}/SET_SELECTED_DATA`);
export const setServiceInfo = createAction(`${PREFIX}/SET_SERVICE_INFO`);
export const toggleEditRole = createAction(`${PREFIX}/TOGGLE_EDIT_ROLE`);
export const toggleEditDay = createAction(`${PREFIX}/TOGGLE_EDIT_DAY`);
//=================
// Default State
//=================
export const defaultState = {
data: [],
meta: {
isEditingDay: false,
isEditingRole: false,
isLoading: false,
isSaving: false,
query: {},
selectedData: null
}
};
//=========
// Reducer
//=========
export const dataReducer = handleActions(
{
[receiveRetrieveEvents]: (state, { payload }) => payload,
[receiveModifyIdEvents]: (state, { payload }) => {
const { date, role, name, serviceInfo } = payload;
let dayIndex = _.findIndex(state, {
date: moment(date).format('YYYY-MM-DD')
});
if (dayIndex === -1) {
state = dotProp.set(state, state.length, {
date,
serviceInfo,
members: [{ name, role }]
});
return state;
}
const roleIndex = _.findIndex(state[dayIndex].members, {
role: payload.role
});
if (roleIndex === -1) {
const total = state[dayIndex].members.length;
return dotProp.set(state, `${dayIndex}.members.${total}`, {
name,
role
});
}
return dotProp.set(
state,
`${dayIndex}.members.${roleIndex}.name`,
payload.name
);
},
[receiveModifyServiceInfo]: (state, { payload }) => {
const { serviceInfo, serviceInfo: { date } } = payload;
const dayIndex = _.findIndex(state, day => {
const id = _.get(day, 'serviceInfo.id', null);
return id === payload.id;
});
if (dayIndex === -1) {
return dotProp.set(state, state.length, {
date,
serviceInfo,
members: []
});
}
return dotProp.set(state, `${dayIndex}.serviceInfo`, payload.serviceInfo);
},
[setEvent]: (state, { payload }) => {
const { date, role, name, serviceInfo } = payload;
const dayIndex = _.findIndex(state, { date: payload.date });
if (dayIndex === -1) {
return dotProp.set(state, state.length, {
date,
serviceInfo,
members: [{ name, role }]
});
}
const roleIndex = _.findIndex(state[dayIndex].members, {
role: payload.role
});
if (roleIndex === -1) {
const total = state[dayIndex].members.length;
return dotProp.set(state, `${dayIndex}.members.${total}`, {
name,
role
});
}
return dotProp.set(
state,
`${dayIndex}.members.${roleIndex}.name`,
payload.name
);
},
[setServiceInfo]: (state, { payload }) => {
const id = _.get(payload, 'id');
const dayIndex = _.findIndex(state, day => {
return id === _.get(day, 'serviceInfo.id');
});
if (dayIndex === -1) {
return dotProp.set(state, state.length, {
date: payload.date,
id: payload.id,
serviceInfo: payload,
members: []
});
}
return dotProp.set(state, `${dayIndex}.serviceInfo`, payload);
}
},
defaultState.data
);
export const selectedDataReducer = reduceReducers(
handleAction(
setSelectedData,
(state, { payload }) => payload,
defaultState.meta.selectedData
),
handleAction(
receiveModifyIdEvents,
() => null,
defaultState.meta.selectedData
),
handleAction(
combineActions(toggleEditDay, toggleEditRole),
{
next(state, { payload }) {
const isClosing =
payload === false || (state && _.isUndefined(payload));
return isClosing ? null : state;
}
},
defaultState.meta.selectedData
)
);
export const queryReducer = handleAction(
requestRetrieveEvents,
(state, { payload }) => payload,
defaultState.meta.query
);
// Avoid duplications for isEditingDayReducer and isEditingRoleReducer
const createIsEditingReducer = (
toggleEditAction,
receiveModifyAction,
defaultValue
) => {
return handleActions(
{
[toggleEditAction]: (state, { payload }) =>
_.isBoolean(payload) ? payload : !state,
[receiveModifyAction]: () => false
},
defaultValue
);
};
export const isEditingDayReducer = createIsEditingReducer(
toggleEditDay,
receiveModifyServiceInfo,
defaultState.meta.isEditingDay
);
export const isEditingRoleReducer = createIsEditingReducer(
toggleEditRole,
receiveModifyIdEvents,
defaultState.meta.isEditingRole
);
export const isLoadingReducer = handleActions(
{
[requestRetrieveEvents]: () => true,
[receiveRetrieveEvents]: () => false
},
defaultState.meta.isLoading
);
export const isSavingReducer = handleActions(
{
[requestModifyIdEvents]: () => true,
[receiveModifyIdEvents]: () => false,
[requestModifyServiceInfo]: () => true,
[receiveModifyServiceInfo]: () => false
},
defaultState.meta.isSaving
);
export default combineReducers({
data: dataReducer,
meta: combineReducers({
query: queryReducer,
isEditingDay: isEditingDayReducer,
isEditingRole: isEditingRoleReducer,
isLoading: isLoadingReducer,
isSaving: isSavingReducer,
selectedData: selectedDataReducer
})
});