@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,6 +1,72 @@
|
|
|
1
|
-
|
|
1
|
+
import { REQUEST_USER_REVIEW, REQUEST_SUBMIT_REVIEW, RECEIVE_USER_REVIEW, RECEIVE_SUBMIT_REVIEW, ERROR_USER_REVIEW, ERROR_SUBMIT_REVIEW, RESET_SUBMIT_REVIEW, FLUSH_USER_REVIEWS, USER_REVIEW_LIFETIME } from "../constants";
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Stores product reviews by their 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 userReviewsByProductId(state = {}, action) {
|
|
10
|
+
switch (action.type) {
|
|
11
|
+
case REQUEST_USER_REVIEW:
|
|
12
|
+
return {
|
|
13
|
+
...state,
|
|
14
|
+
[action.productId]: {
|
|
15
|
+
...state[action.productId],
|
|
16
|
+
isFetching: true,
|
|
17
|
+
review: '',
|
|
18
|
+
expires: 0
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
case RECEIVE_USER_REVIEW:
|
|
22
|
+
return {
|
|
23
|
+
...state,
|
|
24
|
+
[action.productId]: {
|
|
25
|
+
...state[action.productId],
|
|
26
|
+
isFetching: false,
|
|
27
|
+
review: action.review.id,
|
|
28
|
+
expires: Date.now() + USER_REVIEW_LIFETIME
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
case ERROR_SUBMIT_REVIEW:
|
|
32
|
+
case ERROR_USER_REVIEW:
|
|
33
|
+
{
|
|
34
|
+
const newState = {
|
|
35
|
+
...state
|
|
36
|
+
};
|
|
37
|
+
delete newState[action.productId];
|
|
38
|
+
return newState || {};
|
|
39
|
+
}
|
|
40
|
+
case REQUEST_SUBMIT_REVIEW:
|
|
41
|
+
return {
|
|
42
|
+
...state,
|
|
43
|
+
[action.review.productId]: {
|
|
44
|
+
...state[action.review.productId],
|
|
45
|
+
isFetching: true,
|
|
46
|
+
expires: 0
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
case RECEIVE_SUBMIT_REVIEW:
|
|
50
|
+
return {
|
|
51
|
+
...state,
|
|
52
|
+
[action.review.productId]: {
|
|
53
|
+
isFetching: false,
|
|
54
|
+
review: action.review.id,
|
|
55
|
+
expires: action.review.id ? Date.now() + USER_REVIEW_LIFETIME : 0
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
case RESET_SUBMIT_REVIEW:
|
|
59
|
+
return {
|
|
60
|
+
...state,
|
|
61
|
+
[action.review.productId]: {
|
|
62
|
+
...state[action.review.productId],
|
|
63
|
+
isFetching: false,
|
|
64
|
+
review: action.review.id
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
case FLUSH_USER_REVIEWS:
|
|
68
|
+
return {};
|
|
69
|
+
default:
|
|
70
|
+
return state;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,64 +1,168 @@
|
|
|
1
|
-
|
|
1
|
+
import { createSelector } from 'reselect';
|
|
2
|
+
import { generateResultHash } from '@shopgate/pwa-common/helpers/redux';
|
|
3
|
+
import { isUserLoggedIn } from '@shopgate/pwa-common/selectors/user';
|
|
4
|
+
import { REVIEW_PREVIEW_COUNT } from "../constants";
|
|
5
|
+
import * as pipelines from "../constants/Pipelines";
|
|
6
|
+
import { getBaseProductId } from "../../product/selectors/product";
|
|
7
|
+
|
|
8
|
+
/**
|
|
2
9
|
* @param {Object} state The global state.
|
|
3
10
|
* @return {Object}
|
|
4
|
-
*/
|
|
11
|
+
*/
|
|
12
|
+
const getReviewsState = state => state.reviews;
|
|
13
|
+
|
|
14
|
+
/**
|
|
5
15
|
* @param {Object} state The global state.
|
|
6
16
|
* @return {Object}
|
|
7
|
-
*/
|
|
17
|
+
*/
|
|
18
|
+
const getProductReviewsExcerptState = state => state.reviews.reviewsByProductId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
8
21
|
* Select the product reviews state.
|
|
9
22
|
* @param {Object} state The current application state.
|
|
10
23
|
* @return {Object} The product reviews state.
|
|
11
|
-
*/
|
|
24
|
+
*/
|
|
25
|
+
const getReviewsByHash = createSelector(getReviewsState, state => state.reviewsByHash);
|
|
26
|
+
|
|
27
|
+
/**
|
|
12
28
|
* Retrieves the fetching state for the current product's reviews.
|
|
13
29
|
* @param {Object} state The current application state.
|
|
14
30
|
* @return {Object|null} The reviews for a product.
|
|
15
|
-
*/
|
|
31
|
+
*/
|
|
32
|
+
const getCollectionForCurrentBaseProduct = createSelector(getBaseProductId, getReviewsByHash, (productId, reviews) => {
|
|
33
|
+
const hash = generateResultHash({
|
|
34
|
+
pipeline: pipelines.SHOPGATE_CATALOG_GET_PRODUCT_REVIEWS,
|
|
35
|
+
productId
|
|
36
|
+
}, false);
|
|
37
|
+
if (reviews.hasOwnProperty(hash)) {
|
|
38
|
+
return reviews[hash];
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
16
44
|
* Select the product reviews state
|
|
17
45
|
* @param {Object} state The current application state.
|
|
18
46
|
* @return {Object} The product reviews state.
|
|
19
|
-
*/
|
|
47
|
+
*/
|
|
48
|
+
const getReviewsByProductId = createSelector(getReviewsState, state => state.reviewsByProductId);
|
|
49
|
+
|
|
50
|
+
/**
|
|
20
51
|
* Retrieves the reviews collection which contains all reviews data.
|
|
21
52
|
* @param {Object} state The current application state.
|
|
22
53
|
* @return {Object} The reviews collection stored as reviewId => review pairs.
|
|
23
|
-
*/
|
|
54
|
+
*/
|
|
55
|
+
export const getReviews = createSelector(getReviewsState, state => state.reviewsById || {});
|
|
56
|
+
|
|
57
|
+
/**
|
|
24
58
|
* Retrieves the number of reviews for a product
|
|
25
59
|
* @param {Object} state The current application state.
|
|
26
60
|
* @return {number} The total review count for a product
|
|
27
|
-
*/
|
|
61
|
+
*/
|
|
62
|
+
export const getProductReviewCount = createSelector(getBaseProductId, getReviewsByProductId, (productId, reviewsState) => {
|
|
63
|
+
const collection = reviewsState[productId];
|
|
64
|
+
if (!collection || !collection.totalReviewCount) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return collection.totalReviewCount;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/**
|
|
28
71
|
* Retrieves the total number of reviews for a current product.
|
|
29
72
|
* @param {Object} state The current application state.
|
|
30
73
|
* @return {number|null} The total number of reviews.
|
|
31
|
-
*/
|
|
74
|
+
*/
|
|
75
|
+
export const getReviewsTotalCount = createSelector(getCollectionForCurrentBaseProduct, collection => {
|
|
76
|
+
if (!collection || !collection.totalReviewCount) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return collection.totalReviewCount;
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
32
82
|
* Retrieves the total number of currently fetched reviews for a current product.
|
|
33
83
|
* @param {Object} state The current application state.
|
|
34
84
|
* @return {number|null} The current number of fetched reviews.
|
|
35
|
-
*/
|
|
85
|
+
*/
|
|
86
|
+
export const getCurrentReviewCount = createSelector(getCollectionForCurrentBaseProduct, collection => {
|
|
87
|
+
if (!collection || !collection.reviews) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return collection.reviews.length;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
/**
|
|
36
94
|
* Retrieves the information if reviews are currently fetched.
|
|
37
95
|
* @param {Object} state The current application state.
|
|
38
96
|
* @return {bool} The boolean information if reviews are currently being fetched.
|
|
39
|
-
*/
|
|
97
|
+
*/
|
|
98
|
+
export const getReviewsFetchingState = createSelector(getCollectionForCurrentBaseProduct, collection => collection && collection.isFetching);
|
|
99
|
+
|
|
100
|
+
/**
|
|
40
101
|
* Select the user reviews state.
|
|
41
102
|
* @param {Object} state The current application state.
|
|
42
103
|
* @return {Object} The user reviews collection stored as productId => review.
|
|
43
|
-
*/
|
|
104
|
+
*/
|
|
105
|
+
const getUserReviewsByProductId = createSelector(getReviewsState, state => state.userReviewsByProductId);
|
|
106
|
+
|
|
107
|
+
/**
|
|
44
108
|
* Retrieves a user review for a product.
|
|
45
|
-
*/
|
|
109
|
+
*/
|
|
110
|
+
export const getUserReviewForProduct = createSelector(getUserReviewsByProductId, getReviews, (state, props = {}) => props.productId, (userReviews, allReviews, productId) => {
|
|
111
|
+
if (!userReviews || !userReviews[productId] || !allReviews[userReviews[productId].review]) {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
...allReviews[userReviews[productId].review]
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
/**
|
|
46
120
|
* Gets user reviews fetching state. Only the first fetch is considered.
|
|
47
121
|
* @return {bool} True if user review for current product is being fetched.
|
|
48
|
-
*/
|
|
122
|
+
*/
|
|
123
|
+
export const getUserReviewFirstFetchState = createSelector(getBaseProductId, getUserReviewsByProductId, (productId, userReviews) => !!(userReviews && productId && userReviews[productId] && !userReviews[productId].review && userReviews[productId].isFetching));
|
|
124
|
+
|
|
125
|
+
/**
|
|
49
126
|
* Get a user name for the review form.
|
|
50
127
|
* @param {Object} state The state.
|
|
51
128
|
* @returns {string} A user name.
|
|
52
|
-
*/
|
|
129
|
+
*/
|
|
130
|
+
export const getDefaultAuthorName = state => isUserLoggedIn && state.user.data && state.user.data.firstName ? `${state.user.data.firstName} ${state.user.data.lastName}` : '';
|
|
131
|
+
|
|
132
|
+
/**
|
|
53
133
|
* Retrieves the current product reviews.
|
|
54
134
|
* When the user review is available, it will always be the first entry.
|
|
55
135
|
* @param {Object} state The current application state.
|
|
56
136
|
* @return {Array|null} The reviews for a product.
|
|
57
|
-
*/
|
|
58
|
-
|
|
59
|
-
|
|
137
|
+
*/
|
|
138
|
+
export const getProductReviews = createSelector(getCollectionForCurrentBaseProduct, getReviews, getUserReviewForProduct, (collection, allReviews, userReview) => {
|
|
139
|
+
if (!collection || !collection.reviews) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
const reviews = collection.reviews.map(id => allReviews[id]);
|
|
143
|
+
// There is no user review. Returning only from reviews collection.
|
|
144
|
+
if (!userReview.id) {
|
|
145
|
+
return reviews;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// User review always on top. Avoid duplicates.
|
|
149
|
+
return [userReview, ...reviews.filter(r => r.id !== userReview.id)];
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
/**
|
|
60
153
|
* Retrieves the current product reviews excerpt.
|
|
61
154
|
* When user review is available, it will always be the first entry.
|
|
62
155
|
* @param {Object} state The current application state.
|
|
63
156
|
* @return {Array|null} The reviews for a product
|
|
64
|
-
*/
|
|
157
|
+
*/
|
|
158
|
+
export const getProductReviewsExcerpt = createSelector(getBaseProductId, getProductReviewsExcerptState, getReviews, getUserReviewForProduct, (productId, productReviewsState, reviewsState, userReview) => {
|
|
159
|
+
const collection = productReviewsState[productId];
|
|
160
|
+
if (!collection || !collection.reviews) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const reviews = collection.reviews.map(id => reviewsState[id]);
|
|
164
|
+
if (!userReview.id) {
|
|
165
|
+
return reviews;
|
|
166
|
+
}
|
|
167
|
+
return [userReview, ...reviews.filter(r => r.id !== userReview.id)].slice(0, REVIEW_PREVIEW_COUNT);
|
|
168
|
+
});
|
|
@@ -1 +1,100 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.array.reduce.js";
|
|
2
|
+
import { SHOPGATE_CATALOG_GET_PRODUCT_REVIEWS } from "../constants/Pipelines";
|
|
3
|
+
export const existingHash = `{"filters":{},"pipeline":"${SHOPGATE_CATALOG_GET_PRODUCT_REVIEWS}","productId":"9209597131"}`;
|
|
4
|
+
export const testReviews = [{
|
|
5
|
+
author: 'John Canada',
|
|
6
|
+
date: '2017-09-12T15:17:47.000Z',
|
|
7
|
+
rate: 60,
|
|
8
|
+
title: 'title 1',
|
|
9
|
+
review: 'review 2',
|
|
10
|
+
id: 1
|
|
11
|
+
}, {
|
|
12
|
+
author: 'Oleks Bilenko',
|
|
13
|
+
date: '2017-09-12T15:13:03.000Z',
|
|
14
|
+
rate: 80,
|
|
15
|
+
title: 'Title',
|
|
16
|
+
review: 'Review',
|
|
17
|
+
id: 2
|
|
18
|
+
}, {
|
|
19
|
+
author: '',
|
|
20
|
+
date: '2017-09-06T12:38:51.000Z',
|
|
21
|
+
rate: 100,
|
|
22
|
+
title: '',
|
|
23
|
+
review: 'No Name and Title\r\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
|
|
24
|
+
id: 3
|
|
25
|
+
}, {
|
|
26
|
+
author: 'ca ship ship',
|
|
27
|
+
date: '2017-09-06T12:37:40.000Z',
|
|
28
|
+
rate: 40,
|
|
29
|
+
title: 'Test review 2 ',
|
|
30
|
+
review: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
|
|
31
|
+
id: 4
|
|
32
|
+
}, {
|
|
33
|
+
author: 'Carina Hoffmann',
|
|
34
|
+
date: '2017-09-06T12:30:23.000Z',
|
|
35
|
+
rate: 60,
|
|
36
|
+
title: '',
|
|
37
|
+
review: 'Test review',
|
|
38
|
+
id: 5
|
|
39
|
+
}];
|
|
40
|
+
export const emptyState = {
|
|
41
|
+
reviews: {
|
|
42
|
+
reviewsByHash: {},
|
|
43
|
+
reviewsById: {},
|
|
44
|
+
reviewsByProductId: {},
|
|
45
|
+
userReviewsByProductId: {}
|
|
46
|
+
},
|
|
47
|
+
user: {
|
|
48
|
+
login: {
|
|
49
|
+
isLoggedIn: false
|
|
50
|
+
},
|
|
51
|
+
data: {}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export const finalState = {
|
|
55
|
+
product: {
|
|
56
|
+
productsById: {
|
|
57
|
+
9209597131: {
|
|
58
|
+
productData: {
|
|
59
|
+
id: '9209597131'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
reviews: {
|
|
65
|
+
reviewsByProductId: {
|
|
66
|
+
9209597131: {
|
|
67
|
+
isFetching: false,
|
|
68
|
+
totalReviewCount: 5,
|
|
69
|
+
reviews: [1, 2, 3, 4, 5]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
reviewsById: testReviews.reduce((currentReviews, review) => ({
|
|
73
|
+
...currentReviews,
|
|
74
|
+
[review.id]: review
|
|
75
|
+
}), {}),
|
|
76
|
+
reviewsByHash: {
|
|
77
|
+
[`{"filters":{},"pipeline":"${SHOPGATE_CATALOG_GET_PRODUCT_REVIEWS}","productId":"9209597131"}`]: {
|
|
78
|
+
isFetching: false,
|
|
79
|
+
expires: 0,
|
|
80
|
+
reviews: [1, 2, 3, 4, 5],
|
|
81
|
+
totalReviewCount: 10
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
userReviewsByProductId: {
|
|
85
|
+
9209597131: {
|
|
86
|
+
isFetching: false,
|
|
87
|
+
review: testReviews[0].id
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
user: {
|
|
92
|
+
login: {
|
|
93
|
+
isLoggedIn: true
|
|
94
|
+
},
|
|
95
|
+
data: {
|
|
96
|
+
firstName: 'Foo',
|
|
97
|
+
lastName: 'Bar'
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
@@ -1 +1,100 @@
|
|
|
1
|
-
import _cloneDeep from"lodash/cloneDeep";
|
|
1
|
+
import _cloneDeep from "lodash/cloneDeep";
|
|
2
|
+
import { getProductReviews, getProductReviewsExcerpt, getReviewsTotalCount, getCurrentReviewCount, getReviewsFetchingState, getProductReviewCount, getUserReviewForProduct, getDefaultAuthorName } from "./index";
|
|
3
|
+
import { REVIEW_PREVIEW_COUNT } from "../constants";
|
|
4
|
+
import { emptyState, finalState, testReviews } from "./mock";
|
|
5
|
+
describe('Reviews selectors', () => {
|
|
6
|
+
const propsProductId = {
|
|
7
|
+
productId: '9209597131'
|
|
8
|
+
};
|
|
9
|
+
const propsEmpty = {
|
|
10
|
+
productId: null
|
|
11
|
+
};
|
|
12
|
+
describe('getProductReviews', () => {
|
|
13
|
+
it('should return reviews when reviews are available', () => {
|
|
14
|
+
const reviews = getProductReviews(finalState, propsProductId);
|
|
15
|
+
expect(reviews).toEqual(testReviews);
|
|
16
|
+
});
|
|
17
|
+
it('should return empty array when state has no reviews for current product', () => {
|
|
18
|
+
const state = _cloneDeep(finalState);
|
|
19
|
+
const reviews = getProductReviews(state, propsEmpty);
|
|
20
|
+
expect(reviews).toEqual([]);
|
|
21
|
+
});
|
|
22
|
+
it('should return empty array when state is empty', () => {
|
|
23
|
+
const reviews = getProductReviews(emptyState, propsProductId);
|
|
24
|
+
expect(reviews).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('getProductReviewsExcerpt', () => {
|
|
28
|
+
it('should return product reviews when reviews are available', () => {
|
|
29
|
+
const reviews = getProductReviewsExcerpt(finalState, propsProductId);
|
|
30
|
+
expect(reviews).toEqual(testReviews.slice(0, REVIEW_PREVIEW_COUNT));
|
|
31
|
+
});
|
|
32
|
+
it('should return null when state has no reviews for current product', () => {
|
|
33
|
+
const state = _cloneDeep(finalState);
|
|
34
|
+
const reviews = getProductReviewsExcerpt(state, propsEmpty);
|
|
35
|
+
expect(reviews).toBe(null);
|
|
36
|
+
});
|
|
37
|
+
it('should return null when state has no reviews for current product', () => {
|
|
38
|
+
const reviews = getProductReviewsExcerpt(emptyState, propsProductId);
|
|
39
|
+
expect(reviews).toBe(null);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('getReviewsTotalCount', () => {
|
|
43
|
+
it('should return null when no reviews are available', () => {
|
|
44
|
+
const totalCount = getReviewsTotalCount(emptyState, propsProductId);
|
|
45
|
+
expect(totalCount).toBe(null);
|
|
46
|
+
});
|
|
47
|
+
it('should return number when reviews are available', () => {
|
|
48
|
+
const totalCount = getReviewsTotalCount(finalState, propsProductId);
|
|
49
|
+
expect(totalCount).toBeGreaterThan(1);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('getCurrentReviewCount', () => {
|
|
53
|
+
it('should return null when no reviews are available', () => {
|
|
54
|
+
const totalCount = getCurrentReviewCount(emptyState, propsProductId);
|
|
55
|
+
expect(totalCount).toBe(null);
|
|
56
|
+
});
|
|
57
|
+
it('should return number when reviews are available', () => {
|
|
58
|
+
const totalCount = getCurrentReviewCount(finalState, propsProductId);
|
|
59
|
+
expect(totalCount).toBeGreaterThan(1);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('getReviewsFetchingState', () => {
|
|
63
|
+
it('should return fetching state', () => {
|
|
64
|
+
const result = getReviewsFetchingState(finalState, propsProductId);
|
|
65
|
+
expect(result).toEqual(false);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('getProductReviewCount', () => {
|
|
69
|
+
it('should return review count', () => {
|
|
70
|
+
const result = getProductReviewCount(finalState, propsProductId);
|
|
71
|
+
expect(result).toBe(finalState.reviews.reviewsByProductId[9209597131].totalReviewCount);
|
|
72
|
+
});
|
|
73
|
+
it('should return null when there is no reviews', () => {
|
|
74
|
+
const result = getProductReviewCount(emptyState, propsProductId);
|
|
75
|
+
expect(result).toBe(null);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('getUserReviewForProduct', () => {
|
|
79
|
+
it('should return user review', () => {
|
|
80
|
+
const result = getUserReviewForProduct(finalState, propsProductId);
|
|
81
|
+
expect(result).toEqual({
|
|
82
|
+
...finalState.reviews.reviewsById[1]
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
it('should return empty object when no user review is available', () => {
|
|
86
|
+
const result = getUserReviewForProduct(emptyState, propsProductId);
|
|
87
|
+
expect(result).toEqual({});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('getDefaultAuthorName', () => {
|
|
91
|
+
it('should return author name when user is logged in', () => {
|
|
92
|
+
const result = getDefaultAuthorName(finalState, propsProductId);
|
|
93
|
+
expect(result).toBe('Foo Bar');
|
|
94
|
+
});
|
|
95
|
+
it('should return empty string, when user it not logged in', () => {
|
|
96
|
+
const result = getDefaultAuthorName(emptyState, propsProductId);
|
|
97
|
+
expect(result).toBe('');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
package/reviews/streams/index.js
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
|
-
import{main$}from'@shopgate/pwa-common/streams/main';
|
|
1
|
+
import { main$ } from '@shopgate/pwa-common/streams/main';
|
|
2
|
+
import { routeWillEnter$, routeWillLeave$ } from '@shopgate/pwa-common/streams/router';
|
|
3
|
+
import { ITEM_PATH, RECEIVE_PRODUCT, RECEIVE_PRODUCT_CACHED } from '@shopgate/pwa-common-commerce/product/constants';
|
|
4
|
+
import { REQUEST_SUBMIT_REVIEW, RECEIVE_SUBMIT_REVIEW, ERROR_SUBMIT_REVIEW, RESET_SUBMIT_REVIEW } from "../constants";
|
|
5
|
+
export const reviewsWillEnter$ = routeWillEnter$.filter(({
|
|
6
|
+
action
|
|
7
|
+
}) => action.route.pattern === `${ITEM_PATH}/:productId/reviews`);
|
|
8
|
+
export const reviewsWillLeave$ = routeWillLeave$.filter(({
|
|
9
|
+
action
|
|
10
|
+
}) => action.route.pattern === `${ITEM_PATH}/:productId/reviews`);
|
|
11
|
+
|
|
12
|
+
/**
|
|
2
13
|
* Gets triggered when the user tried to submit a review.
|
|
3
14
|
* @type {Observable}
|
|
4
|
-
*/
|
|
15
|
+
*/
|
|
16
|
+
export const requestReviewSubmit$ = main$.filter(({
|
|
17
|
+
action
|
|
18
|
+
}) => action.type === REQUEST_SUBMIT_REVIEW);
|
|
19
|
+
|
|
20
|
+
/**
|
|
5
21
|
* Gets triggered when the user tried to submit a review.
|
|
6
22
|
* @type {Observable}
|
|
7
|
-
*/
|
|
23
|
+
*/
|
|
24
|
+
export const responseReviewSubmit$ = main$.filter(({
|
|
25
|
+
action
|
|
26
|
+
}) => [RECEIVE_SUBMIT_REVIEW, ERROR_SUBMIT_REVIEW, RESET_SUBMIT_REVIEW].includes(action.type));
|
|
27
|
+
|
|
28
|
+
/**
|
|
8
29
|
* Gets triggered when the user submit was successful.
|
|
9
30
|
* @type {Observable}
|
|
10
|
-
*/
|
|
31
|
+
*/
|
|
32
|
+
export const successReviewSubmit$ = main$.filter(({
|
|
33
|
+
action
|
|
34
|
+
}) => action.type === RECEIVE_SUBMIT_REVIEW);
|
|
35
|
+
|
|
36
|
+
/**
|
|
11
37
|
* Gets triggered when the user submit was not successful.
|
|
12
38
|
* @type {Observable}
|
|
13
|
-
*/
|
|
39
|
+
*/
|
|
40
|
+
export const errorReviewSubmit$ = main$.filter(({
|
|
41
|
+
action
|
|
42
|
+
}) => [ERROR_SUBMIT_REVIEW, RESET_SUBMIT_REVIEW].includes(action.type));
|
|
43
|
+
export const shouldFetchReviews$ = main$.filter(({
|
|
44
|
+
action
|
|
45
|
+
}) => action.type === RECEIVE_PRODUCT || action.type === RECEIVE_PRODUCT_CACHED).merge(successReviewSubmit$);
|
package/reviews/streams/spec.js
CHANGED
|
@@ -1 +1,25 @@
|
|
|
1
|
-
import*as actionTypes from"../constants";
|
|
1
|
+
import * as actionTypes from "../constants";
|
|
2
|
+
import * as subjects from "./index";
|
|
3
|
+
const subjectActionsTypes = {
|
|
4
|
+
requestReviewSubmit$: [actionTypes.REQUEST_SUBMIT_REVIEW],
|
|
5
|
+
responseReviewSubmit$: [actionTypes.RECEIVE_SUBMIT_REVIEW, actionTypes.ERROR_SUBMIT_REVIEW, actionTypes.RESET_SUBMIT_REVIEW],
|
|
6
|
+
successReviewSubmit$: [actionTypes.RECEIVE_SUBMIT_REVIEW],
|
|
7
|
+
errorReviewSubmit$: [actionTypes.ERROR_SUBMIT_REVIEW, actionTypes.RESET_SUBMIT_REVIEW]
|
|
8
|
+
};
|
|
9
|
+
describe.skip('Reviews streams', () => {
|
|
10
|
+
it('should filter correctly', () => {
|
|
11
|
+
const possibleSubjects = Object.keys(subjects);
|
|
12
|
+
Object.keys(actionTypes).forEach(typeName => {
|
|
13
|
+
const type = actionTypes[typeName];
|
|
14
|
+
possibleSubjects.forEach(subjectName => {
|
|
15
|
+
const result = subjects[subjectName].operator.predicate({
|
|
16
|
+
action: {
|
|
17
|
+
type
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const shouldBe = subjectActionsTypes[subjectName].includes(type);
|
|
21
|
+
expect(result).toBe(shouldBe);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
import appConfig from'@shopgate/pwa-common/helpers/config';
|
|
1
|
+
import appConfig from '@shopgate/pwa-common/helpers/config';
|
|
2
|
+
import fetchProductReviews from "../actions/fetchProductReviews";
|
|
3
|
+
import { REVIEW_PREVIEW_COUNT } from "../constants";
|
|
4
|
+
import { shouldFetchReviews$ } from "../streams";
|
|
5
|
+
|
|
6
|
+
/**
|
|
2
7
|
* Review subscriptions.
|
|
3
8
|
* @param {Function} subscribe The subscribe function.
|
|
4
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
export default function product(subscribe) {
|
|
11
|
+
if (!appConfig.hasReviews) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
subscribe(shouldFetchReviews$, ({
|
|
15
|
+
action,
|
|
16
|
+
dispatch
|
|
17
|
+
}) => {
|
|
18
|
+
if (action.productData) {
|
|
19
|
+
const {
|
|
20
|
+
id,
|
|
21
|
+
baseProductId
|
|
22
|
+
} = action.productData;
|
|
23
|
+
dispatch(fetchProductReviews(baseProductId || id, REVIEW_PREVIEW_COUNT));
|
|
24
|
+
}
|
|
25
|
+
if (action.review) {
|
|
26
|
+
dispatch(fetchProductReviews(action.review.productId, REVIEW_PREVIEW_COUNT));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import{ERROR_HANDLE_SCANNER}from"../constants"
|
|
1
|
+
import { ERROR_HANDLE_SCANNER } from "../constants";
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Creates the dispatched ERROR_HANDLE_SCANNER action object.
|
|
3
5
|
* @param {string} scope scan scope
|
|
4
6
|
* @param {string} format data format EAN_13, QR_CODE
|
|
5
7
|
* @param {Object} payload scan result
|
|
6
8
|
* @returns {Object}
|
|
7
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
const errorHandleScanner = (scope, format, payload) => ({
|
|
11
|
+
type: ERROR_HANDLE_SCANNER,
|
|
12
|
+
scope,
|
|
13
|
+
format,
|
|
14
|
+
payload
|
|
15
|
+
});
|
|
16
|
+
export default errorHandleScanner;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import{SCANNER_FINISHED}from"../constants"
|
|
1
|
+
import { SCANNER_FINISHED } from "../constants";
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Creates the dispatched SCANNER_FINISHED action object.
|
|
3
5
|
* @param {string} scope scan scope
|
|
4
6
|
* @param {string} format data format EAN_13, QR_CODE
|
|
5
7
|
* @param {Object} payload scan result
|
|
6
8
|
* @returns {Object}
|
|
7
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
const scannerFinished = (scope, format, payload) => ({
|
|
11
|
+
type: SCANNER_FINISHED,
|
|
12
|
+
scope,
|
|
13
|
+
format,
|
|
14
|
+
payload
|
|
15
|
+
});
|
|
16
|
+
export default scannerFinished;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import{START_SCANNER}from"../constants"
|
|
1
|
+
import { START_SCANNER } from "../constants";
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Creates the dispatched START_SCANNER action object.
|
|
3
5
|
* @returns {Object}
|
|
4
|
-
*/
|
|
6
|
+
*/
|
|
7
|
+
const startScanner = () => ({
|
|
8
|
+
type: START_SCANNER
|
|
9
|
+
});
|
|
10
|
+
export default startScanner;
|