@shopgate/pwa-common-commerce 7.30.1-beta.4 → 7.30.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ import { RECEIVE_CATEGORIES } from "../constants";
2
+
3
+ /**
4
+ * Action to put multiple categories into the redux store with a single dispatch.
5
+ * @param {Object[]} categories The received categories.
6
+ * @return {Object} The RECEIVE_CATEGORIES action.
7
+ */
8
+ const receiveCategories = categories => ({
9
+ type: RECEIVE_CATEGORIES,
10
+ categories,
11
+ products: []
12
+ });
13
+ export default receiveCategories;
@@ -11,6 +11,7 @@ export const RECEIVE_ROOT_CATEGORIES = 'RECEIVE_ROOT_CATEGORIES';
11
11
  export const ERROR_ROOT_CATEGORIES = 'ERROR_ROOT_CATEGORIES';
12
12
  export const REQUEST_CATEGORY = 'REQUEST_CATEGORY';
13
13
  export const RECEIVE_CATEGORY = 'RECEIVE_CATEGORY';
14
+ export const RECEIVE_CATEGORIES = 'RECEIVE_CATEGORIES';
14
15
  export const ERROR_CATEGORY = 'ERROR_CATEGORY';
15
16
  export const REQUEST_CATEGORY_CHILDREN = 'REQUEST_CATEGORY_CHILDREN';
16
17
  export const RECEIVE_CATEGORY_CHILDREN = 'RECEIVE_CATEGORY_CHILDREN';
@@ -1,69 +1,96 @@
1
+ import { produce } from 'immer';
1
2
  import { ENOTFOUND } from '@shopgate/pwa-core/constants/Pipeline';
2
- import { CATEGORY_LIFETIME, RECEIVE_ROOT_CATEGORIES, REQUEST_CATEGORY, RECEIVE_CATEGORY, RECEIVE_CATEGORY_CHILDREN, ERROR_CATEGORY } from "../constants";
3
+ import { CATEGORY_LIFETIME, RECEIVE_ROOT_CATEGORIES, REQUEST_CATEGORY, RECEIVE_CATEGORY, RECEIVE_CATEGORIES, RECEIVE_CATEGORY_CHILDREN, ERROR_CATEGORY } from "../constants";
3
4
  import handleCategoryCollection from "./helpers/handleCategoryCollection";
4
5
 
6
+ /**
7
+ * Inserts a category into the draft state.
8
+ * @param {Object} draft The draft state to modify.
9
+ * @param {string} categoryId The ID of the category to insert.
10
+ * @param {Object} categoryData The data of the category to insert.
11
+ * @param {Array} categoryChildren The children of the category to insert.
12
+ */
13
+ const insertCategory = (draft, categoryId, categoryData, categoryChildren) => {
14
+ const entry = draft[categoryId] ?? (draft[categoryId] = {});
15
+ Object.assign(entry, categoryData, {
16
+ expires: Date.now() + CATEGORY_LIFETIME,
17
+ isFetching: false
18
+ });
19
+ const collected = handleCategoryCollection(categoryChildren);
20
+ if (collected && typeof collected === 'object') {
21
+ Object.assign(draft, collected);
22
+ }
23
+ };
24
+
5
25
  /**
6
26
  * Stores categories by their ID.
7
27
  * @param {Object} [state={}] The current state.
8
28
  * @param {Object} action The action object.
9
29
  * @return {Object} The new state.
10
30
  */
11
- const categoriesById = (state = {}, action = {}) => {
31
+ const categoriesById = (state = {}, action = {}) => produce(state, draft => {
12
32
  switch (action.type) {
13
33
  case REQUEST_CATEGORY:
14
- return {
15
- ...state,
16
- [action.categoryId]: {
17
- ...state[action.categoryId],
18
- expires: 0,
19
- isFetching: true
20
- }
21
- };
34
+ {
35
+ const entry = draft[action.categoryId] ?? (draft[action.categoryId] = {});
36
+ entry.expires = 0;
37
+ entry.isFetching = true;
38
+ break;
39
+ }
22
40
  case RECEIVE_CATEGORY:
23
41
  {
42
+ // Strip children from category data. They are handled by the childrenByCategoryId reducer.
24
43
  const {
25
44
  children: ignore,
26
45
  ...categoryData
27
- } = action.categoryData;
28
- return {
29
- ...state,
30
- [action.categoryId]: {
31
- ...state[action.categoryId],
32
- ...categoryData,
33
- expires: Date.now() + CATEGORY_LIFETIME,
34
- isFetching: false
35
- },
36
- ...handleCategoryCollection(action.categoryChildren)
37
- };
46
+ } = action.categoryData || {};
47
+ insertCategory(draft, action.categoryId, categoryData, action.categoryChildren);
48
+ break;
49
+ }
50
+ case RECEIVE_CATEGORIES:
51
+ {
52
+ const categories = action.categories || [];
53
+ categories.forEach(category => {
54
+ const {
55
+ children: ignore,
56
+ ...categoryData
57
+ } = category || {};
58
+ insertCategory(draft, category.id, categoryData, category.children);
59
+ });
60
+ break;
38
61
  }
39
62
  case RECEIVE_ROOT_CATEGORIES:
40
- return {
41
- ...state,
42
- ...handleCategoryCollection(action.categories)
43
- };
63
+ {
64
+ const collected = handleCategoryCollection(action.categories);
65
+ if (collected && typeof collected === 'object') {
66
+ Object.assign(draft, collected);
67
+ }
68
+ break;
69
+ }
44
70
  case RECEIVE_CATEGORY_CHILDREN:
45
- return {
46
- ...state,
47
- ...handleCategoryCollection(action.categoryChildren)
48
- };
49
- case ERROR_CATEGORY:
50
- if (action.errorCode === ENOTFOUND) {
51
- // Remove the temporary entry from the state when noting was found for the categoryId.
52
- const {
53
- [action.categoryId]: ignore,
54
- ...rest
55
- } = state;
56
- return rest;
71
+ {
72
+ const collected = handleCategoryCollection(action.categoryChildren);
73
+ if (collected && typeof collected === 'object') {
74
+ Object.assign(draft, collected);
75
+ }
76
+ break;
57
77
  }
58
- return {
59
- ...state,
60
- [action.categoryId]: {
61
- ...state[action.categoryId],
62
- isFetching: false
78
+ case ERROR_CATEGORY:
79
+ {
80
+ if (action.errorCode === ENOTFOUND) {
81
+ // Remove the temporary entry from the state when nothing was found for the categoryId.
82
+ delete draft[action.categoryId];
83
+ break;
84
+ }
85
+ const entry = draft[action.categoryId];
86
+ if (!entry) {
87
+ break;
63
88
  }
64
- };
89
+ entry.isFetching = false;
90
+ break;
91
+ }
65
92
  default:
66
- return state;
93
+ break;
67
94
  }
68
- };
95
+ });
69
96
  export default categoriesById;
@@ -1,5 +1,19 @@
1
+ import { produce } from 'immer';
1
2
  import { ENOTFOUND } from '@shopgate/pwa-core/constants/Pipeline';
2
- import { CATEGORY_LIFETIME, REQUEST_CATEGORY, RECEIVE_CATEGORY, REQUEST_CATEGORY_CHILDREN, RECEIVE_CATEGORY_CHILDREN, ERROR_CATEGORY, ERROR_CATEGORY_CHILDREN } from "../constants";
3
+ import { CATEGORY_LIFETIME, REQUEST_CATEGORY, RECEIVE_CATEGORY, RECEIVE_CATEGORIES, REQUEST_CATEGORY_CHILDREN, RECEIVE_CATEGORY_CHILDREN, ERROR_CATEGORY, ERROR_CATEGORY_CHILDREN } from "../constants";
4
+
5
+ /**
6
+ * Inserts the given category children into the draft state for the given category ID.
7
+ * @param {Object} draft The draft state to modify.
8
+ * @param {string} categoryId The ID of the category to insert children for.
9
+ * @param {Array} categoryChildren The children to insert.
10
+ */
11
+ const insertChildren = (draft, categoryId, categoryChildren) => {
12
+ const entry = draft[categoryId] ?? (draft[categoryId] = {});
13
+ entry.children = categoryChildren ? categoryChildren.map(child => child.id) : null;
14
+ entry.isFetching = false;
15
+ entry.expires = Date.now() + CATEGORY_LIFETIME;
16
+ };
3
17
 
4
18
  /**
5
19
  * Stores a collection of child category IDs by their parent's category ID.
@@ -7,53 +21,48 @@ import { CATEGORY_LIFETIME, REQUEST_CATEGORY, RECEIVE_CATEGORY, REQUEST_CATEGORY
7
21
  * @param {Object} action The action object.
8
22
  * @returns {Object} The new state.
9
23
  */
10
- const childrenByCategoryId = (state = {}, action = {}) => {
24
+ const childrenByCategoryId = (state = {}, action = {}) => produce(state, draft => {
11
25
  switch (action.type) {
12
26
  case REQUEST_CATEGORY:
13
27
  case REQUEST_CATEGORY_CHILDREN:
14
- return {
15
- ...state,
16
- [action.categoryId]: {
17
- ...state[action.categoryId],
18
- children: null,
19
- isFetching: true,
20
- expires: 0
21
- }
22
- };
28
+ {
29
+ const entry = draft[action.categoryId] ?? (draft[action.categoryId] = {});
30
+ entry.children = null;
31
+ entry.isFetching = true;
32
+ entry.expires = 0;
33
+ break;
34
+ }
23
35
  case RECEIVE_CATEGORY:
24
36
  case RECEIVE_CATEGORY_CHILDREN:
25
37
  {
26
- const actionChildren = action.categoryChildren;
27
- return {
28
- ...state,
29
- [action.categoryId]: {
30
- ...state[action.categoryId],
31
- // If it has children, append them.
32
- children: actionChildren ? action.categoryChildren.map(child => child.id) : null,
33
- isFetching: false,
34
- expires: Date.now() + CATEGORY_LIFETIME
35
- }
36
- };
38
+ insertChildren(draft, action.categoryId, action.categoryChildren);
39
+ break;
40
+ }
41
+ case RECEIVE_CATEGORIES:
42
+ {
43
+ const categories = action.categories || [];
44
+ categories.forEach(category => {
45
+ insertChildren(draft, category.id, category.children);
46
+ });
47
+ break;
37
48
  }
38
49
  case ERROR_CATEGORY:
39
50
  case ERROR_CATEGORY_CHILDREN:
40
- if (action.errorCode === ENOTFOUND) {
41
- // Remove the temporary entry from the state when noting was found for the categoryId.
42
- const {
43
- [action.categoryId]: ignore,
44
- ...rest
45
- } = state;
46
- return rest;
47
- }
48
- return {
49
- ...state,
50
- [action.categoryId]: {
51
- ...state[action.categoryId],
52
- isFetching: false
51
+ {
52
+ if (action.errorCode === ENOTFOUND) {
53
+ // Remove the temporary entry from the state when nothing was found for the categoryId.
54
+ delete draft[action.categoryId];
55
+ break;
53
56
  }
54
- };
57
+ const entry = draft[action.categoryId];
58
+ if (!entry) {
59
+ break;
60
+ }
61
+ entry.isFetching = false;
62
+ break;
63
+ }
55
64
  default:
56
- return state;
65
+ break;
57
66
  }
58
- };
67
+ });
59
68
  export default childrenByCategoryId;
@@ -1,3 +1,4 @@
1
+ import { produce } from 'immer';
1
2
  import { CATEGORY_LIFETIME, REQUEST_ROOT_CATEGORIES, RECEIVE_ROOT_CATEGORIES, ERROR_ROOT_CATEGORIES } from "../constants";
2
3
  import handleReceivedCategories from "./helpers/handleReceivedCategories";
3
4
 
@@ -5,32 +6,26 @@ import handleReceivedCategories from "./helpers/handleReceivedCategories";
5
6
  * Stores a collection of category IDs that represent the
6
7
  * highest level of categories with no parent.
7
8
  * @param {Object} [state={}] The current application state.
8
- * @param {Object} action The action object.
9
+ * @param {Object} [action={}] The action object.
9
10
  * @return {Object} The store data.
10
11
  */
11
- const rootCategories = (state = {}, action = {}) => {
12
+ const rootCategories = (state = {}, action = {}) => produce(state, draft => {
12
13
  switch (action.type) {
13
14
  case REQUEST_ROOT_CATEGORIES:
14
- return {
15
- ...state,
16
- categories: null,
17
- expires: 0,
18
- isFetching: true
19
- };
15
+ draft.categories = null;
16
+ draft.expires = 0;
17
+ draft.isFetching = true;
18
+ break;
20
19
  case RECEIVE_ROOT_CATEGORIES:
21
- return {
22
- ...state,
23
- categories: handleReceivedCategories(action.categories),
24
- expires: Date.now() + CATEGORY_LIFETIME,
25
- isFetching: false
26
- };
20
+ draft.categories = handleReceivedCategories(action.categories);
21
+ draft.expires = Date.now() + CATEGORY_LIFETIME;
22
+ draft.isFetching = false;
23
+ break;
27
24
  case ERROR_ROOT_CATEGORIES:
28
- return {
29
- ...state,
30
- isFetching: false
31
- };
25
+ draft.isFetching = false;
26
+ break;
32
27
  default:
33
- return state;
28
+ break;
34
29
  }
35
- };
30
+ });
36
31
  export default rootCategories;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/pwa-common-commerce",
3
- "version": "7.30.1-beta.4",
3
+ "version": "7.30.2-beta.1",
4
4
  "description": "Commerce library for the Shopgate Connect PWA.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Shopgate <support@shopgate.com>",
@@ -15,12 +15,13 @@
15
15
  "connect"
16
16
  ],
17
17
  "dependencies": {
18
+ "immer": "^11.1.3",
18
19
  "react-cookie": "^4.0.3",
19
20
  "reselect": "^4.1.8"
20
21
  },
21
22
  "devDependencies": {
22
- "@shopgate/pwa-common": "7.30.1-beta.4",
23
- "@shopgate/pwa-core": "7.30.1-beta.4",
23
+ "@shopgate/pwa-common": "7.30.2-beta.1",
24
+ "@shopgate/pwa-core": "7.30.2-beta.1",
24
25
  "lodash": "^4.17.23",
25
26
  "react": "^17.0.2",
26
27
  "react-dom": "^17.0.2"