@riosst100/pwa-marketplace 2.1.5 → 2.1.7
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 +1 -1
- package/src/componentOverrideMapping.js +2 -0
- package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +12 -6
- package/src/overwrites/peregrine/lib/talons/RootComponents/Product/product.gql.js +5 -2
- package/src/overwrites/peregrine/lib/talons/RootComponents/Product/useProduct.js +121 -0
- package/src/overwrites/venia-ui/lib/RootComponents/Product/product.js +58 -0
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +30 -1
package/package.json
CHANGED
|
@@ -15,11 +15,13 @@ module.exports = componentOverrideMapping = {
|
|
|
15
15
|
[`@magento/peregrine/lib/talons/AccountMenu/useAccountMenuItems.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/AccountMenu/useAccountMenuItems.js',
|
|
16
16
|
[`@magento/peregrine/lib/talons/MegaMenu/megaMenu.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/MegaMenu/megaMenu.gql.js',
|
|
17
17
|
[`@magento/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js',
|
|
18
|
+
[`@magento/peregrine/lib/talons/RootComponents/Product/useProduct.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/RootComponents/Product/useProduct.js',
|
|
18
19
|
[`@magento/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js',
|
|
19
20
|
[`@magento/peregrine/lib/util/deriveErrorMessage.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/util/deriveErrorMessage.js',
|
|
20
21
|
[`@magento/venia-ui/lib/components/MegaMenu/megaMenu.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/MegaMenu/megaMenu.js',
|
|
21
22
|
[`@magento/venia-ui/lib/components/FilterModal/FilterList/filterDefault.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/components/FilterModal/FilterList/filterDefault.js',
|
|
22
23
|
[`@magento/venia-ui/lib/RootComponents/Category/categoryContent.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/RootComponents/Category/categoryContent.js',
|
|
24
|
+
[`@magento/venia-ui/lib/RootComponents/Product/product.js`]: '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/RootComponents/Product/product.js',
|
|
23
25
|
[`@magento/peregrine/lib/talons/RootComponents/Category/useCategoryContent.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategoryContent.js',
|
|
24
26
|
[`@magento/peregrine/lib/talons/RootComponents/Category/useCategory.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategory.js',
|
|
25
27
|
[`@magento/peregrine/lib/talons/Breadcrumbs/useBreadcrumbs.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/Breadcrumbs/useBreadcrumbs.js',
|
|
@@ -193,9 +193,17 @@ const getConfigPrice = (product, optionCodes, optionSelections) => {
|
|
|
193
193
|
variants
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
+
const minPrice = product.price_range?.minimum_price.final_price.value;
|
|
197
|
+
const maxPrice = product.price_range?.maximum_price.final_price.value;
|
|
198
|
+
|
|
199
|
+
let val = minPrice;
|
|
200
|
+
if (minPrice != maxPrice) {
|
|
201
|
+
val = minPrice + ' - ' + maxPrice;
|
|
202
|
+
}
|
|
203
|
+
|
|
196
204
|
const priceRange = {
|
|
197
205
|
final_price: {
|
|
198
|
-
value:
|
|
206
|
+
value: val,
|
|
199
207
|
currency: product.price_range?.minimum_price.final_price.currency
|
|
200
208
|
}
|
|
201
209
|
};
|
|
@@ -205,9 +213,6 @@ const getConfigPrice = (product, optionCodes, optionSelections) => {
|
|
|
205
213
|
: priceRange;
|
|
206
214
|
}
|
|
207
215
|
|
|
208
|
-
console.log('value----=====')
|
|
209
|
-
console.log(value)
|
|
210
|
-
|
|
211
216
|
return value;
|
|
212
217
|
};
|
|
213
218
|
|
|
@@ -266,7 +271,8 @@ export const useProductFullDetail = props => {
|
|
|
266
271
|
const {
|
|
267
272
|
addConfigurableProductToCartMutation,
|
|
268
273
|
addSimpleProductToCartMutation,
|
|
269
|
-
product
|
|
274
|
+
product,
|
|
275
|
+
isPreview
|
|
270
276
|
} = props;
|
|
271
277
|
|
|
272
278
|
const [, { dispatch }] = useEventingContext();
|
|
@@ -651,7 +657,7 @@ export const useProductFullDetail = props => {
|
|
|
651
657
|
isEverythingOutOfStock,
|
|
652
658
|
outOfStockVariants,
|
|
653
659
|
isAddToCartDisabled:
|
|
654
|
-
isOutOfStock ||
|
|
660
|
+
isPreview || isOutOfStock ||
|
|
655
661
|
isEverythingOutOfStock ||
|
|
656
662
|
isMissingOptions ||
|
|
657
663
|
isAddConfigurableLoading ||
|
|
@@ -13,8 +13,11 @@ export const GET_STORE_CONFIG_DATA = gql`
|
|
|
13
13
|
`;
|
|
14
14
|
|
|
15
15
|
export const GET_PRODUCT_DETAIL_QUERY = gql`
|
|
16
|
-
query getProductDetailForProductPage($urlKey: String
|
|
17
|
-
products(
|
|
16
|
+
query getProductDetailForProductPage($urlKey: String!, $productPreviewToken: String) {
|
|
17
|
+
products(
|
|
18
|
+
product_preview_token: $productPreviewToken,
|
|
19
|
+
filter: { url_key: { eq: $urlKey } }
|
|
20
|
+
) {
|
|
18
21
|
items {
|
|
19
22
|
id
|
|
20
23
|
uid
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { useQuery } from '@apollo/client';
|
|
2
|
+
import { useEffect, useMemo } from 'react';
|
|
3
|
+
import { useLocation } from 'react-router-dom';
|
|
4
|
+
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
5
|
+
|
|
6
|
+
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
7
|
+
import DEFAULT_OPERATIONS from './product.gql';
|
|
8
|
+
import { useEventingContext } from '@magento/peregrine/lib/context/eventing';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A [React Hook]{@link https://reactjs.org/docs/hooks-intro.html} that
|
|
12
|
+
* controls the logic for the Product Root Component.
|
|
13
|
+
*
|
|
14
|
+
* @kind function
|
|
15
|
+
*
|
|
16
|
+
* @param {object} props
|
|
17
|
+
* @param {Function} props.mapProduct - A function for updating products to the proper shape.
|
|
18
|
+
* @param {GraphQLAST} props.queries.getStoreConfigData - Fetches storeConfig product url suffix using a server query
|
|
19
|
+
* @param {GraphQLAST} props.queries.getProductQuery - Fetches product using a server query
|
|
20
|
+
*
|
|
21
|
+
* @returns {object} result
|
|
22
|
+
* @returns {Bool} result.error - Indicates a network error occurred.
|
|
23
|
+
* @returns {Bool} result.loading - Indicates the query is in flight.
|
|
24
|
+
* @returns {Bool} result.product - The product's details.
|
|
25
|
+
*/
|
|
26
|
+
export const useProduct = props => {
|
|
27
|
+
const { mapProduct } = props;
|
|
28
|
+
|
|
29
|
+
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
|
|
30
|
+
const { getStoreConfigData, getProductDetailQuery } = operations;
|
|
31
|
+
const { pathname, search } = useLocation();
|
|
32
|
+
const [
|
|
33
|
+
,
|
|
34
|
+
{
|
|
35
|
+
actions: { setPageLoading }
|
|
36
|
+
}
|
|
37
|
+
] = useAppContext();
|
|
38
|
+
|
|
39
|
+
const { data: storeConfigData } = useQuery(getStoreConfigData, {
|
|
40
|
+
fetchPolicy: 'cache-and-network',
|
|
41
|
+
nextFetchPolicy: 'cache-first'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const slug = pathname.split('/').pop();
|
|
45
|
+
const productUrlSuffix = storeConfigData?.storeConfig?.product_url_suffix;
|
|
46
|
+
const urlKey = productUrlSuffix ? slug.replace(productUrlSuffix, '') : slug;
|
|
47
|
+
|
|
48
|
+
const params = new URLSearchParams(search);
|
|
49
|
+
const productPreviewToken = params.get('preview');
|
|
50
|
+
|
|
51
|
+
const { error, loading, data } = useQuery(getProductDetailQuery, {
|
|
52
|
+
fetchPolicy: 'cache-and-network',
|
|
53
|
+
nextFetchPolicy: 'cache-first',
|
|
54
|
+
skip: !storeConfigData,
|
|
55
|
+
variables: {
|
|
56
|
+
urlKey,
|
|
57
|
+
productPreviewToken
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const isBackgroundLoading = !!data && loading;
|
|
62
|
+
|
|
63
|
+
const product = useMemo(() => {
|
|
64
|
+
if (!data) {
|
|
65
|
+
// The product isn't in the cache and we don't have a response from GraphQL yet.
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Note: if a product is out of stock _and_ the backend specifies not to
|
|
70
|
+
// display OOS items, the items array will be empty.
|
|
71
|
+
|
|
72
|
+
// Only return the product that we queried for.
|
|
73
|
+
const product = data.products.items.find(
|
|
74
|
+
item => item.url_key === urlKey
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (!product) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return mapProduct(product);
|
|
82
|
+
}, [data, mapProduct, urlKey]);
|
|
83
|
+
|
|
84
|
+
const [, { dispatch }] = useEventingContext();
|
|
85
|
+
|
|
86
|
+
// Update the page indicator if the GraphQL query is in flight.
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
setPageLoading(isBackgroundLoading);
|
|
89
|
+
}, [isBackgroundLoading, setPageLoading]);
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (!error && !loading && product) {
|
|
93
|
+
dispatch({
|
|
94
|
+
type: 'PRODUCT_PAGE_VIEW',
|
|
95
|
+
payload: {
|
|
96
|
+
id: product.id,
|
|
97
|
+
name: product.name,
|
|
98
|
+
sku: product.sku,
|
|
99
|
+
currency_code:
|
|
100
|
+
product?.price_range?.maximum_price?.final_price
|
|
101
|
+
?.currency,
|
|
102
|
+
price: product.price,
|
|
103
|
+
price_range: {
|
|
104
|
+
maximum_price: {
|
|
105
|
+
final_price:
|
|
106
|
+
product?.price_range?.maximum_price?.final_price
|
|
107
|
+
?.value
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
url_key: product.url_key
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}, [error, loading, product, dispatch]);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
error,
|
|
118
|
+
loading,
|
|
119
|
+
product
|
|
120
|
+
};
|
|
121
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
|
+
import { FormattedMessage } from 'react-intl';
|
|
3
|
+
import { string } from 'prop-types';
|
|
4
|
+
import { useProduct } from '@magento/peregrine/lib/talons/RootComponents/Product/useProduct';
|
|
5
|
+
|
|
6
|
+
import ErrorView from '@magento/venia-ui/lib/components/ErrorView';
|
|
7
|
+
import { StoreTitle, Meta } from '@magento/venia-ui/lib/components/Head';
|
|
8
|
+
import ProductFullDetail from '@magento/venia-ui/lib/components/ProductFullDetail';
|
|
9
|
+
import mapProduct from '@magento/venia-ui/lib/util/mapProduct';
|
|
10
|
+
import ProductShimmer from './product.shimmer';
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* As of this writing, there is no single Product query type in the M2.3 schema.
|
|
14
|
+
* The recommended solution is to use filter criteria on a Products query.
|
|
15
|
+
* However, the `id` argument is not supported. See
|
|
16
|
+
* https://github.com/magento/graphql-ce/issues/86
|
|
17
|
+
* TODO: Replace with a single product query when possible.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const Product = props => {
|
|
21
|
+
const { __typename: productType } = props;
|
|
22
|
+
const talonProps = useProduct({
|
|
23
|
+
mapProduct
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const { error, loading, product } = talonProps;
|
|
27
|
+
|
|
28
|
+
if (loading && !product)
|
|
29
|
+
return <ProductShimmer productType={productType} />;
|
|
30
|
+
if (error && !product) return <ErrorView />;
|
|
31
|
+
if (!product) {
|
|
32
|
+
return <ErrorView />;
|
|
33
|
+
return (
|
|
34
|
+
<h1>
|
|
35
|
+
<FormattedMessage
|
|
36
|
+
id={'product.outOfStockTryAgain'}
|
|
37
|
+
defaultMessage={
|
|
38
|
+
'This Product is currently out of stock. Please try again later.'
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
</h1>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Fragment>
|
|
47
|
+
<StoreTitle>{product.name}</StoreTitle>
|
|
48
|
+
<Meta name="description" content={product.meta_description} />
|
|
49
|
+
<ProductFullDetail product={product} />
|
|
50
|
+
</Fragment>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
Product.propTypes = {
|
|
55
|
+
__typename: string.isRequired
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default Product;
|
|
@@ -38,6 +38,7 @@ import ProductLabel from '@riosst100/pwa-marketplace/src/components/ProductLabel
|
|
|
38
38
|
import RFQ from '@riosst100/pwa-marketplace/src/components/RFQ';
|
|
39
39
|
import LinkToOtherStores from '@riosst100/pwa-marketplace/src/components/LinkToOtherStores';
|
|
40
40
|
import Collapsible from '@riosst100/pwa-marketplace/src/components/commons/Collapsible';
|
|
41
|
+
import { useLocation } from 'react-router-dom';
|
|
41
42
|
|
|
42
43
|
// Correlate a GQL error message to a field. GQL could return a longer error
|
|
43
44
|
// string but it may contain contextual info such as product id. We can use
|
|
@@ -75,7 +76,12 @@ const ProductDetailsCollapsible = (props) => {
|
|
|
75
76
|
const ProductFullDetail = props => {
|
|
76
77
|
const { product } = props;
|
|
77
78
|
|
|
78
|
-
const
|
|
79
|
+
const { search } = useLocation();
|
|
80
|
+
|
|
81
|
+
const params = new URLSearchParams(search);
|
|
82
|
+
const isPreview = params.get('preview');
|
|
83
|
+
|
|
84
|
+
const talonProps = useProductFullDetail({ product, isPreview });
|
|
79
85
|
|
|
80
86
|
const {
|
|
81
87
|
breadcrumbCategoryId,
|
|
@@ -438,9 +444,32 @@ const ProductFullDetail = props => {
|
|
|
438
444
|
return result;
|
|
439
445
|
}
|
|
440
446
|
|
|
447
|
+
const productPreviewMessages = isPreview ? (
|
|
448
|
+
<div
|
|
449
|
+
style={{
|
|
450
|
+
backgroundColor: "white", // Light gray background
|
|
451
|
+
border: "1px solid rgb(242 101 102)", // Subtle border
|
|
452
|
+
borderRadius: "5px", // Rounded corners
|
|
453
|
+
padding: "10px 15px", // Space inside the box
|
|
454
|
+
margin: "10px 0px 20px 0", // Space outside the box
|
|
455
|
+
fontSize: "14px", // Readable text size
|
|
456
|
+
color: "rgb(242 101 102)", // Dark gray text
|
|
457
|
+
}}
|
|
458
|
+
>
|
|
459
|
+
<span
|
|
460
|
+
style={{
|
|
461
|
+
fontWeight: "500", // Slightly bold text
|
|
462
|
+
}}
|
|
463
|
+
>
|
|
464
|
+
This is a preview of your product. Only you can see this page.
|
|
465
|
+
</span>
|
|
466
|
+
</div>
|
|
467
|
+
) : null;
|
|
468
|
+
|
|
441
469
|
return (
|
|
442
470
|
<Fragment>
|
|
443
471
|
{breadcrumbs}
|
|
472
|
+
{productPreviewMessages}
|
|
444
473
|
<Form
|
|
445
474
|
className={classes.root}
|
|
446
475
|
data-cy="ProductFullDetail-root"
|