@nyris/nyris-webapp 0.3.47 → 0.3.48

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 (60) hide show
  1. package/build/asset-manifest.json +16 -12
  2. package/build/index.html +1 -1
  3. package/build/js/settings.example.js +84 -13
  4. package/build/{precache-manifest.694373c4d80fe3bb40d0d6526b473852.js → precache-manifest.87ecf17e376539dad2c663829130bfdc.js} +26 -10
  5. package/build/service-worker.js +1 -1
  6. package/build/static/css/main.24b5a712.chunk.css +2 -0
  7. package/build/static/css/main.24b5a712.chunk.css.map +1 -0
  8. package/build/static/js/2.f9395632.chunk.js +3 -0
  9. package/build/static/js/2.f9395632.chunk.js.map +1 -0
  10. package/build/static/js/main.e2a2eb38.chunk.js +3 -0
  11. package/build/static/js/main.e2a2eb38.chunk.js.map +1 -0
  12. package/build/static/media/add.ba46a4bf.svg +4 -0
  13. package/build/static/media/arrow_left.fd9d4390.svg +3 -0
  14. package/build/static/media/arrow_right.c6fdab0b.svg +3 -0
  15. package/build/static/media/minus.3fce6c0a.svg +3 -0
  16. package/package.json +3 -3
  17. package/public/js/settings.example.js +84 -13
  18. package/src/Store/Store.ts +1 -0
  19. package/src/Store/search/Search.ts +36 -0
  20. package/src/Store/search/search.initialState.ts +1 -0
  21. package/src/Store/search/types.ts +1 -0
  22. package/src/common/assets/icons/add.svg +4 -0
  23. package/src/common/assets/icons/minus.svg +3 -0
  24. package/src/components/HeaderMobile.tsx +33 -12
  25. package/src/components/ImagePreviewMobile.tsx +1 -0
  26. package/src/components/Inquiry/InquiryBanner.tsx +1 -1
  27. package/src/components/Layout.tsx +19 -1
  28. package/src/components/MobilePostFilter.tsx +14 -5
  29. package/src/components/PanelResult/PostFilter.tsx +314 -0
  30. package/src/components/PanelResult/{index.tsx → PostFilterAlgolia.tsx} +44 -15
  31. package/src/components/PanelResult/expandable-panel.tsx +20 -14
  32. package/src/components/ProductAttribute.tsx +38 -34
  33. package/src/components/ProductDetailView.tsx +37 -22
  34. package/src/components/ProductList/index.tsx +0 -3
  35. package/src/components/ProductList/useProductList.ts +6 -3
  36. package/src/components/SelectedPostFilter.tsx +103 -0
  37. package/src/components/SidePanel.tsx +18 -7
  38. package/src/components/common.scss +4 -0
  39. package/src/components/current-refinements/getCurrentRefinement.ts +10 -18
  40. package/src/components/icon-label/icon-label.tsx +23 -18
  41. package/src/components/input/inputSearch.tsx +2 -2
  42. package/src/components/pre-filter/index.tsx +16 -10
  43. package/src/components/results/ItemResult.tsx +33 -22
  44. package/src/hooks/useFilter.ts +92 -0
  45. package/src/hooks/useFilteredResult.ts +29 -0
  46. package/src/index.css +2 -1
  47. package/src/page/landingPage/AppMD.tsx +1 -5
  48. package/src/page/landingPage/common.scss +10 -3
  49. package/src/page/result/index.tsx +37 -29
  50. package/src/services/image.ts +0 -5
  51. package/src/translations.ts +9 -0
  52. package/src/types.ts +1 -5
  53. package/build/static/css/main.21021ebe.chunk.css +0 -2
  54. package/build/static/css/main.21021ebe.chunk.css.map +0 -1
  55. package/build/static/js/2.3e652625.chunk.js +0 -3
  56. package/build/static/js/2.3e652625.chunk.js.map +0 -1
  57. package/build/static/js/main.37e28702.chunk.js +0 -3
  58. package/build/static/js/main.37e28702.chunk.js.map +0 -1
  59. /package/build/static/js/{2.3e652625.chunk.js.LICENSE.txt → 2.f9395632.chunk.js.LICENSE.txt} +0 -0
  60. /package/build/static/js/{main.37e28702.chunk.js.LICENSE.txt → main.e2a2eb38.chunk.js.LICENSE.txt} +0 -0
@@ -0,0 +1,4 @@
1
+
2
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M8.625 7.375V3.625C8.625 3.27982 8.34518 3 8 3C7.65482 3 7.375 3.27982 7.375 3.625V7.375H3.625C3.27982 7.375 3 7.65482 3 8C3 8.34518 3.27982 8.625 3.625 8.625H7.375V12.375C7.375 12.7202 7.65482 13 8 13C8.34518 13 8.625 12.7202 8.625 12.375V8.625H12.375C12.7202 8.625 13 8.34518 13 8C13 7.65482 12.7202 7.375 12.375 7.375H8.625Z" fill="#2B2C46"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M6.07845 9.15944C5.74747 8.78211 5.74747 8.21789 6.07845 7.84056L9.53895 3.8956C9.72281 3.68599 10.0491 3.68599 10.233 3.8956C10.3858 4.06978 10.3858 4.33022 10.233 4.5044L7.30652 7.84056C6.97554 8.21789 6.97554 8.78211 7.30652 9.15944L10.233 12.4956C10.3858 12.6698 10.3858 12.9302 10.233 13.1044C10.0491 13.314 9.72281 13.314 9.53895 13.1044L6.07845 9.15944Z" fill="#2B2C46"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M9.92155 9.15944C10.2525 8.78211 10.2525 8.21789 9.92155 7.84056L6.46105 3.8956C6.27719 3.68599 5.95088 3.68599 5.76702 3.8956C5.61423 4.06978 5.61423 4.33022 5.76702 4.5044L8.69348 7.84056C9.02446 8.21789 9.02446 8.78211 8.69348 9.15944L5.76702 12.4956C5.61423 12.6698 5.61423 12.9302 5.76702 13.1044C5.95088 13.314 6.27719 13.314 6.46105 13.1044L9.92155 9.15944Z" fill="#2B2C46"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="3" y="7.36328" width="10" height="1.27383" rx="0.636915" fill="#2B2C46"/>
3
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nyris/nyris-webapp",
3
- "version": "0.3.47",
3
+ "version": "0.3.48",
4
4
  "homepage": "./",
5
5
  "dependencies": {
6
6
  "@algolia/autocomplete-js": "^1.7.1",
@@ -13,8 +13,8 @@
13
13
  "@material-ui/data-grid": "^4.0.0-alpha.37",
14
14
  "@material-ui/icons": "^4.4.1",
15
15
  "@material-ui/lab": "^4.0.0-alpha.60",
16
- "@nyris/nyris-api": "^0.3.47",
17
- "@nyris/nyris-react-components": "^0.3.47",
16
+ "@nyris/nyris-api": "^0.3.48",
17
+ "@nyris/nyris-react-components": "^0.3.48",
18
18
  "@reduxjs/toolkit": "^1.6.1",
19
19
  "@splidejs/react-splide": "^0.7.12",
20
20
  "@types/blueimp-load-image": "^2.23.4",
@@ -1,19 +1,90 @@
1
1
  var settings = {
2
- apiKey: 'xxx',
3
- maxWidth: 500,
4
- maxHeight: 500,
2
+ auth0: {
3
+ enabled: '',
4
+ domain: '',
5
+ clientId: '',
6
+ supportEmail: '',
7
+ },
8
+ algolia: {
9
+ apiKey: '',
10
+ appId: '',
11
+ indexName: '',
12
+ },
13
+ alogoliaFilterField: 'keyword',
14
+ refinements: [
15
+ {
16
+ attribute: 'brand',
17
+ header: 'Brands',
18
+ },
19
+ {
20
+ attribute: 'keyword_0',
21
+ header: 'Category',
22
+ },
23
+ ],
24
+ // Nyris - visual search
25
+ apiKey: '',
26
+ baseUrl: 'https://api.nyris.io',
5
27
  jpegQuality: 0.9,
28
+ maxHeight: 1024,
29
+ maxWidth: 1024,
6
30
  regions: true,
7
- preview: true,
8
- baseUrl: 'https://api.nyris.io',
9
- xOptions: '',
10
- instantRedirectPatterns: [
11
- '^https?://(www.)?youtube.com/',
12
- '^https?://(www.)?youtu.be/',
13
- '^https?://(www.)?vimeo.com/',
14
- '^https?://(www.)?dailymotion.com/',
15
- '^https?://(www.)?dai.ly/',
16
- ],
31
+ responseFormat: 'application/offers.complete+json',
32
+ visualSearchFilterKey: '',
33
+ // UI - theme
34
+ theme: {
35
+ appBarLogoUrl: '',
36
+ headerColor: '',
37
+ logoHeight: '',
38
+ logoWidth: '',
39
+ primaryColor: '',
40
+ secondaryColor: '',
41
+ },
42
+ language: 'en',
43
+ // features
44
+ shareOption: '',
45
+ showFeedbackAndShare: '',
46
+ showPoweredByNyris: '',
47
+ warehouseVariant: false,
48
+ postFilterOption: '',
49
+ preFilterOption: '',
50
+ rfq: {
51
+ enabled: '',
52
+ emailTemplateId: '',
53
+ },
54
+ support: {
55
+ enabled: '',
56
+ emailInquiry: '',
57
+ emailTemplateId: '',
58
+ supportNumber: '',
59
+ description: '',
60
+ },
61
+ cadenas: {
62
+ catalog: '',
63
+ cadenasAPIKey: '',
64
+ cadenas3dWebView: '',
65
+ },
66
+ //UI - labels
67
+ appTitle: '',
68
+ brandName: '',
69
+ headerText: '',
70
+ itemIdLabel: 'SKU',
71
+ preFilterTitle: '',
72
+ CTAButtonText: '',
73
+ //field mappins
74
+ field: {
75
+ ctaLinkField: 'main_offer_link',
76
+ productName: 'title',
77
+ productDetails: 'keyword_1',
78
+ manufacturerNumber: 'keyword_0',
79
+ productTag: 'brand',
80
+ //WarehouseVariant
81
+ warehouseNumber: 'custom_id_key_2',
82
+ warehouseNumberValue: 'custom_id_value_2',
83
+ warehouseShelfNumber: 'custom_id_key_1',
84
+ warehouseShelfNumberValue: 'custom_id_value_1',
85
+ warehouseStock: 'custom_id_key_3',
86
+ warehouseStockValue: 'custom_id_value_3',
87
+ },
17
88
  };
18
89
  settings['customSearchRequest'] = null;
19
90
  settings['responseHook'] = null;
@@ -9,6 +9,7 @@ import { defaultSettings } from './constants';
9
9
  declare var settings: AppSettings;
10
10
 
11
11
  settings.algolia.enabled = true;
12
+ settings.preview = true;
12
13
 
13
14
  let normalizedSettings: AppSettings = {
14
15
  ...defaultSettings,
@@ -2,6 +2,7 @@ import { RectCoords, Region } from '@nyris/nyris-api';
2
2
  import { createSlice, PayloadAction } from '@reduxjs/toolkit';
3
3
  import { DEFAULT_REGION } from '../../constants';
4
4
  import { initialState } from './search.initialState';
5
+ import { isUndefined } from 'lodash';
5
6
 
6
7
  export const searchSlice = createSlice({
7
8
  name: 'search',
@@ -156,6 +157,7 @@ export const searchSlice = createSlice({
156
157
  textSearchInputMobile: '',
157
158
  isShowModalDetailItemMobile: false,
158
159
  preFilter: state.preFilter || {},
160
+ postFilter: {},
159
161
  preFilterDropdown: false,
160
162
  imageCaptureHelpModal: false,
161
163
  };
@@ -260,11 +262,44 @@ export const searchSlice = createSlice({
260
262
  filter: data.payload,
261
263
  };
262
264
  },
265
+ setPostFilter: (state, data: PayloadAction<Record<string, string>>) => {
266
+ const { payload } = data;
267
+
268
+ let filter = { ...state.postFilter } || {};
269
+ const key = Object.keys(payload)[0];
270
+
271
+ if (
272
+ !isUndefined(filter[key]) &&
273
+ !isUndefined(filter[key][payload[key]])
274
+ ) {
275
+ filter[key] = {
276
+ ...filter[key],
277
+ [payload[key]]: !filter[key][payload[key]],
278
+ };
279
+ } else if (!filter[key]) {
280
+ filter = { ...filter, [key]: { [payload[key]]: true } };
281
+ } else {
282
+ filter[key] = { ...filter[key], [payload[key]]: true };
283
+ }
284
+
285
+ return {
286
+ ...state,
287
+ postFilter: { ...filter },
288
+ };
289
+ },
290
+
291
+ clearPostFilter: state => {
292
+ return {
293
+ ...state,
294
+ postFilter: {},
295
+ };
296
+ },
263
297
  },
264
298
  });
265
299
 
266
300
  export const {
267
301
  changeValueTextSearch,
302
+ clearPostFilter,
268
303
  configureFilter,
269
304
  loadFileSelectRegion,
270
305
  loadingActionRegions,
@@ -279,6 +314,7 @@ export const {
279
314
  setFilter,
280
315
  setImageCaptureHelpModal,
281
316
  setImageSearchInput,
317
+ setPostFilter,
282
318
  setPreFilter,
283
319
  setPreFilterDropdown,
284
320
  setRegions,
@@ -26,4 +26,5 @@ export const initialState: SearchState = {
26
26
  page: 1,
27
27
  refinementList: '',
28
28
  },
29
+ postFilter: {},
29
30
  };
@@ -33,4 +33,5 @@ export interface SearchState {
33
33
  setPreFilterDropdown?: any;
34
34
  textSearchInputMobile?: string;
35
35
  valueTextSearch: any;
36
+ postFilter: Record<string, Record<string, boolean>>;
36
37
  }
@@ -0,0 +1,4 @@
1
+
2
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M8.625 7.375V3.625C8.625 3.27982 8.34518 3 8 3C7.65482 3 7.375 3.27982 7.375 3.625V7.375H3.625C3.27982 7.375 3 7.65482 3 8C3 8.34518 3.27982 8.625 3.625 8.625H7.375V12.375C7.375 12.7202 7.65482 13 8 13C8.34518 13 8.625 12.7202 8.625 12.375V8.625H12.375C12.7202 8.625 13 8.34518 13 8C13 7.65482 12.7202 7.375 12.375 7.375H8.625Z" fill="#2B2C46"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="3" y="7.36328" width="10" height="1.27383" rx="0.636915" fill="#2B2C46"/>
3
+ </svg>
@@ -55,6 +55,8 @@ function HeaderMobileComponent(props: Props): JSX.Element {
55
55
  queryText,
56
56
  requestImage,
57
57
  selectedRegion,
58
+ results,
59
+ postFilter,
58
60
  } = search;
59
61
 
60
62
  const query = useQuery();
@@ -162,16 +164,30 @@ function HeaderMobileComponent(props: Props): JSX.Element {
162
164
  );
163
165
  const isPostFilterApplied = useMemo(() => {
164
166
  let isApplied = false;
165
- if (!valueTextSearch?.refinementList) return false;
166
- Object.keys(valueTextSearch?.refinementList).forEach(key => {
167
- if (typeof valueTextSearch.refinementList[key] === 'object') {
168
- isApplied = true;
169
- return;
170
- }
171
- });
167
+
168
+ if (settings.algolia.enabled) {
169
+ if (!valueTextSearch?.refinementList) return false;
170
+ Object.keys(valueTextSearch?.refinementList).forEach(key => {
171
+ if (typeof valueTextSearch.refinementList[key] === 'object') {
172
+ isApplied = true;
173
+ return;
174
+ }
175
+ });
176
+ } else {
177
+ Object.keys(postFilter).forEach(key => {
178
+ const filter = postFilter[key];
179
+ Object.keys(filter).forEach(value => {
180
+ if (filter[value]) {
181
+ isApplied = true;
182
+ return;
183
+ }
184
+ });
185
+ });
186
+ }
187
+
172
188
  return isApplied;
173
189
  // eslint-disable-next-line react-hooks/exhaustive-deps
174
- }, [valueTextSearch?.refinementList]);
190
+ }, [valueTextSearch?.refinementList, settings, postFilter]);
175
191
 
176
192
  const onChangeText = (event: any) => {
177
193
  // debounceSearch(event.currentTarget.value);
@@ -184,11 +200,16 @@ function HeaderMobileComponent(props: Props): JSX.Element {
184
200
  }
185
201
  };
186
202
  const disablePostFilter = useMemo(() => {
187
- return settings.postFilterOption && props.allSearchResults?.hits.length > 0
188
- ? false
189
- : true;
203
+ if (settings.algolia.enabled) {
204
+ return settings.postFilterOption &&
205
+ props.allSearchResults?.hits.length > 0
206
+ ? false
207
+ : true;
208
+ } else {
209
+ return settings.postFilterOption && results?.length > 0 ? false : true;
210
+ }
190
211
  // eslint-disable-next-line react-hooks/exhaustive-deps
191
- }, [settings.postFilterOption, props.allSearchResults?.hits]);
212
+ }, [settings, results, props.allSearchResults?.hits]);
192
213
 
193
214
  return (
194
215
  <div style={{ width: '100%', background: '#fff' }}>
@@ -147,6 +147,7 @@ function ImagePreviewMobileComponent({
147
147
  setEditActive(true);
148
148
  }}
149
149
  showGrip={editActive}
150
+ draggable={editActive ? true : false}
150
151
  />
151
152
  </div>
152
153
  </Box>
@@ -52,7 +52,7 @@ function InquiryBanner({
52
52
  alignSelf: 'end',
53
53
  display: 'flex',
54
54
  alignItems: 'center',
55
- marginRight: '12px',
55
+ // marginRight: '12px',
56
56
  }}
57
57
  className="rfq-box"
58
58
  >
@@ -3,7 +3,11 @@ import { ReactNode } from 'components/common';
3
3
  import React, { memo, useEffect, useState } from 'react';
4
4
  import { useMediaQuery } from 'react-responsive';
5
5
  import { useHistory } from 'react-router-dom';
6
- import { onResetRequestImage, setUpdateSession } from 'Store/search/Search';
6
+ import {
7
+ clearPostFilter,
8
+ onResetRequestImage,
9
+ setUpdateSession,
10
+ } from 'Store/search/Search';
7
11
  import { useAppDispatch, useAppSelector } from 'Store/Store';
8
12
  import { AppState } from '../types';
9
13
  import './appMobile.scss';
@@ -22,6 +26,7 @@ import { translations } from 'translations';
22
26
  import { useAuth0 } from '@auth0/auth0-react';
23
27
  import InstantSearchProvider from './Provider/InstantSearchProvider';
24
28
  import PoweredByNyris from './PoweredByNyris';
29
+ import { useQuery } from 'hooks/useQuery';
25
30
 
26
31
  declare var psol: any;
27
32
 
@@ -64,6 +69,9 @@ function Layout({ children }: ReactNode): JSX.Element {
64
69
  const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
65
70
  const [isOpenFilter, setOpenFilter] = useState<boolean>(false);
66
71
  const history = useHistory();
72
+ const query = useQuery();
73
+ const searchQuery = query.get('query') || '';
74
+
67
75
  let isShowHeaderMobile =
68
76
  (isMobile && history.location?.pathname === '/result') ||
69
77
  history.location?.pathname === '/';
@@ -120,6 +128,16 @@ function Layout({ children }: ReactNode): JSX.Element {
120
128
  };
121
129
  }, []);
122
130
 
131
+ useEffect(() => {
132
+ if (!(search.requestImage && searchQuery)) {
133
+ dispatch(clearPostFilter());
134
+ }
135
+ }, [search.requestImage, searchQuery, dispatch, search.regions]);
136
+
137
+ useEffect(() => {
138
+ dispatch(clearPostFilter());
139
+ }, [dispatch, search.selectedRegion]);
140
+
123
141
  return (
124
142
  <div style={{ position: 'relative' }}>
125
143
  {loadingSearchAlgolia && (
@@ -1,7 +1,10 @@
1
1
  import React, { memo } from 'react';
2
- import ExpandablePanelComponent from 'components/PanelResult';
2
+
3
+ import PostFilterPanel from './PanelResult/PostFilter';
4
+ import PostFilterPanelAlgolia from './PanelResult/PostFilterAlgolia';
3
5
 
4
6
  import { connectStateResults } from 'react-instantsearch-dom';
7
+ import { useAppSelector } from 'Store/Store';
5
8
 
6
9
  interface Props {
7
10
  allSearchResults: any;
@@ -9,11 +12,17 @@ interface Props {
9
12
  }
10
13
 
11
14
  function MobilePostFilter(props: Props) {
15
+ const settings = useAppSelector(state => state.settings);
12
16
  return (
13
- <ExpandablePanelComponent
14
- disjunctiveFacets={props?.allSearchResults?.disjunctiveFacets}
15
- onApply={props.onApply}
16
- />
17
+ <>
18
+ {settings.algolia.enabled && (
19
+ <PostFilterPanelAlgolia
20
+ disjunctiveFacets={props?.allSearchResults?.disjunctiveFacets}
21
+ onApply={props.onApply}
22
+ />
23
+ )}
24
+ {!settings.algolia.enabled && <PostFilterPanel onApply={props.onApply} />}
25
+ </>
17
26
  );
18
27
  }
19
28