@blaze-cms/react-page-builder 0.124.0-alpha.13 → 0.124.0-alpha.18

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/lib/application/query/index.js +8 -2
  3. package/lib/application/query/index.js.map +1 -1
  4. package/lib/components/Card/CardFactory.js +6 -3
  5. package/lib/components/Card/CardFactory.js.map +1 -1
  6. package/lib/components/ItemListButton/ItemListButton.js +171 -0
  7. package/lib/components/ItemListButton/ItemListButton.js.map +1 -0
  8. package/lib/components/ItemListButton/index.js +16 -0
  9. package/lib/components/ItemListButton/index.js.map +1 -0
  10. package/lib/components/ItemListCounter/ItemListCounter.js +114 -0
  11. package/lib/components/ItemListCounter/ItemListCounter.js.map +1 -0
  12. package/lib/components/ItemListCounter/index.js +16 -0
  13. package/lib/components/ItemListCounter/index.js.map +1 -0
  14. package/lib/components/List/ListBuilder.js +12 -6
  15. package/lib/components/List/ListBuilder.js.map +1 -1
  16. package/lib/components/List/ListFactory.js +32 -7
  17. package/lib/components/List/ListFactory.js.map +1 -1
  18. package/lib/components/index.js +10 -0
  19. package/lib/components/index.js.map +1 -1
  20. package/lib/constants/index.js +4 -2
  21. package/lib/constants/index.js.map +1 -1
  22. package/lib/helpers/build-raw-query.js.map +1 -1
  23. package/lib/helpers/get-item-list-data.js +17 -0
  24. package/lib/helpers/get-item-list-data.js.map +1 -0
  25. package/lib/helpers/get-item-list-id.js +23 -0
  26. package/lib/helpers/get-item-list-id.js.map +1 -0
  27. package/lib/helpers/get-item-list-ids.js +28 -0
  28. package/lib/helpers/get-item-list-ids.js.map +1 -0
  29. package/lib/helpers/index.js +24 -0
  30. package/lib/helpers/index.js.map +1 -1
  31. package/lib-es/application/query/index.js +44 -1
  32. package/lib-es/application/query/index.js.map +1 -1
  33. package/lib-es/components/Card/CardFactory.js +7 -4
  34. package/lib-es/components/Card/CardFactory.js.map +1 -1
  35. package/lib-es/components/ItemListButton/ItemListButton.js +118 -0
  36. package/lib-es/components/ItemListButton/ItemListButton.js.map +1 -0
  37. package/lib-es/components/ItemListButton/index.js +3 -0
  38. package/lib-es/components/ItemListButton/index.js.map +1 -0
  39. package/lib-es/components/ItemListCounter/ItemListCounter.js +67 -0
  40. package/lib-es/components/ItemListCounter/ItemListCounter.js.map +1 -0
  41. package/lib-es/components/ItemListCounter/index.js +3 -0
  42. package/lib-es/components/ItemListCounter/index.js.map +1 -0
  43. package/lib-es/components/List/ListBuilder.js +12 -6
  44. package/lib-es/components/List/ListBuilder.js.map +1 -1
  45. package/lib-es/components/List/ListFactory.js +33 -9
  46. package/lib-es/components/List/ListFactory.js.map +1 -1
  47. package/lib-es/components/index.js +6 -0
  48. package/lib-es/components/index.js.map +1 -1
  49. package/lib-es/constants/index.js +2 -1
  50. package/lib-es/constants/index.js.map +1 -1
  51. package/lib-es/helpers/build-raw-query.js.map +1 -1
  52. package/lib-es/helpers/get-item-list-data.js +7 -0
  53. package/lib-es/helpers/get-item-list-data.js.map +1 -0
  54. package/lib-es/helpers/get-item-list-id.js +11 -0
  55. package/lib-es/helpers/get-item-list-id.js.map +1 -0
  56. package/lib-es/helpers/get-item-list-ids.js +13 -0
  57. package/lib-es/helpers/get-item-list-ids.js.map +1 -0
  58. package/lib-es/helpers/index.js +3 -0
  59. package/lib-es/helpers/index.js.map +1 -1
  60. package/package.json +2 -2
  61. package/src/application/query/index.js +50 -1
  62. package/src/components/Card/CardFactory.js +5 -3
  63. package/src/components/ItemListButton/ItemListButton.js +107 -0
  64. package/src/components/ItemListButton/index.js +3 -0
  65. package/src/components/ItemListCounter/ItemListCounter.js +68 -0
  66. package/src/components/ItemListCounter/index.js +3 -0
  67. package/src/components/List/ListBuilder.js +10 -5
  68. package/src/components/List/ListFactory.js +50 -12
  69. package/src/components/index.js +6 -0
  70. package/src/constants/index.js +4 -1
  71. package/src/helpers/build-raw-query.js +1 -0
  72. package/src/helpers/get-item-list-data.js +6 -0
  73. package/src/helpers/get-item-list-id.js +11 -0
  74. package/src/helpers/get-item-list-ids.js +10 -0
  75. package/src/helpers/index.js +3 -0
  76. package/tests/unit/src/components/__snapshots__/index.test.js.snap +8 -0
  77. package/tests/unit/src/helpers/get-item-list-data.test.js +28 -0
  78. package/tests/unit/src/helpers/get-item-list-id.test.js +20 -0
  79. package/tests/unit/src/helpers/get-item-list-ids.test.js +19 -0
@@ -0,0 +1,68 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useRouter } from 'next/router';
4
+ import { useQuery } from '@apollo/client';
5
+ import { BsBookmarkStarFill, BsBookmarkStar } from 'react-icons/bs';
6
+ import { getItemList } from '../../application/query';
7
+ import { getItemListData, getItemListId } from '../../helpers';
8
+
9
+ const ItemListCounter = ({ listName, modifier, url }) => {
10
+ const router = useRouter();
11
+ const idFromStorage = getItemListId(listName);
12
+ const [listId, setListId] = useState(idFromStorage);
13
+
14
+ useEffect(
15
+ () => {
16
+ const storageEventHandler = () => {
17
+ const newId = getItemListId(listName);
18
+ setListId(newId);
19
+ };
20
+
21
+ window.addEventListener('storage', storageEventHandler);
22
+
23
+ return () => {
24
+ window.removeEventListener('storage', storageEventHandler);
25
+ };
26
+ },
27
+ [listName]
28
+ );
29
+
30
+ const { data, error, loading } = useQuery(getItemList, {
31
+ variables: { id: listId },
32
+ skip: !listId
33
+ });
34
+
35
+ if (loading) return '';
36
+ if (error) return error.message;
37
+
38
+ const listItems = getItemListData(data);
39
+ const listLength = listItems.length;
40
+ const CounterIcon = listLength ? BsBookmarkStarFill : BsBookmarkStar;
41
+
42
+ const handleClick = () => router.push('/Resolver', `${url}?itemListId=${listId}`);
43
+
44
+ return (
45
+ <div
46
+ role="button"
47
+ type="button"
48
+ className={`item-list-counter ${modifier}`}
49
+ onClick={handleClick}>
50
+ <CounterIcon />
51
+ <span className="item-list-counter__badge">{listLength}</span>
52
+ </div>
53
+ );
54
+ };
55
+
56
+ ItemListCounter.propTypes = {
57
+ url: PropTypes.string,
58
+ listName: PropTypes.string,
59
+ modifier: PropTypes.string
60
+ };
61
+
62
+ ItemListCounter.defaultProps = {
63
+ url: '',
64
+ listName: '',
65
+ modifier: ''
66
+ };
67
+
68
+ export default ItemListCounter;
@@ -0,0 +1,3 @@
1
+ import ItemListCounter from './ItemListCounter';
2
+
3
+ export default ItemListCounter;
@@ -52,13 +52,15 @@ const ListBuilder = props => {
52
52
  requiredSchema,
53
53
  searchValues,
54
54
  azFilter,
55
- sortProperties
55
+ sortProperties,
56
+ itemListIds
56
57
  } = props;
57
58
  const isInfinite = paginationType === INFINITE;
58
59
  const listComponent = getListComponent(isCard, paginationType);
59
60
  const propsToDisplayValues = checkPropsToUse(propsToDisplay);
60
61
  const entityFields = buildPropsQuery(entitySchema, propsToDisplayValues, props) || '';
61
- const limitToUse = limit || itemsToDisplay.length;
62
+ const itemsToDisplayToUse = itemListIds || itemsToDisplay;
63
+ const limitToUse = limit || itemsToDisplayToUse.length;
62
64
  const shouldApplyDefaultSort = !sortProperties || !sortProperties.length;
63
65
  const itemsPerPageToUse = getItemsPerPageToUse(itemsPerPage, limitToUse);
64
66
  const initialOffset = getCurrentOffset(offset, itemsPerPageToUse, paginationIndex, limitToUse);
@@ -94,7 +96,7 @@ const ListBuilder = props => {
94
96
  stringProps
95
97
  },
96
98
  itemId,
97
- itemsToDisplay,
99
+ itemsToDisplayToUse,
98
100
  shouldApplyDefaultSort,
99
101
  { shouldReturnAggs: true, isAZ }
100
102
  );
@@ -137,7 +139,7 @@ const ListBuilder = props => {
137
139
  azFilter
138
140
  },
139
141
  itemId,
140
- itemsToDisplay,
142
+ itemsToDisplayToUse,
141
143
  shouldApplyDefaultSort,
142
144
  { shouldReturnAggs: false, isAZ }
143
145
  );
@@ -172,6 +174,7 @@ const ListBuilder = props => {
172
174
  isAZ={isAZ}
173
175
  azFilter={azFilter}
174
176
  {...props}
177
+ itemsToDisplay={itemsToDisplayToUse}
175
178
  />
176
179
  );
177
180
  };
@@ -202,12 +205,14 @@ ListBuilder.propTypes = {
202
205
  filterOperator: PropTypes.string.isRequired,
203
206
  paginationType: PropTypes.string,
204
207
  azFilter: PropTypes.string,
205
- sortProperties: PropTypes.array
208
+ sortProperties: PropTypes.array,
209
+ itemListIds: PropTypes.array
206
210
  };
207
211
 
208
212
  ListBuilder.defaultProps = {
209
213
  entityData: {},
210
214
  itemsToDisplay: [],
215
+ itemListIds: null,
211
216
  limit: 0,
212
217
  omitWrappers: false,
213
218
  offset: 0,
@@ -4,7 +4,11 @@ import { parseUrl } from 'query-string';
4
4
  import PropTypes from 'prop-types';
5
5
  import { useRouter } from 'next/router';
6
6
  import { MainContext } from '@blaze-cms/nextjs-components';
7
- import { getSingleEntitySchema, generateSingleItemQuery } from '../../application/query';
7
+ import {
8
+ getSingleEntitySchema,
9
+ generateSingleItemQuery,
10
+ getItemList
11
+ } from '../../application/query';
8
12
  import ListBuilder from './ListBuilder';
9
13
  import { AZ_LIST_TYPE } from './constants';
10
14
  import { getAzQueryFilter, getSortProps } from './helpers';
@@ -19,7 +23,9 @@ import {
19
23
  buildSearchValuesText,
20
24
  getQueryFilters,
21
25
  getInheritedFilters,
22
- getQueryProps
26
+ getQueryProps,
27
+ getItemListId,
28
+ getItemListIds
23
29
  } from '../../helpers';
24
30
  import { useGetEntitySchemasAsObj } from '../../hooks';
25
31
  import { AND_OPERATOR, TEXT_SEARCH, ID, AND, FULL } from '../../constants';
@@ -37,16 +43,18 @@ const ListFactory = props => {
37
43
  sort: defaultSort,
38
44
  searchFilter,
39
45
  operator: filterOperator,
40
- sortProperties
46
+ sortProperties,
47
+ itemListName
41
48
  } = props;
42
-
43
49
  const { isPreview } = useContext(MainContext);
44
50
  const router = useRouter();
45
51
  const { asPath } = router;
46
52
  const parsedQuery = asPath.replace(/%5D/g, ']').replace(/%5B/g, '[');
47
- const { query, url, query: { sort: querySort, sortby: querySortBy } = {} } = parseUrl(
48
- parsedQuery
49
- );
53
+ const {
54
+ query,
55
+ url,
56
+ query: { sort: querySort, sortby: querySortBy, itemListId: queryItemListId } = {}
57
+ } = parseUrl(parsedQuery);
50
58
  const { sortbyFilters, updatedSortProperties } = getSortProps({
51
59
  querySort,
52
60
  sortProperties,
@@ -55,6 +63,7 @@ const ListFactory = props => {
55
63
  defaultSortBy
56
64
  });
57
65
 
66
+ const itemListId = getItemListId(itemListName, queryItemListId);
58
67
  const { itemEntity, itemId } = parent;
59
68
  const itemEntityUpdated = getUnpublishedEntityName(itemEntity);
60
69
  const paginationIndex = getPaginationIndex(query, name);
@@ -98,13 +107,39 @@ const ListFactory = props => {
98
107
  variables: { id: itemId },
99
108
  skip: schemasLoading || (!inheritedFilters.length && queryProps === ID)
100
109
  });
101
- const errorsToCheck = [schemaError, schemasError, requiredSchemaError, itemQueryError];
110
+
111
+ const { data: itemListData = {}, error: itemListError, loading: itemListLoading } = useQuery(
112
+ getItemList,
113
+ {
114
+ variables: { id: itemListId },
115
+ skip: !itemListId
116
+ }
117
+ );
118
+ if (!queryItemListId && itemListId) {
119
+ router.push('/Resolver', `${asPath}?itemListId=${itemListId}`, { shallow: true });
120
+ }
121
+
122
+ const errorsToCheck = [
123
+ schemaError,
124
+ schemasError,
125
+ requiredSchemaError,
126
+ itemQueryError,
127
+ itemListError
128
+ ];
102
129
  const { hasErr, errMsg } = checkForError(errorsToCheck);
103
130
 
104
- if (requiredSchemaLoading || schemasLoading || schemaLoading || itemQueryLoading) return '';
131
+ if (
132
+ requiredSchemaLoading ||
133
+ schemasLoading ||
134
+ schemaLoading ||
135
+ itemQueryLoading ||
136
+ itemListLoading
137
+ )
138
+ return '';
105
139
  if (hasErr) return errMsg;
106
140
  if (!entitySchema) return null;
107
141
 
142
+ const itemListIds = getItemListIds(itemListData);
108
143
  const isCard = type !== FULL;
109
144
  const isAZ = type === AZ_LIST_TYPE;
110
145
  const genericProps = getGenericProps(props);
@@ -147,7 +182,8 @@ const ListFactory = props => {
147
182
  paginationIndex,
148
183
  entityData,
149
184
  inheritedFilters,
150
- filterOperator
185
+ filterOperator,
186
+ itemListIds
151
187
  };
152
188
 
153
189
  return <ListBuilder {...listProps} />;
@@ -165,7 +201,8 @@ ListFactory.propTypes = {
165
201
  sortby: PropTypes.array,
166
202
  sort: PropTypes.string,
167
203
  searchFilter: PropTypes.object,
168
- sortProperties: PropTypes.array
204
+ sortProperties: PropTypes.array,
205
+ itemListName: PropTypes.string
169
206
  };
170
207
 
171
208
  ListFactory.defaultProps = {
@@ -177,7 +214,8 @@ ListFactory.defaultProps = {
177
214
  sortProperties: [],
178
215
  sort: '',
179
216
  operator: AND,
180
- searchFilter: {}
217
+ searchFilter: {},
218
+ itemListName: ''
181
219
  };
182
220
 
183
221
  export default ListFactory;
@@ -42,5 +42,11 @@ export default {
42
42
  import(/* webpackChunkName: "blazePbPasswordResetRequest" */ './PasswordResetRequest')
43
43
  ),
44
44
  breadcrumb: dynamic(() => import(/* webpackChunkName: "blazePbBreadcrumb" */ './Breadcrumb')),
45
+ itemlistbutton: dynamic(() =>
46
+ import(/* webpackChunkName: "blazePbItemListButton" */ './ItemListButton')
47
+ ),
48
+ itemlistcounter: dynamic(() =>
49
+ import(/* webpackChunkName: "blazePbItemListCounter" */ './ItemListCounter')
50
+ ),
45
51
  backtotop: dynamic(() => import(/* webpackChunkName: "blazePbBackToTop" */ './BackToTop'))
46
52
  };
@@ -209,6 +209,8 @@ const DATA_SUMMARY_EMAIL_REGEX = /^([a-z0-9_\.\+-]+)@([\da-z\.-]+)\.([a-z\.]{2,6
209
209
  const DATA_SUMMARY_URL_REGEX = /(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/;
210
210
  const DATA_SUMMARY_TEL_REGEX = /^\+{0,1}[0-9\(\)\.\- \/]{7,}$/; // note: very loose phone number match not for validation
211
211
 
212
+ const LIST_ITEM_LOCAL_KEY = 'blaze_item_list_';
213
+
212
214
  export {
213
215
  BANNER_LOADING,
214
216
  BANNER_EMPTY,
@@ -320,5 +322,6 @@ export {
320
322
  TARGET_BLANK,
321
323
  DATA_SUMMARY_EMAIL_REGEX,
322
324
  DATA_SUMMARY_URL_REGEX,
323
- DATA_SUMMARY_TEL_REGEX
325
+ DATA_SUMMARY_TEL_REGEX,
326
+ LIST_ITEM_LOCAL_KEY
324
327
  };
@@ -62,6 +62,7 @@ const buildRawQuery = (
62
62
 
63
63
  if (itemsToDisplay && itemsToDisplay.length) {
64
64
  const itemsToDisplayIds = getItemsToDisplayIds(itemsToDisplay);
65
+
65
66
  query.bool.must.push({ ids: { values: itemsToDisplayIds } });
66
67
  if (shouldApplySort) {
67
68
  return {
@@ -0,0 +1,6 @@
1
+ const getItemListData = data => {
2
+ if (data && data.getItemList && data.getItemList.listItems) return data.getItemList.listItems;
3
+ return [];
4
+ };
5
+
6
+ export default getItemListData;
@@ -0,0 +1,11 @@
1
+ import { LIST_ITEM_LOCAL_KEY } from '../constants';
2
+
3
+ const getItemListId = (listName, queryId) => {
4
+ if (queryId) return queryId;
5
+ if (!listName || typeof localStorage === 'undefined') return '';
6
+
7
+ const localListName = `${LIST_ITEM_LOCAL_KEY}${listName}`;
8
+ return localStorage.getItem(localListName) || '';
9
+ };
10
+
11
+ export default getItemListId;
@@ -0,0 +1,10 @@
1
+ import getItemListData from './get-item-list-data';
2
+
3
+ const getItemListIds = data => {
4
+ const itemListElements = getItemListData(data);
5
+ return itemListElements.length
6
+ ? itemListElements.map(({ itemId }) => ({ displayItems: [itemId] }))
7
+ : null;
8
+ };
9
+
10
+ export default getItemListIds;
@@ -51,3 +51,6 @@ export { default as getParsedPropValues } from './get-parsed-prop-values';
51
51
  export { default as getSanitizedPropValues } from './get-sanitized-prop-values';
52
52
  export { default as appendImages } from './append-images';
53
53
  export { default as parseTextBlock } from './parse-TextBlock';
54
+ export { default as getItemListId } from './get-item-list-id';
55
+ export { default as getItemListIds } from './get-item-list-ids';
56
+ export { default as getItemListData } from './get-item-list-data';
@@ -46,6 +46,14 @@ Object {
46
46
  "$$typeof": Symbol(react.forward_ref),
47
47
  "render": [Function],
48
48
  },
49
+ "itemlistbutton": Object {
50
+ "$$typeof": Symbol(react.forward_ref),
51
+ "render": [Function],
52
+ },
53
+ "itemlistcounter": Object {
54
+ "$$typeof": Symbol(react.forward_ref),
55
+ "render": [Function],
56
+ },
49
57
  "list": Object {
50
58
  "$$typeof": Symbol(react.forward_ref),
51
59
  "render": [Function],
@@ -0,0 +1,28 @@
1
+ import '@testing-library/jest-dom/extend-expect';
2
+ import getItemListData from '../../../../src/helpers/get-item-list-data';
3
+
4
+ describe('getItemListData helper', () => {
5
+ const noData = getItemListData();
6
+ const noGetItemList = getItemListData({});
7
+ const noListItems = getItemListData({ getItemList: {} });
8
+ const withCorrectData = getItemListData({
9
+ getItemList: { listItems: ['one item', 'two items'] }
10
+ });
11
+
12
+ it('should always return an array', () => {
13
+ expect(Array.isArray(noData)).toBeTruthy();
14
+ expect(Array.isArray(noGetItemList)).toBeTruthy();
15
+ expect(Array.isArray(noListItems)).toBeTruthy();
16
+ expect(Array.isArray(withCorrectData)).toBeTruthy();
17
+ });
18
+
19
+ it('should return an empty array if data passed doesnt have expected props', () => {
20
+ expect(noData).toEqual([]);
21
+ expect(noGetItemList).toEqual([]);
22
+ expect(noListItems).toEqual([]);
23
+ });
24
+
25
+ it('should return listData otherwise', () => {
26
+ expect(withCorrectData).toEqual(['one item', 'two items']);
27
+ });
28
+ });
@@ -0,0 +1,20 @@
1
+ import '@testing-library/jest-dom/extend-expect';
2
+ import getitemListId from '../../../../src/helpers/get-item-list-id';
3
+
4
+ describe('getitemListId helper', () => {
5
+ const noValues = getitemListId();
6
+ const noListId = getitemListId('listName');
7
+ const noListName = getitemListId(null, '123asd');
8
+
9
+ it('should return empty string if no values are passed', () => {
10
+ expect(noValues).toEqual('');
11
+ });
12
+
13
+ it('should return listId if passed', () => {
14
+ expect(noListName).toEqual('123asd');
15
+ });
16
+
17
+ it('should return local value if no id is passed but name is', () => {
18
+ expect(noListId).toEqual('');
19
+ });
20
+ });
@@ -0,0 +1,19 @@
1
+ import '@testing-library/jest-dom/extend-expect';
2
+ import getitemListIds from '../../../../src/helpers/get-item-list-ids';
3
+
4
+ describe('getitemListIds helper', () => {
5
+ const noData = getitemListIds();
6
+ const emptyData = getitemListIds({});
7
+ const withData = getitemListIds({
8
+ getItemList: { listItems: [{ itemId: '123' }, { itemId: '456' }] }
9
+ });
10
+
11
+ it('should return null if no valid data is passed', () => {
12
+ expect(noData).toEqual(null);
13
+ expect(emptyData).toEqual(null);
14
+ });
15
+
16
+ it('should return itemsToDisplay formatted ids', () => {
17
+ expect(withData).toEqual([{ displayItems: ['123'] }, { displayItems: ['456'] }]);
18
+ });
19
+ });