@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.
- package/package.json +31 -0
- package/postcss.config.js +3 -0
- package/src/api/fragments.js +193 -0
- package/src/api/graphql.js +26 -0
- package/src/api/mutations.js +94 -0
- package/src/api/queries.js +225 -0
- package/src/api/search.js +222 -0
- package/src/components/AddToCartButton/AddToCartButton.jsx +32 -0
- package/src/components/AddToCartButton/AddToCartButton.stories.mdx +14 -0
- package/src/components/AddToCartButton/index.js +10 -0
- package/src/components/Alert/Alert.jsx +155 -0
- package/src/components/Alert/index.js +11 -0
- package/src/components/Breadcrumbs/Breadcrumbs.jsx +34 -0
- package/src/components/Breadcrumbs/MockPages.js +14 -0
- package/src/components/Breadcrumbs/index.js +11 -0
- package/src/components/ButtonShimmer/ButtonShimmer.css +32 -0
- package/src/components/ButtonShimmer/ButtonShimmer.jsx +23 -0
- package/src/components/ButtonShimmer/index.js +11 -0
- package/src/components/CategoryFilters/CategoryFilters.jsx +59 -0
- package/src/components/CategoryFilters/index.js +10 -0
- package/src/components/Facets/Facets.jsx +50 -0
- package/src/components/Facets/Range/RangeFacet.js +20 -0
- package/src/components/Facets/Scalar/ScalarFacet.js +29 -0
- package/src/components/Facets/SelectedFilters.js +80 -0
- package/src/components/Facets/format.js +52 -0
- package/src/components/Facets/index.js +14 -0
- package/src/components/Facets/mocks.js +119 -0
- package/src/components/FacetsShimmer/FacetsShimmer.css +49 -0
- package/src/components/FacetsShimmer/FacetsShimmer.jsx +25 -0
- package/src/components/FacetsShimmer/index.js +11 -0
- package/src/components/FilterButton/FilterButton.jsx +40 -0
- package/src/components/FilterButton/index.js +11 -0
- package/src/components/ImageCarousel/Image.jsx +34 -0
- package/src/components/ImageCarousel/ImageCarousel.jsx +103 -0
- package/src/components/ImageCarousel/index.js +11 -0
- package/src/components/InputButtonGroup/InputButtonGroup.jsx +120 -0
- package/src/components/InputButtonGroup/index.js +11 -0
- package/src/components/LabelledInput/LabelledInput.jsx +51 -0
- package/src/components/LabelledInput/index.js +11 -0
- package/src/components/Loading/Loading.jsx +32 -0
- package/src/components/Loading/index.js +11 -0
- package/src/components/NoResults/NoResults.jsx +55 -0
- package/src/components/NoResults/index.js +11 -0
- package/src/components/Pagination/Pagination.jsx +105 -0
- package/src/components/Pagination/index.js +10 -0
- package/src/components/PerPagePicker/PerPagePicker.jsx +114 -0
- package/src/components/PerPagePicker/index.js +11 -0
- package/src/components/Pill/Pill.jsx +34 -0
- package/src/components/Pill/index.js +11 -0
- package/src/components/Pill/mock.js +23 -0
- package/src/components/ProductCardShimmer/ProductCardShimmer.css +72 -0
- package/src/components/ProductCardShimmer/ProductCardShimmer.jsx +28 -0
- package/src/components/ProductCardShimmer/index.js +11 -0
- package/src/components/ProductItem/MockData.js +508 -0
- package/src/components/ProductItem/ProductItem.css +84 -0
- package/src/components/ProductItem/ProductItem.jsx +347 -0
- package/src/components/ProductItem/ProductPrice.jsx +181 -0
- package/src/components/ProductItem/index.js +11 -0
- package/src/components/ProductList/MockData.js +190 -0
- package/src/components/ProductList/ProductList.jsx +127 -0
- package/src/components/ProductList/index.js +11 -0
- package/src/components/ProductList/product-list.css +18 -0
- package/src/components/SearchBar/SearchBar.jsx +33 -0
- package/src/components/SearchBar/index.js +11 -0
- package/src/components/Shimmer/Shimmer.css +82 -0
- package/src/components/Shimmer/Shimmer.jsx +66 -0
- package/src/components/Shimmer/index.js +11 -0
- package/src/components/Slider/Slider.css +61 -0
- package/src/components/Slider/Slider.jsx +103 -0
- package/src/components/Slider/index.jsx +11 -0
- package/src/components/SliderDoubleControl/SliderDoubleControl.css +83 -0
- package/src/components/SliderDoubleControl/SliderDoubleControl.jsx +220 -0
- package/src/components/SliderDoubleControl/index.js +11 -0
- package/src/components/SortDropdown/SortDropdown.jsx +126 -0
- package/src/components/SortDropdown/index.js +11 -0
- package/src/components/SwatchButton/SwatchButton.jsx +72 -0
- package/src/components/SwatchButton/index.js +11 -0
- package/src/components/SwatchButtonGroup/SwatchButtonGroup.jsx +86 -0
- package/src/components/SwatchButtonGroup/index.js +11 -0
- package/src/components/ViewSwitcher/ViewSwitcher.jsx +46 -0
- package/src/components/ViewSwitcher/index.js +11 -0
- package/src/components/WishlistButton/WishlistButton.jsx +67 -0
- package/src/components/WishlistButton/index.js +11 -0
- package/src/containers/App.jsx +145 -0
- package/src/containers/LiveSearchPLPLoader.jsx +24 -0
- package/src/containers/LiveSearchPopoverLoader.jsx +190 -0
- package/src/containers/LiveSearchSRLPLoader.jsx +24 -0
- package/src/containers/ProductListingPage.jsx +66 -0
- package/src/containers/ProductsContainer.jsx +145 -0
- package/src/containers/ProductsHeader.jsx +123 -0
- package/src/context/attributeMetadata.js +63 -0
- package/src/context/cart.js +97 -0
- package/src/context/displayChange.js +90 -0
- package/src/context/events.js +160 -0
- package/src/context/index.js +19 -0
- package/src/context/products.jsx +336 -0
- package/src/context/resultsModifierContext.js +35 -0
- package/src/context/search.jsx +127 -0
- package/src/context/store.jsx +93 -0
- package/src/context/translation.jsx +125 -0
- package/src/context/widgetConfig.jsx +120 -0
- package/src/context/wishlist.jsx +97 -0
- package/src/hooks/eventing/useEventListener.js +13 -0
- package/src/hooks/eventing/useLocation.js +21 -0
- package/src/hooks/eventing/useMagentoExtensionContext.js +28 -0
- package/src/hooks/eventing/usePageView.js +36 -0
- package/src/hooks/eventing/useShopperContext.js +33 -0
- package/src/hooks/eventing/useStorefrontInstanceContext.js +46 -0
- package/src/hooks/eventing/useViewedOffsets.js +74 -0
- package/src/hooks/useAccessibleDropdown.js +148 -0
- package/src/hooks/useLiveSearchPLPConfig.js +112 -0
- package/src/hooks/useLiveSearchPopoverConfig.js +83 -0
- package/src/hooks/useLiveSearchSRLPConfig.js +97 -0
- package/src/hooks/usePagination.js +83 -0
- package/src/hooks/useRangeFacet.js +62 -0
- package/src/hooks/useScalarFacet.js +61 -0
- package/src/hooks/useSliderFacet.js +43 -0
- package/src/i18n/Sorani.js +60 -0
- package/src/i18n/ar_AE.js +60 -0
- package/src/i18n/bg_BG.js +60 -0
- package/src/i18n/bn_IN.js +60 -0
- package/src/i18n/ca_ES.js +60 -0
- package/src/i18n/cs_CZ.js +60 -0
- package/src/i18n/da_DK.js +60 -0
- package/src/i18n/de_DE.js +60 -0
- package/src/i18n/el_GR.js +60 -0
- package/src/i18n/en_GA.js +60 -0
- package/src/i18n/en_GB.js +60 -0
- package/src/i18n/en_US.js +70 -0
- package/src/i18n/es_ES.js +60 -0
- package/src/i18n/et_EE.js +60 -0
- package/src/i18n/eu_ES.js +60 -0
- package/src/i18n/fa_IR.js +60 -0
- package/src/i18n/fi_FI.js +60 -0
- package/src/i18n/fr_FR.js +60 -0
- package/src/i18n/gl_ES.js +60 -0
- package/src/i18n/hi_IN.js +60 -0
- package/src/i18n/hu_HU.js +60 -0
- package/src/i18n/hy_AM.js +60 -0
- package/src/i18n/id_ID.js +60 -0
- package/src/i18n/index.js +89 -0
- package/src/i18n/it_IT.js +60 -0
- package/src/i18n/ja_JP.js +60 -0
- package/src/i18n/ko_KR.js +60 -0
- package/src/i18n/lt_LT.js +60 -0
- package/src/i18n/lv_LV.js +60 -0
- package/src/i18n/nb_NO.js +60 -0
- package/src/i18n/nl_NL.js +60 -0
- package/src/i18n/pt_BR.js +60 -0
- package/src/i18n/pt_PT.js +60 -0
- package/src/i18n/ro_RO.js +60 -0
- package/src/i18n/ru_RU.js +60 -0
- package/src/i18n/sv_SE.js +60 -0
- package/src/i18n/th_TH.js +60 -0
- package/src/i18n/tr_TR.js +60 -0
- package/src/i18n/zh_Hans_CN.js +60 -0
- package/src/i18n/zh_Hant_TW.js +60 -0
- package/src/icons/NoImage.svg +1 -0
- package/src/icons/adjustments.svg +3 -0
- package/src/icons/cart.svg +3 -0
- package/src/icons/checkmark.svg +3 -0
- package/src/icons/chevron.svg +3 -0
- package/src/icons/emptyHeart.svg +3 -0
- package/src/icons/error.svg +3 -0
- package/src/icons/filledHeart.svg +3 -0
- package/src/icons/filter.svg +29 -0
- package/src/icons/gridView.svg +11 -0
- package/src/icons/info.svg +3 -0
- package/src/icons/listView.svg +5 -0
- package/src/icons/loading.svg +6 -0
- package/src/icons/plus.svg +4 -0
- package/src/icons/sort.svg +18 -0
- package/src/icons/warning.svg +3 -0
- package/src/icons/x.svg +3 -0
- package/src/index.jsx +65 -0
- package/src/queries/customerGroupCode.gql.js +10 -0
- package/src/queries/eventing/getMagentoExtensionContext.gql.js +13 -0
- package/src/queries/eventing/getPageType.gql.js +14 -0
- package/src/queries/eventing/getStorefrontContext.gql.js +27 -0
- package/src/queries/index.js +3 -0
- package/src/queries/liveSearchPlpConfigs.gql.js +30 -0
- package/src/queries/liveSearchPopoverConfigs.gql.js +28 -0
- package/src/styles/autocomplete.module.css +56 -0
- package/src/styles/index.css +1638 -0
- package/src/styles/searchBar.module.css +119 -0
- package/src/styles/tokens.css +99 -0
- package/src/targets/intercept.js +21 -0
- package/src/utils/constants.js +26 -0
- package/src/utils/decodeHtmlString.js +13 -0
- package/src/utils/dom.js +14 -0
- package/src/utils/eventing/getCookie.js +9 -0
- package/src/utils/eventing/usePageTypeFromUrl.js +26 -0
- package/src/utils/getProductImage.js +94 -0
- package/src/utils/getProductPrice.js +83 -0
- package/src/utils/getUserViewHistory.js +27 -0
- package/src/utils/handleUrlFilters.js +164 -0
- package/src/utils/htmlStringDecode.js +13 -0
- package/src/utils/modifyResults.js +164 -0
- package/src/utils/sort.js +95 -0
- package/src/utils/useIntersectionObserver.js +27 -0
- package/src/utils/validateStoreDetails.js +39 -0
- 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';
|