@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,13 +1,129 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.array.reduce.js";
|
|
2
|
+
import uniq from 'lodash/uniq';
|
|
3
|
+
import pickBy from 'lodash/pickBy';
|
|
4
|
+
import { ENOTFOUND } from '@shopgate/pwa-core';
|
|
5
|
+
import { SELECT_GLOBAL_LOCATION } from '@shopgate/engage/core';
|
|
6
|
+
import { PRODUCT_LIFETIME, REQUEST_PRODUCTS, RECEIVE_PRODUCTS, ERROR_PRODUCTS, EXPIRE_PRODUCT_BY_ID, EXPIRE_PRODUCTS_BY_HASH, ERROR_PRODUCT, EXPIRE_PRODUCT_DATA } from "../constants";
|
|
7
|
+
|
|
8
|
+
/**
|
|
2
9
|
* Stores a collection of products by the related hash of the request parameters.
|
|
3
10
|
* @param {Object} [state={}] The current state.
|
|
4
11
|
* @param {Object} action The current redux action.
|
|
5
12
|
* @return {Object} The new state.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
*/
|
|
14
|
+
export default function resultsByHash(state = {}, action) {
|
|
15
|
+
switch (action.type) {
|
|
16
|
+
case REQUEST_PRODUCTS:
|
|
17
|
+
return {
|
|
18
|
+
...state,
|
|
19
|
+
[action.hash]: {
|
|
20
|
+
...state[action.hash],
|
|
21
|
+
isFetching: true,
|
|
22
|
+
expires: 0
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
case RECEIVE_PRODUCTS:
|
|
26
|
+
{
|
|
27
|
+
if (!action.hash) {
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
const {
|
|
31
|
+
products
|
|
32
|
+
} = state[action.hash];
|
|
33
|
+
const nextProducts = action.products || [];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* If there are no previous products and no incoming products
|
|
37
|
+
* its set to empty array, otherwise it will be an array of the previous and the
|
|
38
|
+
* new products. Duplicates are removed.
|
|
39
|
+
*/
|
|
40
|
+
const stateProducts = products || nextProducts.length ? uniq([...(products || []), ...nextProducts.map(product => product.id)]) : [];
|
|
41
|
+
return {
|
|
42
|
+
...state,
|
|
43
|
+
[action.hash]: {
|
|
44
|
+
...state[action.hash],
|
|
45
|
+
products: stateProducts,
|
|
46
|
+
totalResultCount: typeof action.totalResultCount !== 'undefined' ? action.totalResultCount : null,
|
|
47
|
+
isFetching: false,
|
|
48
|
+
expires: action.cached ? Date.now() + (action.cachedTime || PRODUCT_LIFETIME) : 0
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Remove not found product from hash results */
|
|
54
|
+
case ERROR_PRODUCT:
|
|
55
|
+
if (action.errorCode === ENOTFOUND) {
|
|
56
|
+
return Object.keys(state).reduce((accumulator, hash) => {
|
|
57
|
+
if (accumulator[hash].products && accumulator[hash].products.includes(action.productId)) {
|
|
58
|
+
accumulator[hash] = {
|
|
59
|
+
...accumulator[hash],
|
|
60
|
+
products: accumulator[hash].products.filter(pId => pId !== action.productId)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return accumulator;
|
|
64
|
+
}, {
|
|
65
|
+
...state
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return state;
|
|
69
|
+
case EXPIRE_PRODUCTS_BY_HASH:
|
|
70
|
+
{
|
|
71
|
+
return {
|
|
72
|
+
...state,
|
|
73
|
+
[action.hash]: {
|
|
74
|
+
...state[action.hash],
|
|
75
|
+
products: [],
|
|
76
|
+
expires: 0
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
case EXPIRE_PRODUCT_BY_ID:
|
|
81
|
+
{
|
|
82
|
+
const productIds = [].concat(action.productId);
|
|
83
|
+
return Object.keys(state).reduce((accumulator, hash) => {
|
|
84
|
+
if (accumulator[hash].products && productIds.some(id => accumulator[hash].products.includes(id))) {
|
|
85
|
+
accumulator[hash] = {
|
|
86
|
+
...accumulator[hash],
|
|
87
|
+
expires: 0,
|
|
88
|
+
...(action.complete && {
|
|
89
|
+
products: accumulator[hash].products.filter(id => !productIds.includes(id))
|
|
90
|
+
})
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return accumulator;
|
|
94
|
+
}, {
|
|
95
|
+
...state
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// Mark all product data as expired
|
|
99
|
+
case EXPIRE_PRODUCT_DATA:
|
|
100
|
+
{
|
|
101
|
+
if (Array.isArray(action.scopes) && action.scopes.includes('price')) {
|
|
102
|
+
return Object.keys(state).reduce((accumulator, hash) => {
|
|
103
|
+
accumulator[hash] = {
|
|
104
|
+
...accumulator[hash],
|
|
105
|
+
expires: 0
|
|
106
|
+
};
|
|
107
|
+
return accumulator;
|
|
108
|
+
}, {
|
|
109
|
+
...state
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return state;
|
|
113
|
+
}
|
|
114
|
+
case ERROR_PRODUCTS:
|
|
115
|
+
return {
|
|
116
|
+
...state,
|
|
117
|
+
[action.hash]: {
|
|
118
|
+
...state[action.hash],
|
|
119
|
+
isFetching: false
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
case SELECT_GLOBAL_LOCATION:
|
|
123
|
+
// Remove all hashes that are not bound to a location
|
|
124
|
+
// because stock information may change per location
|
|
125
|
+
return pickBy(state, (value, key) => !JSON.parse(key).locationCodes);
|
|
126
|
+
default:
|
|
127
|
+
return state;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,6 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
import { PRODUCT_LIFETIME, REQUEST_PRODUCT_SHIPPING, RECEIVE_PRODUCT_SHIPPING, ERROR_PRODUCT_SHIPPING } from "../constants";
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Stores product shipping by it's product ID.
|
|
3
5
|
* @param {Object} [state={}] The current state.
|
|
4
6
|
* @param {Object} action The action object.
|
|
5
7
|
* @return {Object} The new state.
|
|
6
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
export default function shippingByProductId(state = {}, action) {
|
|
10
|
+
switch (action.type) {
|
|
11
|
+
case REQUEST_PRODUCT_SHIPPING:
|
|
12
|
+
return {
|
|
13
|
+
...state,
|
|
14
|
+
[action.productId]: {
|
|
15
|
+
...state[action.productId],
|
|
16
|
+
isFetching: true,
|
|
17
|
+
expires: 0
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
case RECEIVE_PRODUCT_SHIPPING:
|
|
21
|
+
return {
|
|
22
|
+
...state,
|
|
23
|
+
[action.productId]: {
|
|
24
|
+
...state[action.productId],
|
|
25
|
+
shipping: action.shipping,
|
|
26
|
+
isFetching: false,
|
|
27
|
+
expires: Date.now() + PRODUCT_LIFETIME
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
case ERROR_PRODUCT_SHIPPING:
|
|
31
|
+
return {
|
|
32
|
+
...state,
|
|
33
|
+
[action.productId]: {
|
|
34
|
+
...state[action.productId],
|
|
35
|
+
isFetching: false
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
default:
|
|
39
|
+
return state;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,6 +1,60 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.array.reduce.js";
|
|
2
|
+
import { PRODUCT_LIFETIME, REQUEST_PRODUCT_VARIANTS, RECEIVE_PRODUCT_VARIANTS, ERROR_PRODUCT_VARIANTS, EXPIRE_PRODUCT_BY_ID, EXPIRE_PRODUCT_DATA } from "../constants";
|
|
3
|
+
|
|
4
|
+
/**
|
|
2
5
|
* Stores product variants by the ID of the related parent product.
|
|
3
6
|
* @param {Object} [state={}] The current state.
|
|
4
7
|
* @param {Object} action The action object.
|
|
5
8
|
* @return {Object} The new state.
|
|
6
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
export default function variantsByProductId(state = {}, action) {
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
case REQUEST_PRODUCT_VARIANTS:
|
|
13
|
+
return {
|
|
14
|
+
...state,
|
|
15
|
+
[action.productId]: {
|
|
16
|
+
...state[action.productId],
|
|
17
|
+
isFetching: true,
|
|
18
|
+
expires: 0
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
case RECEIVE_PRODUCT_VARIANTS:
|
|
22
|
+
return {
|
|
23
|
+
...state,
|
|
24
|
+
[action.productId]: {
|
|
25
|
+
...state[action.productId],
|
|
26
|
+
variants: action.variants,
|
|
27
|
+
isFetching: false,
|
|
28
|
+
expires: Date.now() + PRODUCT_LIFETIME
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
case ERROR_PRODUCT_VARIANTS:
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
[action.productId]: {
|
|
35
|
+
...state[action.productId],
|
|
36
|
+
isFetching: false
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
case EXPIRE_PRODUCT_BY_ID:
|
|
40
|
+
return {
|
|
41
|
+
...state,
|
|
42
|
+
[action.productId]: {
|
|
43
|
+
...state[action.productId],
|
|
44
|
+
expires: 0
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
case EXPIRE_PRODUCT_DATA:
|
|
48
|
+
{
|
|
49
|
+
return Object.keys(state).reduce((acc, productId) => {
|
|
50
|
+
acc[productId] = {
|
|
51
|
+
...state[productId],
|
|
52
|
+
expires: 0
|
|
53
|
+
};
|
|
54
|
+
return acc;
|
|
55
|
+
}, {});
|
|
56
|
+
}
|
|
57
|
+
default:
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,33 +1,110 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.regexp.flags.js";
|
|
2
|
+
import { createSelector } from 'reselect';
|
|
3
|
+
import { validateSelectorParams } from '@shopgate/pwa-common/helpers/data';
|
|
4
|
+
import { getProduct, getProductId, getProductState, getProductCurrency } from "./product";
|
|
5
|
+
import { OPTION_TYPE_SELECT, OPTION_TYPE_TEXT } from "../constants";
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* Retrieves the product options state.
|
|
3
9
|
* @param {Object} state The application state.
|
|
4
10
|
* @returns {Object} The product options state.
|
|
5
|
-
*/
|
|
11
|
+
*/
|
|
12
|
+
const getProductOptionsState = createSelector(getProductState, state => state.optionsByProductId);
|
|
13
|
+
|
|
14
|
+
/**
|
|
6
15
|
* Finds a product option item by the option id and item id.
|
|
7
16
|
* @param {Object} options All available options.
|
|
8
17
|
* @param {Object} optionId The Id of the option.
|
|
9
18
|
* @param {Object} itemId The Id of the item.
|
|
10
19
|
* @returns {Object}
|
|
11
|
-
*/
|
|
20
|
+
*/
|
|
21
|
+
const findProductOptionItem = (options, optionId, itemId) => options.find(opt => opt.id === optionId).values.find(item => item.id === itemId);
|
|
22
|
+
|
|
23
|
+
/**
|
|
12
24
|
* Retrieves the current products options.
|
|
13
25
|
* @param {Object} state The application state.
|
|
14
26
|
* @returns {Object} The product options.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
*/
|
|
28
|
+
export const getRawProductOptions = createSelector(getProductId, getProductOptionsState, (productId, productOptionsState) => {
|
|
29
|
+
const productOptions = productOptionsState[productId];
|
|
30
|
+
if (!productOptions || productOptions.isFetching) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return productOptions.options;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// TODO: This needs to be optimized!
|
|
37
|
+
const getOptionItems = createSelector(options => options, (options, values) => values, (options, values, option) => option, (options, values, option, selected) => selected, (options, values, option, selected, currency) => currency, (options, values = [], option, selected, currency) => values.map(value => {
|
|
38
|
+
// Add prices to each item that are relative to the current total product price.
|
|
39
|
+
if (!selected) {
|
|
40
|
+
return {
|
|
41
|
+
label: value.label,
|
|
42
|
+
currency,
|
|
43
|
+
value: value.id,
|
|
44
|
+
// Price modifier and difference are equal, when nothing is selected.
|
|
45
|
+
price: value.unitPriceModifier,
|
|
46
|
+
priceDifference: value.unitPriceModifier
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const {
|
|
50
|
+
unitPriceModifier: siblingPrice = 0
|
|
51
|
+
} = findProductOptionItem(options, option.id, selected);
|
|
52
|
+
return {
|
|
53
|
+
label: value.label,
|
|
54
|
+
currency,
|
|
55
|
+
value: value.id,
|
|
56
|
+
// Price which affects the unit price.
|
|
57
|
+
price: value.unitPriceModifier,
|
|
58
|
+
// Difference to the currently selected sibling.
|
|
59
|
+
priceDifference: value.unitPriceModifier - siblingPrice
|
|
60
|
+
};
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
/**
|
|
21
64
|
* Retrieves the current products options and transforms it to the correct data structure.
|
|
22
65
|
* @param {Object} state The application state.
|
|
23
66
|
* @returns {Array} The product options.
|
|
24
|
-
*/
|
|
25
|
-
|
|
67
|
+
*/
|
|
68
|
+
export const getProductOptions = createSelector(getProductCurrency, (state, props = {}) => props.currentOptions, getRawProductOptions, validateSelectorParams((currency, currentOptions, options) => options.map(option => ({
|
|
69
|
+
id: option.id,
|
|
70
|
+
label: option.label,
|
|
71
|
+
type: option.type,
|
|
72
|
+
value: currentOptions[option.id],
|
|
73
|
+
...(option.type === OPTION_TYPE_SELECT && {
|
|
74
|
+
items: getOptionItems(options, option.values, option, currentOptions[option.id], currency)
|
|
75
|
+
}),
|
|
76
|
+
...(option.type === OPTION_TYPE_TEXT && {
|
|
77
|
+
info: option.annotation,
|
|
78
|
+
required: !!option.required,
|
|
79
|
+
price: option.unitPriceModifier
|
|
80
|
+
})
|
|
81
|
+
}))
|
|
82
|
+
// Move select type options on top, keep the rest
|
|
83
|
+
.sort((a, b) => {
|
|
84
|
+
if (a.type === b.type) {
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
if (a.type === 'select') {
|
|
88
|
+
return -1;
|
|
89
|
+
}
|
|
90
|
+
return b.type === 'select' ? 1 : 0;
|
|
91
|
+
})));
|
|
92
|
+
|
|
93
|
+
/**
|
|
26
94
|
* Checks if the product has any options.
|
|
27
95
|
* @param {Object} state The application state.
|
|
28
96
|
* @returns {boolean}
|
|
29
|
-
*/
|
|
97
|
+
*/
|
|
98
|
+
export const hasProductOptions = createSelector(getProduct, product => {
|
|
99
|
+
if (!product) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return product.flags.hasOptions;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
/**
|
|
30
106
|
* Checks if all product options for the product are set
|
|
31
107
|
* @param {Object} state The application state.
|
|
32
108
|
* @returns {boolean}
|
|
33
|
-
*/
|
|
109
|
+
*/
|
|
110
|
+
export const areProductOptionsSet = createSelector(getRawProductOptions, (state, props = {}) => props.options || false, validateSelectorParams((options, currentOptions) => options.length === Object.keys(currentOptions).length));
|
|
@@ -1,23 +1,72 @@
|
|
|
1
|
-
import{createSelector}from'reselect';
|
|
1
|
+
import { createSelector } from 'reselect';
|
|
2
|
+
import { logDeprecationMessage } from '@shopgate/pwa-core/helpers';
|
|
3
|
+
import { getProduct, getBaseProduct, hasBaseProductVariants, getVariantProductId, getProductVariants } from "./product";
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Checks, if the products of the product page are loading. Depending on the configuration of the
|
|
3
7
|
* base product, it also checks, if the loading process of a selected variant is currently ongoing.
|
|
4
8
|
* @param {Object} state The current application state.
|
|
5
9
|
* @param {Object} props The component props.
|
|
6
10
|
* @return {boolean}
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if(
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
*/
|
|
12
|
+
export const isProductPageLoading = createSelector(getBaseProduct, hasBaseProductVariants, getProductVariants, getVariantProductId, getProduct, (baseProduct, hasVariants, variants, variantId, product) => {
|
|
13
|
+
// Check if the base product is already present.
|
|
14
|
+
if (!baseProduct) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
const baseProductActive = !!baseProduct?.active;
|
|
18
|
+
|
|
19
|
+
// Check if the base product has variants.
|
|
20
|
+
if (hasVariants && baseProductActive) {
|
|
21
|
+
const variantsFetching = !variants;
|
|
22
|
+
|
|
23
|
+
// Check if the variant list is currently fetching.
|
|
24
|
+
if (variantsFetching) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const variantSelected = !!variantId;
|
|
28
|
+
// Check if one of the variants is currently selected by the user.
|
|
29
|
+
if (variantSelected) {
|
|
30
|
+
// Check if the product data of the selected variant is already present.
|
|
31
|
+
return !product;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
13
38
|
* Checks, if the product page is currently in a state, that a product can be ordered.
|
|
14
39
|
* @todo Consider the real orderable state of the products.
|
|
15
40
|
* @param {Object} state The application state.
|
|
16
41
|
* @return {boolean}
|
|
17
42
|
* @deprecated
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if(
|
|
23
|
-
return
|
|
43
|
+
*/
|
|
44
|
+
export const isProductPageOrderable = createSelector(getBaseProduct, hasBaseProductVariants, getProductVariants, getVariantProductId, getProduct, (baseProduct, hasVariants, variants, variantId, product) => {
|
|
45
|
+
logDeprecationMessage('The selector isProductPageOrderable()');
|
|
46
|
+
// Check if the base product is already present.
|
|
47
|
+
if (!baseProduct) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const baseProductActive = !!baseProduct?.active;
|
|
51
|
+
if (!baseProductActive) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check if the base product has variants.
|
|
56
|
+
if (hasVariants) {
|
|
57
|
+
const variantsFetching = !variants;
|
|
58
|
+
|
|
59
|
+
// Check if the variant list is currently fetching.
|
|
60
|
+
if (variantsFetching) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const variantSelected = !!variantId;
|
|
64
|
+
// Check if one of the variants is currently selected by the user.
|
|
65
|
+
if (variantSelected) {
|
|
66
|
+
// Check if the product data of the selected variant is already present.
|
|
67
|
+
return !!product;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
});
|
|
@@ -1,36 +1,99 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.array.reduce.js";
|
|
2
|
+
import { createSelector } from 'reselect';
|
|
3
|
+
import { validateSelectorParams } from '@shopgate/pwa-common/helpers/data';
|
|
4
|
+
import { getProduct, getProductUnitPrice, hasBaseProductVariants, isVariantSelected } from "./product";
|
|
5
|
+
import { getRawProductOptions, hasProductOptions, areProductOptionsSet } from "./options";
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* Calculates the additional price for the current product.
|
|
3
9
|
* @param {Object} state The application state.
|
|
4
10
|
* @returns {number}
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
*/
|
|
12
|
+
export const getProductPriceAddition = createSelector((state, props = {}) => props.options, getRawProductOptions, validateSelectorParams((options, productOptions) => Object.keys(options).map(optionId => {
|
|
13
|
+
const itemId = options[optionId];
|
|
14
|
+
const productOption = productOptions.find(item => item.id === optionId);
|
|
15
|
+
if (productOption.type === 'select') {
|
|
16
|
+
const optionItems = productOptions.find(item => item.id === optionId).values;
|
|
17
|
+
return optionItems.find(item => item.id === itemId).unitPriceModifier;
|
|
18
|
+
}
|
|
19
|
+
if (productOption.type === 'text' && itemId) {
|
|
20
|
+
return productOption.unitPriceModifier;
|
|
21
|
+
}
|
|
22
|
+
return 0;
|
|
23
|
+
})
|
|
24
|
+
// Sum up all active option item modifiers to calculate the additional price of the product.
|
|
25
|
+
.reduce((a, b) => a + b, 0),
|
|
26
|
+
// If product has no options return 0
|
|
27
|
+
0));
|
|
28
|
+
/**
|
|
8
29
|
* Calculates the total price by summing up additional product option costs.
|
|
9
30
|
* @param {Object} state The application state.
|
|
10
31
|
* @returns {number}
|
|
11
|
-
*/
|
|
32
|
+
*/
|
|
33
|
+
export const getProductTotalPrice = createSelector(getProductUnitPrice, getProductPriceAddition, validateSelectorParams((basePrice, priceAddition) => basePrice + priceAddition));
|
|
34
|
+
|
|
35
|
+
/**
|
|
12
36
|
* Checks if the full price is already available.
|
|
13
37
|
* When a product has variants with different prices the full price is not available.
|
|
14
38
|
* If the children is selected the full price is available.
|
|
15
39
|
* @param {Object} state The application state.
|
|
16
40
|
* @returns {boolean} The product options.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
*/
|
|
42
|
+
export const isFullPriceAvailable = createSelector(hasBaseProductVariants, isVariantSelected, hasProductOptions, areProductOptionsSet, (hasVariants, isChildrenSelected, hasOptions, areOptionsSet) => {
|
|
43
|
+
// If product has neither variants nor options the full price is available.
|
|
44
|
+
if (!hasVariants && !hasOptions) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* If the product has variants and options,
|
|
50
|
+
* the full price is only available if options and children are set.
|
|
51
|
+
*/
|
|
52
|
+
if (hasVariants && hasOptions) {
|
|
53
|
+
return isChildrenSelected && areOptionsSet;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* If the product has only options,
|
|
58
|
+
* the full price is only available if the options are set.
|
|
59
|
+
*/
|
|
60
|
+
if (!hasVariants && hasOptions) {
|
|
61
|
+
return areOptionsSet;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* If the product has only variants,
|
|
66
|
+
* the full price is only available if the children is set.
|
|
67
|
+
*/
|
|
68
|
+
if (hasVariants && !hasOptions) {
|
|
69
|
+
return isChildrenSelected;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
28
75
|
* Retrieves the current product and adds the total price and manipulates the min price
|
|
29
76
|
* to be always 0 when it is not needed.
|
|
30
77
|
* @param {Object} state The application state.
|
|
31
78
|
* @returns {Object} The extended product data.
|
|
32
|
-
*/
|
|
79
|
+
*/
|
|
80
|
+
export const getCalculatedProduct = createSelector(getProduct, getProductTotalPrice, getProductPriceAddition, validateSelectorParams((product, totalPrice, addition) => ({
|
|
81
|
+
...product,
|
|
82
|
+
price: {
|
|
83
|
+
...product.price,
|
|
84
|
+
modifier: addition,
|
|
85
|
+
totalPrice
|
|
86
|
+
}
|
|
87
|
+
})));
|
|
88
|
+
|
|
89
|
+
/**
|
|
33
90
|
* Retrieves the current product price data.
|
|
34
91
|
* @param {Object} state The current application state.
|
|
35
92
|
* @return {Object|null}
|
|
36
|
-
*/
|
|
93
|
+
*/
|
|
94
|
+
export const getProductPrice = createSelector(getCalculatedProduct, product => {
|
|
95
|
+
if (!product || !product.price) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return product.price;
|
|
99
|
+
});
|