@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,84 @@
|
|
|
1
|
+
.grid-container {
|
|
2
|
+
display: grid;
|
|
3
|
+
gap: 1px;
|
|
4
|
+
height: auto;
|
|
5
|
+
grid-template-columns: auto 1fr 1fr;
|
|
6
|
+
border-top: 2px solid #e5e7eb;
|
|
7
|
+
padding: 10px;
|
|
8
|
+
grid-template-areas:
|
|
9
|
+
'product-image product-details product-price'
|
|
10
|
+
'product-image product-description product-description'
|
|
11
|
+
'product-image product-ratings product-add-to-cart';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.product-image {
|
|
15
|
+
grid-area: product-image;
|
|
16
|
+
width: fit-content;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.product-details {
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
grid-area: product-details;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.product-price {
|
|
25
|
+
grid-area: product-price;
|
|
26
|
+
display: grid;
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
justify-content: end;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.product-description {
|
|
33
|
+
grid-area: product-description;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.product-description:hover {
|
|
37
|
+
text-decoration: underline;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.product-ratings {
|
|
41
|
+
grid-area: product-ratings;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.product-add-to-cart {
|
|
45
|
+
grid-area: product-add-to-cart;
|
|
46
|
+
display: grid;
|
|
47
|
+
justify-content: end;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@media screen and (max-width: 767px) {
|
|
51
|
+
.grid-container {
|
|
52
|
+
display: grid;
|
|
53
|
+
gap: 10px;
|
|
54
|
+
height: auto;
|
|
55
|
+
border-top: 2px solid #e5e7eb;
|
|
56
|
+
padding: 10px;
|
|
57
|
+
grid-template-areas:
|
|
58
|
+
'product-image product-image product-image'
|
|
59
|
+
'product-details product-details product-details'
|
|
60
|
+
'product-price product-price product-price'
|
|
61
|
+
'product-description product-description product-description'
|
|
62
|
+
'product-ratings product-ratings product-ratings'
|
|
63
|
+
'product-add-to-cart product-add-to-cart product-add-to-cart';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.product-image {
|
|
67
|
+
display: flex;
|
|
68
|
+
justify-content: center;
|
|
69
|
+
align-items: center;
|
|
70
|
+
width: auto;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.product-price {
|
|
74
|
+
justify-content: start;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.product-add-to-cart {
|
|
78
|
+
justify-content: center;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.product-details {
|
|
82
|
+
justify-content: center;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,347 @@
|
|
|
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, { useState } from 'react';
|
|
11
|
+
import '../ProductItem/ProductItem.css';
|
|
12
|
+
|
|
13
|
+
import { useCart, useProducts, useSensor, useStore } from '../../context';
|
|
14
|
+
import NoImage from '../../icons/NoImage.svg';
|
|
15
|
+
import {
|
|
16
|
+
generateOptimizedImages,
|
|
17
|
+
getProductImageURLs,
|
|
18
|
+
} from '../../utils/getProductImage';
|
|
19
|
+
import { htmlStringDecode } from '../../utils/htmlStringDecode';
|
|
20
|
+
import AddToCartButton from '../AddToCartButton';
|
|
21
|
+
import { ImageCarousel } from '../ImageCarousel';
|
|
22
|
+
import { SwatchButtonGroup } from '../SwatchButtonGroup';
|
|
23
|
+
import ProductPrice from './ProductPrice';
|
|
24
|
+
import { SEARCH_UNIT_ID } from '../../utils/constants';
|
|
25
|
+
import { sanitizeRefinedImages } from '../../utils/modifyResults';
|
|
26
|
+
import { useResultsModifier } from '../../context/resultsModifierContext';
|
|
27
|
+
|
|
28
|
+
const ProductItem = ({
|
|
29
|
+
item,
|
|
30
|
+
currencySymbol,
|
|
31
|
+
currencyRate,
|
|
32
|
+
setRoute,
|
|
33
|
+
refineProduct,
|
|
34
|
+
setCartUpdated,
|
|
35
|
+
setItemAdded,
|
|
36
|
+
setError,
|
|
37
|
+
addToCart,
|
|
38
|
+
}) => {
|
|
39
|
+
const { product, productView } = item;
|
|
40
|
+
const [carouselIndex, setCarouselIndex] = useState(0);
|
|
41
|
+
const [selectedSwatch, setSelectedSwatch] = useState('');
|
|
42
|
+
const [imagesFromRefinedProduct, setImagesFromRefinedProduct] = useState(null);
|
|
43
|
+
const [refinedProduct, setRefinedProduct] = useState();
|
|
44
|
+
const [isHovering, setIsHovering] = useState(false);
|
|
45
|
+
const { addToCartGraphQL, refreshCart } = useCart();
|
|
46
|
+
const { viewType } = useProducts();
|
|
47
|
+
const {
|
|
48
|
+
config: { optimizeImages, imageBaseWidth, imageCarousel, listview },
|
|
49
|
+
} = useStore();
|
|
50
|
+
|
|
51
|
+
const { screenSize } = useSensor();
|
|
52
|
+
|
|
53
|
+
const handleMouseOver = () => {
|
|
54
|
+
setIsHovering(true);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleMouseOut = () => {
|
|
58
|
+
setIsHovering(false);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const { baseUrl, baseUrlWithoutProtocol } = useResultsModifier();
|
|
62
|
+
|
|
63
|
+
const handleSelection = async (optionIds, sku) => {
|
|
64
|
+
const data = await refineProduct(optionIds, sku);
|
|
65
|
+
setSelectedSwatch(optionIds[0]);
|
|
66
|
+
setImagesFromRefinedProduct(sanitizeRefinedImages(data.refineProduct.images, baseUrl, baseUrlWithoutProtocol, true));
|
|
67
|
+
setRefinedProduct(data);
|
|
68
|
+
setCarouselIndex(0);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const isSelected = (id) => {
|
|
72
|
+
const selected = selectedSwatch ? selectedSwatch === id : false;
|
|
73
|
+
return selected;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const productImageArray = imagesFromRefinedProduct
|
|
77
|
+
? getProductImageURLs(imagesFromRefinedProduct.length ? imagesFromRefinedProduct : [], imageCarousel ? 3 : 1)
|
|
78
|
+
: getProductImageURLs(
|
|
79
|
+
productView.images && productView.images.length ? productView.images : [],
|
|
80
|
+
imageCarousel ? 3 : 1, // number of images to display in carousel
|
|
81
|
+
product.image && product.image.url ? product.image.url : undefined
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
let optimizedImageArray = [];
|
|
86
|
+
|
|
87
|
+
if (optimizeImages) {
|
|
88
|
+
optimizedImageArray = generateOptimizedImages(
|
|
89
|
+
productImageArray,
|
|
90
|
+
imageBaseWidth !== undefined && imageBaseWidth !== null ? imageBaseWidth : 200
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const discount = refinedProduct
|
|
95
|
+
? refinedProduct.refineProduct?.priceRange?.minimum?.regular?.amount
|
|
96
|
+
?.value >
|
|
97
|
+
refinedProduct.refineProduct?.priceRange?.minimum?.final?.amount?.value
|
|
98
|
+
: product?.price_range?.minimum_price?.regular_price?.value >
|
|
99
|
+
product?.price_range?.minimum_price?.final_price?.value ||
|
|
100
|
+
productView?.price?.regular?.amount?.value >
|
|
101
|
+
productView?.price?.final?.amount?.value;
|
|
102
|
+
|
|
103
|
+
const isSimple = product?.__typename === 'SimpleProduct';
|
|
104
|
+
const isComplexProductView = productView?.__typename === 'ComplexProductView';
|
|
105
|
+
const isBundle = product?.__typename === 'BundleProduct';
|
|
106
|
+
const isGrouped = product?.__typename === 'GroupedProduct';
|
|
107
|
+
const isGiftCard = product?.__typename === 'GiftCardProduct';
|
|
108
|
+
const isConfigurable = product?.__typename === 'ConfigurableProduct';
|
|
109
|
+
|
|
110
|
+
const onProductClick = () => {
|
|
111
|
+
window.magentoStorefrontEvents?.publish.searchProductClick(
|
|
112
|
+
SEARCH_UNIT_ID,
|
|
113
|
+
product?.sku
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const productUrl = setRoute
|
|
118
|
+
? setRoute({ sku: productView?.sku, urlKey: productView?.urlKey })
|
|
119
|
+
: product?.canonical_url;
|
|
120
|
+
|
|
121
|
+
const handleAddToCart = async () => {
|
|
122
|
+
setError(false);
|
|
123
|
+
if (isSimple) {
|
|
124
|
+
if (addToCart) {
|
|
125
|
+
await addToCart(productView.sku, [], 1);
|
|
126
|
+
} else {
|
|
127
|
+
const response = await addToCartGraphQL(productView.sku);
|
|
128
|
+
|
|
129
|
+
if (
|
|
130
|
+
response?.errors ||
|
|
131
|
+
response?.data?.addProductsToCart?.user_errors.length > 0
|
|
132
|
+
) {
|
|
133
|
+
setError(true);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setItemAdded(product.name);
|
|
138
|
+
refreshCart && refreshCart();
|
|
139
|
+
setCartUpdated(true);
|
|
140
|
+
}
|
|
141
|
+
} else if (productUrl) {
|
|
142
|
+
window.open(productUrl, '_self');
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (listview && viewType === 'listview') {
|
|
147
|
+
return (
|
|
148
|
+
<>
|
|
149
|
+
<div className="grid-container">
|
|
150
|
+
<div
|
|
151
|
+
className={`product-image ds-sdk-product-item__image relative rounded-md overflow-hidden}`}
|
|
152
|
+
>
|
|
153
|
+
<a
|
|
154
|
+
href={productUrl}
|
|
155
|
+
onClick={onProductClick}
|
|
156
|
+
className="!text-primary hover:no-underline hover:text-primary"
|
|
157
|
+
>
|
|
158
|
+
{/* Image */}
|
|
159
|
+
{productImageArray.length ? (
|
|
160
|
+
<ImageCarousel
|
|
161
|
+
images={
|
|
162
|
+
optimizedImageArray.length
|
|
163
|
+
? optimizedImageArray
|
|
164
|
+
: productImageArray
|
|
165
|
+
}
|
|
166
|
+
productName={product.name}
|
|
167
|
+
carouselIndex={carouselIndex}
|
|
168
|
+
setCarouselIndex={setCarouselIndex}
|
|
169
|
+
/>
|
|
170
|
+
) : (
|
|
171
|
+
<img src={NoImage} className={`max-h-[250px] max-w-[200px] pr-5 m-auto object-cover object-center lg:w-full`} />
|
|
172
|
+
// <NoImage
|
|
173
|
+
// className={`max-h-[250px] max-w-[200px] pr-5 m-auto object-cover object-center lg:w-full`}
|
|
174
|
+
// />
|
|
175
|
+
)}
|
|
176
|
+
</a>
|
|
177
|
+
</div>
|
|
178
|
+
<div className="product-details">
|
|
179
|
+
<div className="flex flex-col w-1/3">
|
|
180
|
+
{/* Product name */}
|
|
181
|
+
<a
|
|
182
|
+
href={productUrl}
|
|
183
|
+
onClick={onProductClick}
|
|
184
|
+
className="!text-primary hover:no-underline hover:text-primary"
|
|
185
|
+
>
|
|
186
|
+
<div className="ds-sdk-product-item__product-name mt-xs text-sm text-primary">
|
|
187
|
+
{product.name !== null && htmlStringDecode(product.name)}
|
|
188
|
+
</div>
|
|
189
|
+
<div className="ds-sdk-product-item__product-sku mt-xs text-sm text-primary">
|
|
190
|
+
SKU:
|
|
191
|
+
{product.sku !== null && htmlStringDecode(product.sku)}
|
|
192
|
+
</div>
|
|
193
|
+
</a>
|
|
194
|
+
|
|
195
|
+
{/* Swatch */}
|
|
196
|
+
{!screenSize.mobile &&
|
|
197
|
+
productView?.options &&
|
|
198
|
+
productView.options?.length > 0 && (
|
|
199
|
+
<div className="ds-sdk-product-item__product-swatch flex flex-row mt-sm text-sm text-primary pb-6">
|
|
200
|
+
{productView?.options?.map(
|
|
201
|
+
(swatches) =>
|
|
202
|
+
swatches.id === 'color' && (
|
|
203
|
+
<SwatchButtonGroup
|
|
204
|
+
key={`${productView?.sku}-${option.id}`}
|
|
205
|
+
isSelected={isSelected}
|
|
206
|
+
swatches={swatches.values && swatches.values.length ? swatches.values : []}
|
|
207
|
+
showMore={onProductClick}
|
|
208
|
+
productUrl={productUrl}
|
|
209
|
+
onClick={handleSelection}
|
|
210
|
+
sku={productView?.sku}
|
|
211
|
+
/>
|
|
212
|
+
)
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
<div className="product-price">
|
|
220
|
+
<a
|
|
221
|
+
href={productUrl}
|
|
222
|
+
onClick={onProductClick}
|
|
223
|
+
className="!text-primary hover:no-underline hover:text-primary"
|
|
224
|
+
>
|
|
225
|
+
<ProductPrice
|
|
226
|
+
item={refinedProduct !== undefined && refinedProduct !== null ? refinedProduct : item}
|
|
227
|
+
isBundle={isBundle}
|
|
228
|
+
isGrouped={isGrouped}
|
|
229
|
+
isGiftCard={isGiftCard}
|
|
230
|
+
isConfigurable={isConfigurable}
|
|
231
|
+
isComplexProductView={isComplexProductView}
|
|
232
|
+
discount={discount}
|
|
233
|
+
currencySymbol={currencySymbol}
|
|
234
|
+
currencyRate={currencyRate}
|
|
235
|
+
/>
|
|
236
|
+
</a>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="product-description text-sm text-primary mt-xs">
|
|
239
|
+
<a
|
|
240
|
+
href={productUrl}
|
|
241
|
+
onClick={onProductClick}
|
|
242
|
+
className="!text-primary hover:no-underline hover:text-primary"
|
|
243
|
+
>
|
|
244
|
+
{product.short_description?.html ? (
|
|
245
|
+
<>
|
|
246
|
+
<span
|
|
247
|
+
dangerouslySetInnerHTML={{
|
|
248
|
+
__html: product.short_description.html,
|
|
249
|
+
}}
|
|
250
|
+
/>
|
|
251
|
+
</>
|
|
252
|
+
) : (
|
|
253
|
+
<span />
|
|
254
|
+
)}
|
|
255
|
+
</a>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<div className="product-ratings" />
|
|
259
|
+
<div className="product-add-to-cart">
|
|
260
|
+
<div className="pb-4 h-[38px] w-96">
|
|
261
|
+
<AddToCartButton onClick={handleAddToCart} />
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<div
|
|
271
|
+
className="ds-sdk-product-item group relative flex flex-col max-w-sm justify-between h-full hover:border-[1.5px] border-solid hover:shadow-lg border-offset-2 p-5"
|
|
272
|
+
style={{
|
|
273
|
+
'borderColor': '#D5D5D5',
|
|
274
|
+
}}
|
|
275
|
+
onMouseEnter={handleMouseOver}
|
|
276
|
+
onMouseLeave={handleMouseOut}
|
|
277
|
+
>
|
|
278
|
+
<a
|
|
279
|
+
href={productUrl}
|
|
280
|
+
onClick={onProductClick}
|
|
281
|
+
className="!text-primary hover:no-underline hover:text-primary"
|
|
282
|
+
>
|
|
283
|
+
<div className="ds-sdk-product-item__main relative flex flex-col justify-between h-full">
|
|
284
|
+
<div className="ds-sdk-product-item__image relative w-full h-full rounded-md overflow-hidden">
|
|
285
|
+
{productImageArray.length ? (
|
|
286
|
+
<ImageCarousel
|
|
287
|
+
images={
|
|
288
|
+
optimizedImageArray.length
|
|
289
|
+
? optimizedImageArray
|
|
290
|
+
: productImageArray
|
|
291
|
+
}
|
|
292
|
+
productName={product.name}
|
|
293
|
+
carouselIndex={carouselIndex}
|
|
294
|
+
setCarouselIndex={setCarouselIndex}
|
|
295
|
+
/>
|
|
296
|
+
) : (
|
|
297
|
+
<img src={NoImage} className={`max-h-[45rem] w-full object-cover object-center lg:w-full`} />
|
|
298
|
+
// <NoImage
|
|
299
|
+
// className={`max-h-[45rem] w-full object-cover object-center lg:w-full`}
|
|
300
|
+
// />
|
|
301
|
+
)}
|
|
302
|
+
</div>
|
|
303
|
+
<div className="flex flex-row">
|
|
304
|
+
<div className="flex flex-col">
|
|
305
|
+
<div className="ds-sdk-product-item__product-name mt-md text-sm text-primary">
|
|
306
|
+
{product.name !== null && htmlStringDecode(product.name)}
|
|
307
|
+
</div>
|
|
308
|
+
<ProductPrice
|
|
309
|
+
item={refinedProduct !== undefined && refinedProduct !== null ? refinedProduct : item}
|
|
310
|
+
isBundle={isBundle}
|
|
311
|
+
isGrouped={isGrouped}
|
|
312
|
+
isGiftCard={isGiftCard}
|
|
313
|
+
isConfigurable={isConfigurable}
|
|
314
|
+
isComplexProductView={isComplexProductView}
|
|
315
|
+
discount={discount}
|
|
316
|
+
currencySymbol={currencySymbol}
|
|
317
|
+
currencyRate={currencyRate}
|
|
318
|
+
/>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
</a>
|
|
323
|
+
|
|
324
|
+
{!screenSize.mobile && productView?.options && productView.options?.length > 0 && (
|
|
325
|
+
<div className="ds-sdk-product-item__product-swatch mt-sm text-sm text-primary pb-6">
|
|
326
|
+
{productView?.options.map((option) => (
|
|
327
|
+
<SwatchButtonGroup
|
|
328
|
+
key={`${productView?.sku}-${option.id}`}
|
|
329
|
+
isSelected={isSelected}
|
|
330
|
+
swatches={option.values && option.values.length ? option.values : []}
|
|
331
|
+
showMore={onProductClick}
|
|
332
|
+
productUrl={productUrl}
|
|
333
|
+
onClick={handleSelection}
|
|
334
|
+
sku={productView?.sku}
|
|
335
|
+
/>
|
|
336
|
+
))}
|
|
337
|
+
</div>
|
|
338
|
+
)}
|
|
339
|
+
|
|
340
|
+
<div className="ds-sdk-product-item__add-to-cart py-2">
|
|
341
|
+
<AddToCartButton onClick={handleAddToCart} />
|
|
342
|
+
</div>
|
|
343
|
+
</div>
|
|
344
|
+
);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
export default ProductItem;
|
|
@@ -0,0 +1,181 @@
|
|
|
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, { useContext } from 'react';
|
|
11
|
+
import { TranslationContext } from '../../context/translation';
|
|
12
|
+
import { getProductPrice } from '../../utils/getProductPrice';
|
|
13
|
+
|
|
14
|
+
const ProductPrice = ({
|
|
15
|
+
isComplexProductView,
|
|
16
|
+
item,
|
|
17
|
+
isBundle,
|
|
18
|
+
isGrouped,
|
|
19
|
+
isGiftCard,
|
|
20
|
+
isConfigurable,
|
|
21
|
+
discount,
|
|
22
|
+
currencySymbol,
|
|
23
|
+
currencyRate
|
|
24
|
+
}) => {
|
|
25
|
+
const translation = useContext(TranslationContext);
|
|
26
|
+
let price;
|
|
27
|
+
|
|
28
|
+
if ('product' in item) {
|
|
29
|
+
price =
|
|
30
|
+
item && item.product && item.product.price_range && item.product.price_range.minimum_price && item.product.price_range.minimum_price.final_price
|
|
31
|
+
? item.product.price_range.minimum_price.final_price : item && item.product && item.product.price_range && item.product.price_range.minimum_price && item.product.price_range.minimum_price.regular_price
|
|
32
|
+
? item.product.price_range.minimum_price.regular_price : undefined;
|
|
33
|
+
} else {
|
|
34
|
+
price =
|
|
35
|
+
item && item.refineProduct && item.refineProduct.priceRange && item.refineProduct.priceRange.minimum && item.refineProduct.priceRange.minimum.final
|
|
36
|
+
? item.refineProduct.priceRange.minimum.final
|
|
37
|
+
: item && item.refineProduct && item.refineProduct.price && item.refineProduct.price.final
|
|
38
|
+
? item.refineProduct.price.final : undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const getBundledPrice = (item, currencySymbol, currencyRate) => {
|
|
42
|
+
const bundlePriceTranslationOrder =
|
|
43
|
+
translation.ProductCard.bundlePrice.split(' ');
|
|
44
|
+
return bundlePriceTranslationOrder.map((word, index) =>
|
|
45
|
+
word === '{fromBundlePrice}' ? (
|
|
46
|
+
`${getProductPrice(item, currencySymbol, currencyRate, false, true)} `
|
|
47
|
+
) : word === '{toBundlePrice}' ? (
|
|
48
|
+
getProductPrice(item, currencySymbol, currencyRate, true, true)
|
|
49
|
+
) : (
|
|
50
|
+
<span className="text-gray-500 text-xs font-normal mr-xs" key={index}>
|
|
51
|
+
{word}
|
|
52
|
+
</span>
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const getPriceFormat = (item, currencySymbol, currencyRate, isGiftCard) => {
|
|
58
|
+
const priceTranslation = isGiftCard
|
|
59
|
+
? translation.ProductCard.from
|
|
60
|
+
: translation.ProductCard.startingAt;
|
|
61
|
+
const startingAtTranslationOrder = priceTranslation.split('{productPrice}');
|
|
62
|
+
return startingAtTranslationOrder.map((word, index) =>
|
|
63
|
+
word === '' ? (
|
|
64
|
+
getProductPrice(item, currencySymbol, currencyRate, false, true)
|
|
65
|
+
) : (
|
|
66
|
+
<span className="text-gray-500 text-xs font-normal mr-xs" key={index}>
|
|
67
|
+
{word}
|
|
68
|
+
</span>
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const getDiscountedPrice = (discount) => {
|
|
74
|
+
const discountPrice = discount ? (
|
|
75
|
+
<>
|
|
76
|
+
<span className="line-through pr-2">
|
|
77
|
+
{getProductPrice(item, currencySymbol, currencyRate, false, false)}
|
|
78
|
+
</span>
|
|
79
|
+
<span className="text-secondary">
|
|
80
|
+
{getProductPrice(item, currencySymbol, currencyRate, false, true)}
|
|
81
|
+
</span>
|
|
82
|
+
</>
|
|
83
|
+
) : (
|
|
84
|
+
getProductPrice(item, currencySymbol, currencyRate, false, true)
|
|
85
|
+
);
|
|
86
|
+
const discountedPriceTranslation = translation.ProductCard.asLowAs;
|
|
87
|
+
const discountedPriceTranslationOrder =
|
|
88
|
+
discountedPriceTranslation.split('{discountPrice}');
|
|
89
|
+
return discountedPriceTranslationOrder.map((word, index) =>
|
|
90
|
+
word === '' ? (
|
|
91
|
+
discountPrice
|
|
92
|
+
) : (
|
|
93
|
+
<span className="text-gray-500 text-xs font-normal mr-xs" key={index}>
|
|
94
|
+
{word}
|
|
95
|
+
</span>
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<>
|
|
102
|
+
{price && (
|
|
103
|
+
<div className="ds-sdk-product-price">
|
|
104
|
+
{!isBundle &&
|
|
105
|
+
!isGrouped &&
|
|
106
|
+
!isConfigurable &&
|
|
107
|
+
!isComplexProductView &&
|
|
108
|
+
discount && (
|
|
109
|
+
<p className="ds-sdk-product-price--discount mt-xs text-sm font-medium text-gray-900 my-auto">
|
|
110
|
+
<span className="line-through pr-2">
|
|
111
|
+
{getProductPrice(
|
|
112
|
+
item,
|
|
113
|
+
currencySymbol,
|
|
114
|
+
currencyRate,
|
|
115
|
+
false,
|
|
116
|
+
false
|
|
117
|
+
)}
|
|
118
|
+
</span>
|
|
119
|
+
<span className="text-secondary">
|
|
120
|
+
{getProductPrice(
|
|
121
|
+
item,
|
|
122
|
+
currencySymbol,
|
|
123
|
+
currencyRate,
|
|
124
|
+
false,
|
|
125
|
+
true
|
|
126
|
+
)}
|
|
127
|
+
</span>
|
|
128
|
+
</p>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{!isBundle &&
|
|
132
|
+
!isGrouped &&
|
|
133
|
+
!isGiftCard &&
|
|
134
|
+
!isConfigurable &&
|
|
135
|
+
!isComplexProductView &&
|
|
136
|
+
!discount && (
|
|
137
|
+
<p className="ds-sdk-product-price--no-discount mt-xs text-sm font-medium text-gray-900 my-auto">
|
|
138
|
+
{getProductPrice(
|
|
139
|
+
item,
|
|
140
|
+
currencySymbol,
|
|
141
|
+
currencyRate,
|
|
142
|
+
false,
|
|
143
|
+
true
|
|
144
|
+
)}
|
|
145
|
+
</p>
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
{isBundle && (
|
|
149
|
+
<div className="ds-sdk-product-price--bundle">
|
|
150
|
+
<p className="mt-xs text-sm font-medium text-gray-900 my-auto">
|
|
151
|
+
{getBundledPrice(item, currencySymbol, currencyRate)}
|
|
152
|
+
</p>
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
|
|
156
|
+
{isGrouped && (
|
|
157
|
+
<p className="ds-sdk-product-price--grouped mt-xs text-sm font-medium text-gray-900 my-auto">
|
|
158
|
+
{getPriceFormat(item, currencySymbol, currencyRate, false)}
|
|
159
|
+
</p>
|
|
160
|
+
)}
|
|
161
|
+
|
|
162
|
+
{isGiftCard && (
|
|
163
|
+
<p className="ds-sdk-product-price--gift-card mt-xs text-sm font-medium text-gray-900 my-auto">
|
|
164
|
+
{getPriceFormat(item, currencySymbol, currencyRate, true)}
|
|
165
|
+
</p>
|
|
166
|
+
)}
|
|
167
|
+
|
|
168
|
+
{!isGrouped &&
|
|
169
|
+
!isBundle &&
|
|
170
|
+
(isConfigurable || isComplexProductView) && (
|
|
171
|
+
<p className="ds-sdk-product-price--configurable mt-xs text-sm font-medium text-gray-900 my-auto">
|
|
172
|
+
{getDiscountedPrice(discount)}
|
|
173
|
+
</p>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
</>
|
|
178
|
+
);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export default ProductPrice;
|
|
@@ -0,0 +1,11 @@
|
|
|
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 './ProductItem';
|
|
11
|
+
export { default as ProductItem } from './ProductItem';
|