@shopgate/engage 7.11.1 → 7.12.0-beta.1

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.
Files changed (39) hide show
  1. package/package.json +7 -7
  2. package/reviews/components/Reviews/components/AllReviewsLink/connector.js +10 -0
  3. package/reviews/components/Reviews/components/AllReviewsLink/index.js +4 -0
  4. package/reviews/components/Reviews/components/AllReviewsLink/style.js +4 -0
  5. package/reviews/components/Reviews/components/Header/components/AverageRating/index.js +7 -0
  6. package/reviews/components/Reviews/components/Header/components/AverageRating/style.js +1 -0
  7. package/reviews/components/Reviews/components/Header/components/NoReviews/index.js +3 -0
  8. package/reviews/components/Reviews/components/Header/components/NoReviews/style.js +1 -0
  9. package/reviews/components/Reviews/components/Header/components/ReviewsExcerpt/index.js +4 -0
  10. package/reviews/components/Reviews/components/Header/components/ReviewsExcerpt/style.js +2 -0
  11. package/reviews/components/Reviews/components/Header/components/WriteReviewLink/index.js +4 -0
  12. package/reviews/components/Reviews/components/Header/components/WriteReviewLink/spec.js +5 -0
  13. package/reviews/components/Reviews/components/Header/connector.js +6 -0
  14. package/reviews/components/Reviews/components/Header/index.js +6 -0
  15. package/reviews/components/Reviews/components/Header/spec.js +6 -0
  16. package/reviews/components/Reviews/components/List/components/Info/components/Author/index.js +5 -0
  17. package/reviews/components/Reviews/components/List/components/Info/components/ReviewDate/index.js +5 -0
  18. package/reviews/components/Reviews/components/List/components/Info/index.js +6 -0
  19. package/reviews/components/Reviews/components/List/components/Info/style.js +1 -0
  20. package/reviews/components/Reviews/components/List/components/Rating/index.js +5 -0
  21. package/reviews/components/Reviews/components/List/components/Rating/style.js +1 -0
  22. package/reviews/components/Reviews/components/List/components/Review/index.js +5 -0
  23. package/reviews/components/Reviews/components/List/components/Text/index.js +5 -0
  24. package/reviews/components/Reviews/components/List/components/Text/style.js +1 -0
  25. package/reviews/components/Reviews/components/List/components/Title/index.js +5 -0
  26. package/reviews/components/Reviews/components/List/components/Title/style.js +1 -0
  27. package/reviews/components/Reviews/components/List/index.js +5 -0
  28. package/reviews/components/Reviews/components/List/spec.js +1 -0
  29. package/reviews/components/Reviews/components/List/style.js +1 -0
  30. package/reviews/components/Reviews/components/RatingCount/index.js +4 -0
  31. package/reviews/components/Reviews/components/RatingCount/spec.js +1 -0
  32. package/reviews/components/Reviews/components/RatingCount/style.js +2 -0
  33. package/reviews/components/Reviews/components/ReviewsInfo/index.js +6 -0
  34. package/reviews/components/Reviews/connector.js +6 -0
  35. package/reviews/components/Reviews/index.js +6 -0
  36. package/reviews/components/Reviews/mock.js +22 -0
  37. package/reviews/components/Reviews/spec.js +7 -0
  38. package/reviews/components/Reviews/style.js +1 -0
  39. package/reviews/index.js +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/engage",
3
- "version": "7.11.1",
3
+ "version": "7.12.0-beta.1",
4
4
  "description": "Shopgate's ENGAGE library.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Shopgate <support@shopgate.com>",
@@ -16,12 +16,12 @@
16
16
  ],
17
17
  "dependencies": {
18
18
  "@shopgate/native-modules": "1.0.0-beta.18",
19
- "@shopgate/pwa-common": "7.11.1",
20
- "@shopgate/pwa-common-commerce": "7.11.1",
21
- "@shopgate/pwa-core": "7.11.1",
22
- "@shopgate/pwa-ui-ios": "7.11.1",
23
- "@shopgate/pwa-ui-material": "7.11.1",
24
- "@shopgate/pwa-ui-shared": "7.11.1",
19
+ "@shopgate/pwa-common": "7.12.0-beta.1",
20
+ "@shopgate/pwa-common-commerce": "7.12.0-beta.1",
21
+ "@shopgate/pwa-core": "7.12.0-beta.1",
22
+ "@shopgate/pwa-ui-ios": "7.12.0-beta.1",
23
+ "@shopgate/pwa-ui-material": "7.12.0-beta.1",
24
+ "@shopgate/pwa-ui-shared": "7.12.0-beta.1",
25
25
  "@stripe/react-stripe-js": "^1.1.2",
26
26
  "@stripe/stripe-js": "^1.3.1",
27
27
  "@virtuous/conductor": "~2.5.0",
@@ -0,0 +1,10 @@
1
+ import{connect}from'react-redux';import{getProductReviewCount}from'@shopgate/pwa-common-commerce/reviews/selectors';/**
2
+ * Maps the contents of the state to the component props.
3
+ * @param {Object} state The current application state.
4
+ * @param {Object} props The current component props.
5
+ * @return {Object} The extended component props.
6
+ */var mapStateToProps=function mapStateToProps(state,props){return{count:getProductReviewCount(state,props)};};/**
7
+ * @param {Object} next The next component props.
8
+ * @param {Object} prev The previous component props.
9
+ * @returns {boolean}
10
+ */var areStatePropsEqual=function areStatePropsEqual(next,prev){if(prev.count!==next.count){return false;}return true;};export default connect(mapStateToProps,null,null,{areStatePropsEqual:areStatePropsEqual});
@@ -0,0 +1,4 @@
1
+ import React from'react';import PropTypes from'prop-types';import{bin2hex}from'@shopgate/pwa-common/helpers/data';import I18n from'@shopgate/pwa-common/components/I18n';import{ITEM_PATH}from'@shopgate/pwa-common-commerce/product/constants/index';import{REVIEW_PREVIEW_COUNT}from'@shopgate/pwa-common-commerce/reviews/constants';import ButtonLink from'@shopgate/pwa-ui-shared/ButtonLink';import connect from"./connector";import{container}from"./style";/**
2
+ * @param {Object} props The component props.
3
+ * @returns {JSX}
4
+ */var AllReviewsLink=function AllReviewsLink(props){if(!props.productId||props.count<=REVIEW_PREVIEW_COUNT){return null;}return React.createElement("div",{className:"".concat(container," engage__reviews__all-reviews-link"),"data-test-id":"showAllReviewsButton"},React.createElement(ButtonLink,{href:"".concat(ITEM_PATH,"/").concat(bin2hex(props.productId),"/reviews")},React.createElement(I18n.Text,{string:"reviews.button_all",params:props})));};AllReviewsLink.defaultProps={count:0,productId:null};export default connect(AllReviewsLink);
@@ -0,0 +1,4 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables;/**
2
+ * Styles for a link parent container.
3
+ * @type {string}
4
+ */export var container=css({display:'flex',justifyContent:'flex-end',textAlign:'right',marginTop:-variables.gap.small,marginBottom:-variables.gap.big});
@@ -0,0 +1,7 @@
1
+ import React from'react';import PropTypes from'prop-types';import RatingStars from'@shopgate/pwa-ui-shared/RatingStars';import Link from'@shopgate/pwa-common/components/Link';import{ITEM_PATH}from'@shopgate/pwa-common-commerce/product/constants';import{bin2hex}from'@shopgate/pwa-common/helpers/data';import appConfig from'@shopgate/pwa-common/helpers/config';import RatingCount from"../../../RatingCount";import{container}from"./style";/**
2
+ * The average rating and number of ratings for a product.
3
+ * @param {Object} rating The rating values.
4
+ * @param {string} productId The related product ID.
5
+ * @returns {JSX}
6
+ */var AverageRating=function AverageRating(_ref){var average=_ref.average,count=_ref.count,productId=_ref.productId;if(!productId){return null;}return React.createElement(Link,{"data-test-id":"ratedStarsAverage",tagName:"a",href:"".concat(ITEM_PATH,"/").concat(bin2hex(productId),"/write_review"),disabled:!appConfig.showWriteReview,className:container,itemProp:"item",itemScope:true,itemType:"http://schema.org/Review"// eslint-disable-next-line jsx-a11y/aria-role
7
+ ,role:"text"},React.createElement(RatingStars,{value:average,display:"large"}),React.createElement(RatingCount,{count:count}));};AverageRating.defaultProps={average:0,count:0,productId:null};export default AverageRating;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';var container=css({alignItems:'center',display:'flex',flexDirection:'column',justifyContent:'space-between',marginBottom:8}).toString();export{container};
@@ -0,0 +1,3 @@
1
+ import React,{Fragment}from'react';import PropTypes from'prop-types';import I18n from'@shopgate/pwa-common/components/I18n';import appConfig from'@shopgate/pwa-common/helpers/config';import AverageRating from"../AverageRating";import WriteReviewLink from"../WriteReviewLink";import*as styles from"./style";/**
2
+ * @return {JSX}
3
+ */var NoReviews=function NoReviews(_ref){var productId=_ref.productId;return React.createElement("div",{className:styles.container,"aria-hidden":true},React.createElement(AverageRating,{productId:productId}),React.createElement("div",{className:styles.noReviews},appConfig.showWriteReview&&React.createElement(Fragment,null,React.createElement(I18n.Text,{string:"reviews.no_reviews"}),React.createElement(WriteReviewLink,{productId:productId}))));};NoReviews.defaultProps={productId:null};export default NoReviews;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables;export var container=css({fontWeight:500,margin:0});export var noReviews=css({display:'flex',justifyContent:'space-between',flexDirection:'column',alignItems:'center',marginTop:variables.gap.small,padding:"0 ".concat(variables.gap.small,"px"),textAlign:'center'});
@@ -0,0 +1,4 @@
1
+ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React from'react';import PropTypes from'prop-types';import classNames from'classnames';import appConfig from'@shopgate/pwa-common/helpers/config';import I18n from'@shopgate/pwa-common/components/I18n';import RatingNumber from'@shopgate/pwa-ui-shared/RatingNumber';import AverageRating from"../AverageRating";import WriteReviewLink from"../WriteReviewLink";import*as styles from"./style";/* eslint-disable jsx-a11y/aria-role */ /**
2
+ * @param {Object} props The component props.
3
+ * @returns {JSX}
4
+ */var ReviewsExcerpt=function ReviewsExcerpt(_ref){var _classNames;var productId=_ref.productId,average=_ref.average,count=_ref.count,withTopGap=_ref.withTopGap;return React.createElement("div",{className:classNames('engage__reviews__reviews-excerpt',(_classNames={},_defineProperty(_classNames,styles.withTopGapContainer,withTopGap),_defineProperty(_classNames,styles.container,!withTopGap),_classNames)),id:"reviewsExcerpt"},React.createElement(AverageRating,{productId:productId,average:average,count:count}),React.createElement("div",{className:styles.reviewsLine,role:"text"},React.createElement(I18n.Text,{string:"reviews.rating",className:styles.averageRatingText},React.createElement(RatingNumber,{rating:average,className:styles.averageRatingNumber})),appConfig.showWriteReview&&React.createElement(WriteReviewLink,{productId:productId})));};/* eslint-enable jsx-a11y/aria-role */ReviewsExcerpt.defaultProps={average:0,count:0,productId:null,withTopGap:false};export default ReviewsExcerpt;
@@ -0,0 +1,2 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var colors=themeConfig.colors,variables=themeConfig.variables;export var container=css({fontWeight:500,margin:0});export var withTopGapContainer=css(container,{marginTop:variables.gap.xbig});export var reviewsLine=css({display:'flex',justifyContent:'space-between',alignItems:'baseline',padding:"0 0 ".concat(variables.gap.small,"px"),marginBottom:-2});export var averageRatingNumber=css({// Before the custom properties the primary color was used for this class.
2
+ color:"var(--color-secondary, ".concat(colors.primary,")"),marginLeft:variables.gap.small}).toString();export var averageRatingText=css({marginLeft:variables.gap.big}).toString();
@@ -0,0 +1,4 @@
1
+ import React from'react';import PropTypes from'prop-types';import I18n from'@shopgate/pwa-common/components/I18n';import{i18n}from'@shopgate/engage/core';import{ITEM_PATH}from'@shopgate/pwa-common-commerce/product/constants';import{bin2hex}from'@shopgate/pwa-common/helpers/data';import ButtonLink from'@shopgate/pwa-ui-shared/ButtonLink';/**
2
+ * Link to add a review.
3
+ * @returns {JSX|null}
4
+ */var WriteReviewLink=function WriteReviewLink(_ref){var productId=_ref.productId;return React.createElement("div",{"data-test-id":"writeReview","aria-hidden":true,className:"engage__reviews__write-review-link"},React.createElement(ButtonLink,{href:"".concat(ITEM_PATH,"/").concat(bin2hex(productId),"/write_review"),noGap:true,"aria-label":i18n.text('reviews.button_add')},React.createElement(I18n.Text,{string:"reviews.button_add"})));};export default WriteReviewLink;
@@ -0,0 +1,5 @@
1
+ import React from'react';import{Provider}from'react-redux';import configureStore from'redux-mock-store';import{mount}from'enzyme';import{mockedStateWithAll}from'@shopgate/pwa-common-commerce/reviews/mock';import WriteReviewLink from"./index";var mockedStore=configureStore();/**
2
+ * Creates component with provided store state.
3
+ * @param {Object} mockedState Mocked stage.
4
+ * @return {ReactWrapper}
5
+ */var createComponent=function createComponent(mockedState){var Component=React.createElement(Provider,{store:mockedStore(mockedState)},React.createElement(WriteReviewLink,{productId:"foo"}));return mount(Component);};describe('<WriteReviewLink>',function(){var component=null;beforeEach(function(){jest.resetModules();});it('should render when current product is set',function(){component=createComponent(mockedStateWithAll);expect(component).toMatchSnapshot();expect(component.find('span').exists()).toBe(true);});});
@@ -0,0 +1,6 @@
1
+ import{connect}from'react-redux';import{getBaseProductId,getProductRating}from'@shopgate/pwa-common-commerce/product/selectors/product';/**
2
+ * Maps the contents of the state to the component props.
3
+ * @param {Object} state The current application state.
4
+ * @param {Object} props The component props.
5
+ * @return {Object} The extended component props.
6
+ */var mapStateToProps=function mapStateToProps(state,props){return{productId:getBaseProductId(state,props),rating:getProductRating(state,props)};};export default connect(mapStateToProps);
@@ -0,0 +1,6 @@
1
+ import React from'react';import PropTypes from'prop-types';import NoReviews from"./components/NoReviews";import ReviewsExcerpt from"./components/ReviewsExcerpt";import connect from"./connector";/**
2
+ * The header of the reviews component
3
+ * @param {Object} rating The rating values
4
+ * @param {bool} withTopGap Adds additional top gap when true.
5
+ * @returns {JSX}
6
+ */var Header=function Header(_ref){var productId=_ref.productId,rating=_ref.rating,withTopGap=_ref.withTopGap;if(!rating){return null;}var _rating$average=rating.average,average=_rating$average===void 0?0:_rating$average,_rating$count=rating.count,count=_rating$count===void 0?0:_rating$count;if(!average){return React.createElement(NoReviews,{productId:productId});}return React.createElement(ReviewsExcerpt,{productId:productId,average:average,count:count,withTopGap:withTopGap});};Header.defaultProps={productId:null,rating:null,withTopGap:false};export default connect(Header);
@@ -0,0 +1,6 @@
1
+ import React from'react';import{Provider}from'react-redux';import{mount}from'enzyme';import configureStore from'redux-mock-store';import mockRenderOptions from'@shopgate/pwa-common/helpers/mocks/mockRenderOptions';import{mockProductId,mockedStateWithoutReview,mockedStateWithAll}from'@shopgate/pwa-common-commerce/reviews/mock';import Header from"./index";var mockedStore=configureStore();/**
2
+ * Creates component with provided store state.
3
+ * @param {Object} mockedState Mocked stage.
4
+ * @param {Object|null} props Rating prop.
5
+ * @return {ReactWrapper}
6
+ */var createComponent=function createComponent(mockedState){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return mount(React.createElement(Provider,{store:mockedStore(mockedState)},React.createElement(Header,props)),mockRenderOptions);};describe('<Header />',function(){var header=null;it('should render empty',function(){var productId=mockProductId;var rating=mockedStateWithoutReview.product.productsById[productId].productData.rating;header=createComponent(mockedStateWithoutReview,{productId:productId,rating:rating});expect(header.find('Header').exists()).toBe(true);expect(header).toMatchSnapshot();expect(header.find('RatingStars').prop('value')).toEqual(0);expect(header.find('RatingCount').html()).toBe(null);});it('should render rating summary',function(){var productId=mockProductId;var rating=mockedStateWithAll.product.productsById[productId].productData.rating;header=createComponent(mockedStateWithAll,{productId:productId,rating:rating});expect(header.find('Header').exists()).toBe(true);expect(header).toMatchSnapshot();expect(header.find('RatingStars').prop('value')).toEqual(rating.average);expect(header.find('RatingCount').prop('count')).toEqual(rating.count);});it('should render null when no review is provided',function(){header=createComponent(mockedStateWithAll,{productId:'some-id'});expect(header.html()).toBe(null);});});
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import I18n from'@shopgate/pwa-common/components/I18n';/**
2
+ * Review Author Component.
3
+ * @param {string} author The author's name.
4
+ * @returns {JSX|null}
5
+ */var Author=function Author(_ref){var author=_ref.author;if(!author){return null;}return React.createElement(I18n.Text,{string:"reviews.author",params:{author:author}});};Author.defaultProps={author:null};export default Author;
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import I18n from'@shopgate/pwa-common/components/I18n';/**
2
+ * Review Date Component.
3
+ * @param {string} date The date of a review.
4
+ * @returns {JSX}
5
+ */var ReviewDate=function ReviewDate(_ref){var date=_ref.date;return React.createElement(I18n.Date,{timestamp:new Date(date).getTime(),format:"long"});};ReviewDate.defaultProps={date:null};export default ReviewDate;
@@ -0,0 +1,6 @@
1
+ import React from'react';import PropTypes from'prop-types';import styles from"./style";import ReviewDate from"./components/ReviewDate";import Author from"./components/Author";/**
2
+ * Review Info Component.
3
+ * @param {Object} props The props.
4
+ * @returns {JSX}
5
+ */var Info=function Info(_ref){var review=_ref.review;return(// eslint-disable-next-line jsx-a11y/aria-role
6
+ React.createElement("div",{className:styles,role:"text"},React.createElement(ReviewDate,{date:review.date}),' ',React.createElement(Author,{author:review.author})));};Info.defaultProps={review:null};export default Info;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var colors=themeConfig.colors;export default css({color:"var(--color-text-medium-emphasis, ".concat(colors.shade3,")"),fontSize:14}).toString();
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import RatingStars from'@shopgate/pwa-ui-shared/RatingStars';import styles from"./style";/**
2
+ * Review Rating Component.
3
+ * @param {number} rate The rating value.
4
+ * @returns {JSX}
5
+ */var Rating=function Rating(_ref){var rate=_ref.rate;return React.createElement("div",{className:styles.container},React.createElement(RatingStars,{value:rate,className:styles.stars}));};Rating.defaultProps={rate:0};export default Rating;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';var container=css({alignItems:'center',display:'flex',margin:'4px 0'}).toString();var stars=css({display:'inline-block',lineHeight:1}).toString();export default{container:container,stars:stars};
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import Title from"../Title";import Rating from"../Rating";import Text from"../Text";import Info from"../Info";/**
2
+ * Single Review Component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX}
5
+ */var Review=function Review(_ref){var review=_ref.review;return React.createElement("div",{"data-test-id":"reviewTitle: ".concat(review.title)},React.createElement(Title,{title:review.title}),React.createElement(Rating,{rate:review.rate}),React.createElement(Text,{review:review.review}),React.createElement(Info,{review:review}));};export default Review;
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import styles from"./style";/**
2
+ * Review Text Component
3
+ * @param {string} review The review text
4
+ * @returns {JSX|null}
5
+ */var Text=function Text(_ref){var review=_ref.review;if(!review){return null;}return React.createElement("div",{className:styles},"\"".concat(review,"\""));};Text.defaultProps={review:null};export default Text;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export default css({fontSize:14,fontStyle:'italic',whiteSpace:'pre-line'}).toString();
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import styles from"./style";/**
2
+ * Review Title Component.
3
+ * @param {string} title The title of the review.
4
+ * @returns {JSX}
5
+ */var Title=function Title(_ref){var title=_ref.title;return React.createElement("div",{className:styles},title);};Title.defaultProps={title:null};export default Title;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export default css({fontWeight:500,lineHeight:'20px'}).toString();
@@ -0,0 +1,5 @@
1
+ function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){_typeof=function _typeof(obj){return typeof obj;};}else{_typeof=function _typeof(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};}return _typeof(obj);}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor;}function _possibleConstructorReturn(self,call){if(call&&(_typeof(call)==="object"||typeof call==="function")){return call;}return _assertThisInitialized(self);}function _assertThisInitialized(self){if(self===void 0){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}function _getPrototypeOf(o){_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf:function _getPrototypeOf(o){return o.__proto__||Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function");}subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:true,configurable:true}});if(superClass)_setPrototypeOf(subClass,superClass);}function _setPrototypeOf(o,p){_setPrototypeOf=Object.setPrototypeOf||function _setPrototypeOf(o,p){o.__proto__=p;return o;};return _setPrototypeOf(o,p);}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React,{PureComponent}from'react';import PropTypes from'prop-types';import{SurroundPortals}from'@shopgate/engage/components';import{PRODUCT_REVIEWS_ENTRY}from'@shopgate/engage/product';import Title from"./components/Title";import Rating from"./components/Rating";import Text from"./components/Text";import Info from"./components/Info";import styles from"./style";/**
2
+ * Review List Component.
3
+ */var List=/*#__PURE__*/function(_PureComponent){_inherits(List,_PureComponent);function List(){_classCallCheck(this,List);return _possibleConstructorReturn(this,_getPrototypeOf(List).apply(this,arguments));}_createClass(List,[{key:"render",/**
4
+ * @returns {JSX}
5
+ */value:function render(){var reviews=this.props.reviews;if(!reviews||reviews.length===0){return null;}return React.createElement("ul",{className:"engage__reviews__list"},reviews.map(function(review){return React.createElement("li",{key:review.id,className:styles,"data-test-id":"reviewTitle: ".concat(review.title)},React.createElement(SurroundPortals,{portalName:PRODUCT_REVIEWS_ENTRY,portalProps:{review:review}},React.createElement(Title,{title:review.title}),React.createElement(Rating,{rate:review.rate}),React.createElement(Text,{review:review.review}),React.createElement(Info,{review:review})));}));}}]);return List;}(PureComponent);_defineProperty(List,"defaultProps",{reviews:null});export default List;
@@ -0,0 +1 @@
1
+ import React from'react';import{mount}from'enzyme';import mockRenderOptions from'@shopgate/pwa-common/helpers/mocks/mockRenderOptions';import List from"./index";describe('<List />',function(){var list=null;var reviews=[{id:'a',author:'',date:'2017-09-06T12:38:51.000Z',rate:100,title:'',review:'No Name and Title Lorem ipsum dolor sit amet, con… takimata sanctus est Lorem ipsum dolor sit amet.'},{id:'b',author:'username123',date:'2017-09-06T12:37:40.000Z',rate:40,title:'Test review 2 ',review:'Lorem ipsum dolor sit amet, consetetur sadipscing … takimata sanctus est Lorem ipsum dolor sit amet.'},{id:'c',author:'Carina Hoffmann',date:'2017-09-06T12:30:23.000Z',rate:60,title:'',review:'Test review'},{id:'d',author:'',date:'2017-09-06T12:30:23.000Z',rate:20,title:'',review:''}];beforeEach(function(){list=mount(React.createElement(List,{reviews:[]}),mockRenderOptions);});it('should not render when no reviews given',function(){expect(list).toMatchSnapshot();expect(list.find('Review').exists()).toBe(false);});it('should render list with reviews',function(){list.setProps({reviews:reviews});expect(list).toMatchSnapshot();expect(list.find('List > ul').exists()).toBe(true);list.find('Review').forEach(function(node,i){var ratingNode=node.find('Rating');expect(ratingNode.prop('rate')).toEqual(reviews[i].rate);expect(ratingNode.find('RatingStars').prop('value')).toEqual(reviews[i].rate);expect(node.find('Info').prop('review').date).toEqual(reviews[i].date);if(reviews[i].author){expect(node.find('Info').prop('review').author).toEqual(reviews[i].author);}if(reviews[i].title){expect(node.find('Title').prop('title')).toEqual(reviews[i].title);}if(reviews[i].review){expect(node.find('Text').prop('review')).toEqual(reviews[i].review);}});});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var colors=themeConfig.colors,variables=themeConfig.variables;export default css({marginLeft:variables.gap.big,padding:"".concat(variables.gap.big,"px ").concat(variables.gap.big,"px ").concat(variables.gap.big,"px 0"),borderTop:"1px solid ".concat(colors.shade7)}).toString();
@@ -0,0 +1,4 @@
1
+ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React from'react';import PropTypes from'prop-types';import classNames from'classnames';import I18n from'@shopgate/pwa-common/components/I18n';import{greyStyle,prominentStyle}from"./style";/**
2
+ * @param {Object} props The component props.
3
+ * @returns {JSX}
4
+ */var RatingCount=function RatingCount(props){var _classNames;if(!props.count){return null;}return React.createElement(I18n.Text,{string:"reviews.review_count",params:props,className:classNames((_classNames={},_defineProperty(_classNames,greyStyle,true),_defineProperty(_classNames,prominentStyle,props.prominent),_classNames),'engage__reviews__rating-count')});};RatingCount.defaultProps={count:null,prominent:false};export default RatingCount;
@@ -0,0 +1 @@
1
+ import React from'react';import{mount}from'enzyme';import RatingCount from"./index";describe('<RatingCount>',function(){it('should render nothing when count is 0',function(){var rating=mount(React.createElement(RatingCount,{count:0}));expect(rating.find('span').exists()).toBe(false);});it('should render text when count is more than 0',function(){var rating=mount(React.createElement(RatingCount,{count:1}));expect(rating.find('span').exists()).toBe(true);});});
@@ -0,0 +1,2 @@
1
+ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var colors=themeConfig.colors;var main={fontSize:12,margin:'0 0.5em',lineHeight:'2em'};var greyStyle=css(_extends({},main,{color:colors.shade3,fontSize:12})).toString();var prominentStyle=css(_extends({},main,{// Before the custom properties the primary color was used for this class.
2
+ color:"var(--color-secondary, ".concat(colors.primary,")")})).toString();export{greyStyle,prominentStyle};
@@ -0,0 +1,6 @@
1
+ import React from'react';import{css}from'glamor';import classNames from'classnames';import appConfig from'@shopgate/pwa-common/helpers/config';import{Link}from'@shopgate/engage/components';var styles={root:css({textAlign:'center',fontSize:'.875rem',fontWeight:300,lineHeight:1.5,padding:'0.8125rem 1rem 1rem'}).toString(),link:css({textAlign:'center',fontWeight:600,marginTop:8}).toString()};var _appConfig$reviewsInf=appConfig.reviewsInfo;_appConfig$reviewsInf=_appConfig$reviewsInf===void 0?{}:_appConfig$reviewsInf;var text=_appConfig$reviewsInf.text,linkText=_appConfig$reviewsInf.linkText,linkUrl=_appConfig$reviewsInf.linkUrl;/**
2
+ * The ReviewsInfo component
3
+ * @param {Object} props The component props
4
+ * @param {Array} [props.reviews] The reviews shown inside the Reviews component
5
+ * @returns {JSX}
6
+ */var ReviewsInfo=function ReviewsInfo(){if(!text){return null;}return React.createElement("div",{className:classNames(styles.root,'engage__reviews__review_info_text')},React.createElement("div",null,text,linkText&&linkUrl&&React.createElement(Link,{href:linkUrl,className:styles.link},linkText)));};export default ReviewsInfo;
@@ -0,0 +1,6 @@
1
+ import{connect}from'react-redux';import{getProductReviewsExcerpt}from'@shopgate/pwa-common-commerce/reviews/selectors';import{makeIsBaseProductActive}from'@shopgate/engage/product';/**
2
+ * Maps the contents of the state to the component props.
3
+ * @param {Object} state The current application state.
4
+ * @param {Object} props The component props.
5
+ * @return {Object} The extended component props.
6
+ */var makeMapStateToProps=function makeMapStateToProps(){var isBaseProductActive=makeIsBaseProductActive();return function(state,props){return{reviews:getProductReviewsExcerpt(state,props),productActive:isBaseProductActive(state,props)};};};export default connect(makeMapStateToProps);
@@ -0,0 +1,6 @@
1
+ import React from'react';import PropTypes from'prop-types';import appConfig from'@shopgate/pwa-common/helpers/config';import{SurroundPortals}from'@shopgate/engage/components';import{PRODUCT_REVIEWS}from'@shopgate/engage/product';import List from"./components/List";import Header from"./components/Header";import AllReviewsLink from"./components/AllReviewsLink";import ReviewsInfo from"./components/ReviewsInfo";import styles from"./style";import connect from"./connector";/**
2
+ * @param {Object} props The component props.
3
+ * @param {Object} props.productId The id of the product, the review belongs to.
4
+ * @param {Array} props.reviews Reviews which should be shown in the product page.
5
+ * @returns {JSX}
6
+ */function Reviews(_ref){var productId=_ref.productId,productActive=_ref.productActive,reviews=_ref.reviews;return React.createElement(SurroundPortals,{portalName:PRODUCT_REVIEWS,portalProps:{productId:productId}},appConfig.hasReviews&&productActive&&React.createElement("div",{className:"".concat(styles.container," engage__reviews__reviews"),"data-test-id":"reviewSection"},React.createElement(Header,{productId:productId}),React.createElement(List,{productId:productId,reviews:reviews}),React.createElement(AllReviewsLink,{productId:productId}),React.createElement(ReviewsInfo,null)));}Reviews.defaultProps={productId:null,productActive:true,reviews:null};export default connect(Reviews);
@@ -0,0 +1,22 @@
1
+ import{themeConfig as mockedConfig}from'@shopgate/pwa-common/helpers/config/mock';var mockedProduct={productId:'foo',rating:{average:0,count:0}};var mockedProductWithRating={productId:'foo',rating:{average:50,count:4}};/**
2
+ * Creates mocked review object.
3
+ * @param {string|number} id Anything that can be an id.
4
+ * @return {Object}
5
+ */export var mockReview=function mockReview(id){return{id:id,author:'',date:'2017-09-06T12:38:51.000Z',rate:100,title:'',review:'No Name and Title Lorem ipsum dolor sit amet, con… takimata sanctus est Lorem ipsum dolor sit amet.'};};/**
6
+ * Mocked state with 4 reviews.
7
+ * @type {Object}
8
+ */export var mockedStateWithAll={product:{productsById:{foo:{productData:mockedProductWithRating}}},reviews:{reviewsById:{1:mockReview(1),2:mockReview(2),3:mockReview(3),4:mockReview(4)},reviewsByProductId:{foo:{reviews:[1,2,3,4],totalReviewCount:4}}}};/**
9
+ * Similar to mockedStateWithAll, but contains only two reviews.
10
+ * @type {Object}
11
+ */export var mockedStateWithTwoReviews=function(){// Must do deep clone here.
12
+ var mockedState=JSON.parse(JSON.stringify(mockedStateWithAll));mockedState.reviews.reviewsByProductId.foo.reviews=mockedState.reviews.reviewsByProductId.foo.reviews.slice(0,2);mockedState.reviews.reviewsByProductId.foo.totalReviewCount=2;return mockedState;}();/**
13
+ * Mocked state with product only. Reviews not fetched.
14
+ * @type {Object}
15
+ */export var mockedStateWithoutReview={product:{productsById:{foo:{productData:mockedProduct}}},reviews:{reviewsById:{},reviewsByProductId:{}}};/**
16
+ * Mocked state without data.
17
+ * @type {{product: {productsById: {}}}}
18
+ */export var mockedStateProductEmpty={product:{productsById:{}}};/**
19
+ * Sets up mocks.
20
+ * @param {bool} mockReviewsAvailable A feature flag "hasReviews" value.
21
+ * @type {Function}
22
+ */export var setMocks=function setMocks(){var mockReviewsAvailable=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;jest.doMock('@shopgate/pwa-common/helpers/config',function(){return{get hasReviews(){return mockReviewsAvailable;},get showWriteReview(){return true;},themeConfig:mockedConfig};});};
@@ -0,0 +1,7 @@
1
+ import React from'react';import{Provider}from'react-redux';import configureStore from'redux-mock-store';import{mount}from'enzyme';import mockRenderOptions from'@shopgate/pwa-common/helpers/mocks/mockRenderOptions';import{mockedStateWithAll,mockedStateWithoutReview,mockedStateWithTwoReviews,setMocks}from'@shopgate/pwa-common-commerce/reviews/mock';var mockedStore=configureStore();/**
2
+ * @returns {JSX}
3
+ */var Header=function Header(){return React.createElement("div",null);};var mock=Header;jest.mock("./components/Header",function(){return mock;});jest.mock('@shopgate/engage/product',function(){return{PRODUCT_REVIEWS:'product.reviews',makeIsBaseProductActive:jest.fn(function(){return function(){return true;};})};});jest.mock('@shopgate/engage/components');beforeEach(function(){jest.resetModules();});/**
4
+ * Creates component with provided store state.
5
+ * @param {Object} mockedState Mocked stage.
6
+ * @return {ReactWrapper}
7
+ */var createComponent=function createComponent(mockedState){/* eslint-disable global-require */var Reviews=require("./index")["default"];/* eslint-enable global-require */return mount(React.createElement(Provider,{store:mockedStore(mockedState)},React.createElement(Reviews,{productId:"foo"})),mockRenderOptions);};describe('<Reviews />',function(){var component=null;it('should render when no reviews and rating given',function(){setMocks();component=createComponent(mockedStateWithoutReview);expect(component).toMatchSnapshot();expect(component.find('Header').exists()).toBe(true);expect(component.find('List').exists()).toBe(true);expect(component.find('AllReviewsLink').exists()).toBe(true);});it('should render reviews, header and all reviews link',function(){setMocks();component=createComponent(mockedStateWithAll);expect(component).toMatchSnapshot();expect(component.find('Header').exists()).toBe(true);expect(component.find('List').exists()).toBe(true);expect(component.find('AllReviewsLink').find('div').exists()).toBe(true);});it('should render reviews, header, but no all reviews link',function(){setMocks();component=createComponent(mockedStateWithTwoReviews);expect(component).toMatchSnapshot();expect(component.find('Header').exists()).toBe(true);expect(component.find('List').exists()).toBe(true);expect(component.find('AllReviewsLink').find('div').exists()).toBe(false);});it('should not render when feature flag is off',function(){setMocks(false);component=createComponent(mockedStateWithAll);expect(component).toMatchSnapshot();expect(component.find('Header').exists()).toBe(false);expect(component.find('List').exists()).toBe(false);expect(component.find('AllReviewsLink').exists()).toBe(false);});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables;var container=css({marginBottom:variables.gap.small});export default{container:container};
package/reviews/index.js CHANGED
@@ -3,4 +3,5 @@ export{default as fetchProductReviews}from'@shopgate/pwa-common-commerce/reviews
3
3
  export*from'@shopgate/pwa-common-commerce/reviews/constants/index';export*from'@shopgate/pwa-common-commerce/reviews/constants/Pipelines';export*from'@shopgate/pwa-common-commerce/reviews/constants/Portals';// SELECTORS
4
4
  export*from'@shopgate/pwa-common-commerce/reviews/selectors';// STREAMS
5
5
  export*from'@shopgate/pwa-common-commerce/reviews/streams';// MOCKS
6
- export*from'@shopgate/pwa-common-commerce/reviews/mock';
6
+ export*from'@shopgate/pwa-common-commerce/reviews/mock';// COMPONENTS
7
+ export{default as Reviews}from"./components/Reviews";