@magento/venia-pwa-live-search 1.0.0-alpha6

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 (202) hide show
  1. package/package.json +31 -0
  2. package/postcss.config.js +3 -0
  3. package/src/api/fragments.js +193 -0
  4. package/src/api/graphql.js +26 -0
  5. package/src/api/mutations.js +94 -0
  6. package/src/api/queries.js +225 -0
  7. package/src/api/search.js +222 -0
  8. package/src/components/AddToCartButton/AddToCartButton.jsx +32 -0
  9. package/src/components/AddToCartButton/AddToCartButton.stories.mdx +14 -0
  10. package/src/components/AddToCartButton/index.js +10 -0
  11. package/src/components/Alert/Alert.jsx +155 -0
  12. package/src/components/Alert/index.js +11 -0
  13. package/src/components/Breadcrumbs/Breadcrumbs.jsx +34 -0
  14. package/src/components/Breadcrumbs/MockPages.js +14 -0
  15. package/src/components/Breadcrumbs/index.js +11 -0
  16. package/src/components/ButtonShimmer/ButtonShimmer.css +32 -0
  17. package/src/components/ButtonShimmer/ButtonShimmer.jsx +23 -0
  18. package/src/components/ButtonShimmer/index.js +11 -0
  19. package/src/components/CategoryFilters/CategoryFilters.jsx +59 -0
  20. package/src/components/CategoryFilters/index.js +10 -0
  21. package/src/components/Facets/Facets.jsx +50 -0
  22. package/src/components/Facets/Range/RangeFacet.js +20 -0
  23. package/src/components/Facets/Scalar/ScalarFacet.js +29 -0
  24. package/src/components/Facets/SelectedFilters.js +80 -0
  25. package/src/components/Facets/format.js +52 -0
  26. package/src/components/Facets/index.js +14 -0
  27. package/src/components/Facets/mocks.js +119 -0
  28. package/src/components/FacetsShimmer/FacetsShimmer.css +49 -0
  29. package/src/components/FacetsShimmer/FacetsShimmer.jsx +25 -0
  30. package/src/components/FacetsShimmer/index.js +11 -0
  31. package/src/components/FilterButton/FilterButton.jsx +40 -0
  32. package/src/components/FilterButton/index.js +11 -0
  33. package/src/components/ImageCarousel/Image.jsx +34 -0
  34. package/src/components/ImageCarousel/ImageCarousel.jsx +103 -0
  35. package/src/components/ImageCarousel/index.js +11 -0
  36. package/src/components/InputButtonGroup/InputButtonGroup.jsx +120 -0
  37. package/src/components/InputButtonGroup/index.js +11 -0
  38. package/src/components/LabelledInput/LabelledInput.jsx +51 -0
  39. package/src/components/LabelledInput/index.js +11 -0
  40. package/src/components/Loading/Loading.jsx +32 -0
  41. package/src/components/Loading/index.js +11 -0
  42. package/src/components/NoResults/NoResults.jsx +55 -0
  43. package/src/components/NoResults/index.js +11 -0
  44. package/src/components/Pagination/Pagination.jsx +105 -0
  45. package/src/components/Pagination/index.js +10 -0
  46. package/src/components/PerPagePicker/PerPagePicker.jsx +114 -0
  47. package/src/components/PerPagePicker/index.js +11 -0
  48. package/src/components/Pill/Pill.jsx +34 -0
  49. package/src/components/Pill/index.js +11 -0
  50. package/src/components/Pill/mock.js +23 -0
  51. package/src/components/ProductCardShimmer/ProductCardShimmer.css +72 -0
  52. package/src/components/ProductCardShimmer/ProductCardShimmer.jsx +28 -0
  53. package/src/components/ProductCardShimmer/index.js +11 -0
  54. package/src/components/ProductItem/MockData.js +508 -0
  55. package/src/components/ProductItem/ProductItem.css +84 -0
  56. package/src/components/ProductItem/ProductItem.jsx +347 -0
  57. package/src/components/ProductItem/ProductPrice.jsx +181 -0
  58. package/src/components/ProductItem/index.js +11 -0
  59. package/src/components/ProductList/MockData.js +190 -0
  60. package/src/components/ProductList/ProductList.jsx +127 -0
  61. package/src/components/ProductList/index.js +11 -0
  62. package/src/components/ProductList/product-list.css +18 -0
  63. package/src/components/SearchBar/SearchBar.jsx +33 -0
  64. package/src/components/SearchBar/index.js +11 -0
  65. package/src/components/Shimmer/Shimmer.css +82 -0
  66. package/src/components/Shimmer/Shimmer.jsx +66 -0
  67. package/src/components/Shimmer/index.js +11 -0
  68. package/src/components/Slider/Slider.css +61 -0
  69. package/src/components/Slider/Slider.jsx +103 -0
  70. package/src/components/Slider/index.jsx +11 -0
  71. package/src/components/SliderDoubleControl/SliderDoubleControl.css +83 -0
  72. package/src/components/SliderDoubleControl/SliderDoubleControl.jsx +220 -0
  73. package/src/components/SliderDoubleControl/index.js +11 -0
  74. package/src/components/SortDropdown/SortDropdown.jsx +126 -0
  75. package/src/components/SortDropdown/index.js +11 -0
  76. package/src/components/SwatchButton/SwatchButton.jsx +72 -0
  77. package/src/components/SwatchButton/index.js +11 -0
  78. package/src/components/SwatchButtonGroup/SwatchButtonGroup.jsx +86 -0
  79. package/src/components/SwatchButtonGroup/index.js +11 -0
  80. package/src/components/ViewSwitcher/ViewSwitcher.jsx +46 -0
  81. package/src/components/ViewSwitcher/index.js +11 -0
  82. package/src/components/WishlistButton/WishlistButton.jsx +67 -0
  83. package/src/components/WishlistButton/index.js +11 -0
  84. package/src/containers/App.jsx +145 -0
  85. package/src/containers/LiveSearchPLPLoader.jsx +24 -0
  86. package/src/containers/LiveSearchPopoverLoader.jsx +190 -0
  87. package/src/containers/LiveSearchSRLPLoader.jsx +24 -0
  88. package/src/containers/ProductListingPage.jsx +66 -0
  89. package/src/containers/ProductsContainer.jsx +145 -0
  90. package/src/containers/ProductsHeader.jsx +123 -0
  91. package/src/context/attributeMetadata.js +63 -0
  92. package/src/context/cart.js +97 -0
  93. package/src/context/displayChange.js +90 -0
  94. package/src/context/events.js +160 -0
  95. package/src/context/index.js +19 -0
  96. package/src/context/products.jsx +336 -0
  97. package/src/context/resultsModifierContext.js +35 -0
  98. package/src/context/search.jsx +127 -0
  99. package/src/context/store.jsx +93 -0
  100. package/src/context/translation.jsx +125 -0
  101. package/src/context/widgetConfig.jsx +120 -0
  102. package/src/context/wishlist.jsx +97 -0
  103. package/src/hooks/eventing/useEventListener.js +13 -0
  104. package/src/hooks/eventing/useLocation.js +21 -0
  105. package/src/hooks/eventing/useMagentoExtensionContext.js +28 -0
  106. package/src/hooks/eventing/usePageView.js +36 -0
  107. package/src/hooks/eventing/useShopperContext.js +33 -0
  108. package/src/hooks/eventing/useStorefrontInstanceContext.js +46 -0
  109. package/src/hooks/eventing/useViewedOffsets.js +74 -0
  110. package/src/hooks/useAccessibleDropdown.js +148 -0
  111. package/src/hooks/useLiveSearchPLPConfig.js +112 -0
  112. package/src/hooks/useLiveSearchPopoverConfig.js +83 -0
  113. package/src/hooks/useLiveSearchSRLPConfig.js +97 -0
  114. package/src/hooks/usePagination.js +83 -0
  115. package/src/hooks/useRangeFacet.js +62 -0
  116. package/src/hooks/useScalarFacet.js +61 -0
  117. package/src/hooks/useSliderFacet.js +43 -0
  118. package/src/i18n/Sorani.js +60 -0
  119. package/src/i18n/ar_AE.js +60 -0
  120. package/src/i18n/bg_BG.js +60 -0
  121. package/src/i18n/bn_IN.js +60 -0
  122. package/src/i18n/ca_ES.js +60 -0
  123. package/src/i18n/cs_CZ.js +60 -0
  124. package/src/i18n/da_DK.js +60 -0
  125. package/src/i18n/de_DE.js +60 -0
  126. package/src/i18n/el_GR.js +60 -0
  127. package/src/i18n/en_GA.js +60 -0
  128. package/src/i18n/en_GB.js +60 -0
  129. package/src/i18n/en_US.js +70 -0
  130. package/src/i18n/es_ES.js +60 -0
  131. package/src/i18n/et_EE.js +60 -0
  132. package/src/i18n/eu_ES.js +60 -0
  133. package/src/i18n/fa_IR.js +60 -0
  134. package/src/i18n/fi_FI.js +60 -0
  135. package/src/i18n/fr_FR.js +60 -0
  136. package/src/i18n/gl_ES.js +60 -0
  137. package/src/i18n/hi_IN.js +60 -0
  138. package/src/i18n/hu_HU.js +60 -0
  139. package/src/i18n/hy_AM.js +60 -0
  140. package/src/i18n/id_ID.js +60 -0
  141. package/src/i18n/index.js +89 -0
  142. package/src/i18n/it_IT.js +60 -0
  143. package/src/i18n/ja_JP.js +60 -0
  144. package/src/i18n/ko_KR.js +60 -0
  145. package/src/i18n/lt_LT.js +60 -0
  146. package/src/i18n/lv_LV.js +60 -0
  147. package/src/i18n/nb_NO.js +60 -0
  148. package/src/i18n/nl_NL.js +60 -0
  149. package/src/i18n/pt_BR.js +60 -0
  150. package/src/i18n/pt_PT.js +60 -0
  151. package/src/i18n/ro_RO.js +60 -0
  152. package/src/i18n/ru_RU.js +60 -0
  153. package/src/i18n/sv_SE.js +60 -0
  154. package/src/i18n/th_TH.js +60 -0
  155. package/src/i18n/tr_TR.js +60 -0
  156. package/src/i18n/zh_Hans_CN.js +60 -0
  157. package/src/i18n/zh_Hant_TW.js +60 -0
  158. package/src/icons/NoImage.svg +1 -0
  159. package/src/icons/adjustments.svg +3 -0
  160. package/src/icons/cart.svg +3 -0
  161. package/src/icons/checkmark.svg +3 -0
  162. package/src/icons/chevron.svg +3 -0
  163. package/src/icons/emptyHeart.svg +3 -0
  164. package/src/icons/error.svg +3 -0
  165. package/src/icons/filledHeart.svg +3 -0
  166. package/src/icons/filter.svg +29 -0
  167. package/src/icons/gridView.svg +11 -0
  168. package/src/icons/info.svg +3 -0
  169. package/src/icons/listView.svg +5 -0
  170. package/src/icons/loading.svg +6 -0
  171. package/src/icons/plus.svg +4 -0
  172. package/src/icons/sort.svg +18 -0
  173. package/src/icons/warning.svg +3 -0
  174. package/src/icons/x.svg +3 -0
  175. package/src/index.jsx +65 -0
  176. package/src/queries/customerGroupCode.gql.js +10 -0
  177. package/src/queries/eventing/getMagentoExtensionContext.gql.js +13 -0
  178. package/src/queries/eventing/getPageType.gql.js +14 -0
  179. package/src/queries/eventing/getStorefrontContext.gql.js +27 -0
  180. package/src/queries/index.js +3 -0
  181. package/src/queries/liveSearchPlpConfigs.gql.js +30 -0
  182. package/src/queries/liveSearchPopoverConfigs.gql.js +28 -0
  183. package/src/styles/autocomplete.module.css +56 -0
  184. package/src/styles/index.css +1638 -0
  185. package/src/styles/searchBar.module.css +119 -0
  186. package/src/styles/tokens.css +99 -0
  187. package/src/targets/intercept.js +21 -0
  188. package/src/utils/constants.js +26 -0
  189. package/src/utils/decodeHtmlString.js +13 -0
  190. package/src/utils/dom.js +14 -0
  191. package/src/utils/eventing/getCookie.js +9 -0
  192. package/src/utils/eventing/usePageTypeFromUrl.js +26 -0
  193. package/src/utils/getProductImage.js +94 -0
  194. package/src/utils/getProductPrice.js +83 -0
  195. package/src/utils/getUserViewHistory.js +27 -0
  196. package/src/utils/handleUrlFilters.js +164 -0
  197. package/src/utils/htmlStringDecode.js +13 -0
  198. package/src/utils/modifyResults.js +164 -0
  199. package/src/utils/sort.js +95 -0
  200. package/src/utils/useIntersectionObserver.js +27 -0
  201. package/src/utils/validateStoreDetails.js +39 -0
  202. package/src/wrappers/wrapUseApp.js +28 -0
@@ -0,0 +1,119 @@
1
+ .root {
2
+ composes: items-center from global;
3
+ composes: justify-items-center from global;
4
+ composes: justify-self-center from global;
5
+ composes: max-w-site from global;
6
+ composes: px-xs from global;
7
+ composes: py-0 from global;
8
+ composes: w-full from global;
9
+
10
+ @apply hidden;
11
+ }
12
+
13
+ .root_open {
14
+ composes: root;
15
+
16
+ composes: z-dropdown from global;
17
+ @apply grid;
18
+ }
19
+
20
+ .form {
21
+ composes: grid from global;
22
+ composes: items-center from global;
23
+ composes: justify-items-stretch from global;
24
+ composes: w-full from global;
25
+ }
26
+
27
+ .container {
28
+ composes: inline-flex from global;
29
+ composes: items-center from global;
30
+ composes: justify-center from global;
31
+ composes: max-w-[24rem] from global;
32
+ composes: pb-xs from global;
33
+ composes: relative from global;
34
+ composes: w-full from global;
35
+ }
36
+
37
+ .search {
38
+ composes: grid from global;
39
+ composes: relative from global;
40
+ }
41
+
42
+ .autocomplete {
43
+ composes: grid from global;
44
+ /* composes: relative from global; */
45
+ composes: z-menu from global;
46
+ }
47
+
48
+ .popover {
49
+ composes: absolute from global;
50
+ composes: bg-white from global;
51
+ composes: gap-3 from global;
52
+ composes: grid from global;
53
+ composes: left-0 from global;
54
+ composes: p-xs from global;
55
+ composes: rounded-b-md from global;
56
+ composes: rounded-t-none from global;
57
+ composes: shadow-inputFocus from global;
58
+ composes: text-sm from global;
59
+ composes: z-menu from global;
60
+ transition-property: opacity, transform, visibility;
61
+ top: 2.5rem;
62
+ }
63
+
64
+ .root_hidden {
65
+ composes: root;
66
+
67
+ composes: invisible from global;
68
+ composes: opacity-0 from global;
69
+ transform: translate3d(0, -2rem, 0);
70
+ transition-duration: 192ms;
71
+ transition-timing-function: var(--venia-global-anim-out);
72
+ }
73
+
74
+ .root_visible {
75
+ composes: root;
76
+
77
+ composes: opacity-100 from global;
78
+ composes: visible from global;
79
+ transform: translate3d(0, 0, 0);
80
+ transition-duration: 224ms;
81
+ transition-timing-function: var(--venia-global-anim-in);
82
+ }
83
+
84
+ .message {
85
+ composes: px-3 from global;
86
+ composes: py-0 from global;
87
+ composes: text-center from global;
88
+ composes: text-subtle from global;
89
+
90
+ composes: empty_hidden from global;
91
+ }
92
+
93
+ .suggestions {
94
+ composes: gap-2xs from global;
95
+ composes: grid from global;
96
+
97
+ composes: empty_hidden from global;
98
+ }
99
+
100
+ .product-price {
101
+ display: grid;
102
+ grid-area: product-price;
103
+ height: 100%;
104
+ justify-content: left !important;
105
+ width: 100%;
106
+ }
107
+
108
+ .livesearch_root .ds-sdk-add-to-cart-button button svg {
109
+ display: none !important;
110
+ }
111
+
112
+ .search input {
113
+ padding-left: calc(1.875rem * var(--iconsBefore, 0) + 0.625rem);
114
+ padding-right: calc(1.875rem * var(--iconsAfter, 0) + 0.625rem);
115
+ }
116
+
117
+ /* .popover {
118
+
119
+ } */
@@ -0,0 +1,99 @@
1
+ /* Tokens */
2
+ .ds-widgets {
3
+ @import 'tailwindcss/base';
4
+ @import 'tailwindcss/components';
5
+ @import 'tailwindcss/utilities';
6
+
7
+ font-size: 1.6rem;
8
+
9
+ /* Colors */
10
+ --color-body: #fff;
11
+ --color-on-body: #222;
12
+
13
+ --color-surface: #e6e6e6;
14
+ --color-on-surface: #222;
15
+
16
+ --color-primary: #222;
17
+ --color-on-primary: #fff;
18
+
19
+ --color-secondary: #ff0000;
20
+ --color-on-secondary: #fff;
21
+
22
+ --color-gray-1: #f3f4f6;
23
+ --color-gray-2: #e5e7eb;
24
+ --color-gray-3: #d1d5db;
25
+ --color-gray-4: #9ca3af;
26
+ --color-gray-5: #6b7280;
27
+ --color-gray-6: #4b5563;
28
+ --color-gray-7: #374151;
29
+ --color-gray-8: #1f2937;
30
+ --color-gray-9: #111827;
31
+
32
+ /* Spacing: gaps, margin, padding, etc. */
33
+ --spacing-xxs: 0.15625em;
34
+ --spacing-xs: 0.3125em;
35
+ --spacing-sm: 0.625em;
36
+ --spacing-md: 1.25em;
37
+ --spacing-lg: 2.5em;
38
+ --spacing-xl: 3.75em;
39
+ --spacing-2xl: 4.25em;
40
+ --spacing-3xl: 4.75em;
41
+
42
+ /* Font Families */
43
+ --font-body: sans-serif;
44
+
45
+ /* Font Sizes */
46
+ --font-xs: 0.75em;
47
+ --font-sm: 0.875em;
48
+ --font-md: 1em;
49
+ --font-lg: 1.125em;
50
+ --font-xl: 1.25em;
51
+ --font-2xl: 1.5em;
52
+ --font-3xl: 1.875em;
53
+ --font-4xl: 2.25em;
54
+ --font-5xl: 3em;
55
+
56
+ /* Font Weights */
57
+ --font-thin: 100;
58
+ --font-extralight: 200;
59
+ --font-light: 300;
60
+ --font-normal: 400;
61
+ --font-medium: 500;
62
+ --font-semibold: 600;
63
+ --font-bold: 700;
64
+ --font-extrabold: 800;
65
+ --font-black: 900;
66
+
67
+ /* Line Heights */
68
+ --leading-none: 1;
69
+ --leading-tight: 1.25;
70
+ --leading-snug: 1.375;
71
+ --leading-normal: 1.5;
72
+ --leading-relaxed: 1.625;
73
+ --leading-loose: 2;
74
+ --leading-3: '.75em';
75
+ --leading-4: '1em';
76
+ --leading-5: '1.25em';
77
+ --leading-6: '1.5em';
78
+ --leading-7: '1.75em';
79
+ --leading-8: '2em';
80
+ --leading-9: '2.25em';
81
+ --leading-10: '2.5em';
82
+ }
83
+
84
+ .ds-widgets input[type='checkbox'] {
85
+ font-size: 80%;
86
+ margin: 0;
87
+ top: 0;
88
+ }
89
+
90
+ .block-display {
91
+ display: block;
92
+ }
93
+
94
+ .loading-spinner-on-mobile {
95
+ position: fixed;
96
+ top: 50%;
97
+ left: 50%;
98
+ transform: translate(-50%, -50%);
99
+ }
@@ -0,0 +1,21 @@
1
+ module.exports = targets => {
2
+ const { specialFeatures } = targets.of('@magento/pwa-buildpack');
3
+ specialFeatures.tap(flags => {
4
+ /**
5
+ * Wee need to activate esModules, GQL Queries and deactivate cssModules to allow build pack to load our extension
6
+ * {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
7
+ */
8
+ flags[targets.name] = {
9
+ esModules: true,
10
+ cssModules: false,
11
+ graphqlQueries: true
12
+ };
13
+ });
14
+
15
+ targets.of('@magento/peregrine').talons.tap(talons => {
16
+ talons.App.useApp.wrapWith(
17
+ `@magento/venia-pwa-live-search/src/wrappers/wrapUseApp`
18
+ );
19
+ return talons;
20
+ });
21
+ };
@@ -0,0 +1,26 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ export const DEFAULT_PAGE_SIZE = 24;
9
+ export const DEFAULT_PAGE_SIZE_OPTIONS = '12,24,36';
10
+ export const DEFAULT_MIN_QUERY_LENGTH = 3;
11
+ export const PRODUCT_COLUMNS = {
12
+ desktop: 4,
13
+ tablet: 3,
14
+ mobile: 2
15
+ };
16
+
17
+ export const SEARCH_SORT_DEFAULT = [
18
+ { attribute: 'relevance', direction: 'DESC' }
19
+ ];
20
+ export const CATEGORY_SORT_DEFAULT = [
21
+ { attribute: 'position', direction: 'ASC' }
22
+ ];
23
+
24
+ export const SEARCH_UNIT_ID = 'livesearch-plp';
25
+ export const BOOLEAN_YES = 'yes';
26
+ export const BOOLEAN_NO = 'no';
@@ -0,0 +1,13 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ const decodeHtmlString = input => {
9
+ const doc = new DOMParser().parseFromString(input, 'text/html');
10
+ return doc.documentElement.textContent;
11
+ };
12
+
13
+ export { decodeHtmlString };
@@ -0,0 +1,14 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ export const moveToTop = () => {
9
+ window.scrollTo({ top: 0 });
10
+ };
11
+
12
+ export const classNames = (...classes) => {
13
+ return classes.filter(Boolean).join(' ');
14
+ };
@@ -0,0 +1,9 @@
1
+ export const getDecodedCookie = key => {
2
+ const encodedCookie = document.cookie
3
+ .split('; ')
4
+ .find(row => row.startsWith(key))
5
+ .split('=')[1];
6
+ const decodedCookie = decodeURIComponent(encodedCookie);
7
+ const value = JSON.parse(decodedCookie);
8
+ return value;
9
+ };
@@ -0,0 +1,26 @@
1
+ // src/hooks/eventing/usePageTypeFromUrl.js
2
+ import { useQuery } from '@apollo/client';
3
+ import query from '../../queries/eventing/getPageType.gql';
4
+
5
+ const pagetypeMap = {
6
+ CMS_PAGE: 'CMS',
7
+ CATEGORY: 'Category',
8
+ PRODUCT: 'Product',
9
+ '/cart': 'Cart',
10
+ '/checkout': 'Checkout'
11
+ };
12
+
13
+ const usePageTypeFromUrl = pathname => {
14
+ const { data } = useQuery(query.resolvePagetypeQuery, {
15
+ fetchPolicy: 'cache-and-network',
16
+ nextFetchPolicy: 'cache-first',
17
+ variables: { url: pathname }
18
+ });
19
+
20
+ const type = data?.urlResolver?.type;
21
+ const pageType = pagetypeMap[type] || pagetypeMap[pathname];
22
+
23
+ return pageType;
24
+ };
25
+
26
+ export default usePageTypeFromUrl;
@@ -0,0 +1,94 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ const getProductImageURLs = (images, amount = 3, topImageUrl) => {
9
+ const imageUrlArray = [];
10
+ //const url = new URL(window.location.href);
11
+ //original protocol
12
+ //const protocol = url.protocol;
13
+
14
+ //making protocol empty
15
+ //const protocol = '';
16
+ // const topImageUrl = "http://master-7rqtwti-wdxwuaerh4gbm.eu-4.magentosite.cloud/media/catalog/product/3/1/31t0a-sopll._ac_.jpg";
17
+ for (const image of images) {
18
+ const imageUrl = image.url?.replace(/^https?:\/\//, '');
19
+ if (imageUrl) {
20
+ //original
21
+ //imageUrlArray.push(`${protocol}//${imageUrl}`);
22
+
23
+ //to remove protocol
24
+ imageUrlArray.push(`${imageUrl}`);
25
+ }
26
+ }
27
+
28
+ if (topImageUrl) {
29
+ //original
30
+ // const topImageUrlFormatted = `${protocol}//${topImageUrl.replace(
31
+ // /^https?:\/\//,
32
+ // ''
33
+ // )}`;
34
+
35
+ //to remove protocol
36
+ const topImageUrlFormatted = `${topImageUrl.replace(
37
+ /^https?:\/\//,
38
+ ''
39
+ )}`;
40
+
41
+ const index = topImageUrlFormatted.indexOf(topImageUrlFormatted);
42
+ if (index > -1) {
43
+ imageUrlArray.splice(index, 1);
44
+ }
45
+
46
+ imageUrlArray.unshift(topImageUrlFormatted);
47
+ }
48
+
49
+ return imageUrlArray.slice(0, amount);
50
+ };
51
+
52
+ const resolveImageUrl = (url, opts) => {
53
+ const [base, query] = url.split('?');
54
+ const params = new URLSearchParams(query);
55
+
56
+ Object.entries(opts).forEach(([key, value]) => {
57
+ if (value !== undefined && value !== null) {
58
+ params.set(key, String(value));
59
+ }
60
+ });
61
+
62
+ return `${base}?${params.toString()}`;
63
+ };
64
+
65
+ const generateOptimizedImages = (imageUrls, baseImageWidth) => {
66
+ const baseOptions = {
67
+ fit: 'cover',
68
+ crop: false,
69
+ dpi: 1
70
+ };
71
+
72
+ const imageUrlArray = [];
73
+
74
+ for (const imageUrl of imageUrls) {
75
+ const src = resolveImageUrl(imageUrl, {
76
+ ...baseOptions,
77
+ width: baseImageWidth
78
+ });
79
+ const dpiSet = [1, 2, 3];
80
+ const srcset = dpiSet.map(dpi => {
81
+ return `${resolveImageUrl(imageUrl, {
82
+ ...baseOptions,
83
+ auto: 'webp',
84
+ quality: 80,
85
+ width: baseImageWidth * dpi
86
+ })} ${dpi}x`;
87
+ });
88
+ imageUrlArray.push({ src, srcset });
89
+ }
90
+
91
+ return imageUrlArray;
92
+ };
93
+
94
+ export { generateOptimizedImages, getProductImageURLs };
@@ -0,0 +1,83 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ import getSymbolFromCurrency from 'currency-symbol-map';
9
+
10
+ const getProductPrice = (
11
+ product,
12
+ currencySymbol,
13
+ currencyRate,
14
+ useMaximum = false,
15
+ useFinal = false
16
+ ) => {
17
+ let priceType;
18
+ let price;
19
+ if ('product' in product) {
20
+ priceType = product?.product?.price_range?.minimum_price;
21
+
22
+ if (useMaximum) {
23
+ priceType = product?.product?.price_range?.maximum_price;
24
+ }
25
+
26
+ price = priceType?.regular_price;
27
+ if (useFinal) {
28
+ price = priceType?.final_price;
29
+ }
30
+ } else {
31
+ //getting error because the nullish coalescing operator (??) isn't supported by your Babel/Webpack setup yet.
32
+ // priceType =
33
+ // product?.refineProduct?.priceRange?.minimum ??
34
+ // product?.refineProduct?.price;
35
+
36
+ //workaround
37
+ priceType =
38
+ product &&
39
+ product.refineProduct &&
40
+ product.refineProduct.priceRange &&
41
+ product.refineProduct.priceRange.minimum
42
+ ? product.refineProduct.priceRange.minimum
43
+ : product &&
44
+ product.refineProduct &&
45
+ product.refineProduct.price
46
+ ? product.refineProduct.price
47
+ : undefined;
48
+
49
+ if (useMaximum) {
50
+ priceType = product?.refineProduct?.priceRange?.maximum;
51
+ }
52
+
53
+ price = priceType?.regular?.amount;
54
+ if (useFinal) {
55
+ price = priceType?.final?.amount;
56
+ }
57
+ }
58
+
59
+ // if currency symbol is configurable within Commerce, that symbol is used
60
+ let currency = price?.currency;
61
+
62
+ if (currencySymbol) {
63
+ currency = currencySymbol;
64
+ } else {
65
+ //getting error because the nullish coalescing operator (??) isn't supported by your Babel/Webpack setup yet.
66
+ //currency = getSymbolFromCurrency(currency) ?? '$';
67
+
68
+ // work around
69
+ currency =
70
+ getSymbolFromCurrency(currency) !== undefined &&
71
+ getSymbolFromCurrency(currency) !== null
72
+ ? getSymbolFromCurrency(currency)
73
+ : '$';
74
+ }
75
+
76
+ const convertedPrice = currencyRate
77
+ ? price?.value * parseFloat(currencyRate)
78
+ : price?.value;
79
+
80
+ return convertedPrice ? `${currency}${convertedPrice.toFixed(2)}` : '';
81
+ };
82
+
83
+ export { getProductPrice };
@@ -0,0 +1,27 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ const getUserViewHistory = () => {
9
+ const userViewHistory = localStorage?.getItem('ds-view-history-time-decay')
10
+ ? JSON.parse(localStorage.getItem('ds-view-history-time-decay'))
11
+ : null;
12
+
13
+ if (userViewHistory && Array.isArray(userViewHistory)) {
14
+ // https://git.corp.adobe.com/magento-datalake/magento2-snowplow-js/blob/main/src/utils.js#L177
15
+ // this shows localStorage is guaranteed sorted by unique by most recent timestamp as last index.
16
+
17
+ // MSRCH-2740: send the top 200 most recently viewed unique SKUs
18
+ return userViewHistory.slice(-200).map(v => ({
19
+ sku: v.sku,
20
+ dateTime: v.date
21
+ }));
22
+ }
23
+
24
+ return [];
25
+ };
26
+
27
+ export { getUserViewHistory };
@@ -0,0 +1,164 @@
1
+ // Copyright 2024 Adobe
2
+ // All Rights Reserved.
3
+ //
4
+ // NOTICE: Adobe permits you to use, modify, and distribute this file in
5
+ // accordance with the terms of the Adobe license agreement accompanying
6
+ // it.
7
+
8
+ // Luma Specific URL handling
9
+ import { DEFAULT_PAGE_SIZE } from '../utils/constants';
10
+
11
+ const nonFilterKeys = {
12
+ search: 'q',
13
+ search_query: 'search_query',
14
+ pagination: 'p',
15
+ sort: 'product_list_order',
16
+ page_size: 'page_size'
17
+ };
18
+
19
+ const addUrlFilter = filter => {
20
+ const url = new URL(window.location.href);
21
+ const params = new URLSearchParams(url.searchParams);
22
+ const attribute = filter.attribute;
23
+ if (filter.range) {
24
+ const filt = filter.range;
25
+ if (getValueFromUrl(attribute)) {
26
+ params.delete(attribute);
27
+ params.append(attribute, `${filt.from}--${filt.to}`);
28
+ } else {
29
+ params.append(attribute, `${filt.from}--${filt.to}`);
30
+ }
31
+ } else {
32
+ const filt = filter.in || [];
33
+ const filterParams = params.getAll(attribute);
34
+ filt.map(f => {
35
+ if (!filterParams.includes(f)) {
36
+ params.append(attribute, f);
37
+ }
38
+ });
39
+ }
40
+ setWindowHistory(url.pathname, params);
41
+ };
42
+
43
+ const removeUrlFilter = (name, option) => {
44
+ const url = new URL(window.location.href);
45
+ const params = new URLSearchParams(url.searchParams);
46
+ const allValues = url.searchParams.getAll(name);
47
+ params.delete(name);
48
+ if (option) {
49
+ allValues.splice(allValues.indexOf(option), 1);
50
+ allValues.forEach(val => params.append(name, val));
51
+ }
52
+ setWindowHistory(url.pathname, params);
53
+ };
54
+
55
+ const removeAllUrlFilters = () => {
56
+ const url = new URL(window.location.href);
57
+ const params = new URLSearchParams(url.searchParams);
58
+ for (const key of url.searchParams.keys()) {
59
+ if (!Object.values(nonFilterKeys).includes(key)) {
60
+ params.delete(key);
61
+ }
62
+ }
63
+ setWindowHistory(url.pathname, params);
64
+ };
65
+
66
+ const handleUrlSort = sortOption => {
67
+ const url = new URL(window.location.href);
68
+ const params = new URLSearchParams(url.searchParams);
69
+ params.set('product_list_order', sortOption);
70
+ setWindowHistory(url.pathname, params);
71
+ };
72
+
73
+ const handleViewType = viewType => {
74
+ const url = new URL(window.location.href);
75
+ const params = new URLSearchParams(url.searchParams);
76
+ params.set('view_type', viewType);
77
+ setWindowHistory(url.pathname, params);
78
+ };
79
+
80
+ const handleUrlPageSize = pageSizeOption => {
81
+ const url = new URL(window.location.href);
82
+ const params = new URLSearchParams(url.searchParams);
83
+ if (pageSizeOption === DEFAULT_PAGE_SIZE) {
84
+ params.delete('page_size');
85
+ } else {
86
+ params.set('page_size', pageSizeOption.toString());
87
+ }
88
+ setWindowHistory(url.pathname, params);
89
+ };
90
+
91
+ const handleUrlPagination = pageNumber => {
92
+ const url = new URL(window.location.href);
93
+ const params = new URLSearchParams(url.searchParams);
94
+ if (pageNumber === 1) {
95
+ params.delete('p');
96
+ } else {
97
+ params.set('p', pageNumber.toString());
98
+ }
99
+ setWindowHistory(url.pathname, params);
100
+ };
101
+
102
+ const getFiltersFromUrl = filterableAttributes => {
103
+ const params = getSearchParams();
104
+
105
+ const filters = [];
106
+ for (const [key, value] of params.entries()) {
107
+ if (
108
+ filterableAttributes.includes(key) &&
109
+ !Object.values(nonFilterKeys).includes(key)
110
+ ) {
111
+ if (value.includes('--')) {
112
+ const range = value.split('--');
113
+ const filter = {
114
+ attribute: key,
115
+ range: { from: Number(range[0]), to: Number(range[1]) }
116
+ };
117
+ filters.push(filter);
118
+ } else {
119
+ const attributeIndex = filters.findIndex(
120
+ filter => filter.attribute == key
121
+ );
122
+ if (attributeIndex !== -1) {
123
+ filters[attributeIndex].in.push(value);
124
+ } else {
125
+ const filter = { attribute: key, in: [value] };
126
+ filters.push(filter);
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ return filters;
133
+ };
134
+
135
+ const getValueFromUrl = param => {
136
+ const params = getSearchParams();
137
+ const filter = params.get(param);
138
+ return filter || '';
139
+ };
140
+
141
+ const getSearchParams = () => {
142
+ const search = window.location.search;
143
+ return new URLSearchParams(search);
144
+ };
145
+
146
+ const setWindowHistory = (pathname, params) => {
147
+ if (params.toString() === '') {
148
+ window.history.pushState({}, '', `${pathname}`);
149
+ } else {
150
+ window.history.pushState({}, '', `${pathname}?${params.toString()}`);
151
+ }
152
+ };
153
+
154
+ export {
155
+ addUrlFilter,
156
+ getFiltersFromUrl,
157
+ getValueFromUrl,
158
+ handleUrlPageSize,
159
+ handleUrlPagination,
160
+ handleUrlSort,
161
+ handleViewType,
162
+ removeAllUrlFilters,
163
+ removeUrlFilter
164
+ };