diff --git a/src/create/create.js b/src/create/create.js index 265a9c0..af5079f 100644 --- a/src/create/create.js +++ b/src/create/create.js @@ -1,118 +1,69 @@ -const debug = require("debug")("ReduxList:Create") - -import { findWith, isNothing, map, reduce, hasWith, is } from "@mutantlove/m" +const debug = require("debug")("ReduxList:CreateAction") /** - * Call API to create item. Dispatch actions before, after success and after - * error + * Call list.create method to add result to slice.items * - * @param {Function} dispatch Redux dispatch - * @param {Function} api API method - * @param {string} actionStart Action before API call - * @param {string} actionSuccess Action after success - * @param {string} actionError Action after error + * @param {String} listName Slice name - for error messages + * @param {Function} dispatch Redux dispatch + * @param {Function} api API method + * @param {String} actionStart Dispatch before API call + * @param {String} actionEnd Dispatch after successfull API call + * @param {String} actionError Dispatch after failed API call + * @param {Function} onChange Appy on items array before changing state * - * @param {Object} data Model data + * @param {Object} data Model data + * @param {Array} rest Other paramaters passed when calling list.create * - * @return {Promise} + * @return {Promise>} */ export const createAction = ({ + listName, dispatch, api, actionStart, - actionSuccess, + actionEnd, actionError, -}) => async (data, ...rest) => { + onChange, +}) => (data, ...rest) => { dispatch({ type: actionStart, - payload: data, + payload: { + listName, + items: Array.isArray(data) ? data : [data], + }, }) - // Resolve promise on both success and error with {result, error} obj - try { - const result = await api(data, ...rest) - - dispatch({ - type: actionSuccess, - payload: result, + return Promise.resolve() + .then(() => api(data, ...rest)) + .then(result => { + dispatch({ + type: actionEnd, + payload: { + listName, + items: Array.isArray(result) ? result : [result], + onChange, + }, + }) + + return { result } }) - - return { result } - } catch (error) { - // wrapping here and not in the reducer so that both resolved error and - // state error match - const stateError = { - date: new Date(), - data: { - name: error.name, - message: error.message, - status: error.status, - body: error.body, - }, - } - - dispatch({ - type: actionError, - payload: stateError, - }) - - return { error: stateError } - } -} - -export const createStartReducer = (state, payload) => ({ - ...state, - creating: Array.isArray(payload) ? payload : [payload], -}) - -export const createSuccessReducer = (state, payload) => { - const items = Array.isArray(payload) ? payload : [payload] - const itemWithoutId = findWith({ - id: isNothing, - })(items) - - if (is(itemWithoutId)) { - throw new TypeError( - `createSuccessReducer: trying to create item "${itemWithoutId}" without id property` - ) - } - - return { - ...state, - - // if exists, replace, else add to end of array - items: reduce((acc, item) => { - const exists = hasWith({ id: item.id })(state.items) - - if (exists) { - debug( - `createSuccessReducer: ID "${item.id}" already exists, replacing`, - { - createdItem: item, - existingItems: state.items, - } - ) + .catch(error => { + // reducer and promise resolve the same data + const stateError = { + date: new Date(), + data: { + name: error.name, + message: error.message, + status: error.status, + body: error.body, + }, } - return exists - ? map(mItem => (mItem.id === item.id ? item : mItem))(acc) - : [...acc, item] - }, state.items)(items), + dispatch({ + type: actionError, + payload: stateError, + }) - // reset error after successfull action - errors: { - ...state.errors, - create: null, - }, - creating: [], - } + return { error: stateError } + }) } - -export const createErrorReducer = (state, error = {}) => ({ - ...state, - errors: { - ...state.errors, - create: error, - }, - creating: [], -}) diff --git a/src/index.js b/src/index.js index 2d8abd2..4f5a1fa 100644 --- a/src/index.js +++ b/src/index.js @@ -2,50 +2,56 @@ const debug = require("debug")("ReduxList:Main") import { hasKey } from "@mutantlove/m" + +import { createAction } from "./create/create" import { - createAction, - createStartReducer, - createSuccessReducer, - createErrorReducer, -} from "./create/create" + startReducer as createStartReducer, + endReducer as createEndReducer, + errorReducer as createErrorReducer, +} from "./create/create.reducers" + +import { readAction } from "./read/read" import { - readAction, - readStartReducer, - readSuccessReducer, - readErrorReducer, -} from "./read/read" + startReducer as readStartReducer, + endReducer as readEndReducer, + errorReducer as readErrorReducer, +} from "./read/read.reducers" + +import { readOneAction } from "./read-one/read-one" import { - readOneAction, - readOneStartReducer, - readOneSuccessReducer, - readOneErrorReducer, -} from "./read-one/read-one" + startReducer as readOneStartReducer, + endReducer as readOneEndReducer, + errorReducer as readOneErrorReducer, +} from "./read-one/read-one.reducers" + +import { updateAction } from "./update/update" import { - updateAction, - updateStartReducer, - updateSuccessReducer, - updateErrorReducer, -} from "./update/update" + startReducer as updateStartReducer, + endReducer as updateEndReducer, + errorReducer as updateErrorReducer, +} from "./update/update.reducers" + +import { removeAction } from "./remove/remove" import { - removeAction, - removeStartReducer, - removeSuccessReducer, - removeErrorReducer, -} from "./remove/remove" + startReducer as removeStartReducer, + endReducer as removeEndReducer, + errorReducer as removeErrorReducer, +} from "./remove/remove.reducers" import { buildQueue } from "./lib/queue" const collections = Object.create(null) /** - * List factory function + * Construct a set of actions and reducers to manage a state slice as an array * - * @param {string} name Unique name so actions dont overlap - * @param {Object} methods Object with CRUD method + * @param {string} name Unique name so actions dont overlap + * @param {Object} methods Object with CRUD method + * @param {Function} onChange Function triggered on every list change * * @return {Object} */ -const buildList = (name, methods = {}) => { +const buildList = (name, methods = {}, onChange) => { if (hasKey(name)(collections)) { throw new Error(`ReduxList: List with name "${name}" already exists`) } @@ -54,33 +60,24 @@ const buildList = (name, methods = {}) => { const queue = buildQueue() const createStart = `${name}_CREATE_START` - const createSuccess = `${name}_CREATE_SUCCESS` + const createEnd = `${name}_CREATE_END` const createError = `${name}_CREATE_ERROR` const readStart = `${name}_READ_START` - const readSuccess = `${name}_READ_END` + const readEnd = `${name}_READ_END` const readError = `${name}_READ_ERROR` const readOneStart = `${name}_READ-ONE_START` - const readOneSuccess = `${name}_READ-ONE_END` + const readOneEnd = `${name}_READ-ONE_END` const readOneError = `${name}_READ-ONE_ERROR` const updateStart = `${name}_UPDATE_START` - const updateSuccess = `${name}_UPDATE_SUCCESS` + const updateEnd = `${name}_UPDATE_END` const updateError = `${name}_UPDATE_ERROR` const removeStart = `${name}_REMOVE_START` - const removeSuccess = `${name}_REMOVE_SUCCESS` + const removeEnd = `${name}_REMOVE_END` const removeError = `${name}_REMOVE_ERROR` return { name, - /** - * Create an item, dispatch events before and after API call - * - * @param {Function} dispatch Redux dispatch function - * @param {Object} data Item data - * @param {Object} options Action options - * - * @return {void} - */ create: ( dispatch, data, @@ -95,20 +92,27 @@ const buildList = (name, methods = {}) => { if (isLocal) { dispatch({ - type: createSuccess, - payload: data, + type: createEnd, + payload: { + listName: name, + items: Array.isArray(data) ? data : [data], + onChange, + }, }) return Promise.resolve({ result: data }) } return queue.enqueue({ + id: `${name}__create`, fn: createAction({ + listName: name, dispatch, api: methods.create, actionStart: createStart, - actionSuccess: createSuccess, + actionEnd: createEnd, actionError: createError, + onChange, }), // queue calls fn(...args) @@ -116,14 +120,6 @@ const buildList = (name, methods = {}) => { }) }, - /** - * Load list items, dispatch events before and after - * - * @param {Function} dispatch Redux dispatch function - * @param {Array} args API method parameters - * - * @return {void} - */ read: (dispatch, ...args) => { if (typeof methods.read !== "function") { throw new TypeError( @@ -132,12 +128,14 @@ const buildList = (name, methods = {}) => { } return queue.enqueue({ + id: `${name}__read`, fn: readAction({ dispatch, api: methods.read, actionStart: readStart, - actionSuccess: readSuccess, + actionEnd: readEnd, actionError: readError, + onChange, }), // queue calls fn(...args) @@ -145,14 +143,6 @@ const buildList = (name, methods = {}) => { }) }, - /** - * Load one item, dispatch events before and after - * - * @param {Function} dispatch Redux dispatch function - * @param {Array} args API method parameters - * - * @return {void} - */ readOne: (dispatch, ...args) => { if (typeof methods.readOne !== "function") { throw new TypeError( @@ -161,12 +151,15 @@ const buildList = (name, methods = {}) => { } return queue.enqueue({ + id: `${name}__readOne`, fn: readOneAction({ + listName: name, dispatch, api: methods.readOne, actionStart: readOneStart, - actionSuccess: readOneSuccess, + actionEnd: readOneEnd, actionError: readOneError, + onChange, }), // queue calls fn(...args) @@ -174,15 +167,6 @@ const buildList = (name, methods = {}) => { }) }, - /** - * Update an item, dispatch events before and after - * - * @param {Function} dispatch Redux dispatch function - * @param {Number|string} id Item id - * @param {Object} data Item data - * - * @return {void} - */ update: ( dispatch, id, @@ -198,20 +182,27 @@ const buildList = (name, methods = {}) => { if (isLocal) { dispatch({ - type: updateSuccess, - payload: { id, ...data }, + type: updateEnd, + payload: { + listName: name, + item: { id, ...data }, + onChange, + }, }) return Promise.resolve({ result: { id, ...data } }) } return queue.enqueue({ + id: `${name}__update`, fn: updateAction({ + listName: name, dispatch, api: methods.update, actionStart: updateStart, - actionSuccess: updateSuccess, + actionEnd: updateEnd, actionError: updateError, + onChange, }), // queue calls fn(...args) @@ -219,16 +210,6 @@ const buildList = (name, methods = {}) => { }) }, - /** - * Delete an item, dispatch events before and after - * - * @param {Function} dispatch Redux dispatch function - * @param {Number|string} id Item id - * - * @param {Array} args API method parameters - * - * @return {void} - */ remove: ( dispatch, id, @@ -243,9 +224,11 @@ const buildList = (name, methods = {}) => { if (isLocal) { dispatch({ - type: removeSuccess, + type: removeEnd, payload: { - id, + listName: name, + item: { id }, + onChange, }, }) @@ -253,12 +236,15 @@ const buildList = (name, methods = {}) => { } return queue.enqueue({ + id: `${name}__remove`, fn: removeAction({ + listName: name, dispatch, api: methods.remove, actionStart: removeStart, - actionSuccess: removeSuccess, + actionEnd: removeEnd, actionError: removeError, + onChange, }), // queue calls fn(...args) @@ -266,16 +252,9 @@ const buildList = (name, methods = {}) => { }) }, - /** - * Empty list - * - * @param {Function} dispatch Redux dispatch function - * - * @return {void} - */ clear: dispatch => { dispatch({ - type: readSuccess, + type: readEnd, payload: { items: [], shouldClear: true, @@ -285,16 +264,6 @@ const buildList = (name, methods = {}) => { return Promise.resolve([]) }, - /** - * Instead of a traditional switch by type - * - * @param {Object} state The state - * @param {Object} arg2 The argument 2 - * @param {string} arg2.type The type - * @param {mixed} arg2.payload The payload - * - * @return {Object} - */ reducer: ( state = { items: [], @@ -303,7 +272,14 @@ const buildList = (name, methods = {}) => { updating: [], removing: [], - errors: {}, + errors: { + read: null, + readOne: null, + create: null, + remove: null, + update: null, + }, + loadDate: null, isLoading: false, }, @@ -313,40 +289,40 @@ const buildList = (name, methods = {}) => { // Create case createStart: return createStartReducer(state, payload) - case createSuccess: - return createSuccessReducer(state, payload) + case createEnd: + return createEndReducer(state, payload) case createError: return createErrorReducer(state, payload) // Read case readStart: return readStartReducer(state, payload) - case readSuccess: - return readSuccessReducer(state, payload) + case readEnd: + return readEndReducer(state, payload) case readError: return readErrorReducer(state, payload) // ReadOne case readOneStart: return readOneStartReducer(state, payload) - case readOneSuccess: - return readOneSuccessReducer(state, payload) + case readOneEnd: + return readOneEndReducer(state, payload) case readOneError: return readOneErrorReducer(state, payload) // Update case updateStart: return updateStartReducer(state, payload) - case updateSuccess: - return updateSuccessReducer(state, payload) + case updateEnd: + return updateEndReducer(state, payload) case updateError: return updateErrorReducer(state, payload) // Delete case removeStart: return removeStartReducer(state, payload) - case removeSuccess: - return removeSuccessReducer(state, payload) + case removeEnd: + return removeEndReducer(state, payload) case removeError: return removeErrorReducer(state, payload) diff --git a/src/read-one/read-one.js b/src/read-one/read-one.js index 8e4d666..2f3069b 100644 --- a/src/read-one/read-one.js +++ b/src/read-one/read-one.js @@ -1,27 +1,37 @@ -const debug = require("debug")("ReduxList:ReadOne") +const debug = require("debug")("ReduxList:ReadOneAction") -import { hasKey, map, push, merge, when, hasWith, isEmpty } from "@mutantlove/m" +import { hasKey, isEmpty } from "@mutantlove/m" /** - * Call API to fetch one item, dispatch events before and after + * Call list.readOne method to add/update item in slice.items * - * @param {Function} dispatch Redux dispatch - * @param {Function} api API method - * @param {string} actionStartName Action dispatched before API call - * @param {string} actionEndName Action dispatched after API call + * @param {String} listName Slice name - for error messages + * @param {Function} dispatch Redux dispatch + * @param {Function} api API method + * @param {String} actionStart Dispatch before API call + * @param {String} actionEnd Dispatch after successfull API call + * @param {String} actionError Dispatched after failed API call + * @param {Function} onChange Appy on items array before changing state * - * @returns {Object[]} + * + * @param {string|number} id Id of item to update or add + * @param {Array} rest Other paramaters passed when calling list + * instance .readOne + * + * @return {Promise>} */ export const readOneAction = ({ + listName, dispatch, api, actionStart, - actionSuccess, + actionEnd, actionError, -}) => async (id, ...args) => { + onChange, +}) => (id, ...args) => { if (isEmpty(id)) { throw new TypeError( - `ReduxList: readOneAction - cannot call readOne method without a valid "id" param. Expected something, got "${JSON.stringify( + `ReduxList: "${listName}".readOne ID param missing. Expected something, got "${JSON.stringify( id )}"` ) @@ -32,64 +42,39 @@ export const readOneAction = ({ payload: id, }) - try { - const result = await api(id, ...args) + return Promise.resolve() + .then(() => api(id, ...args)) + .then(result => { + dispatch({ + type: actionEnd, + payload: { + item: { + ...result, + id: hasKey("id")(result) ? result.id : id, + }, + onChange, + }, + }) - dispatch({ - type: actionSuccess, - payload: { - ...result, - id: hasKey("id")(result) ? result.id : id, - }, + return { result } }) + .catch(error => { + // reducer and promise resolve the same data + const stateError = { + date: new Date(), + data: { + name: error.name, + message: error.message, + status: error.status, + body: error.body, + }, + } - return { result } - } catch (error) { - // wrapping here so that both reducer and this current promise - // resolve/pass the same data - const stateError = { - date: new Date(), - data: { - name: error.name, - message: error.message, - status: error.status, - body: error.body, - }, - } + dispatch({ + type: actionError, + payload: stateError, + }) - dispatch({ - type: actionError, - payload: stateError, + return { error: stateError } }) - - return { error: stateError } - } } - -export const readOneStartReducer = (state, id) => ({ - ...state, - reading: id, -}) - -export const readOneSuccessReducer = (state, payload) => ({ - ...state, - items: when( - hasWith({ id: payload.id }), - map(item => (item.id === payload.id ? merge(item, payload) : item)), - push(payload) - )(state.items), - reading: null, - errors: { - ...state.errors, - readOne: null, - }, -}) - -export const readOneErrorReducer = (state, error = {}) => ({ - ...state, - errors: { - ...state.errors, - readOne: error, - }, - reading: null, -}) diff --git a/src/read/read.js b/src/read/read.js index 40087c3..266e78e 100644 --- a/src/read/read.js +++ b/src/read/read.js @@ -1,32 +1,30 @@ -const debug = require("debug")("ReduxList:Read") - -import { - pipe, - push, - hasWith, - flatten, - reduce, - when, - merge, - map, -} from "@mutantlove/m" +const debug = require("debug")("ReduxList:ReadAction") /** - * Call API to fetch items, dispatch events before and after + * Call list.read method to set slice.items array + * + * @param {Function} dispatch Redux dispatch + * @param {Function} api API method + * @param {String} actionStart Dispatch before API call + * @param {String} actionEnd Dispatch after successfull API call + * @param {String} actionError Dispatched after failed API call + * @param {Function} onChange Appy on items array before changing state * - * @param {Function} dispatch Redux dispatch - * @param {Function} api API method - * @param {string} actionStartName Action dispatched before API call - * @param {string} actionEndName Action dispatched after API call + * @param {Object} query Control/Filter attributes + * @param {Boolean} opt.shouldClear If true, method result will replace existing + * items. Otherwise, merge both arrays by id + * @param {Object} opt.rest Other options passed when calling list + * instance .read * - * @returns {Object[]} + * @return {Promise>} */ export const readAction = ({ dispatch, api, actionStart, - actionSuccess, + actionEnd, actionError, + onChange, }) => (query = {}, { shouldClear = true, ...rest } = {}) => { dispatch({ type: actionStart, @@ -36,17 +34,18 @@ export const readAction = ({ .then(() => api(query, { shouldClear, ...rest })) .then(result => { dispatch({ - type: actionSuccess, + type: actionEnd, payload: { items: Array.isArray(result) ? result : [result], shouldClear, + onChange, }, }) return { result } }) .catch(error => { - // reducer and this promise resolve with the same data + // reducer and promise resolve the same data const stateError = { date: new Date(), data: { @@ -65,40 +64,3 @@ export const readAction = ({ return { error: stateError } }) } - -export const readStartReducer = state => ({ - ...state, - isLoading: true, -}) - -export const readSuccessReducer = (state, { items, shouldClear }) => ({ - ...state, - items: shouldClear - ? items - : pipe( - flatten, - reduce( - (acc, accItem) => - when( - hasWith({ id: accItem.id }), - map(item => - item.id === accItem.id ? merge(item, accItem) : item - ), - push(accItem) - )(acc), - [] - ) - )([state.items, items]), - loadDate: new Date(), - isLoading: false, -}) - -export const readErrorReducer = (state, error = {}) => ({ - ...state, - errors: { - ...state.errors, - read: error, - }, - items: [], - isLoading: false, -}) diff --git a/src/remove/remove.js b/src/remove/remove.js index 3761897..1078899 100644 --- a/src/remove/remove.js +++ b/src/remove/remove.js @@ -1,30 +1,36 @@ -const debug = require("debug")("ReduxList:Remove") +const debug = require("debug")("ReduxList:RemoveAction") -import { filterWith, findWith, isEmpty, hasWith, hasKey } from "@mutantlove/m" +import { isEmpty, hasKey } from "@mutantlove/m" /** - * Call API to delete an item, dispatch events before and after + * Call list.remove method to remove item from slice.items * - * @param {Function} dispatch Redux dispatch - * @param {Function} api API method - * @param {string} actionStart Action before API call - * @param {string} actionSuccess Action after success - * @param {string} actionError Action after error + * @param {String} listName Slice name - for error messages + * @param {Function} dispatch Redux dispatch + * @param {Function} api API method + * @param {String} actionStart Dispatch before API call + * @param {String} actionEnd Dispatch after successfull API call + * @param {String} actionError Dispatch after failed API call + * @param {Function} onChange Appy on items array before changing state * - * @param {string|number} id Id of item to delete + * @param {string|number} id Id of item to delete + * @param {Array} rest Other paramaters passed when calling list + * instance .remove * - * @return {Object} + * @return {Promise>} */ export const removeAction = ({ + listName, dispatch, api, actionStart, - actionSuccess, + actionEnd, actionError, -}) => async (id, ...rest) => { + onChange, +}) => (id, ...rest) => { if (isEmpty(id)) { throw new TypeError( - `ReduxList: removeAction - cannot call remove method without a valid "id" param. Expected something, got "${JSON.stringify( + `ReduxList: "${listName}".remove ID param missing. Expected something, got "${JSON.stringify( id )}"` ) @@ -35,73 +41,40 @@ export const removeAction = ({ payload: id, }) - // Resolve promise on both success and error with {result, error} obj - try { - const result = await api(id, ...rest) + return Promise.resolve() + .then(() => api(id, ...rest)) + .then(result => { + dispatch({ + type: actionEnd, + payload: { + listName, + item: { + ...result, + id: hasKey("id")(result) ? result.id : id, + }, + onChange, + }, + }) - dispatch({ - type: actionSuccess, - payload: { - ...result, - id: hasKey("id")(result) ? result.id : id, - }, + return { result } }) + .catch(error => { + // reducer and promise resolve the same data + const stateError = { + date: new Date(), + data: { + name: error.name, + message: error.message, + status: error.status, + body: error.body, + }, + } - return { result } - } catch (error) { - // wrapping here so that both reducer and this current promise - // resolve/pass the same data - const stateError = { - date: new Date(), - data: { - name: error.name, - message: error.message, - status: error.status, - body: error.body, - }, - } + dispatch({ + type: actionError, + payload: stateError, + }) - dispatch({ - type: actionError, - payload: stateError, + return { error: stateError } }) - - return { error: stateError } - } -} - -export const removeStartReducer = (state, id) => ({ - ...state, - removing: [findWith({ id })(state.items)], -}) - -export const removeSuccessReducer = (state, item) => { - if (!hasWith({ id: item.id })(state.items)) { - debug( - `removeSuccessReducer: ID "${item.id}" does not exist, doing nothing (will still trigger a rerender)`, - { - deletedItem: item, - existingItems: state.items, - } - ) - } - - return { - ...state, - items: filterWith({ "!id": item.id })(state.items), - errors: { - ...state.errors, - remove: null, - }, - removing: [], - } } - -export const removeErrorReducer = (state, error = {}) => ({ - ...state, - errors: { - ...state.errors, - remove: error, - }, - removing: [], -}) diff --git a/src/update/update.js b/src/update/update.js index 3cb069c..a69de65 100644 --- a/src/update/update.js +++ b/src/update/update.js @@ -1,27 +1,35 @@ -const debug = require("debug")("ReduxList:Update") +const debug = require("debug")("ReduxList:UpdateAction") -import { map, merge, isEmpty, hasWith, hasKey } from "@mutantlove/m" +import { isEmpty, hasKey } from "@mutantlove/m" /** - * Call API to update an item, dispatch events before and after + * Call list.update method to change existing item in slice.items * - * @param {Function} dispatch Redux dispatch - * @param {Function} api API method - * @param {string} actionStartName Action dispatched before API call - * @param {string} actionEndName Action dispatched after API call + * @param {String} listName Slice name - for error messages + * @param {Function} dispatch Redux dispatch + * @param {Function} api API method + * @param {String} actionStart Dispatch before API call + * @param {String} actionEnd Dispatch after successfull API call + * @param {String} actionError Dispatch after failed API call + * @param {Function} onChange Appy on items array before changing state * - * @return {Promise} + * @param {string|number} id Id of item to update + * @param {Array} rest Other paramaters passed when calling list.update + * + * @return {Promise>} */ export const updateAction = ({ + listName, dispatch, api, actionStart, - actionSuccess, + actionEnd, actionError, -}) => async (id, data, ...rest) => { + onChange, +}) => (id, data, ...rest) => { if (isEmpty(id)) { throw new TypeError( - `ReduxList: updateAction - cannot call update method without a valid "id" param. Expected something, got "${JSON.stringify( + `ReduxList: "${listName}".update ID param missing. Expected something, got "${JSON.stringify( id )}"` ) @@ -32,75 +40,40 @@ export const updateAction = ({ payload: { id, data }, }) - // Resolve promise on both success and error with {result, error} obj - try { - const result = await api(id, data, ...rest) + return Promise.resolve() + .then(() => api(id, data, ...rest)) + .then(result => { + dispatch({ + type: actionEnd, + payload: { + listName, + item: { + ...result, + id: hasKey("id")(result) ? result.id : id, + }, + onChange, + }, + }) - dispatch({ - type: actionSuccess, - payload: { - ...result, - id: hasKey("id")(result) ? result.id : id, - }, + return { result } }) + .catch(error => { + // reducer and promise resolve the same data + const stateError = { + date: new Date(), + data: { + name: error.name, + message: error.message, + status: error.status, + body: error.body, + }, + } - return { result } - } catch (error) { - // wrapping here so that both reducer and this current promise - // resolve/pass the same data - const stateError = { - date: new Date(), - data: { - name: error.name, - message: error.message, - status: error.status, - body: error.body, - }, - } + dispatch({ + type: actionError, + payload: stateError, + }) - dispatch({ - type: actionError, - payload: stateError, + return { error: stateError } }) - - return { error: stateError } - } } - -export const updateStartReducer = (state, { id, data }) => ({ - ...state, - updating: { id, data }, -}) - -export const updateSuccessReducer = (state, payload) => { - if (hasWith({ id: payload.id })(state.items)) { - debug( - `updateSuccessReducer: ID "${payload.id}" does not exist, doint nothing (will still trigger a rerender)`, - { - payload, - existingItems: state.items, - } - ) - } - - return { - ...state, - items: map(item => (item.id === payload.id ? merge(item, payload) : item))( - state.items - ), - updating: {}, - errors: { - ...state.errors, - update: null, - }, - } -} - -export const updateErrorReducer = (state, error = {}) => ({ - ...state, - updating: {}, - errors: { - ...state.errors, - update: error, - }, -})