171 lines
4.8 KiB
JavaScript
171 lines
4.8 KiB
JavaScript
import _ from 'lodash';
|
|
import { handleActions } from 'redux-actions';
|
|
import getSectionState from 'Utilities/State/getSectionState';
|
|
import updateSectionState from 'Utilities/State/updateSectionState';
|
|
import {
|
|
SET,
|
|
UPDATE,
|
|
UPDATE_ITEM,
|
|
UPDATE_SERVER_SIDE_COLLECTION,
|
|
CLEAR_PENDING_CHANGES,
|
|
REMOVE_ITEM
|
|
} from 'Store/Actions/baseActions';
|
|
|
|
const omittedProperties = [
|
|
'section',
|
|
'id'
|
|
];
|
|
|
|
function createItemMap(data) {
|
|
return data.reduce((acc, d, index) => {
|
|
acc[d.id] = index;
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
export default function createHandleActions(handlers, defaultState, section) {
|
|
return handleActions({
|
|
|
|
[SET]: function(state, { payload }) {
|
|
const payloadSection = payload.section;
|
|
const [baseSection] = payloadSection.split('.');
|
|
|
|
if (section === baseSection) {
|
|
const newState = Object.assign(getSectionState(state, payloadSection),
|
|
_.omit(payload, omittedProperties));
|
|
|
|
return updateSectionState(state, payloadSection, newState);
|
|
}
|
|
|
|
return state;
|
|
},
|
|
|
|
[UPDATE]: function(state, { payload }) {
|
|
const payloadSection = payload.section;
|
|
const [baseSection] = payloadSection.split('.');
|
|
|
|
if (section === baseSection) {
|
|
const newState = getSectionState(state, payloadSection);
|
|
|
|
if (_.isArray(payload.data)) {
|
|
newState.items = payload.data;
|
|
newState.itemMap = createItemMap(payload.data);
|
|
} else {
|
|
newState.item = payload.data;
|
|
}
|
|
|
|
return updateSectionState(state, payloadSection, newState);
|
|
}
|
|
|
|
return state;
|
|
},
|
|
|
|
[UPDATE_ITEM]: function(state, { payload }) {
|
|
const {
|
|
section: payloadSection,
|
|
updateOnly = false,
|
|
...otherProps
|
|
} = payload;
|
|
|
|
const [baseSection] = payloadSection.split('.');
|
|
|
|
if (section === baseSection) {
|
|
const newState = getSectionState(state, payloadSection);
|
|
const items = newState.items;
|
|
|
|
// Client side collections that are created by adding items to an
|
|
// existing array may not have an itemMap, the array is probably empty,
|
|
// but on the offchance it's not create a new item map based on the
|
|
// items in the array.
|
|
const itemMap = newState.itemMap ?? createItemMap(items);
|
|
const index = payload.id in itemMap ? itemMap[payload.id] : -1;
|
|
|
|
newState.items = [...items];
|
|
|
|
// TODO: Move adding to it's own reducer
|
|
if (index >= 0) {
|
|
const item = items[index];
|
|
const newItem = { ...item, ...otherProps };
|
|
|
|
// if the item to update is equal to existing, then don't actually update
|
|
// to prevent costly reselections
|
|
if (_.isEqual(item, newItem)) {
|
|
return state;
|
|
}
|
|
|
|
newState.items.splice(index, 1, newItem);
|
|
} else if (!updateOnly) {
|
|
const newIndex = newState.items.push({ ...otherProps }) - 1;
|
|
|
|
newState.itemMap = { ...itemMap };
|
|
newState.itemMap[payload.id] = newIndex;
|
|
}
|
|
|
|
return updateSectionState(state, payloadSection, newState);
|
|
}
|
|
|
|
return state;
|
|
},
|
|
|
|
[CLEAR_PENDING_CHANGES]: function(state, { payload }) {
|
|
const payloadSection = payload.section;
|
|
const [baseSection] = payloadSection.split('.');
|
|
|
|
if (section === baseSection) {
|
|
const newState = getSectionState(state, payloadSection);
|
|
newState.pendingChanges = {};
|
|
|
|
if (newState.hasOwnProperty('saveError')) {
|
|
newState.saveError = null;
|
|
}
|
|
|
|
return updateSectionState(state, payloadSection, newState);
|
|
}
|
|
|
|
return state;
|
|
},
|
|
|
|
[REMOVE_ITEM]: function(state, { payload }) {
|
|
const payloadSection = payload.section;
|
|
const [baseSection] = payloadSection.split('.');
|
|
|
|
if (section === baseSection) {
|
|
const newState = getSectionState(state, payloadSection);
|
|
|
|
newState.items = [...newState.items];
|
|
_.remove(newState.items, { id: payload.id });
|
|
|
|
newState.itemMap = createItemMap(newState.items);
|
|
|
|
return updateSectionState(state, payloadSection, newState);
|
|
}
|
|
|
|
return state;
|
|
},
|
|
|
|
[UPDATE_SERVER_SIDE_COLLECTION]: function(state, { payload }) {
|
|
const payloadSection = payload.section;
|
|
const [baseSection] = payloadSection.split('.');
|
|
|
|
if (section === baseSection) {
|
|
const data = payload.data;
|
|
const newState = getSectionState(state, payloadSection);
|
|
|
|
const serverState = _.omit(data, ['records']);
|
|
const calculatedState = {
|
|
totalPages: Math.max(Math.ceil(data.totalRecords / data.pageSize), 1),
|
|
items: data.records,
|
|
itemMap: createItemMap(data.records)
|
|
};
|
|
|
|
return updateSectionState(state, payloadSection, Object.assign(newState, serverState, calculatedState));
|
|
}
|
|
|
|
return state;
|
|
},
|
|
|
|
...handlers
|
|
|
|
}, defaultState);
|
|
}
|