@woocommerce/data
Version:
WooCommerce Admin data store and utilities
245 lines (244 loc) • 11.6 kB
JavaScript
import CRUD_ACTIONS from './crud-actions';
import { filterDataByKeys, getRequestIdentifier, organizeItemsById, } from './utils';
import { getTotalCountResourceName } from '../utils';
import { TYPES } from './action-types';
export const createReducer = (additionalReducer) => {
const reducer = (state = {
items: {},
data: {},
itemsCount: {},
errors: {},
requesting: {},
}, payload) => {
var _a, _b, _c;
const itemData = state.data || {};
if (payload && 'type' in payload) {
switch (payload.type) {
case TYPES.CREATE_ITEM_ERROR:
const createItemErrorRequestId = getRequestIdentifier(payload.errorType, payload.query || {});
return {
...state,
errors: {
...state.errors,
[createItemErrorRequestId]: payload.error,
},
requesting: {
...state.requesting,
[createItemErrorRequestId]: false,
},
};
case TYPES.GET_ITEMS_TOTAL_COUNT_ERROR:
case TYPES.GET_ITEMS_ERROR:
return {
...state,
errors: {
...state.errors,
[getRequestIdentifier(payload.errorType, (payload.query || {}))]: payload.error,
},
};
case TYPES.GET_ITEMS_TOTAL_COUNT_SUCCESS:
return {
...state,
itemsCount: {
...state.itemsCount,
[getTotalCountResourceName(CRUD_ACTIONS.GET_ITEMS, (payload.query || {}))]: payload.totalCount,
},
};
case TYPES.CREATE_ITEM_SUCCESS: {
const { options = {} } = payload;
const { objItems, ids } = organizeItemsById([payload.item], options.optimisticUrlParameters, itemData);
const data = {
...itemData,
...objItems,
};
const createItemSuccessRequestId = getRequestIdentifier(CRUD_ACTIONS.CREATE_ITEM, ids[0], payload.query);
const getItemQueryId = getRequestIdentifier(CRUD_ACTIONS.GET_ITEMS, options.optimisticQueryUpdate);
const getItemCountQueryId = getTotalCountResourceName(CRUD_ACTIONS.GET_ITEMS, (options === null || options === void 0 ? void 0 : options.optimisticQueryUpdate) || {});
let currentItems = state.items;
const currentItemsByQueryId = ((_a = currentItems[getItemQueryId]) === null || _a === void 0 ? void 0 : _a.data) || [];
let nextItemsData = [...currentItemsByQueryId, ...ids];
let itemsCount = state.itemsCount;
/*
* Check it needs to update the store with the new item,
* optimistically.
*/
if (options === null || options === void 0 ? void 0 : options.optimisticQueryUpdate) {
/*
* If the query has an order_by property, sort the items
* by the order_by property.
*
* The sort criteria could be different from the
* the server side.
* Ensure to keep in sync with the server side, for instance,
* by invalidating the cache.
*
* Todo: Add a mechanism to use the server side sorting criteria.
*/
if ((_b = options.optimisticQueryUpdate) === null || _b === void 0 ? void 0 : _b.order_by) {
const order_by = (_c = options.optimisticQueryUpdate) === null || _c === void 0 ? void 0 : _c.order_by;
/*
* Pick the data to sort by the order_by property,
* from the data store,
* based on the nextItemsData ids.
*/
let sourceDataToOrderBy = Object.values(filterDataByKeys(data, nextItemsData));
sourceDataToOrderBy = sourceDataToOrderBy.sort((a, b) => String(a[order_by])
.toLowerCase()
.localeCompare(String(b[order_by]).toLowerCase()));
// Pick the ids from the sorted data.
const { ids: sortedIds } = organizeItemsById(sourceDataToOrderBy, options.optimisticUrlParameters);
// Update the items data with the sorted ids.
nextItemsData = sortedIds;
}
currentItems = {
...currentItems,
[getItemQueryId]: {
data: nextItemsData,
},
};
itemsCount = {
...state.itemsCount,
[getItemCountQueryId]: nextItemsData.length,
};
}
return {
...state,
items: currentItems,
itemsCount,
data,
requesting: {
...state.requesting,
[createItemSuccessRequestId]: false,
},
};
}
case TYPES.GET_ITEM_SUCCESS:
return {
...state,
data: {
...itemData,
[payload.key]: {
...(itemData[payload.key] || {}),
...payload.item,
},
},
};
case TYPES.UPDATE_ITEM_SUCCESS:
const updateItemSuccessRequestId = getRequestIdentifier(CRUD_ACTIONS.UPDATE_ITEM, payload.key, payload.query);
return {
...state,
data: {
...itemData,
[payload.key]: {
...(itemData[payload.key] || {}),
...payload.item,
},
},
requesting: {
...state.requesting,
[updateItemSuccessRequestId]: false,
},
};
case TYPES.DELETE_ITEM_SUCCESS:
const deleteItemSuccessRequestId = getRequestIdentifier(CRUD_ACTIONS.DELETE_ITEM, payload.key, payload.force);
const itemKeys = Object.keys(state.data);
const nextData = itemKeys.reduce((items, key) => {
if (key !== payload.key.toString()) {
items[key] = state.data[key];
return items;
}
if (payload.force) {
return items;
}
items[key] = payload.item;
return items;
}, {});
return {
...state,
data: nextData,
requesting: {
...state.requesting,
[deleteItemSuccessRequestId]: false,
},
};
case TYPES.DELETE_ITEM_ERROR:
const deleteItemErrorRequestId = getRequestIdentifier(payload.errorType, payload.key, payload.force);
return {
...state,
errors: {
...state.errors,
[deleteItemErrorRequestId]: payload.error,
},
requesting: {
...state.requesting,
[deleteItemErrorRequestId]: false,
},
};
case TYPES.GET_ITEM_ERROR:
return {
...state,
errors: {
...state.errors,
[getRequestIdentifier(payload.errorType, payload.key)]: payload.error,
},
};
case TYPES.UPDATE_ITEM_ERROR:
const upateItemErrorRequestId = getRequestIdentifier(payload.errorType, payload.key, payload.query);
return {
...state,
errors: {
...state.errors,
[upateItemErrorRequestId]: payload.error,
},
requesting: {
...state.requesting,
[upateItemErrorRequestId]: false,
},
};
case TYPES.GET_ITEMS_SUCCESS:
const { objItems, ids } = organizeItemsById(payload.items, payload.urlParameters, itemData);
const itemQuery = getRequestIdentifier(CRUD_ACTIONS.GET_ITEMS, (payload.query || {}));
return {
...state,
items: {
...state.items,
[itemQuery]: { data: ids },
},
data: {
...state.data,
...objItems,
},
};
case TYPES.CREATE_ITEM_REQUEST:
return {
...state,
requesting: {
...state.requesting,
[getRequestIdentifier(CRUD_ACTIONS.CREATE_ITEM, payload.query)]: true,
},
};
case TYPES.DELETE_ITEM_REQUEST:
return {
...state,
requesting: {
...state.requesting,
[getRequestIdentifier(CRUD_ACTIONS.DELETE_ITEM, payload.key, payload.force)]: true,
},
};
case TYPES.UPDATE_ITEM_REQUEST:
return {
...state,
requesting: {
...state.requesting,
[getRequestIdentifier(CRUD_ACTIONS.UPDATE_ITEM, payload.key, payload.query)]: true,
},
};
}
}
if (additionalReducer) {
return additionalReducer(state, payload);
}
return state;
};
return reducer;
};