@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,145 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ import React, { useEffect } from 'react';
11
+ import { ProductCardShimmer } from '../components/ProductCardShimmer';
12
+ import { useProducts, useSensor, useTranslation } from '../context';
13
+ import { handleUrlPageSize, handleUrlPagination } from '../utils/handleUrlFilters';
14
+
15
+ import { Alert } from '../components/Alert';
16
+ import { Pagination } from '../components/Pagination';
17
+ import { PerPagePicker } from '../components/PerPagePicker';
18
+ import { ProductList } from '../components/ProductList';
19
+
20
+ const ProductsContainer = ({ showFilters }) => {
21
+ const productsCtx = useProducts();
22
+ const { screenSize } = useSensor();
23
+
24
+ const {
25
+ variables,
26
+ items,
27
+ setCurrentPage,
28
+ currentPage,
29
+ setPageSize,
30
+ pageSize,
31
+ totalPages,
32
+ totalCount,
33
+ minQueryLength,
34
+ minQueryLengthReached,
35
+ pageSizeOptions,
36
+ loading,
37
+ } = productsCtx;
38
+
39
+ const translation = useTranslation();
40
+
41
+ const goToPage = (page) => {
42
+ if (typeof page === 'number') {
43
+ setCurrentPage(page);
44
+ handleUrlPagination(page);
45
+ }
46
+ };
47
+
48
+ const onPageSizeChange = (pageSizeOption) => {
49
+ setPageSize(pageSizeOption);
50
+ handleUrlPageSize(pageSizeOption);
51
+ };
52
+
53
+ const getPageSizeTranslation = (pageSize, pageSizeOptions) => {
54
+ const pageSizeTranslation = translation.ProductContainers.pagePicker;
55
+ const pageSizeTranslationOrder = pageSizeTranslation.split(' ');
56
+
57
+ return pageSizeTranslationOrder.map((word, index) =>
58
+ word === '{pageSize}' ? (
59
+ <PerPagePicker
60
+ key={index}
61
+ pageSizeOptions={pageSizeOptions}
62
+ value={pageSize}
63
+ onChange={onPageSizeChange}
64
+ />
65
+ ) : (
66
+ `${word} `
67
+ )
68
+ );
69
+ };
70
+
71
+ useEffect(() => {
72
+ if (currentPage < 1) {
73
+ goToPage(1);
74
+ }
75
+ }, []);
76
+
77
+ const productCardArray = Array.from({ length: 8 });
78
+
79
+ if (!minQueryLengthReached) {
80
+ const templateMinQueryText = translation.ProductContainers.minquery;
81
+ const title = templateMinQueryText
82
+ .replace('{variables.phrase}', variables.phrase)
83
+ .replace('{minQueryLength}', minQueryLength);
84
+
85
+ return (
86
+ <div className="ds-sdk-min-query__page mx-auto max-w-8xl py-12 px-4 sm:px-6 lg:px-8">
87
+ <Alert title={title} type="warning" description="" />
88
+ </div>
89
+ );
90
+ }
91
+
92
+ if (!totalCount) {
93
+ return (
94
+ <div className="ds-sdk-no-results__page mx-auto max-w-8xl py-12 px-4 sm:px-6 lg:px-8">
95
+ <Alert
96
+ title={translation.ProductContainers.noresults}
97
+ type="warning"
98
+ description=""
99
+ />
100
+ </div>
101
+ );
102
+ }
103
+
104
+ return (
105
+ <>
106
+ {loading ? (
107
+ <div
108
+ style={{
109
+ gridTemplateColumns: `repeat(${screenSize.columns}, minmax(0, 1fr))`,
110
+ }}
111
+ className="ds-sdk-product-list__grid mt-md grid grid-cols-1 gap-y-8 gap-x-md sm:grid-cols-2 md:grid-cols-3 xl:gap-x-4 pl-8"
112
+ >
113
+ {productCardArray.map((_, index) => (
114
+ <ProductCardShimmer key={index} />
115
+ ))}
116
+ </div>
117
+ ) : (
118
+ <ProductList
119
+ products={items}
120
+ numberOfColumns={screenSize.columns}
121
+ showFilters={showFilters}
122
+ />
123
+ )}
124
+
125
+ <div
126
+ className={`flex flex-row justify-between max-w-full ${
127
+ showFilters ? 'mx-auto' : 'mr-auto'
128
+ } w-full h-full`}
129
+ >
130
+ <div>
131
+ {getPageSizeTranslation(pageSize, pageSizeOptions)}
132
+ </div>
133
+ {totalPages > 1 && (
134
+ <Pagination
135
+ currentPage={currentPage}
136
+ totalPages={totalPages}
137
+ onPageChange={goToPage}
138
+ />
139
+ )}
140
+ </div>
141
+ </>
142
+ );
143
+ };
144
+
145
+ export default ProductsContainer;
@@ -0,0 +1,123 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ import React, { useCallback, useEffect, useState } from 'react';
11
+
12
+ import ViewSwitcher from '../components/ViewSwitcher';
13
+ import Facets from '../components/Facets';
14
+ import { FilterButton } from '../components/FilterButton';
15
+ import { SearchBar } from '../components/SearchBar';
16
+ import { SortDropdown } from '../components/SortDropdown';
17
+
18
+ import {
19
+ useAttributeMetadata,
20
+ useProducts,
21
+ useSearch,
22
+ useStore,
23
+ useTranslation,
24
+ } from '../context';
25
+
26
+ import { getValueFromUrl, handleUrlSort } from '../utils/handleUrlFilters';
27
+ import {
28
+ defaultSortOptions,
29
+ generateGQLSortInput,
30
+ getSortOptionsfromMetadata,
31
+ } from '../utils/sort';
32
+
33
+ export const ProductsHeader = ({ facets, totalCount, screenSize }) => {
34
+ const searchCtx = useSearch();
35
+ const storeCtx = useStore();
36
+ const attributeMetadata = useAttributeMetadata();
37
+ const productsCtx = useProducts();
38
+ const translation = useTranslation();
39
+
40
+ const [showMobileFacet, setShowMobileFacet] = useState(
41
+ !!productsCtx.variables.filter?.length
42
+ );
43
+ const [sortOptions, setSortOptions] = useState(defaultSortOptions());
44
+
45
+ const getSortOptions = useCallback(() => {
46
+ setSortOptions(
47
+ getSortOptionsfromMetadata(
48
+ attributeMetadata?.sortable,
49
+ storeCtx?.config?.displayOutOfStock,
50
+ storeCtx?.config?.currentCategoryUrlPath,
51
+ translation
52
+ )
53
+ );
54
+ }, [storeCtx, translation, attributeMetadata]);
55
+
56
+ useEffect(() => {
57
+ getSortOptions();
58
+ }, [getSortOptions]);
59
+
60
+ const defaultSortOption = storeCtx.config?.currentCategoryUrlPath
61
+ ? 'position_ASC'
62
+ : 'relevance_DESC';
63
+
64
+ const sortFromUrl = getValueFromUrl('product_list_order');
65
+ const sortByDefault = sortFromUrl ? sortFromUrl : defaultSortOption;
66
+
67
+ const [sortBy, setSortBy] = useState(sortByDefault);
68
+
69
+ const onSortChange = (sortOption) => {
70
+ setSortBy(sortOption);
71
+ searchCtx.setSort(generateGQLSortInput(sortOption));
72
+ handleUrlSort(sortOption);
73
+ };
74
+
75
+ return (
76
+ <div className="flex flex-col max-w-5xl lg:max-w-full ml-auto w-full h-full">
77
+ <div
78
+ className={`flex gap-x-2.5 mb-[1px] ${
79
+ screenSize.mobile ? 'justify-between' : 'justify-end'
80
+ }`}
81
+ >
82
+ <div>
83
+ {screenSize.mobile ? (
84
+ totalCount > 0 && (
85
+ <div className="pb-4">
86
+ <FilterButton
87
+ displayFilter={() => setShowMobileFacet(!showMobileFacet)}
88
+ type="mobile"
89
+ />
90
+ </div>
91
+ )
92
+ ) : (
93
+ storeCtx.config.displaySearchBox && (
94
+ <SearchBar
95
+ phrase={searchCtx.phrase}
96
+ onKeyPress={(e) => {
97
+ if (e.key === 'Enter') {
98
+ searchCtx.setPhrase(e.target.value);
99
+ }
100
+ }}
101
+ onClear={() => searchCtx.setPhrase('')}
102
+ placeholder={translation.SearchBar.placeholder}
103
+ />
104
+ )
105
+ )}
106
+ </div>
107
+ {totalCount > 0 && (
108
+ <>
109
+ {storeCtx?.config?.listview && <ViewSwitcher />}
110
+ <SortDropdown
111
+ sortOptions={sortOptions}
112
+ value={sortBy}
113
+ onChange={onSortChange}
114
+ />
115
+ </>
116
+ )}
117
+ </div>
118
+ {screenSize.mobile && showMobileFacet && (
119
+ <Facets searchFacets={facets} />
120
+ )}
121
+ </div>
122
+ );
123
+ };
@@ -0,0 +1,63 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ import React, { createContext, useContext, useEffect, useState } from 'react';
11
+ import { getAttributeMetadata } from '../api/search';
12
+ import { useStore } from './store';
13
+
14
+ // Remove the interface and type annotations since we're using JavaScript
15
+ const AttributeMetadataContext = createContext({
16
+ sortable: [],
17
+ filterableInSearch: []
18
+ });
19
+
20
+ const AttributeMetadataProvider = ({ children }) => {
21
+ const [attributeMetadata, setAttributeMetadata] = useState({
22
+ sortable: [],
23
+ filterableInSearch: null
24
+ });
25
+
26
+ const storeCtx = useStore();
27
+
28
+ useEffect(() => {
29
+ const fetchData = async () => {
30
+ const data = await getAttributeMetadata({
31
+ ...storeCtx,
32
+ apiUrl: storeCtx.apiUrl
33
+ });
34
+ if (data?.attributeMetadata) {
35
+ setAttributeMetadata({
36
+ sortable: data.attributeMetadata.sortable,
37
+ filterableInSearch: data.attributeMetadata.filterableInSearch.map(
38
+ attribute => attribute.attribute
39
+ )
40
+ });
41
+ }
42
+ };
43
+
44
+ fetchData();
45
+ }, [storeCtx]); // Added storeCtx as dependency to handle any changes to the context
46
+
47
+ const attributeMetadataContext = {
48
+ ...attributeMetadata
49
+ };
50
+
51
+ return (
52
+ <AttributeMetadataContext.Provider value={attributeMetadataContext}>
53
+ {children}
54
+ </AttributeMetadataContext.Provider>
55
+ );
56
+ };
57
+
58
+ const useAttributeMetadata = () => {
59
+ const attributeMetadataCtx = useContext(AttributeMetadataContext);
60
+ return attributeMetadataCtx;
61
+ };
62
+
63
+ export { AttributeMetadataProvider, useAttributeMetadata };
@@ -0,0 +1,97 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ import React, { createContext, useContext, useState } from 'react';
11
+ import { getGraphQL } from '../api/graphql';
12
+ import { ADD_TO_CART } from '../api/mutations';
13
+ import { GET_CUSTOMER_CART } from '../api/queries';
14
+ import { useProducts } from './products';
15
+ import { useStore } from './store';
16
+
17
+ // Removed TypeScript interface and type annotations
18
+
19
+ const CartContext = createContext({});
20
+
21
+ const useCart = () => {
22
+ return useContext(CartContext);
23
+ };
24
+
25
+ const CartProvider = ({ children }) => {
26
+ const [cart, setCart] = useState({ cartId: '' });
27
+ const { refreshCart, resolveCartId } = useProducts();
28
+ const { storeViewCode, config } = useStore();
29
+
30
+ const initializeCustomerCart = async () => {
31
+ let cartId = '';
32
+ if (!resolveCartId) {
33
+ const customerResponse = await getGraphQL(
34
+ GET_CUSTOMER_CART,
35
+ {},
36
+ storeViewCode,
37
+ config && config.baseUrl
38
+ );
39
+
40
+ cartId =
41
+ customerResponse &&
42
+ customerResponse.data &&
43
+ customerResponse.data.customerCart &&
44
+ customerResponse.data.customerCart.id
45
+ ? customerResponse.data.customerCart.id
46
+ : '';
47
+ } else {
48
+ const resolvedCartId = await resolveCartId();
49
+ cartId = resolvedCartId != null ? resolvedCartId : '';
50
+ }
51
+
52
+ setCart({ ...cart, cartId });
53
+ return cartId;
54
+ };
55
+
56
+ const addToCartGraphQL = async sku => {
57
+ let cartId = cart.cartId;
58
+ if (!cartId) {
59
+ cartId = await initializeCustomerCart();
60
+ }
61
+ const cartItems = [
62
+ {
63
+ quantity: 1,
64
+ sku
65
+ }
66
+ ];
67
+
68
+ const variables = {
69
+ cartId,
70
+ cartItems
71
+ };
72
+
73
+ const response = await getGraphQL(
74
+ ADD_TO_CART,
75
+ variables,
76
+ storeViewCode,
77
+ config?.baseUrl
78
+ );
79
+
80
+ return response;
81
+ };
82
+
83
+ const cartContext = {
84
+ cart,
85
+ initializeCustomerCart,
86
+ addToCartGraphQL,
87
+ refreshCart
88
+ };
89
+
90
+ return (
91
+ <CartContext.Provider value={cartContext}>
92
+ {children}
93
+ </CartContext.Provider>
94
+ );
95
+ };
96
+
97
+ export { CartProvider, useCart };
@@ -0,0 +1,90 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ import React, { createContext, useContext, useState, useEffect } from 'react';
11
+ import { PRODUCT_COLUMNS } from '../utils/constants';
12
+
13
+ // Removed TypeScript interfaces
14
+
15
+ const DefaultScreenSizeObject = {
16
+ mobile: false,
17
+ tablet: false,
18
+ desktop: false,
19
+ columns: PRODUCT_COLUMNS.desktop
20
+ };
21
+
22
+ const useSensor = () => {
23
+ const { screenSize } = useContext(ResizeChangeContext);
24
+
25
+ const [result, setResult] = useState(DefaultScreenSizeObject);
26
+
27
+ useEffect(() => {
28
+ const size = screenSize ? screenSize : DefaultScreenSizeObject;
29
+ setResult(size);
30
+ }, [screenSize]);
31
+
32
+ return { screenSize: result };
33
+ };
34
+
35
+ export const ResizeChangeContext = createContext({});
36
+
37
+ const getColumn = screenSize => {
38
+ if (screenSize.desktop) {
39
+ return PRODUCT_COLUMNS.desktop;
40
+ }
41
+ if (screenSize.tablet) {
42
+ return PRODUCT_COLUMNS.tablet;
43
+ }
44
+ if (screenSize.mobile) {
45
+ return PRODUCT_COLUMNS.mobile;
46
+ }
47
+ // Fallback just in case
48
+ return PRODUCT_COLUMNS.desktop;
49
+ };
50
+
51
+ const Resize = ({ children }) => {
52
+ const detectDevice = () => {
53
+ const result = { ...DefaultScreenSizeObject };
54
+
55
+ result.mobile = window.matchMedia(
56
+ 'screen and (max-width: 767px)'
57
+ ).matches;
58
+ result.tablet = window.matchMedia(
59
+ 'screen and (min-width: 768px) and (max-width: 960px)'
60
+ ).matches;
61
+ result.desktop = window.matchMedia(
62
+ 'screen and (min-width: 961px)'
63
+ ).matches;
64
+ result.columns = getColumn(result);
65
+ return result;
66
+ };
67
+
68
+ const [screenSize, setScreenSize] = useState(detectDevice());
69
+
70
+ useEffect(() => {
71
+ window.addEventListener('resize', handleResize);
72
+ return () => {
73
+ window.removeEventListener('resize', handleResize);
74
+ };
75
+ });
76
+
77
+ const handleResize = () => {
78
+ setScreenSize({ ...screenSize, ...detectDevice() });
79
+ };
80
+
81
+ return (
82
+ <ResizeChangeContext.Provider value={{ screenSize }}>
83
+ {children}
84
+ </ResizeChangeContext.Provider>
85
+ );
86
+ };
87
+
88
+ export default Resize;
89
+
90
+ export { useSensor };
@@ -0,0 +1,160 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ import mse from '@adobe/magento-storefront-events-sdk';
11
+
12
+ const updateSearchInputCtx = (
13
+ searchUnitId,
14
+ searchRequestId,
15
+ phrase,
16
+ filters,
17
+ pageSize,
18
+ currentPage,
19
+ sort
20
+ ) => {
21
+ if (!mse) {
22
+ // don't break search if events are broken/not loading
23
+ return;
24
+ }
25
+
26
+ const searchInputResult = mse.context.getSearchInput();
27
+ const searchInputCtx =
28
+ searchInputResult !== null && searchInputResult !== undefined
29
+ ? searchInputResult
30
+ : { units: [] };
31
+
32
+ const searchInputUnit = {
33
+ searchUnitId,
34
+ searchRequestId,
35
+ queryTypes: ['products', 'suggestions'],
36
+ phrase,
37
+ pageSize,
38
+ currentPage,
39
+ filter: filters,
40
+ sort
41
+ };
42
+
43
+ const searchInputUnitIndex = searchInputCtx.units.findIndex(
44
+ unit => unit.searchUnitId === searchUnitId
45
+ );
46
+
47
+ if (searchInputUnitIndex < 0) {
48
+ searchInputCtx.units.push(searchInputUnit);
49
+ } else {
50
+ searchInputCtx.units[searchInputUnitIndex] = searchInputUnit;
51
+ }
52
+
53
+ mse.context.setSearchInput(searchInputCtx);
54
+ };
55
+
56
+ const updateSearchResultsCtx = (searchUnitId, searchRequestId, results) => {
57
+ const mse = window.magentoStorefrontEvents;
58
+ if (!mse) {
59
+ return;
60
+ }
61
+
62
+ const searchResultsResult = mse.context.getSearchResults();
63
+ const searchResultsCtx =
64
+ searchResultsResult !== null && searchResultsResult !== undefined
65
+ ? searchResultsResult
66
+ : { units: [] };
67
+
68
+ const searchResultUnitIndex = searchResultsCtx.units.findIndex(
69
+ unit => unit.searchUnitId === searchUnitId
70
+ );
71
+
72
+ const searchResultUnit = {
73
+ searchUnitId,
74
+ searchRequestId,
75
+ products: createProducts(results.items),
76
+ categories: [],
77
+ suggestions: createSuggestions(results.suggestions),
78
+ page: results?.page_info?.current_page || 1,
79
+ perPage: results?.page_info?.page_size || 20,
80
+ facets: createFacets(results.facets)
81
+ };
82
+
83
+ if (searchResultUnitIndex < 0) {
84
+ searchResultsCtx.units.push(searchResultUnit);
85
+ } else {
86
+ searchResultsCtx.units[searchResultUnitIndex] = searchResultUnit;
87
+ }
88
+
89
+ mse.context.setSearchResults(searchResultsCtx);
90
+ };
91
+
92
+ const createProducts = items => {
93
+ if (!items) {
94
+ return [];
95
+ }
96
+
97
+ return items.map((item, index) => ({
98
+ name: item && item.product && item.product.name,
99
+ sku: item && item.product && item.product.sku,
100
+ url:
101
+ item &&
102
+ item.product &&
103
+ item.product.canonical_url !== undefined &&
104
+ item.product.canonical_url !== null
105
+ ? item.product.canonical_url
106
+ : '',
107
+ imageUrl:
108
+ item &&
109
+ item.productView &&
110
+ Array.isArray(item.productView.images) &&
111
+ item.productView.images.length
112
+ ? item.productView.images[0].url !== undefined &&
113
+ item.productView.images[0].url !== null
114
+ ? item.productView.images[0].url
115
+ : ''
116
+ : '',
117
+ price:
118
+ item &&
119
+ item.productView &&
120
+ item.productView.price &&
121
+ item.productView.price.final &&
122
+ item.productView.price.final.amount &&
123
+ item.productView.price.final.amount.value !== undefined &&
124
+ item.productView.price.final.amount.value !== null
125
+ ? item.productView.price.final.amount.value
126
+ : item &&
127
+ item.product &&
128
+ item.product.price_range &&
129
+ item.product.price_range.minimum_price &&
130
+ item.product.price_range.minimum_price.final_price &&
131
+ item.product.price_range.minimum_price.final_price.value,
132
+ rank: index
133
+ }));
134
+ };
135
+
136
+ const createSuggestions = items => {
137
+ if (!items) {
138
+ return [];
139
+ }
140
+
141
+ return items.map((suggestion, index) => ({
142
+ suggestion,
143
+ rank: index
144
+ }));
145
+ };
146
+
147
+ const createFacets = items => {
148
+ if (!items) {
149
+ return [];
150
+ }
151
+
152
+ return items.map(item => ({
153
+ attribute: item?.attribute,
154
+ title: item?.title,
155
+ type: item?.type || 'PINNED',
156
+ buckets: item?.buckets.map(bucket => bucket)
157
+ }));
158
+ };
159
+
160
+ export { updateSearchInputCtx, updateSearchResultsCtx };
@@ -0,0 +1,19 @@
1
+ /*
2
+ Copyright 2024 Adobe
3
+ All Rights Reserved.
4
+
5
+ NOTICE: Adobe permits you to use, modify, and distribute this file in
6
+ accordance with the terms of the Adobe license agreement accompanying
7
+ it.
8
+ */
9
+
10
+ export * from './attributeMetadata';
11
+ export * from './store';
12
+ export * from './widgetConfig';
13
+ export * from './search';
14
+ export * from './products';
15
+ export * from './displayChange';
16
+ export * from './events';
17
+ export * from './translation';
18
+ export * from './cart';
19
+ export * from './wishlist';