@blaze-cms/react-page-builder 0.124.0-alpha.14 → 0.124.0-alpha.19

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 (52) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/lib/components/Card/CardContainer.js +2 -5
  3. package/lib/components/Card/CardContainer.js.map +1 -1
  4. package/lib/components/Card/CardFactory.js +2 -31
  5. package/lib/components/Card/CardFactory.js.map +1 -1
  6. package/lib/components/ItemListButton/ItemListButton.js +4 -1
  7. package/lib/components/ItemListButton/ItemListButton.js.map +1 -1
  8. package/lib/components/ItemListCounter/ItemListCounter.js +23 -5
  9. package/lib/components/ItemListCounter/ItemListCounter.js.map +1 -1
  10. package/lib/components/List/ListFactory.js +6 -0
  11. package/lib/components/List/ListFactory.js.map +1 -1
  12. package/lib/components/SearchContent/SearchContent.js +206 -0
  13. package/lib/components/SearchContent/SearchContent.js.map +1 -0
  14. package/lib/components/SearchContent/index.js +2 -299
  15. package/lib/components/SearchContent/index.js.map +1 -1
  16. package/lib/components/index.js +1 -1
  17. package/lib/components/index.js.map +1 -1
  18. package/lib/constants/index.js +1 -5
  19. package/lib/constants/index.js.map +1 -1
  20. package/lib/helpers/get-item-list-id.js +4 -1
  21. package/lib/helpers/get-item-list-id.js.map +1 -1
  22. package/lib-es/components/Card/CardContainer.js +2 -5
  23. package/lib-es/components/Card/CardContainer.js.map +1 -1
  24. package/lib-es/components/Card/CardFactory.js +4 -27
  25. package/lib-es/components/Card/CardFactory.js.map +1 -1
  26. package/lib-es/components/ItemListButton/ItemListButton.js +2 -1
  27. package/lib-es/components/ItemListButton/ItemListButton.js.map +1 -1
  28. package/lib-es/components/ItemListCounter/ItemListCounter.js +3 -3
  29. package/lib-es/components/ItemListCounter/ItemListCounter.js.map +1 -1
  30. package/lib-es/components/List/ListFactory.js +7 -0
  31. package/lib-es/components/List/ListFactory.js.map +1 -1
  32. package/lib-es/components/SearchContent/SearchContent.js +155 -0
  33. package/lib-es/components/SearchContent/SearchContent.js.map +1 -0
  34. package/lib-es/components/SearchContent/index.js +1 -203
  35. package/lib-es/components/SearchContent/index.js.map +1 -1
  36. package/lib-es/components/index.js +1 -1
  37. package/lib-es/components/index.js.map +1 -1
  38. package/lib-es/constants/index.js +1 -2
  39. package/lib-es/constants/index.js.map +1 -1
  40. package/lib-es/helpers/get-item-list-id.js +2 -1
  41. package/lib-es/helpers/get-item-list-id.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/components/Card/CardContainer.js +0 -3
  44. package/src/components/Card/CardFactory.js +4 -22
  45. package/src/components/ItemListButton/ItemListButton.js +2 -2
  46. package/src/components/ItemListCounter/ItemListCounter.js +4 -3
  47. package/src/components/List/ListFactory.js +3 -0
  48. package/src/components/SearchContent/SearchContent.js +158 -0
  49. package/src/components/SearchContent/index.js +2 -218
  50. package/src/components/index.js +1 -1
  51. package/src/constants/index.js +1 -1
  52. package/src/helpers/get-item-list-id.js +2 -1
@@ -1,34 +1,17 @@
1
1
  import React from 'react';
2
2
  import { useQuery } from '@apollo/client';
3
- import { useRouter } from 'next/router';
4
3
  import PropTypes from 'prop-types';
5
- import { parseUrl } from 'query-string';
6
- import { getSingleEntitySchema, getItemList } from '../../application/query';
4
+ import { getSingleEntitySchema } from '../../application/query';
7
5
  import CardRender from './CardRender';
8
- import {
9
- buildPropsQuery,
10
- getGenericProps,
11
- checkPropsToUse,
12
- getItemListId,
13
- getItemListIds
14
- } from '../../helpers';
6
+ import { buildPropsQuery, getGenericProps, checkPropsToUse } from '../../helpers';
15
7
  import { WITH_BANNER } from '../../constants';
16
8
 
17
9
  const CardFactory = ({ entity, propsToDisplay, itemsToDisplay, itemListName, ...cardProps }) => {
18
- const router = useRouter();
19
- const { asPath } = router;
20
- const parsedQuery = asPath.replace(/%5D/g, ']').replace(/%5B/g, '[');
21
- const { query: { itemListId: queryItemListId } = {} } = parseUrl(parsedQuery);
22
- const itemListId = getItemListId(itemListName, queryItemListId);
23
10
  const { data, error, loading } = useQuery(getSingleEntitySchema, {
24
11
  variables: { id: entity }
25
12
  });
26
- const { data: itemListData = {}, loading: itemListLoading } = useQuery(getItemList, {
27
- variables: { id: itemListId },
28
- skip: !itemListId
29
- });
30
13
 
31
- if (loading || itemListLoading) return '';
14
+ if (loading) return '';
32
15
  if (error) return error.message;
33
16
  if (!data) return null;
34
17
 
@@ -36,14 +19,13 @@ const CardFactory = ({ entity, propsToDisplay, itemsToDisplay, itemListName, ...
36
19
  const extraProps = buildPropsQuery(data, propsToDisplayValues, cardProps) || '';
37
20
  const { gridModifier, ...cardRenderProps } = getGenericProps(cardProps);
38
21
  const extraModifierForBanner = cardRenderProps.banner ? WITH_BANNER : '';
39
- const itemListIds = getItemListIds(itemListData);
40
22
 
41
23
  return (
42
24
  <CardRender
43
25
  gridModifier={`${gridModifier}${extraModifierForBanner}`}
44
26
  bannerModifier={extraModifierForBanner}
45
27
  entity={entity}
46
- itemsToDisplay={itemListIds || itemsToDisplay}
28
+ itemsToDisplay={itemsToDisplay}
47
29
  propsToDisplay={propsToDisplay}
48
30
  entityFields={extraProps}
49
31
  {...cardRenderProps}
@@ -49,7 +49,8 @@ const ItemListButton = ({ listName, parent, modifier }) => {
49
49
  } = listAddResult;
50
50
 
51
51
  if (!listId) {
52
- localStorage.setItem(LIST_ITEM_LOCAL_KEY(listName), id);
52
+ const localListName = `${LIST_ITEM_LOCAL_KEY}${listName}`;
53
+ localStorage.setItem(localListName, id);
53
54
  window.dispatchEvent(new Event('storage'));
54
55
  }
55
56
  }
@@ -75,7 +76,6 @@ const ItemListButton = ({ listName, parent, modifier }) => {
75
76
 
76
77
  const listItems = getItemListData(data);
77
78
  const isInList = !!listItems.find(({ itemId: idToCheck }) => idToCheck === itemId);
78
-
79
79
  const Icon = getIcon();
80
80
 
81
81
  return (
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from 'react';
1
+ import React, { useState, useEffect } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useRouter } from 'next/router';
4
4
  import { useQuery } from '@apollo/client';
@@ -34,6 +34,7 @@ const ItemListCounter = ({ listName, modifier, url }) => {
34
34
 
35
35
  if (loading) return '';
36
36
  if (error) return error.message;
37
+
37
38
  const listItems = getItemListData(data);
38
39
  const listLength = listItems.length;
39
40
  const CounterIcon = listLength ? BsBookmarkStarFill : BsBookmarkStar;
@@ -44,10 +45,10 @@ const ItemListCounter = ({ listName, modifier, url }) => {
44
45
  <div
45
46
  role="button"
46
47
  type="button"
47
- className={`icon-button item-list-counter ${modifier}`}
48
+ className={`item-list-counter ${modifier}`}
48
49
  onClick={handleClick}>
49
50
  <CounterIcon />
50
- <span className="icon-button__badge">{listLength}</span>
51
+ <span className="item-list-counter__badge">{listLength}</span>
51
52
  </div>
52
53
  );
53
54
  };
@@ -115,6 +115,9 @@ const ListFactory = props => {
115
115
  skip: !itemListId
116
116
  }
117
117
  );
118
+ if (!queryItemListId && itemListId) {
119
+ router.push('/Resolver', `${asPath}?itemListId=${itemListId}`, { shallow: true });
120
+ }
118
121
 
119
122
  const errorsToCheck = [
120
123
  schemaError,
@@ -0,0 +1,158 @@
1
+ import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useRouter } from 'next/router';
4
+ import { useDebounceSearch } from '@blaze-cms/plugin-search-ui';
5
+ import BlazeLink from '../BlazeLink';
6
+
7
+ const SearchContent = ({
8
+ entities,
9
+ searchInputAlignment,
10
+ searchInputWrapperMobile,
11
+ searchInputWrapperDesktop,
12
+ collapsible,
13
+ isMobile,
14
+ placeholder
15
+ }) => {
16
+ const [collapsed, setCollapsed] = useState(collapsible);
17
+ const router = useRouter();
18
+
19
+ const {
20
+ loading,
21
+ results,
22
+ searchTerm,
23
+ setSearchTerm,
24
+ setPreviousSearchTerm,
25
+ debouncedSearchTerm,
26
+ previousSearchTerm
27
+ } = useDebounceSearch({
28
+ entities,
29
+ initialSearchTerm: '',
30
+ resultKeys: 'id, name, image { url }, url'
31
+ });
32
+
33
+ console.log({
34
+ searchTerm,
35
+ loading,
36
+ results,
37
+ setSearchTerm,
38
+ setPreviousSearchTerm,
39
+ debouncedSearchTerm,
40
+ previousSearchTerm
41
+ });
42
+
43
+ const handleClick = (e, url) => {
44
+ e.preventDefault();
45
+ router.push(url);
46
+ };
47
+
48
+ const handleKeyPress = e => {
49
+ if (e.key === 'Enter' && e.target.value !== '') {
50
+ router.push(`/search?search_term=${e.target.value}`);
51
+ }
52
+ };
53
+
54
+ const SearchResults = () => {
55
+ return results.map(result => {
56
+ if (!result.url) return null;
57
+ const { id, name, image, url } = result;
58
+ return (
59
+ <BlazeLink href={url} onClick={e => handleClick(e, url)} key={id}>
60
+ <div className="search-content--results__wrapper">
61
+ {image.url ? (
62
+ <img src={image.url} alt={name} className="search-content--results__image" />
63
+ ) : null}
64
+ <span className="search-content--results__title">{name}</span>
65
+ </div>
66
+ </BlazeLink>
67
+ );
68
+ });
69
+ };
70
+
71
+ return collapsed ? (
72
+ <div className={isMobile ? searchInputWrapperMobile : searchInputWrapperDesktop}>
73
+ <div className="search-content--collapse__wrapper">
74
+ <label className="search-content--collapse__label">
75
+ <span className="search-content--collapse__icon_wrapper">
76
+ <svg className="search-content--collapse__icon" viewBox="0 0 20 20">
77
+ <path
78
+ fillRule="evenodd"
79
+ d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
80
+ clipRule="evenodd"
81
+ />
82
+ </svg>
83
+ </span>
84
+ <input
85
+ onFocus={() => setCollapsed(false)}
86
+ onChange={e => setSearchTerm(e.target.value)}
87
+ type="text"
88
+ name="search"
89
+ className="search-content--collapse__input"
90
+ />
91
+ </label>
92
+ </div>
93
+ </div>
94
+ ) : (
95
+ <>
96
+ <div className={`${isMobile ? searchInputWrapperMobile : searchInputWrapperDesktop}`}>
97
+ <div className="search-content--expanded__wrapper">
98
+ <label className="search-content--expanded__label">
99
+ <span className="search-content--expanded__icon_wrapper">
100
+ <svg className="search-content--expanded__icon" viewBox="0 0 20 20">
101
+ <path
102
+ fillRule="evenodd"
103
+ d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
104
+ clipRule="evenodd"
105
+ />
106
+ </svg>
107
+ </span>
108
+ <input
109
+ type="text"
110
+ name="search"
111
+ onChange={e => setSearchTerm(e.target.value)}
112
+ onKeyPress={handleKeyPress}
113
+ className="search-content--expanded__input"
114
+ placeholder={placeholder}
115
+ onBlur={() => {
116
+ if (!collapsible) return;
117
+ if (!searchTerm || searchTerm === '') setCollapsed(true);
118
+ }}
119
+ />
120
+ </label>
121
+ </div>
122
+ {results && (
123
+ <div className="search-content--results__wrapper">
124
+ <div className="search-content--results__wrapper--message">
125
+ <div className="text-sm pt-2">{`Search results for: ${searchTerm}`}</div>
126
+ <div className="search-content--results__message">
127
+ <div className="search-content--results__content">
128
+ <SearchResults />
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ )}
134
+ </div>
135
+ </>
136
+ );
137
+ };
138
+
139
+ SearchContent.propTypes = {
140
+ searchInputAlignment: PropTypes.string,
141
+ searchInputWrapperMobile: PropTypes.string,
142
+ searchInputWrapperDesktop: PropTypes.string,
143
+ placeholder: PropTypes.string,
144
+ isMobile: PropTypes.bool,
145
+ collapsible: PropTypes.bool,
146
+ entities: PropTypes.array.isRequired
147
+ };
148
+
149
+ SearchContent.defaultProps = {
150
+ searchInputAlignment: '',
151
+ searchInputWrapperMobile: '',
152
+ searchInputWrapperDesktop: '',
153
+ placeholder: '',
154
+ isMobile: false,
155
+ collapsible: false
156
+ };
157
+
158
+ export default SearchContent;
@@ -1,219 +1,3 @@
1
- import React, { useState } from 'react';
2
- import PropTypes from 'prop-types';
3
- import { gql, useApolloClient } from '@apollo/client';
1
+ import SearchContent from "./SearchContent";
4
2
 
5
- import { useRouter } from 'next/router';
6
- import { getPublishedContent } from '../../application/query';
7
- import BlazeLink from '../BlazeLink';
8
-
9
- const logError = error => error;
10
-
11
- const SearchContent = ({
12
- entities,
13
- searchInputAlignment,
14
- searchInputWrapperMobile,
15
- searchInputWrapperDesktop,
16
- collapsible,
17
- isMobile,
18
- placeholder
19
- }) => {
20
- const [collapsed, setCollapsed] = useState(collapsible);
21
- const [searchTerm, setSearchTerm] = useState(null);
22
- const [data, setData] = useState([]);
23
-
24
- const router = useRouter();
25
- const client = useApolloClient();
26
-
27
- const capitalize = s => {
28
- if (typeof s !== 'string') return '';
29
- return s.charAt(0).toUpperCase() + s.slice(1);
30
- };
31
-
32
- React.useEffect(() => {
33
- if (data && data.length !== 0) return;
34
-
35
- const promises = entities.map(entity => {
36
- const [a, b] = entity.split('_');
37
-
38
- const entityName = capitalize(a) + capitalize(b);
39
-
40
- const rawQueryStringified = JSON.stringify({
41
- size: 0,
42
- query: {
43
- bool: {
44
- should: [
45
- {
46
- match: {
47
- docType: entity
48
- }
49
- }
50
- ],
51
- minimum_should_match: 1
52
- }
53
- }
54
- });
55
-
56
- const query = gql`
57
- ${getPublishedContent(entityName)}
58
- `;
59
-
60
- try {
61
- return client.query({
62
- query,
63
- variables: {
64
- rawQueryStringified,
65
- offset: 0,
66
- limit: 5
67
- }
68
- });
69
- } catch (e) {
70
- return [];
71
- }
72
- });
73
-
74
- try {
75
- (async () => {
76
- try {
77
- const fetchResults = await Promise.all(promises);
78
- const searchResults = fetchResults
79
- .map(result => {
80
- const { data: resultData } = result;
81
- return resultData.searchPublishedContent.results;
82
- })
83
- .flat();
84
-
85
- setData(searchResults);
86
- } catch (e) {
87
- logError(e);
88
- }
89
- })();
90
- } catch (e) {
91
- logError(e);
92
- }
93
- });
94
-
95
- const handleClick = (e, url) => {
96
- e.preventDefault();
97
- router.push(url);
98
- };
99
-
100
- const handleKeyPress = e => {
101
- if (e.key === 'Enter' && e.target.value !== '') {
102
- router.push(`/search?search_term=${e.target.value}`);
103
- }
104
- };
105
-
106
- const renderResults = () =>
107
- // eslint-disable-next-line no-undef
108
- data?.map(dataItem => {
109
- const { name, image, url } = dataItem;
110
-
111
- if (searchTerm && searchTerm !== '') {
112
- if (name.includes(searchTerm)) {
113
- return (
114
- <BlazeLink href={url} onClick={e => handleClick(e, url)}>
115
- <div className="search-content--results__wrapper">
116
- {image.url ? (
117
- <img src={image.url} alt={name} className="search-content--results__image" />
118
- ) : null}
119
- <span className="search-content--results__title">{name}</span>
120
- </div>
121
- </BlazeLink>
122
- );
123
- }
124
-
125
- return null;
126
- }
127
- });
128
-
129
- const searchResultsMessage = searchTerm ? `Search results for: ${searchTerm}` : '';
130
-
131
- return collapsed ? (
132
- <div className={isMobile ? searchInputWrapperMobile : searchInputWrapperDesktop}>
133
- <div className="search-content--collapse__wrapper">
134
- <label className="search-content--collapse__label">
135
- <span className="search-content--collapse__icon_wrapper">
136
- <svg className="search-content--collapse__icon" viewBox="0 0 20 20">
137
- <path
138
- fillRule="evenodd"
139
- d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
140
- clipRule="evenodd"
141
- />
142
- </svg>
143
- </span>
144
- <input
145
- onFocus={() => setCollapsed(false)}
146
- onChange={e => setSearchTerm(e.target.value)}
147
- type="text"
148
- name="search"
149
- value=""
150
- className="search-content--collapse__input"
151
- />
152
- </label>
153
- </div>
154
- </div>
155
- ) : (
156
- <>
157
- <div className={`${isMobile ? searchInputWrapperMobile : searchInputWrapperDesktop}`}>
158
- <div className="search-content--expanded__wrapper">
159
- <label className="search-content--expanded__label">
160
- <span className="search-content--expanded__icon_wrapper">
161
- <svg className="search-content--expanded__icon" viewBox="0 0 20 20">
162
- <path
163
- fillRule="evenodd"
164
- d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
165
- clipRule="evenodd"
166
- />
167
- </svg>
168
- </span>
169
- <input
170
- type="text"
171
- name="search"
172
- onChange={e => setSearchTerm(e.target.value)}
173
- onKeyPress={handleKeyPress}
174
- className="search-content--expanded__input"
175
- placeholder={placeholder}
176
- onBlur={() => {
177
- if (!collapsible) return;
178
- if (!searchTerm || searchTerm === '') setCollapsed(true);
179
- }}
180
- />
181
- </label>
182
- </div>
183
- {data &&
184
- searchResultsMessage !== '' && (
185
- <div className="search-content--results__wrapper">
186
- <div className="search-content--results__wrapper--message">
187
- <div className="text-sm pt-2">{searchResultsMessage}</div>
188
-
189
- <div className="search-content--results__message">
190
- <div className="search-content--results__content">{renderResults()}</div>
191
- </div>
192
- </div>
193
- </div>
194
- )}
195
- </div>
196
- </>
197
- );
198
- };
199
-
200
- SearchContent.propTypes = {
201
- searchInputAlignment: PropTypes.string,
202
- searchInputWrapperMobile: PropTypes.string,
203
- searchInputWrapperDesktop: PropTypes.string,
204
- placeholder: PropTypes.string,
205
- isMobile: PropTypes.bool,
206
- collapsible: PropTypes.bool,
207
- entities: PropTypes.array.isRequired
208
- };
209
-
210
- SearchContent.defaultProps = {
211
- searchInputAlignment: '',
212
- searchInputWrapperMobile: '',
213
- searchInputWrapperDesktop: '',
214
- placeholder: '',
215
- isMobile: false,
216
- collapsible: false
217
- };
218
-
219
- export default SearchContent;
3
+ export default SearchContent;
@@ -18,7 +18,7 @@ export default {
18
18
  video: dynamic(() => import(/* webpackChunkName: "blazePbVideo" */ './Video')),
19
19
  wrapper: dynamic(() => import(/* webpackChunkName: "blazePbWrapper" */ './Wrapper')),
20
20
  searchcontent: dynamic(() =>
21
- import(/* webpackChunkName: "blazePbSearchFilter" */ './SearchContent')
21
+ import(/* webpackChunkName: "blazePbSearchFilter" */ './SearchContent/SearchContent')
22
22
  ),
23
23
  searchfilter: dynamic(() =>
24
24
  import(/* webpackChunkName: "blazePbSearchFilter" */ './SearchFilter')
@@ -209,7 +209,7 @@ 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 = name => `blaze_item_list_${name}`;
212
+ const LIST_ITEM_LOCAL_KEY = 'blaze_item_list_';
213
213
 
214
214
  export {
215
215
  BANNER_LOADING,
@@ -4,7 +4,8 @@ const getItemListId = (listName, queryId) => {
4
4
  if (queryId) return queryId;
5
5
  if (!listName || typeof localStorage === 'undefined') return '';
6
6
 
7
- return localStorage.getItem(LIST_ITEM_LOCAL_KEY(listName)) || '';
7
+ const localListName = `${LIST_ITEM_LOCAL_KEY}${listName}`;
8
+ return localStorage.getItem(localListName) || '';
8
9
  };
9
10
 
10
11
  export default getItemListId;