11/**
22 * External dependencies
33 */
4- import { map , flowRight , omit , forEach , filter } from 'lodash' ;
4+ import { map , flowRight , omit , filter , mapValues } from 'lodash' ;
55
66/**
77 * WordPress dependencies
@@ -20,6 +20,16 @@ import {
2020import { DEFAULT_ENTITY_KEY } from '../entities' ;
2121import getQueryParts from './get-query-parts' ;
2222
23+ function getContextFromAction ( action ) {
24+ const { query } = action ;
25+ if ( ! query ) {
26+ return 'default' ;
27+ }
28+
29+ const queryParts = getQueryParts ( query ) ;
30+ return queryParts . context ;
31+ }
32+
2333/**
2434 * Returns a merged array of item IDs, given details of the received paginated
2535 * items. The array is sparse-like with `undefined` entries where holes exist.
@@ -71,24 +81,30 @@ export function getMergedItemIds( itemIds, nextItemIds, page, perPage ) {
7181 *
7282 * @return {Object } Next state.
7383 */
74- function items ( state = { } , action ) {
84+ export function items ( state = { } , action ) {
7585 switch ( action . type ) {
76- case 'RECEIVE_ITEMS' :
86+ case 'RECEIVE_ITEMS' : {
87+ const context = getContextFromAction ( action ) ;
7788 const key = action . key || DEFAULT_ENTITY_KEY ;
7889 return {
7990 ...state ,
80- ...action . items . reduce ( ( accumulator , value ) => {
81- const itemId = value [ key ] ;
82- accumulator [ itemId ] = conservativeMapItem (
83- state [ itemId ] ,
84- value
85- ) ;
86- return accumulator ;
87- } , { } ) ,
91+ [ context ] : {
92+ ...state [ context ] ,
93+ ...action . items . reduce ( ( accumulator , value ) => {
94+ const itemId = value [ key ] ;
95+ accumulator [ itemId ] = conservativeMapItem (
96+ state ?. [ context ] ?. [ itemId ] ,
97+ value
98+ ) ;
99+ return accumulator ;
100+ } , { } ) ,
101+ } ,
88102 } ;
103+ }
89104 case 'REMOVE_ITEMS' :
90- const newState = omit ( state , action . itemIds ) ;
91- return newState ;
105+ return mapValues ( state , ( contextState ) =>
106+ omit ( contextState , action . itemIds )
107+ ) ;
92108 }
93109 return state ;
94110}
@@ -106,32 +122,45 @@ function items( state = {}, action ) {
106122 * @return {Object<string,boolean> } Next state.
107123 */
108124export function itemIsComplete ( state = { } , action ) {
109- const { type, query, key = DEFAULT_ENTITY_KEY } = action ;
110- if ( type !== 'RECEIVE_ITEMS' ) {
111- return state ;
125+ switch ( action . type ) {
126+ case 'RECEIVE_ITEMS' : {
127+ const context = getContextFromAction ( action ) ;
128+ const { query, key = DEFAULT_ENTITY_KEY } = action ;
129+
130+ // An item is considered complete if it is received without an associated
131+ // fields query. Ideally, this would be implemented in such a way where the
132+ // complete aggregate of all fields would satisfy completeness. Since the
133+ // fields are not consistent across all entity types, this would require
134+ // introspection on the REST schema for each entity to know which fields
135+ // compose a complete item for that entity.
136+ const queryParts = query ? getQueryParts ( query ) : { } ;
137+ const isCompleteQuery =
138+ ! query || ! Array . isArray ( queryParts . fields ) ;
139+
140+ return {
141+ ...state ,
142+ [ context ] : {
143+ ...state [ context ] ,
144+ ...action . items . reduce ( ( result , item ) => {
145+ const itemId = item [ key ] ;
146+
147+ // Defer to completeness if already assigned. Technically the
148+ // data may be outdated if receiving items for a field subset.
149+ result [ itemId ] =
150+ state ?. [ context ] ?. [ itemId ] || isCompleteQuery ;
151+
152+ return result ;
153+ } , { } ) ,
154+ } ,
155+ } ;
156+ }
157+ case 'REMOVE_ITEMS' :
158+ return mapValues ( state , ( contextState ) =>
159+ omit ( contextState , action . itemIds )
160+ ) ;
112161 }
113162
114- // An item is considered complete if it is received without an associated
115- // fields query. Ideally, this would be implemented in such a way where the
116- // complete aggregate of all fields would satisfy completeness. Since the
117- // fields are not consistent across all entity types, this would require
118- // introspection on the REST schema for each entity to know which fields
119- // compose a complete item for that entity.
120- const isCompleteQuery =
121- ! query || ! Array . isArray ( getQueryParts ( query ) . fields ) ;
122-
123- return {
124- ...state ,
125- ...action . items . reduce ( ( result , item ) => {
126- const itemId = item [ key ] ;
127-
128- // Defer to completeness if already assigned. Technically the
129- // data may be outdated if receiving items for a field subset.
130- result [ itemId ] = state [ itemId ] || isCompleteQuery ;
131-
132- return result ;
133- } , { } ) ,
134- } ;
163+ return state ;
135164}
136165
137166/**
@@ -163,6 +192,8 @@ const receiveQueries = flowRight( [
163192 return action ;
164193 } ) ,
165194
195+ onSubKey ( 'context' ) ,
196+
166197 // Queries shape is shared, but keyed by query `stableKey` part. Original
167198 // reducer tracks only a single query object.
168199 onSubKey ( 'stableKey' ) ,
@@ -194,17 +225,18 @@ const queries = ( state = {}, action ) => {
194225 case 'RECEIVE_ITEMS' :
195226 return receiveQueries ( state , action ) ;
196227 case 'REMOVE_ITEMS' :
197- const newState = { ...state } ;
198228 const removedItems = action . itemIds . reduce ( ( result , itemId ) => {
199229 result [ itemId ] = true ;
200230 return result ;
201231 } , { } ) ;
202- forEach ( newState , ( queryItems , key ) => {
203- newState [ key ] = filter ( queryItems , ( queryId ) => {
204- return ! removedItems [ queryId ] ;
232+
233+ return mapValues ( state , ( contextQueries ) => {
234+ return mapValues ( contextQueries , ( queryItems ) => {
235+ return filter ( queryItems , ( queryId ) => {
236+ return ! removedItems [ queryId ] ;
237+ } ) ;
205238 } ) ;
206239 } ) ;
207- return newState ;
208240 default :
209241 return state ;
210242 }
0 commit comments