Skip to content

Commit adab1aa

Browse files
authored
implemented storage status update on error request (#64)
* implemented storage status update on error request * change version
1 parent 426f7f2 commit adab1aa

File tree

9 files changed

+327
-10
lines changed

9 files changed

+327
-10
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@shoutem/redux-io",
3-
"version": "3.2.4-beta.0",
3+
"version": "3.2.4",
44
"description": "Action creators, reducers and middleware for simple handling of normalized json api data in state",
55
"main": "index.js",
66
"scripts": {

src/actions/remove.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function remove(schema, item, params = {}, options = {}) {
7777
},
7878
{
7979
type: REMOVE_ERROR,
80-
meta: extendMetaWithResponse(meta),
80+
meta: extendMetaWithResponse({ ...meta, payload: { data: item } }),
8181
},
8282
],
8383
},

src/actions/update.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export function update(schema, item = null, params = {}, options = {}) {
8383
},
8484
{
8585
type: UPDATE_ERROR,
86-
meta: extendMetaWithResponse(meta),
86+
meta: extendMetaWithResponse({ ...meta, payload: { data: item } }),
8787
},
8888
],
8989
},

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export {
9191
REMOVE_ERROR,
9292
OBJECT_REMOVED,
9393
OBJECT_REMOVING,
94+
OBJECT_ERROR,
9495
CREATE_REQUEST,
9596
CREATE_SUCCESS,
9697
CREATE_ERROR,

src/middlewares/apiStateMiddleware.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,12 @@ const actionHandlers = {
326326
const invalidateResources = _.get(action.meta, 'options.invalidateResources');
327327
const invalidateReferences = _.get(action.meta, 'options.invalidateReferences');
328328

329+
// Dispatch updated objects
329330
if (invalidateResources !== false) {
330-
// Dispatch updated objects from and change collections status to idle & invalid
331331
data.map(item => dispatch(makeObjectAction(action, OBJECT_UPDATED, item)));
332332
}
333333

334+
// Change collections status to idle & invalid
334335
if (invalidateReferences !== false) {
335336
dispatch(makeIndexAction(
336337
action,
@@ -341,10 +342,16 @@ const actionHandlers = {
341342
}
342343
},
343344
[UPDATE_ERROR]: (action, data, dispatch) => {
344-
// Change collection status to idle and invalid
345345
const schema = action.meta.schema;
346+
const invalidateResources = _.get(action.meta, 'options.invalidateResources');
346347
const invalidateReferences = _.get(action.meta, 'options.invalidateReferences');
347348

349+
// Dispatch objects with error
350+
if (invalidateResources !== false) {
351+
data.map(item => dispatch(makeObjectAction(action, OBJECT_ERROR, item)));
352+
}
353+
354+
// Change collection status to idle and invalid
348355
if (invalidateReferences !== false) {
349356
dispatch(makeIndexAction(
350357
action,
@@ -394,10 +401,16 @@ const actionHandlers = {
394401
}
395402
},
396403
[REMOVE_ERROR]: (action, data, dispatch) => {
397-
// Change collections status to idle and invalid
398404
const schema = action.meta.schema;
405+
const invalidateResources = _.get(action.meta, 'options.invalidateResources');
399406
const invalidateReferences = _.get(action.meta, 'options.invalidateReferences');
400407

408+
// Dispatch objects with error
409+
if (invalidateResources !== false) {
410+
data.map(item => dispatch(makeObjectAction(action, OBJECT_ERROR, item)));
411+
}
412+
413+
// Change collections status to idle and invalid
401414
if (invalidateReferences !== false) {
402415
dispatch(makeIndexAction(
403416
action,
@@ -478,8 +491,9 @@ function handleFailedRequest(action, dispatch) {
478491
return;
479492
}
480493

481-
// Update reference status for corresponding error action
482-
actionHandlers[errorAction](action, undefined, dispatch);
494+
const data = getData(_.get(action, 'meta.payload'));
495+
// Update reference and object status for corresponding error action
496+
actionHandlers[errorAction](action, data, dispatch);
483497
}
484498

485499
/**

src/reducers/storage.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
OBJECT_UPDATED,
88
OBJECT_REMOVING,
99
OBJECT_REMOVED,
10+
OBJECT_ERROR,
1011
} from './../consts';
1112
import {
1213
STATUS,
@@ -133,6 +134,19 @@ export default function storage(schema, initialState = {}) {
133134
cloneStatus(state, newState);
134135
return newState;
135136
}
137+
case OBJECT_ERROR: {
138+
const newItem = { ...currentItem };
139+
setStatus(newItem, mergeItemStatus(
140+
currentItem,
141+
{
142+
validationStatus: validationStatus.INVALID,
143+
busyStatus: busyStatus.IDLE,
144+
}
145+
));
146+
const newState = { ...state, [newItem.id]: newItem };
147+
cloneStatus(state, newState);
148+
return newState;
149+
}
136150
default: {
137151
if (state[STATUS]) {
138152
return state;

test/actions/remove.spec.js

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import rio, {
1010
REMOVE_ERROR,
1111
OBJECT_REMOVING,
1212
OBJECT_REMOVED,
13+
OBJECT_ERROR,
1314
REFERENCE_STATUS,
1415
apiStateMiddleware,
1516
JSON_API_SOURCE,
@@ -74,6 +75,14 @@ describe('Delete action creator', () => {
7475
headers: {}
7576
},
7677
};
78+
79+
const expectedErrorResponseMeta = {
80+
payload: {
81+
data: item,
82+
},
83+
...expectedResponseMeta,
84+
};
85+
7786
const metaResponse = [{}, {}, new Response(null, {
7887
"status": 200,
7988
"headers": {},
@@ -84,7 +93,7 @@ describe('Delete action creator', () => {
8493
expect(types[1].type).to.equal(REMOVE_SUCCESS);
8594
expect(types[1].meta(...metaResponse)).to.deep.equal(expectedResponseMeta);
8695
expect(types[2].type).to.equal(REMOVE_ERROR);
87-
expect(types[2].meta(...metaResponse)).to.deep.equal(expectedResponseMeta);
96+
expect(types[2].meta(...metaResponse)).to.deep.equal(expectedErrorResponseMeta);
8897
});
8998

9099
it('creates a valid action with valid endpoint with filled params', () => {
@@ -463,4 +472,116 @@ describe('Delete action creator', () => {
463472
});
464473
}).then(done).catch(done);
465474
});
475+
476+
it('produces valid storage and collection actions after error', done => {
477+
const schema = 'schema_test';
478+
const item = { id: 1, type: schema };
479+
const expectedPayload = {
480+
data: item,
481+
};
482+
483+
nock('http://api.server.local')
484+
.delete('/apps/1')
485+
.reply(400, {}, { 'Content-Type': 'vnd.api+json' });
486+
487+
const config = {
488+
headers: {
489+
'Content-Type': 'application/vnd.api+json',
490+
},
491+
endpoint: 'http://api.server.local/apps/1',
492+
};
493+
494+
const schemaConfig = {
495+
schema,
496+
request: config,
497+
};
498+
499+
const expectedMeta = {
500+
source: JSON_API_SOURCE,
501+
schema,
502+
endpoint: config.endpoint,
503+
params: {},
504+
options: {},
505+
};
506+
507+
const action = remove(schemaConfig, item);
508+
509+
const store = mockStore({});
510+
store.dispatch(action)
511+
.then(() => {
512+
const performedActions = store.getActions();
513+
expect(performedActions).to.have.length(4);
514+
515+
const batchedRemovingActions = performedActions[0];
516+
const actionCollBusyRequest = batchedRemovingActions.payload[0];
517+
expect(actionCollBusyRequest.type).to.equal(REFERENCE_STATUS);
518+
expect(actionCollBusyRequest.meta)
519+
.to.deep.equal({ ...expectedMeta, tag: '*', timestamp: actionCollBusyRequest.meta.timestamp });
520+
const expectedCollBusyStatusPayload = {
521+
validationStatus: validationStatus.INVALID,
522+
busyStatus: busyStatus.BUSY,
523+
};
524+
expect(actionCollBusyRequest.payload).to.deep.equal(expectedCollBusyStatusPayload);
525+
526+
const actionObjDeleting = batchedRemovingActions.payload[1];
527+
expect(actionObjDeleting.type).to.equal(OBJECT_REMOVING);
528+
expect(actionObjDeleting.meta).to.deep.equal({
529+
...expectedMeta,
530+
transformation: {},
531+
timestamp: actionObjDeleting.meta.timestamp
532+
});
533+
534+
expect(performedActions[1].type).to.equal(REMOVE_REQUEST);
535+
536+
const batchedErroredActions = performedActions[2];
537+
const actionObjErrored = batchedErroredActions.payload[0];
538+
expect(actionObjErrored.type).to.equal(OBJECT_ERROR);
539+
expect(actionObjErrored.meta).to.deep.equal({
540+
...expectedMeta,
541+
payload: expectedPayload,
542+
transformation: {},
543+
timestamp: actionObjErrored.meta.timestamp,
544+
response: {
545+
status: 400,
546+
headers: {
547+
"content-type": "vnd.api+json",
548+
}
549+
},
550+
});
551+
552+
const actionCollStatus = batchedErroredActions.payload[1];
553+
expect(actionCollStatus.type).to.equal(REFERENCE_STATUS);
554+
expect(actionCollStatus.meta).to.deep.equal({
555+
...expectedMeta,
556+
payload: expectedPayload,
557+
tag: '*',
558+
timestamp: actionCollStatus.meta.timestamp,
559+
response: {
560+
status: 400,
561+
headers: {
562+
"content-type": "vnd.api+json",
563+
}
564+
},
565+
});
566+
const expectedCollStatusPayload = {
567+
validationStatus: validationStatus.INVALID,
568+
busyStatus: busyStatus.IDLE,
569+
};
570+
expect(actionCollStatus.payload).to.deep.equal(expectedCollStatusPayload);
571+
572+
const errorAction = performedActions[3];
573+
expect(errorAction.type).to.equal(REMOVE_ERROR);
574+
expect(errorAction.meta).to.deep.equal({
575+
...expectedMeta,
576+
payload: expectedPayload,
577+
timestamp: errorAction.meta.timestamp,
578+
response: {
579+
status: 400,
580+
headers: {
581+
"content-type": "vnd.api+json",
582+
}
583+
},
584+
});
585+
}).then(done).catch(done);
586+
});
466587
});

0 commit comments

Comments
 (0)