@shopgate/pwa-common-commerce 7.30.0-alpha.7 → 7.30.0-alpha.9
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/cart/action-creators/addCouponsToCart.js +9 -2
- package/cart/action-creators/addProductsToCart.js +9 -2
- package/cart/action-creators/deleteCouponsFromCart.js +9 -2
- package/cart/action-creators/deleteProductsFromCart.js +9 -2
- package/cart/action-creators/errorAddCouponsToCart.js +10 -2
- package/cart/action-creators/errorAddProductsToCart.js +10 -2
- package/cart/action-creators/errorCart.js +8 -2
- package/cart/action-creators/errorDeleteCouponsFromCart.js +10 -2
- package/cart/action-creators/errorDeleteProductsFromCart.js +10 -2
- package/cart/action-creators/errorUpdateProductsInCart.js +10 -2
- package/cart/action-creators/receiveCart.js +9 -2
- package/cart/action-creators/requestCart.js +8 -2
- package/cart/action-creators/setCartProductPendingCount.js +9 -2
- package/cart/action-creators/setCouponFieldError.js +9 -2
- package/cart/action-creators/setCouponFieldValue.js +9 -2
- package/cart/action-creators/setFulfillmentSlot.js +9 -2
- package/cart/action-creators/successAddCouponsToCart.js +10 -2
- package/cart/action-creators/successAddProductsToCart.js +8 -2
- package/cart/action-creators/successDeleteCouponsFromCart.js +8 -2
- package/cart/action-creators/successDeleteProductsFromCart.js +8 -2
- package/cart/action-creators/successUpdateProductsInCart.js +8 -2
- package/cart/action-creators/updateProductsInCart.js +9 -2
- package/cart/actions/addCouponsToCart.js +52 -8
- package/cart/actions/addProductsToCart.js +80 -11
- package/cart/actions/deleteCouponsFromCart.js +39 -6
- package/cart/actions/deleteProductsFromCart.js +38 -6
- package/cart/actions/fetchCart.js +52 -8
- package/cart/actions/updateProductsInCart.js +44 -6
- package/cart/constants/PipelineErrors.js +6 -1
- package/cart/constants/Pipelines.js +6 -1
- package/cart/constants/Portals.js +85 -1
- package/cart/constants/index.js +39 -2
- package/cart/helpers/config.js +47 -2
- package/cart/helpers/createPipelineErrorList.js +30 -4
- package/cart/helpers/fulfillmentSlots.js +37 -4
- package/cart/helpers/index.js +14 -3
- package/cart/helpers/quantity.js +23 -4
- package/cart/helpers/shipping.js +57 -2
- package/cart/helpers/tax.js +26 -2
- package/cart/index.js +25 -5
- package/cart/mock.js +130 -1
- package/cart/reducers/couponField.js +30 -2
- package/cart/reducers/data.js +98 -6
- package/cart/reducers/index.js +7 -1
- package/cart/selectors/index.js +181 -31
- package/cart/selectors/spec.js +189 -2
- package/cart/streams/index.js +176 -29
- package/cart/subscriptions/index.js +307 -30
- package/category/action-creators/errorCategory.js +10 -2
- package/category/action-creators/errorCategoryChildren.js +9 -2
- package/category/action-creators/errorRootCategories.js +8 -2
- package/category/action-creators/receiveCategory.js +12 -2
- package/category/action-creators/receiveCategoryChildren.js +10 -2
- package/category/action-creators/receiveRootCategories.js +9 -2
- package/category/action-creators/requestCategory.js +9 -2
- package/category/action-creators/requestCategoryChildren.js +9 -2
- package/category/action-creators/requestRootCategories.js +8 -2
- package/category/actions/fetchCategory.js +47 -5
- package/category/actions/fetchCategoryChildren.js +30 -2
- package/category/actions/fetchCategoryOrRootCategories.js +16 -2
- package/category/actions/fetchCategoryProducts.js +36 -2
- package/category/actions/fetchRootCategories.js +31 -2
- package/category/actions/getCategory.js +10 -2
- package/category/constants/Pipelines.js +3 -1
- package/category/constants/Portals.js +56 -3
- package/category/constants/index.js +17 -2
- package/category/helpers/index.js +27 -3
- package/category/index.js +19 -5
- package/category/mock.js +176 -1
- package/category/reducers/categoriesById.js +65 -3
- package/category/reducers/childrenByCategoryId.js +55 -4
- package/category/reducers/helpers/handleCategoryCollection.js +24 -3
- package/category/reducers/helpers/handleReceivedCategories.js +3 -1
- package/category/reducers/index.js +12 -2
- package/category/reducers/rootCategories.js +31 -2
- package/category/selectors/index.js +115 -16
- package/category/streams/index.js +82 -4
- package/category/subscriptions/index.js +96 -3
- package/checkout/action-creators/successCheckout.js +9 -2
- package/checkout/actions/fetchCheckoutUrl.js +28 -3
- package/checkout/constants/Pipelines.js +1 -1
- package/checkout/constants/index.js +3 -2
- package/checkout/index.js +11 -4
- package/checkout/selectors/index.js +7 -2
- package/checkout/streams/index.js +8 -2
- package/checkout/subscriptions/index.js +35 -6
- package/favorites/action-creators/index.js +206 -24
- package/favorites/actions/addFavorites.js +41 -3
- package/favorites/actions/addFavoritesList.js +27 -2
- package/favorites/actions/fetchFavoriteIds.js +49 -5
- package/favorites/actions/fetchFavorites.js +60 -5
- package/favorites/actions/fetchFavoritesList.js +47 -3
- package/favorites/actions/fetchFavoritesListsWithItems.js +32 -3
- package/favorites/actions/getFavorites.js +6 -2
- package/favorites/actions/removeFavorites.js +32 -3
- package/favorites/actions/removeFavoritesList.js +24 -2
- package/favorites/actions/toggleFavorites.js +68 -10
- package/favorites/actions/updateFavorites.js +39 -3
- package/favorites/actions/updateFavoritesList.js +26 -2
- package/favorites/constants/Pipelines.js +9 -1
- package/favorites/constants/Portals.js +32 -4
- package/favorites/constants/index.js +37 -5
- package/favorites/index.js +14 -4
- package/favorites/mock.js +89 -4
- package/favorites/reducers/index.js +7 -1
- package/favorites/reducers/lists.js +74 -2
- package/favorites/reducers/products.js +231 -24
- package/favorites/selectors/index.js +188 -24
- package/favorites/streams/index.js +135 -23
- package/favorites/streams/spec.js +517 -8
- package/favorites/subscriptions/index.js +260 -25
- package/favorites/subscriptions/spec.js +700 -28
- package/filter/action-creators/errorFilters.js +9 -2
- package/filter/action-creators/index.js +4 -1
- package/filter/action-creators/receiveFilters.js +10 -2
- package/filter/action-creators/requestFilters.js +9 -2
- package/filter/action-creators/updateFilters.js +8 -2
- package/filter/actions/fetchFilters.js +46 -3
- package/filter/actions/getFilters.js +6 -2
- package/filter/actions/helpers/buildFilterParams.js +34 -2
- package/filter/actions/helpers/buildRequestFilters.js +35 -2
- package/filter/actions/helpers/processFilters.js +10 -2
- package/filter/actions/helpers/processParams.js +26 -2
- package/filter/constants/Pipelines.js +1 -1
- package/filter/constants/Portals.js +39 -3
- package/filter/constants/index.js +8 -1
- package/filter/index.js +12 -4
- package/filter/reducers/helpers/enrichFilters.js +11 -3
- package/filter/reducers/index.js +5 -1
- package/filter/reducers/resultsByHash.js +43 -3
- package/filter/selectors/index.js +47 -6
- package/filter/streams/index.js +30 -1
- package/filter/subscriptions/index.js +34 -2
- package/market/constants/Portals.js +22 -4
- package/market/constants/index.js +2 -1
- package/market/helpers/showReturnPolicy.js +3 -1
- package/market/helpers/showTaxDisclaimer.js +3 -1
- package/market/index.js +6 -2
- package/orders/constants.js +2 -1
- package/package.json +4 -4
- package/product/action-creators/deleteProductsByIds.js +10 -2
- package/product/action-creators/errorProduct.js +10 -2
- package/product/action-creators/errorProductDescription.js +10 -2
- package/product/action-creators/errorProductImages.js +10 -2
- package/product/action-creators/errorProductMedia.js +10 -2
- package/product/action-creators/errorProductOptions.js +10 -2
- package/product/action-creators/errorProductProperties.js +10 -2
- package/product/action-creators/errorProductRelations.js +9 -2
- package/product/action-creators/errorProductShipping.js +10 -2
- package/product/action-creators/errorProductVariants.js +10 -2
- package/product/action-creators/errorProducts.js +9 -2
- package/product/action-creators/expireProductById.js +10 -2
- package/product/action-creators/expireProductData.js +11 -2
- package/product/action-creators/expireProductsByHash.js +9 -2
- package/product/action-creators/productNotAvailable.js +10 -2
- package/product/action-creators/provideProduct.js +9 -2
- package/product/action-creators/receiveProduct.js +10 -2
- package/product/action-creators/receiveProductCached.js +9 -2
- package/product/action-creators/receiveProductDescription.js +10 -2
- package/product/action-creators/receiveProductImages.js +10 -2
- package/product/action-creators/receiveProductMedia.js +10 -2
- package/product/action-creators/receiveProductOptions.js +10 -2
- package/product/action-creators/receiveProductProperties.js +10 -2
- package/product/action-creators/receiveProductRelations.js +12 -2
- package/product/action-creators/receiveProductShipping.js +10 -2
- package/product/action-creators/receiveProductVariants.js +10 -2
- package/product/action-creators/receiveProducts.js +16 -2
- package/product/action-creators/receiveProductsCached.js +9 -2
- package/product/action-creators/refreshExpiredPDPData.js +8 -2
- package/product/action-creators/requestProduct.js +10 -2
- package/product/action-creators/requestProductDescription.js +9 -2
- package/product/action-creators/requestProductImages.js +9 -2
- package/product/action-creators/requestProductMedia.js +9 -2
- package/product/action-creators/requestProductOptions.js +9 -2
- package/product/action-creators/requestProductProperties.js +9 -2
- package/product/action-creators/requestProductRelations.js +10 -2
- package/product/action-creators/requestProductShipping.js +9 -2
- package/product/action-creators/requestProductVariants.js +9 -2
- package/product/action-creators/requestProducts.js +9 -2
- package/product/action-creators/setProductId.js +9 -2
- package/product/action-creators/setProductQuantity.js +9 -2
- package/product/action-creators/setProductVariantId.js +9 -2
- package/product/actions/changeSortOrder.js +21 -2
- package/product/actions/fetchHighlightProducts.js +18 -2
- package/product/actions/fetchLiveshoppingProducts.js +14 -2
- package/product/actions/fetchProduct.js +52 -3
- package/product/actions/fetchProductDescription.js +30 -2
- package/product/actions/fetchProductImages.js +31 -2
- package/product/actions/fetchProductMedia.js +35 -2
- package/product/actions/fetchProductOptions.js +31 -2
- package/product/actions/fetchProductProperties.js +30 -2
- package/product/actions/fetchProductRelations.js +63 -2
- package/product/actions/fetchProductShipping.js +31 -2
- package/product/actions/fetchProductVariants.js +31 -2
- package/product/actions/fetchProducts.js +189 -17
- package/product/actions/fetchProductsById.js +68 -8
- package/product/actions/fetchProductsByQuery.js +102 -18
- package/product/actions/getHighlightProducts.js +6 -2
- package/product/actions/getLiveshoppingProducts.js +6 -2
- package/product/actions/getProduct.js +6 -2
- package/product/actions/getProductDescription.js +6 -2
- package/product/actions/getProductImages.js +6 -2
- package/product/actions/getProductOptions.js +6 -2
- package/product/actions/getProductProperties.js +6 -2
- package/product/actions/getProductRelations.js +6 -2
- package/product/actions/getProductShipping.js +6 -2
- package/product/actions/getProductVariants.js +6 -2
- package/product/actions/getProducts.js +6 -2
- package/product/actions/getProductsById.js +6 -2
- package/product/actions/getProductsByQuery.js +6 -2
- package/product/actions/processProductFlags.js +35 -3
- package/product/actions/updateMetadata.js +17 -2
- package/product/collections/ProductImageFormats.js +48 -8
- package/product/collections/index.js +1 -1
- package/product/constants/Pipelines.js +12 -1
- package/product/constants/Portals.js +200 -33
- package/product/constants/index.js +90 -18
- package/product/helpers/index.js +61 -8
- package/product/index.js +36 -6
- package/product/mock.js +1002 -2
- package/product/reducers/descriptionsByProductId.js +54 -5
- package/product/reducers/helpers/formatOptions.js +17 -2
- package/product/reducers/helpers/handleProductCollection.js +19 -2
- package/product/reducers/imagesByProductId.js +51 -4
- package/product/reducers/index.js +23 -1
- package/product/reducers/mediaByProductId.js +55 -3
- package/product/reducers/optionsByProductId.js +41 -2
- package/product/reducers/productRelationsByHash.js +43 -2
- package/product/reducers/productsById.js +122 -7
- package/product/reducers/propertiesByProductId.js +48 -2
- package/product/reducers/resultsByHash.js +125 -9
- package/product/reducers/shippingByProductId.js +37 -2
- package/product/reducers/variantsByProductId.js +56 -2
- package/product/selectors/options.js +90 -13
- package/product/selectors/page.js +62 -13
- package/product/selectors/price.js +81 -18
- package/product/selectors/product.js +549 -59
- package/product/selectors/product.mock.js +327 -12
- package/product/selectors/relations.js +35 -5
- package/product/selectors/variants.js +91 -15
- package/product/streams/index.js +167 -13
- package/product/subscriptions/index.js +210 -4
- package/reviews/action-creators/errorProductReviews.js +9 -2
- package/reviews/action-creators/errorReviews.js +9 -2
- package/reviews/action-creators/errorSubmitReview.js +9 -2
- package/reviews/action-creators/errorUserReview.js +9 -2
- package/reviews/action-creators/flushUserReview.js +8 -2
- package/reviews/action-creators/receiveProductReviews.js +11 -2
- package/reviews/action-creators/receiveReviews.js +12 -2
- package/reviews/action-creators/receiveSubmitReview.js +9 -2
- package/reviews/action-creators/receiveUserReview.js +10 -2
- package/reviews/action-creators/requestProductReviews.js +10 -2
- package/reviews/action-creators/requestReviews.js +9 -2
- package/reviews/action-creators/requestSubmitReview.js +9 -2
- package/reviews/action-creators/requestUserReview.js +9 -2
- package/reviews/action-creators/resetSubmittedReview.js +9 -2
- package/reviews/action-creators/spec.js +40 -1
- package/reviews/actions/fetchProductReviews.js +37 -2
- package/reviews/actions/fetchReviews.js +38 -2
- package/reviews/actions/fetchUserReview.js +31 -2
- package/reviews/actions/flushUserReview.js +5 -1
- package/reviews/actions/getProductReviews.js +6 -2
- package/reviews/actions/getUserReview.js +6 -2
- package/reviews/actions/spec.js +241 -4
- package/reviews/actions/submitReview.js +63 -3
- package/reviews/constants/Pipelines.js +4 -1
- package/reviews/constants/Portals.js +4 -1
- package/reviews/constants/index.js +26 -7
- package/reviews/index.js +15 -4
- package/reviews/mock.js +172 -11
- package/reviews/reducers/index.js +11 -1
- package/reviews/reducers/mock.js +14 -2
- package/reviews/reducers/reviewsByHash.js +52 -6
- package/reviews/reducers/reviewsById.js +27 -2
- package/reviews/reducers/reviewsByProductId.js +47 -2
- package/reviews/reducers/spec.js +211 -2
- package/reviews/reducers/userReviewsByProductId.js +68 -2
- package/reviews/selectors/index.js +123 -19
- package/reviews/selectors/mock.js +100 -1
- package/reviews/selectors/spec.js +100 -1
- package/reviews/streams/index.js +37 -5
- package/reviews/streams/spec.js +25 -1
- package/reviews/subscriptions/index.js +27 -2
- package/scanner/action-creators/errorHandleScanner.js +11 -2
- package/scanner/action-creators/scannerFinished.js +11 -2
- package/scanner/action-creators/startScanner.js +8 -2
- package/scanner/action-creators/successHandleScanner.js +11 -2
- package/scanner/actions/handleBarCode.js +22 -2
- package/scanner/actions/handleNoResults.js +23 -2
- package/scanner/actions/handleQrCode.js +116 -6
- package/scanner/actions/handleSearch.js +33 -2
- package/scanner/constants/Portals.js +22 -1
- package/scanner/constants/index.js +17 -1
- package/scanner/helpers/index.js +115 -5
- package/scanner/index.js +19 -5
- package/scanner/streams/index.js +36 -1
- package/scanner/subscriptions/index.js +78 -8
- package/search/action-creators/errorSearchResults.js +10 -2
- package/search/action-creators/receiveSearchResults.js +11 -2
- package/search/action-creators/receiveSearchSuggestions.js +10 -2
- package/search/action-creators/requestSearchResults.js +10 -2
- package/search/action-creators/requestSearchSuggestions.js +9 -2
- package/search/actions/fetchSearchResults.js +66 -8
- package/search/actions/fetchSearchSuggestions.js +36 -2
- package/search/constants/Pipelines.js +1 -1
- package/search/constants/Portals.js +9 -2
- package/search/constants/index.js +10 -2
- package/search/helpers/index.js +5 -2
- package/search/helpers/removeHighlightingPlaceholders.js +4 -1
- package/search/helpers/spec.js +19 -1
- package/search/index.js +17 -5
- package/search/reducers/index.js +38 -2
- package/search/selectors/index.js +23 -4
- package/search/streams/index.js +51 -3
- package/search/subscriptions/index.js +132 -5
|
@@ -1,40 +1,74 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.regexp.flags.js";
|
|
2
|
+
import { createSelector } from 'reselect';
|
|
3
|
+
import isEqual from 'lodash/isEqual';
|
|
4
|
+
import { getCurrentState } from '@shopgate/pwa-common/selectors/router';
|
|
5
|
+
import { logger } from '@shopgate/pwa-core/helpers';
|
|
6
|
+
import { generateResultHash } from '@shopgate/pwa-common/helpers/redux';
|
|
7
|
+
import { getSortOrder } from '@shopgate/pwa-common/selectors/history';
|
|
8
|
+
import { SORT_SCOPE_CATEGORY, SORT_SCOPE_SEARCH } from '@shopgate/engage/filter/constants';
|
|
9
|
+
import { getPreferredLocation } from '@shopgate/engage/locations/selectors';
|
|
10
|
+
import { getIsLocationBasedShopping } from '@shopgate/engage/core/selectors/merchantSettings';
|
|
11
|
+
import { getActiveFilters } from "../../filter/selectors";
|
|
12
|
+
import { filterProperties } from "../helpers";
|
|
13
|
+
|
|
14
|
+
/**
|
|
2
15
|
* Retrieves the product state from the store.
|
|
3
16
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
4
17
|
* @param {Object} state The current application state.
|
|
5
18
|
* @return {Object} The product state.
|
|
6
|
-
*/
|
|
19
|
+
*/
|
|
20
|
+
export const getProductState = state => state.product || {};
|
|
21
|
+
|
|
22
|
+
/**
|
|
7
23
|
* Selects all products from the store.
|
|
8
24
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
9
25
|
* @param {Object} state The current application state.
|
|
10
26
|
* @return {Object} The collection of products.
|
|
11
|
-
*/
|
|
27
|
+
*/
|
|
28
|
+
export const getProducts = createSelector(getProductState, state => state.productsById || {});
|
|
29
|
+
|
|
30
|
+
/**
|
|
12
31
|
* Selects the product shipping state.
|
|
13
32
|
* @param {Object} state The current application state.
|
|
14
33
|
* @param {Object} props The component props.
|
|
15
34
|
* @return {Object} The product shipping state.
|
|
16
|
-
*/
|
|
35
|
+
*/
|
|
36
|
+
export const getProductShippingState = createSelector(getProductState, state => state.shippingByProductId || {});
|
|
37
|
+
|
|
38
|
+
/**
|
|
17
39
|
* Selects the product description state.
|
|
18
40
|
* @param {Object} state The current application state.
|
|
19
41
|
* @param {Object} props The component props.
|
|
20
42
|
* @return {Object} The product description state.
|
|
21
|
-
*/
|
|
43
|
+
*/
|
|
44
|
+
export const getProductDescriptionState = createSelector(getProductState, state => state.descriptionsByProductId || {});
|
|
45
|
+
|
|
46
|
+
/**
|
|
22
47
|
* Selects the product properties state.
|
|
23
48
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
24
49
|
* @param {Object} state The current application state.
|
|
25
50
|
* @param {Object} props The component props.
|
|
26
51
|
* @return {Object} The product properties state.
|
|
27
|
-
*/
|
|
52
|
+
*/
|
|
53
|
+
export const getProductPropertiesState = createSelector(getProductState, state => state.propertiesByProductId || {});
|
|
54
|
+
|
|
55
|
+
/**
|
|
28
56
|
* Selects the product images state.
|
|
29
57
|
* @param {Object} state The current application state.
|
|
30
58
|
* @param {Object} props The component props.
|
|
31
59
|
* @return {Object} The product images state.
|
|
32
|
-
*/
|
|
60
|
+
*/
|
|
61
|
+
export const getProductImagesState = createSelector(getProductState, state => state.imagesByProductId || {});
|
|
62
|
+
|
|
63
|
+
/**
|
|
33
64
|
* Selects the product variants state.
|
|
34
65
|
* @param {Object} state The current application state.
|
|
35
66
|
* @param {Object} props The component props.
|
|
36
67
|
* @return {Object} The product variants state.
|
|
37
|
-
*/
|
|
68
|
+
*/
|
|
69
|
+
export const getProductVariantsState = createSelector(getProductState, state => state.variantsByProductId || {});
|
|
70
|
+
|
|
71
|
+
/**
|
|
38
72
|
* Retrieves a product by id from state. Different to getProduct() which returns the product
|
|
39
73
|
* entity data if available, this selector returns the pure state entry for a given productId.
|
|
40
74
|
* So the expires and the isFetching property is processable.
|
|
@@ -42,223 +76,679 @@ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<argum
|
|
|
42
76
|
* @param {Object} state The current application state.
|
|
43
77
|
* @param {Object} props The component props.
|
|
44
78
|
* @return {Object|null} The dedicated product.
|
|
45
|
-
*/
|
|
79
|
+
*/
|
|
80
|
+
export const getProductById = createSelector(getProducts, (state, props) => props, (products, props) => {
|
|
81
|
+
if (typeof props !== 'object') {
|
|
82
|
+
logger.warn('Invocation of getProductById() with a productId will be deprecated soon. Please provide a props object.');
|
|
83
|
+
return products[props] || null;
|
|
84
|
+
}
|
|
85
|
+
if (!props.productId) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return products[props.productId] || null;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
/**
|
|
46
92
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
47
|
-
*/
|
|
93
|
+
*/
|
|
94
|
+
export const getProductDataById = createSelector(getProductById, product => product ? product.productData : undefined);
|
|
95
|
+
|
|
96
|
+
/**
|
|
48
97
|
* Retrieves the id of the current selected product from the component props. When the props
|
|
49
98
|
* contain a variant id it will return this one instead of the product id.
|
|
50
99
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
51
100
|
* @param {Object} state The current application state.
|
|
52
101
|
* @param {Object} [props] The component props.
|
|
53
102
|
* @return {string|null} The id of the current product.
|
|
54
|
-
*/
|
|
103
|
+
*/
|
|
104
|
+
export const getProductId = (state, props) => {
|
|
105
|
+
if (!state) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
if (typeof props === 'undefined') {
|
|
109
|
+
/**
|
|
55
110
|
* Before PWA 6.0 some product selectors relied on a "currentProduct" state which doesn't exist
|
|
56
111
|
* anymore. Their successors require a props object which contains a productId or a variantId.
|
|
57
112
|
* To support debugging an error will be logged, if the props are missing at invocation.
|
|
58
|
-
*/
|
|
59
|
-
|
|
113
|
+
*/
|
|
114
|
+
logger.error('getProductId() needs to be called with a props object that includes a productId.');
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Since a variantId can have falsy values, we need an "undefined" check here.
|
|
119
|
+
if (typeof props.variantId !== 'undefined' && props.variantId !== null) {
|
|
120
|
+
return props.variantId;
|
|
121
|
+
}
|
|
122
|
+
return props.productId || null;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
60
126
|
* Gets the variant id out of the selector props.
|
|
61
127
|
* @param {Object} state The current application state.
|
|
62
128
|
* @param {Object} props The component props.
|
|
63
129
|
* @returns {string|null}
|
|
64
|
-
*/
|
|
130
|
+
*/
|
|
131
|
+
export const getVariantProductId = (state, props) => {
|
|
132
|
+
if (typeof props === 'undefined') {
|
|
133
|
+
/**
|
|
65
134
|
* Before PWA 6.0 the variant selectors relied on a "currentProduct" state which doesn't exist
|
|
66
135
|
* anymore. Their successors require a props object which contains a variantId.
|
|
67
136
|
* To support debugging an error will be logged, if the props are missing at invocation.
|
|
68
|
-
*/
|
|
137
|
+
*/
|
|
138
|
+
logger.error('getVariantId() needs to be called with a props object that includes a variantId.');
|
|
139
|
+
}
|
|
140
|
+
const {
|
|
141
|
+
variantId = null
|
|
142
|
+
} = props || {};
|
|
143
|
+
return variantId;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
69
147
|
* Checks if currently a variant is selected within the props.
|
|
70
148
|
* @param {Object} state The current application state.
|
|
71
149
|
* @param {Object} props The component props.
|
|
72
150
|
* @returns {boolean}
|
|
73
|
-
*/
|
|
151
|
+
*/
|
|
152
|
+
export const isVariantSelected = (state, props) => !!getVariantProductId(state, props);
|
|
153
|
+
|
|
154
|
+
/**
|
|
74
155
|
* Retrieves the product data for the passed productId from the store.
|
|
75
156
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
76
157
|
* @param {Object} state The current application state.
|
|
77
158
|
* @param {Object} props The component props.
|
|
78
159
|
* @return {Object} The current product.
|
|
79
|
-
*/
|
|
160
|
+
*/
|
|
161
|
+
export const getProduct = createSelector(getProducts, getProductId, (products, productId) => {
|
|
162
|
+
const {
|
|
163
|
+
productData
|
|
164
|
+
} = products[productId] || {};
|
|
165
|
+
return productData || null;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/**
|
|
80
169
|
* Retrieves the product name.
|
|
81
170
|
* @param {Object} state The current application state.
|
|
82
171
|
* @param {Object} props The component props.
|
|
83
172
|
* @return {string|null}
|
|
84
|
-
*/
|
|
173
|
+
*/
|
|
174
|
+
export const getProductName = createSelector(getCurrentState, getProduct, (routeState, product) => {
|
|
175
|
+
if (!product) {
|
|
176
|
+
if (!routeState || !routeState.title) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
return routeState.title;
|
|
180
|
+
}
|
|
181
|
+
return product.name;
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
/**
|
|
85
185
|
* Retrieves the product long name.
|
|
86
186
|
* @param {Object} state The current application state.
|
|
87
187
|
* @param {Object} props The component props.
|
|
88
188
|
* @return {string|null}
|
|
89
|
-
*/
|
|
189
|
+
*/
|
|
190
|
+
export const getProductLongName = createSelector(getCurrentState, getProduct, (routeState, product) => {
|
|
191
|
+
if (!product) {
|
|
192
|
+
if (!routeState || !routeState.title) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return routeState.title;
|
|
196
|
+
}
|
|
197
|
+
if (!product.longName) {
|
|
198
|
+
return product.name;
|
|
199
|
+
}
|
|
200
|
+
return product.longName;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
/**
|
|
90
204
|
* Retrieves the product rating.
|
|
91
205
|
* @param {Object} state The current application state.
|
|
92
206
|
* @param {Object} props The component props.
|
|
93
207
|
* @return {Object|null}
|
|
94
|
-
*/
|
|
208
|
+
*/
|
|
209
|
+
export const getProductRating = createSelector(getProduct, product => {
|
|
210
|
+
if (!product) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return product.rating;
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
/**
|
|
95
217
|
* Retrieves the product manufacturer.
|
|
96
218
|
* @param {Object} state The current application state.
|
|
97
219
|
* @param {Object} props The component props.
|
|
98
220
|
* @return {string|null}
|
|
99
|
-
*/
|
|
221
|
+
*/
|
|
222
|
+
export const getProductManufacturer = createSelector(getProduct, product => {
|
|
223
|
+
if (!product) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
return product.manufacturer;
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
/**
|
|
100
230
|
* Retrieves the product stock information.
|
|
101
231
|
* @param {Object} state The current application state.
|
|
102
232
|
* @param {Object} props The component props.
|
|
103
233
|
* @return {Object|null}
|
|
104
|
-
*/
|
|
234
|
+
*/
|
|
235
|
+
export const getProductStock = createSelector(getProduct, product => {
|
|
236
|
+
if (!product) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
return product.stock;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
/**
|
|
105
243
|
* Retrieves the product availability.
|
|
106
244
|
* @param {Object} state The current application state.
|
|
107
245
|
* @param {Object} props The component props.
|
|
108
246
|
* @return {Object|null}
|
|
109
|
-
*/
|
|
247
|
+
*/
|
|
248
|
+
export const getProductAvailability = createSelector(getProduct, product => {
|
|
249
|
+
if (!product) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return product.availability;
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
/**
|
|
110
256
|
* Retrieves the product flags.
|
|
111
257
|
* @param {Object} state The current application state.
|
|
112
258
|
* @param {Object} props The component props.
|
|
113
259
|
* @return {Object|null}
|
|
114
|
-
*/
|
|
260
|
+
*/
|
|
261
|
+
export const getProductFlags = createSelector(getProduct, product => {
|
|
262
|
+
if (!product) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return product.flags;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
/**
|
|
115
269
|
* Retrieves the product price object.
|
|
116
270
|
* @param {Object} state The current application state.
|
|
117
271
|
* @param {Object} props The component props.
|
|
118
272
|
* @return {string}
|
|
119
|
-
*/
|
|
273
|
+
*/
|
|
274
|
+
export const getProductPriceData = createSelector(getProduct, product => {
|
|
275
|
+
if (!product) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return product.price;
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
/**
|
|
120
282
|
* Retrieves the product currency.
|
|
121
283
|
* @param {Object} state The current application state.
|
|
122
284
|
* @param {Object} props The component props.
|
|
123
285
|
* @todo Move to the price selectors
|
|
124
286
|
* @return {string|null}
|
|
125
|
-
*/
|
|
287
|
+
*/
|
|
288
|
+
export const getProductCurrency = createSelector(getProductPriceData, price => {
|
|
289
|
+
if (!price) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return price.currency;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
/**
|
|
126
296
|
* Retrieves the product discount.
|
|
127
297
|
* @param {Object} state The current application state.
|
|
128
298
|
* @param {Object} props The component props.
|
|
129
299
|
* @return {string|null}
|
|
130
|
-
*/
|
|
300
|
+
*/
|
|
301
|
+
export const getProductDiscount = createSelector(getProductPriceData, price => {
|
|
302
|
+
if (!price) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
return price.discount || 0;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
/**
|
|
131
309
|
* Retrieves the unit price from a product.
|
|
132
310
|
* @param {Object} state The current application state.
|
|
133
311
|
* @param {Object} props The component props.
|
|
134
312
|
* @todo Move to the price selectors
|
|
135
313
|
* @return {number|null}
|
|
136
|
-
*/
|
|
314
|
+
*/
|
|
315
|
+
export const getProductUnitPrice = createSelector(getProductPriceData, price => {
|
|
316
|
+
if (!price) {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
return price.unitPrice;
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
/**
|
|
137
323
|
* Determines if a product has variants.
|
|
138
324
|
* @param {Object} state The current application state.
|
|
139
325
|
* @param {Object} props The component props.
|
|
140
326
|
* @return {boolean}
|
|
141
|
-
*/
|
|
327
|
+
*/
|
|
328
|
+
export const hasProductVariants = createSelector(getProductFlags, flags => {
|
|
329
|
+
if (!flags) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
return flags.hasVariants;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
/**
|
|
142
336
|
* Determines if a product has variety (variants, options).
|
|
143
337
|
* This product can not be added to a cart. Selecting of variety should be done on PDP
|
|
144
338
|
* @param {Object} state The current application state.
|
|
145
339
|
* @param {Object} props The component props.
|
|
146
340
|
* @return {boolean}
|
|
147
|
-
*/
|
|
341
|
+
*/
|
|
342
|
+
export const hasProductVariety = createSelector(getProductFlags, flags => {
|
|
343
|
+
if (!flags) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
return flags.hasVariants || flags.hasOptions;
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
/**
|
|
148
350
|
* Determines if a product is a base product.
|
|
149
351
|
* @param {Object} state The current application state.
|
|
150
352
|
* @param {Object} props The component props.
|
|
151
353
|
* @todo Check if returning null is correct.
|
|
152
354
|
* @return {boolean|null}
|
|
153
|
-
*/
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
355
|
+
*/
|
|
356
|
+
export const isBaseProduct = createSelector(getProduct, hasProductVariants, (product, hasVariants) => {
|
|
357
|
+
if (!product) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Base products are simple products without variants or products with related variant products.
|
|
363
|
+
* At variant products the baseProductId is used to reference the base product.
|
|
364
|
+
*/
|
|
365
|
+
return product.baseProductId === null || hasVariants;
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
/**
|
|
157
369
|
* Determines a baseProductId for the products which are referenced within the props.
|
|
158
370
|
* When a variantId is passed, the selector will return the id of the related base product.
|
|
159
371
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
160
372
|
* @param {Object} state The current application state.
|
|
161
373
|
* @param {Object} props The component props.
|
|
162
374
|
* @return {string|null}
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
|
|
375
|
+
*/
|
|
376
|
+
export const getBaseProductId = createSelector(getProduct, (_, props = {}) => props.productId, (_, props = {}) => props.variantId, (product, productId, variantId) => {
|
|
377
|
+
if (!product) {
|
|
378
|
+
// Return the productId when both ids are present, but no variant product is available yet.
|
|
379
|
+
if (typeof productId !== 'undefined' && typeof variantId !== 'undefined') {
|
|
380
|
+
return productId;
|
|
381
|
+
}
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
// First try to determine a baseProductId for a selected product
|
|
385
|
+
const {
|
|
386
|
+
baseProductId = null
|
|
387
|
+
} = product;
|
|
388
|
+
return baseProductId || product.id;
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
/**
|
|
166
392
|
* Retrieves the base product data for the passed productId from the store.
|
|
167
393
|
* @deprecated Also exists within @shopgate/engage/product/selectors/product
|
|
168
394
|
* @param {Object} state The current application state.
|
|
169
395
|
* @returns {Object|null} The current product.
|
|
170
|
-
*/
|
|
396
|
+
*/
|
|
397
|
+
export const getBaseProduct = createSelector(getProducts, getBaseProductId, (products, baseProductId) => {
|
|
398
|
+
if (!baseProductId) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
const {
|
|
402
|
+
productData = null
|
|
403
|
+
} = products[baseProductId] || {};
|
|
404
|
+
return productData;
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
/**
|
|
171
408
|
* Determines if a base product has variants.
|
|
172
409
|
* @param {Object} state The current application state.
|
|
173
410
|
* @param {Object} props The component props.
|
|
174
411
|
* @return {boolean}
|
|
175
|
-
*/
|
|
412
|
+
*/
|
|
413
|
+
export const hasBaseProductVariants = createSelector(getBaseProduct, baseProduct => {
|
|
414
|
+
if (!baseProduct) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
const {
|
|
418
|
+
flags: {
|
|
419
|
+
hasVariants = false
|
|
420
|
+
} = {}
|
|
421
|
+
} = baseProduct;
|
|
422
|
+
return hasVariants;
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
/**
|
|
176
426
|
* Retrieves the metadata for the given product.
|
|
177
427
|
* @param {Object} state The current application state.
|
|
178
428
|
* @return {Object|null}
|
|
179
|
-
*/
|
|
429
|
+
*/
|
|
430
|
+
export const getProductMetadata = createSelector(getProduct, product => {
|
|
431
|
+
if (!product) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
return product.metadata;
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
/**
|
|
180
438
|
* Retrieves the metadata for the given product.
|
|
181
439
|
* @param {Object} state The current application state.
|
|
182
440
|
* @return {Object|null}
|
|
183
|
-
*/
|
|
441
|
+
*/
|
|
442
|
+
export const getBaseProductMetadata = createSelector(getBaseProduct, product => {
|
|
443
|
+
if (!product) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
return product.metadata;
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
/**
|
|
184
450
|
* Retrieves the shipping data for the given product.
|
|
185
451
|
* @param {Object} state The current application state.
|
|
186
452
|
* @param {Object} props The component props.
|
|
187
453
|
* @return {Object|null}
|
|
188
|
-
*/
|
|
454
|
+
*/
|
|
455
|
+
export const getProductShipping = createSelector(getProductShippingState, getProductId, (shipping, productId) => {
|
|
456
|
+
const entry = shipping[productId];
|
|
457
|
+
if (!entry || !entry.shipping) {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
return entry.shipping;
|
|
461
|
+
});
|
|
462
|
+
export const getProductPropertiesUnfiltered = createSelector(getProductId, getProductPropertiesState, (productId, properties) => {
|
|
463
|
+
const entry = properties[productId];
|
|
464
|
+
if (!entry || entry.isFetching || typeof entry.properties === 'undefined') {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
return entry.properties;
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
/**
|
|
189
471
|
* Retrieves the properties for the given product.
|
|
190
472
|
* @param {Object} state The current application state.
|
|
191
473
|
* @param {Object} props The component props.
|
|
192
474
|
* @return {Object|null}
|
|
193
|
-
*/
|
|
475
|
+
*/
|
|
476
|
+
export const getProductProperties = createSelector(getProductPropertiesState, getProductId, (properties, productId) => {
|
|
477
|
+
const entry = properties[productId];
|
|
478
|
+
if (!entry || !entry.properties) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
return filterProperties(entry.properties);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
/**
|
|
194
485
|
* Retrieves the description for the given product.
|
|
195
486
|
* @param {Object} state The current application state.
|
|
196
487
|
* @param {Object} props The component props.
|
|
197
488
|
* @return {string|null}
|
|
198
|
-
*/
|
|
489
|
+
*/
|
|
490
|
+
export const getProductDescription = createSelector(getProductDescriptionState, getProductId, (descriptions, productId) => {
|
|
491
|
+
const entry = descriptions[productId];
|
|
492
|
+
if (!entry || typeof entry.description === 'undefined') {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
return entry.description;
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
/**
|
|
199
499
|
* Retrieves the images for the given product. If the props contain a variantId, and the related
|
|
200
500
|
* product does not have images, the selector tries to pick images from its base product.
|
|
201
501
|
* @param {Object} state The current application state.
|
|
202
502
|
* @param {Object} props The component props.
|
|
203
503
|
* @return {Array|null}
|
|
204
|
-
*/
|
|
205
|
-
|
|
206
|
-
|
|
504
|
+
*/
|
|
505
|
+
export const getProductImages = createSelector(getProductImagesState, getProductId, getBaseProductId, (images, productId, baseProductId) => {
|
|
506
|
+
const {
|
|
507
|
+
images: productImages,
|
|
508
|
+
isFetching
|
|
509
|
+
} = images[productId] || {};
|
|
510
|
+
if (isFetching) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// If the product doesn't have images after fetching
|
|
515
|
+
if (baseProductId && (!Array.isArray(productImages) || !productImages.length)) {
|
|
516
|
+
// ...check the base product.
|
|
517
|
+
const {
|
|
518
|
+
images: baseProductImages
|
|
519
|
+
} = images[baseProductId] || {};
|
|
520
|
+
if (!Array.isArray(baseProductImages) || !baseProductImages.length) {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
return baseProductImages;
|
|
524
|
+
}
|
|
525
|
+
return productImages || null;
|
|
526
|
+
});
|
|
527
|
+
export const getFeaturedImage = createSelector(getProduct, getBaseProduct, (product, baseProduct) => {
|
|
528
|
+
let productImage = null;
|
|
529
|
+
let baseProductImage = null;
|
|
530
|
+
if (product?.featuredMedia) {
|
|
531
|
+
productImage = product.featuredMedia.type === 'image' ? product.featuredMedia.url : null;
|
|
532
|
+
}
|
|
533
|
+
if (baseProduct?.featuredMedia) {
|
|
534
|
+
baseProductImage = baseProduct.featuredMedia.type === 'image' ? baseProduct.featuredMedia.url : null;
|
|
535
|
+
}
|
|
536
|
+
return productImage || baseProductImage || product?.featuredImageBaseUrl || product?.featuredImageUrl;
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
/**
|
|
207
540
|
* Retrieves the product variant data.
|
|
208
541
|
* @param {Object} state The current application state.
|
|
209
542
|
* @param {Object} props The component props.
|
|
210
543
|
* @return {Object|null}
|
|
211
|
-
*/
|
|
544
|
+
*/
|
|
545
|
+
export const getProductVariants = createSelector(getProductVariantsState, getBaseProductId, (variants, baseProductId) => {
|
|
546
|
+
const entry = variants[baseProductId];
|
|
547
|
+
if (!entry || !entry.variants) {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
return entry.variants;
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
/**
|
|
212
554
|
* Retrieves a product for the selected variant id from the store.
|
|
213
555
|
* @param {Object} state The current application state.
|
|
214
556
|
* @param {Object} props The component props.
|
|
215
557
|
* @returns {Object|null} The selected variant or null if none is selected
|
|
216
|
-
*/
|
|
558
|
+
*/
|
|
559
|
+
export const getSelectedVariant = createSelector(getProduct, isVariantSelected, (product, selected) => {
|
|
560
|
+
if (!product || !selected) {
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
return product;
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
/**
|
|
217
567
|
* Determines if a product is orderable.
|
|
218
568
|
* @param {Object} state The current application state.
|
|
219
569
|
* @param {Object} props The component props.
|
|
220
570
|
* @return {boolean}
|
|
221
|
-
*/
|
|
571
|
+
*/
|
|
572
|
+
export const isProductOrderable = createSelector(getProductStock, stockInfo => !!(stockInfo && stockInfo.orderable));
|
|
573
|
+
|
|
574
|
+
/**
|
|
222
575
|
* Retrieves the product id of a variant product. When no variantId is passed within
|
|
223
576
|
* the props, the selector will return NULL.
|
|
224
577
|
* @param {Object} state The current application state.
|
|
225
578
|
* @param {Object} props The component props.
|
|
226
579
|
* @return {string|null}
|
|
227
|
-
*/
|
|
580
|
+
*/
|
|
581
|
+
export const getVariantId = createSelector(getProduct, product => {
|
|
582
|
+
if (!product) {
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
const {
|
|
586
|
+
id,
|
|
587
|
+
baseProductId
|
|
588
|
+
} = product;
|
|
589
|
+
return baseProductId !== null ? id : null;
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
/**
|
|
228
593
|
* Retrieves an availability object for a passed set of variant characteristics.
|
|
229
594
|
* @param {Object} state The current application state.
|
|
230
595
|
* @param {Object} props The component props.
|
|
231
596
|
* @return {Object|null}
|
|
232
|
-
*/
|
|
597
|
+
*/
|
|
598
|
+
export const getVariantAvailabilityByCharacteristics = createSelector(getProductVariants, (state, props = {}) => props.characteristics, (variants, characteristics) => {
|
|
599
|
+
if (!variants) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
const found = variants.products.find(product => isEqual(product.characteristics, characteristics));
|
|
603
|
+
if (!found) {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
return found.availability;
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
/**
|
|
233
610
|
* Creates a selector that determines fulfillment params for product requests
|
|
234
|
-
*/
|
|
611
|
+
*/
|
|
612
|
+
export const getFulfillmentParams = createSelector(getIsLocationBasedShopping, getPreferredLocation, (isLocationBasedShopping, location) => {
|
|
613
|
+
if (!isLocationBasedShopping || !location) {
|
|
614
|
+
return {};
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
locationCodes: [location.code]
|
|
618
|
+
};
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
/**
|
|
235
622
|
* Retrieves the generated result hash for a category id or search phrase.
|
|
236
623
|
* @param {Object} state The current application state.
|
|
237
624
|
* @param {Object} props The component props.
|
|
238
625
|
* @returns {string|null} The result hash.
|
|
239
|
-
*/
|
|
626
|
+
*/
|
|
627
|
+
export const getResultHash = createSelector((state, props = {}) => props.categoryId, (state, props = {}) => props.searchPhrase, (state, props = {}) => props.params, (state, props) => getSortOrder(state, props), getActiveFilters, getFulfillmentParams, (categoryId, searchPhrase, params, sort, filters, fulfillmentParams) => {
|
|
628
|
+
if (categoryId) {
|
|
629
|
+
return generateResultHash({
|
|
630
|
+
categoryId,
|
|
631
|
+
sort,
|
|
632
|
+
...(filters && {
|
|
633
|
+
filters
|
|
634
|
+
}),
|
|
635
|
+
...params,
|
|
636
|
+
...fulfillmentParams
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
if (searchPhrase) {
|
|
640
|
+
return generateResultHash({
|
|
641
|
+
searchPhrase,
|
|
642
|
+
sort,
|
|
643
|
+
...params,
|
|
644
|
+
...(filters && {
|
|
645
|
+
filters
|
|
646
|
+
}),
|
|
647
|
+
...fulfillmentParams
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
return null;
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
/**
|
|
240
654
|
* Retrieves the result by hash.
|
|
241
655
|
* @param {Object} state The application state.
|
|
242
656
|
* @param {Object} props The component props.
|
|
243
657
|
* @returns {Object} The result.
|
|
244
|
-
*/
|
|
658
|
+
*/
|
|
659
|
+
export const getResultByHash = createSelector(getProductState, getResultHash, (productState, hash) => {
|
|
660
|
+
const results = productState.resultsByHash[hash];
|
|
661
|
+
if (!results) {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
return results;
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
/**
|
|
245
668
|
* Populates the product result object.
|
|
246
669
|
* @param {Object} state The application state.
|
|
247
670
|
* @param {Object} props The component props.
|
|
248
671
|
* @param {string} hash The result hash.
|
|
249
672
|
* @param {Object} result The result.
|
|
250
673
|
* @return {Object} The product result.
|
|
251
|
-
*/
|
|
674
|
+
*/
|
|
675
|
+
export const getPopulatedProductsResult = (state, props, hash, result) => {
|
|
676
|
+
const {
|
|
677
|
+
searchPhrase
|
|
678
|
+
} = props;
|
|
679
|
+
const sort = getSortOrder(state, {
|
|
680
|
+
...props,
|
|
681
|
+
scope: typeof searchPhrase === 'undefined' ? SORT_SCOPE_CATEGORY : SORT_SCOPE_SEARCH
|
|
682
|
+
});
|
|
683
|
+
let products = [];
|
|
684
|
+
let totalProductCount = !hash ? 0 : null;
|
|
685
|
+
const expired = !!(result && result.expires && result.expires > 0 && result.expires < Date.now());
|
|
686
|
+
if (result && result.products) {
|
|
687
|
+
totalProductCount = result.totalResultCount;
|
|
688
|
+
products = result.products.map(productId => getProductById(state, {
|
|
689
|
+
productId
|
|
690
|
+
}).productData);
|
|
691
|
+
}
|
|
692
|
+
return {
|
|
693
|
+
products,
|
|
694
|
+
totalProductCount,
|
|
695
|
+
sort,
|
|
696
|
+
hash,
|
|
697
|
+
expired
|
|
698
|
+
};
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
/**
|
|
252
702
|
* Retrieves the populated product result.
|
|
253
703
|
* @param {Object} state The application state.
|
|
254
704
|
* @param {Object} props The component props.
|
|
255
705
|
* @returns {Object} The product result.
|
|
256
|
-
*/
|
|
706
|
+
*/
|
|
707
|
+
export const getProductsResult = createSelector(state => state, (state, props) => props, getResultHash, getResultByHash, getPopulatedProductsResult);
|
|
708
|
+
|
|
709
|
+
/**
|
|
257
710
|
* Selector factory which creates a selector to retrieve a product results object based on a custom
|
|
258
711
|
* hash string.
|
|
259
712
|
* @param {string} hash A resultsByHash hash string
|
|
260
713
|
* @returns {Function}
|
|
261
|
-
*/
|
|
714
|
+
*/
|
|
715
|
+
export const makeGetProductResultByCustomHash = hash => {
|
|
716
|
+
const parsedHash = JSON.parse(hash);
|
|
717
|
+
return createSelector(state => state, (state, props) => props, getProductState, (state, props, productState) => {
|
|
718
|
+
const {
|
|
719
|
+
searchPhrase
|
|
720
|
+
} = props;
|
|
721
|
+
let products = [];
|
|
722
|
+
let totalProductCount = !hash ? 0 : null;
|
|
723
|
+
const sort = parsedHash?.sort || getSortOrder(state, {
|
|
724
|
+
...props,
|
|
725
|
+
scope: typeof searchPhrase === 'undefined' ? SORT_SCOPE_CATEGORY : SORT_SCOPE_SEARCH
|
|
726
|
+
});
|
|
727
|
+
const result = productState.resultsByHash[hash];
|
|
728
|
+
if (result && result.products) {
|
|
729
|
+
totalProductCount = result.totalResultCount;
|
|
730
|
+
products = result.products.map(productId => getProductById(state, {
|
|
731
|
+
productId
|
|
732
|
+
}).productData);
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
products,
|
|
736
|
+
totalProductCount,
|
|
737
|
+
sort,
|
|
738
|
+
hash
|
|
739
|
+
};
|
|
740
|
+
});
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
/**
|
|
262
744
|
* Selector mappings for PWA < 6.0
|
|
263
745
|
* @deprecated
|
|
264
|
-
*/
|
|
746
|
+
*/
|
|
747
|
+
export const getCurrentProduct = getProduct;
|
|
748
|
+
export const getCurrentProductId = getProductId;
|
|
749
|
+
export const getCurrentBaseProductId = getBaseProductId;
|
|
750
|
+
export const getCurrentBaseProduct = getBaseProduct;
|
|
751
|
+
export const getCurrentProductStock = getProductStock;
|
|
752
|
+
export const getProductStockInfo = getProductStock;
|
|
753
|
+
export const getProductBasePrice = getProductUnitPrice;
|
|
754
|
+
export const isOrderable = isProductOrderable;
|