@shopgate/engage 7.12.7-beta.1 → 7.12.7-beta.3

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 (32) hide show
  1. package/favorites/components/Item/Item.js +3 -3
  2. package/filter/components/FilterPageContent/components/ApplyButton/index.js +7 -0
  3. package/filter/components/FilterPageContent/components/ApplyButton/spec.js +1 -0
  4. package/filter/components/FilterPageContent/components/ApplyButton/style.js +1 -0
  5. package/filter/components/FilterPageContent/components/ResetButton/index.js +7 -0
  6. package/filter/components/FilterPageContent/components/ResetButton/spec.js +1 -0
  7. package/filter/components/FilterPageContent/components/ResetButton/style.js +1 -0
  8. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.js +7 -0
  9. package/filter/components/FilterPageContent/components/Selector/components/Selected/spec.js +1 -0
  10. package/filter/components/FilterPageContent/components/Selector/components/Selected/style.js +1 -0
  11. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.js +7 -0
  12. package/filter/components/FilterPageContent/components/Selector/components/Toggle/spec.js +1 -0
  13. package/filter/components/FilterPageContent/components/Selector/components/Toggle/style.js +1 -0
  14. package/filter/components/FilterPageContent/components/Selector/components/ValueButton/index.js +7 -0
  15. package/filter/components/FilterPageContent/components/Selector/components/ValueButton/spec.js +1 -0
  16. package/filter/components/FilterPageContent/components/Selector/components/ValueButton/style.js +2 -0
  17. package/filter/components/FilterPageContent/components/Selector/index.js +12 -0
  18. package/filter/components/FilterPageContent/components/Selector/spec.js +1 -0
  19. package/filter/components/FilterPageContent/components/Selector/style.js +1 -0
  20. package/filter/components/FilterPageContent/index.js +6 -0
  21. package/filter/components/FilterPageContentWithProvider/index.js +13 -0
  22. package/filter/components/PriceSlider/components/Label/index.js +1 -1
  23. package/filter/components/PriceSlider/index.js +1 -1
  24. package/filter/constants/index.js +1 -1
  25. package/filter/helpers/index.js +1 -0
  26. package/filter/hooks/filterPage.js +5 -0
  27. package/filter/hooks/index.js +1 -1
  28. package/filter/index.js +2 -3
  29. package/filter/providers/FilterPageProvider.context.js +54 -0
  30. package/filter/providers/FilterPageProvider.js +98 -0
  31. package/filter/providers/index.js +1 -1
  32. package/package.json +7 -7
@@ -5,10 +5,10 @@ var _css;function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableTo
5
5
  * @returns {Object}
6
6
  */var mapDispatchToProps=function mapDispatchToProps(dispatch){return{showModal:function showModal(){return dispatch(showModalAction.apply(void 0,arguments));},historyPush:function historyPush(){return dispatch(historyPushAction.apply(void 0,arguments));},updateFavoriteItem:function updateFavoriteItem(productId,listId,quantity,notes){dispatch(updateFavorite(productId,listId,quantity,notes));},openCommentDialog:function openCommentDialog(productId,listId){return dispatch(openFavoritesCommentDialog(productId,listId));}};};var styles={root:css({display:'flex',position:'relative','&:not(:last-child)':{marginBottom:16}}).toString(),imageContainer:css((_css={flex:0.4,marginRight:18},_defineProperty(_css,responsiveMediaQuery('>=xs',{appAlways:true}),{maxWidth:120,minWidth:80}),_defineProperty(_css,responsiveMediaQuery('>=md',{webOnly:true}),{maxWidth:120,minWidth:80}),_defineProperty(_css,responsiveMediaQuery('>=md',{webOnly:true}),{width:120,flex:'none'}),_css)).toString(),infoContainer:css({flex:1,display:'flex',flexDirection:'column',flexWrap:'wrap',gap:8}).toString(),infoContainerRow:css({flexDirection:'row',display:'flex',justifyContent:'space-between'}).toString(),quantityContainer:css({flexDirection:'row',display:'flex',alignItems:'center',flexWrap:'wrap',gap:16}).toString(),priceContainer:css({minWidth:100}).toString(),priceInfo:css({wordBreak:'break-word',fontSize:'0.875rem',lineHeight:'0.875rem',color:'var(--color-text-low-emphasis)',padding:"".concat(variables.gap.xsmall,"px 0")}).toString(),titleWrapper:css({display:'flex',flexDirection:'column',gap:8}).toString(),titleContainer:css({marginRight:10,flex:1}).toString(),title:css({fontSize:17,fontWeight:600}).toString(),removeContainer:css({display:'flex',flexShrink:0,alignItems:'flex-start'})};/**
7
7
  * Favorite Item component
8
- * @return {JSX}
9
- */var FavoriteItem=function FavoriteItem(_ref){var _product$price,_product$price2,_product$price3;var listId=_ref.listId,product=_ref.product,notes=_ref.notes,quantity=_ref.quantity,remove=_ref.remove,addToCart=_ref.addToCart,isBaseProduct=_ref.isBaseProduct,isOrderable=_ref.isOrderable,isRopeProductOrderable=_ref.isRopeProductOrderable,hasVariants=_ref.hasVariants,showModal=_ref.showModal,historyPush=_ref.historyPush,updateFavoriteItem=_ref.updateFavoriteItem,openCommentDialog=_ref.openCommentDialog;var _ref2=getThemeSettings('AppImages')||{},gridResolutions=_ref2.ListImage;var _useState=useState(!isOrderable&&!hasVariants),_useState2=_slicedToArray(_useState,2),isDisabled=_useState2[0],setIsDisabled=_useState2[1];var currency=((_product$price=product.price)===null||_product$price===void 0?void 0:_product$price.currency)||'EUR';var defaultPrice=((_product$price2=product.price)===null||_product$price2===void 0?void 0:_product$price2.unitPrice)||0;var specialPrice=(_product$price3=product.price)===null||_product$price3===void 0?void 0:_product$price3.unitPriceStriked;var hasStrikePrice=typeof specialPrice==='number'&&specialPrice>=defaultPrice;var characteristics=(product===null||product===void 0?void 0:product.characteristics)||[];var productLink="".concat(ITEM_PATH,"/").concat(bin2hex(product.id));var notesButtonRef=useRef();var _useState3=useState(quantity),_useState4=_slicedToArray(_useState3,2),internalQuantity=_useState4[0],setInternalQuantity=_useState4[1];useEffect(function(){setInternalQuantity(quantity);},[quantity]);useLayoutEffect(function(){setIsDisabled(!isOrderable&&!hasVariants);},[hasVariants,isOrderable]);var handleOpenComment=useCallback(function(e){e.preventDefault();e.stopPropagation();openCommentDialog(product.id,listId);},[listId,openCommentDialog,product.id]);var handleAddToCart=useCallback(function(e){e.preventDefault();e.stopPropagation();if(isBaseProduct&&hasVariants){// Called for a parent product. User needs to confirm the navigation to the PDP
8
+ * @return {JSX.Element}
9
+ */var FavoriteItem=function FavoriteItem(_ref){var _product$price,_product$price2,_product$price3;var listId=_ref.listId,product=_ref.product,notes=_ref.notes,quantity=_ref.quantity,remove=_ref.remove,addToCart=_ref.addToCart,isBaseProduct=_ref.isBaseProduct,isOrderable=_ref.isOrderable,isRopeProductOrderable=_ref.isRopeProductOrderable,hasVariants=_ref.hasVariants,showModal=_ref.showModal,historyPush=_ref.historyPush,updateFavoriteItem=_ref.updateFavoriteItem,openCommentDialog=_ref.openCommentDialog;var _ref2=getThemeSettings('AppImages')||{},gridResolutions=_ref2.ListImage;var _useState=useState(!isOrderable&&!hasVariants),_useState2=_slicedToArray(_useState,2),isDisabled=_useState2[0],setIsDisabled=_useState2[1];var currency=((_product$price=product.price)===null||_product$price===void 0?void 0:_product$price.currency)||'EUR';var defaultPrice=((_product$price2=product.price)===null||_product$price2===void 0?void 0:_product$price2.unitPrice)||0;var specialPrice=(_product$price3=product.price)===null||_product$price3===void 0?void 0:_product$price3.unitPriceStriked;var hasStrikePrice=typeof specialPrice==='number'&&specialPrice>defaultPrice;var characteristics=(product===null||product===void 0?void 0:product.characteristics)||[];var productLink="".concat(ITEM_PATH,"/").concat(bin2hex(product.id));var notesButtonRef=useRef();var _useState3=useState(quantity),_useState4=_slicedToArray(_useState3,2),internalQuantity=_useState4[0],setInternalQuantity=_useState4[1];useEffect(function(){setInternalQuantity(quantity);},[quantity]);useLayoutEffect(function(){setIsDisabled(!isOrderable&&!hasVariants);},[hasVariants,isOrderable]);var handleOpenComment=useCallback(function(e){e.preventDefault();e.stopPropagation();openCommentDialog(product.id,listId);},[listId,openCommentDialog,product.id]);var handleAddToCart=useCallback(function(e){e.preventDefault();e.stopPropagation();if(isBaseProduct&&hasVariants){// Called for a parent product. User needs to confirm the navigation to the PDP
10
10
  showModal({title:null,type:MODAL_VARIANT_SELECT,message:'favorites.modal.message',confirm:'favorites.modal.confirm',dismiss:'common.cancel',params:{productId:product.id}});return false;}if(!isRopeProductOrderable){// Product is not orderable for ROPE. So users need to do some corrections. Just redirect.
11
11
  historyPush({pathname:productLink});return false;}broadcastLiveMessage('product.adding_item',{params:{count:1}});return addToCart(e);},[addToCart,hasVariants,historyPush,isBaseProduct,isRopeProductOrderable,product.id,productLink,showModal]);var commonPortalProps=useMemo(function(){var availability=product.availability,id=product.id,name=product.name;return{availability:availability,characteristics:characteristics,id:id,name:name,price:defaultPrice,listId:listId};},[characteristics,defaultPrice,listId,product]);var ctaPortalProps=useMemo(function(){return{isLoading:false,noShadow:false,listId:listId,isBaseProduct:isBaseProduct,isDisabled:isDisabled,productId:product.id,handleRemoveFromCart:remove,handleAddToCart:handleAddToCart};},[handleAddToCart,isBaseProduct,isDisabled,listId,product.id,remove]);var handleChangeQuantity=useCallback(function(newQuantity){// Do nothing when quantity didn't change
12
12
  if(newQuantity===quantity)return;updateFavoriteItem(product.id,listId,newQuantity,notes);},[listId,notes,product.id,quantity,updateFavoriteItem]);var handleDeleteComment=useCallback(function(event){event.preventDefault();event.stopPropagation();updateFavoriteItem(product.id,listId,quantity,'');setTimeout(function(){if(notesButtonRef===null||notesButtonRef===void 0?void 0:notesButtonRef.current){// Focus the add button after item deletion to improve a11y
13
- notesButtonRef.current.focus();}broadcastLiveMessage('favorites.comments.removed');},300);},[listId,product.id,quantity,updateFavoriteItem]);return React.createElement(ProductListEntryProvider,{productId:product.id},React.createElement(SurroundPortals,{portalName:FAVORITES_LIST_ITEM,portalProps:product},React.createElement("div",{className:styles.root},React.createElement(Link,{className:styles.imageContainer,component:"div",href:productLink,"aria-hidden":true},React.createElement(ProductImage,{src:product.featuredImageBaseUrl,resolutions:gridResolutions})),React.createElement("div",{className:styles.infoContainer},React.createElement("div",{className:classNames(styles.infoContainerRow)},React.createElement("div",{className:styles.titleWrapper},React.createElement(SurroundPortals,{portalName:FAVORITES_PRODUCT_NAME,portalProps:commonPortalProps},React.createElement(TextLink,{href:productLink,tag:"span",className:styles.titleContainer},React.createElement("span",{className:styles.title// eslint-disable-next-line react/no-danger
13
+ notesButtonRef.current.focus();}broadcastLiveMessage('favorites.comments.removed');},300);},[listId,product.id,quantity,updateFavoriteItem]);return React.createElement(ProductListEntryProvider,{productId:product.id},React.createElement(SurroundPortals,{portalName:FAVORITES_LIST_ITEM,portalProps:product},React.createElement("div",{className:classNames(styles.root,'engage__favorites__item')},React.createElement(Link,{className:classNames(styles.imageContainer,'engage__favorites__item__image-container'),component:"div",href:productLink,"aria-hidden":true},React.createElement(ProductImage,{className:classNames('engage__favorites__item__image'),src:product.featuredImageBaseUrl,resolutions:gridResolutions})),React.createElement("div",{className:classNames(styles.infoContainer,'engage__favorites__item__info-container')},React.createElement("div",{className:classNames(styles.infoContainerRow)},React.createElement("div",{className:styles.titleWrapper},React.createElement(SurroundPortals,{portalName:FAVORITES_PRODUCT_NAME,portalProps:commonPortalProps},React.createElement(TextLink,{href:productLink,tag:"span",className:classNames(styles.titleContainer,'engage__favorites__item__title-container')},React.createElement("span",{className:styles.title// eslint-disable-next-line react/no-danger
14
14
  ,dangerouslySetInnerHTML:{__html:"".concat(product.name)}})))),React.createElement("div",{className:styles.removeContainer},React.createElement(Remove,{onClick:remove}))),React.createElement(ItemCharacteristics,{characteristics:characteristics}),React.createElement(StockInfoLists,{product:product}),React.createElement("div",{className:styles.infoContainerRow},React.createElement("div",{className:styles.quantityContainer},React.createElement(SurroundPortals,{portalName:FAVORITES_QUANTITY,portalProps:commonPortalProps},React.createElement(ItemQuantity,{quantity:internalQuantity,onChange:handleChangeQuantity})),React.createElement(SurroundPortals,{portalName:FAVORITES_PRODUCT_PRICE,portalProps:commonPortalProps},React.createElement("div",{className:styles.priceContainer},hasStrikePrice?React.createElement(PriceStriked,{value:specialPrice,currency:currency}):null,React.createElement(Price,{currency:currency,discounted:hasStrikePrice,taxDisclaimer:true,unitPrice:defaultPrice}),React.createElement(PriceInfo,{product:product,currency:currency,className:styles.priceInfo})))),React.createElement(SurroundPortals,{portalName:FAVORITES_ADD_TO_CART,portalProps:ctaPortalProps},React.createElement(AddToCart,{onClick:handleAddToCart,isLoading:false,isDisabled:isDisabled,"aria-label":i18n.text('product.add_to_cart')}))),React.createElement(SurroundPortals,{portalName:FAVORITES_NOTES,portalProps:commonPortalProps},React.createElement(ItemNotes,{notes:notes,onClickDeleteComment:handleDeleteComment,onClickOpenComment:handleOpenComment,notesButtonRef:notesButtonRef}))))));};FavoriteItem.defaultProps={isBaseProduct:true,isOrderable:true,isRopeProductOrderable:true,hasVariants:false,notes:undefined,quantity:1};export default connect(makeMapStateToProps,mapDispatchToProps)(FavoriteItem);
@@ -0,0 +1,7 @@
1
+ import React,{memo}from'react';import PropTypes from'prop-types';import{I18n,Button,SurroundPortals}from'@shopgate/engage/components';import{PORTAL_FILTER_APPLY_BUTTON}from'@shopgate/engage/filter/constants';import{withWidgetSettings}from'@shopgate/engage/core';import styles from"./style";/**
2
+ * The filter apply button component.
3
+ * @param {Object} props The component props
4
+ * @param {boolean} props.disabled Whether the button is disabled
5
+ * @param {Function} props.onClick Click handler for the button
6
+ * @returns {JSX.Element}
7
+ */var FilterApplyButton=function FilterApplyButton(_ref){var disabled=_ref.disabled,onClick=_ref.onClick,widgetSettings=_ref.widgetSettings;var buttonTextColor=widgetSettings.buttonTextColor,buttonTextColorDisabled=widgetSettings.buttonTextColorDisabled;var buttonColor=!disabled?buttonTextColor:buttonTextColorDisabled;return React.createElement(SurroundPortals,{portalName:PORTAL_FILTER_APPLY_BUTTON,portalProps:{disabled:disabled,onClick:onClick,widgetSettings:widgetSettings}},React.createElement("div",{className:styles.wrapper},React.createElement(Button,{className:styles.button,flat:true,type:"primary",onClick:onClick,disabled:disabled,testId:"applyFilterButton"},React.createElement(I18n.Text,{string:"filter.apply",style:{color:buttonColor}}))));};FilterApplyButton.defaultProps={disabled:false};export default withWidgetSettings(memo(FilterApplyButton),'@shopgate/engage/components/AppBar');
@@ -0,0 +1 @@
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 React from'react';import{shallow}from'enzyme';import ApplyButton from"./index";var clickMock=jest.fn();jest.mock('@shopgate/engage/components');jest.mock('@shopgate/engage/core',function(){return{withWidgetSettings:function withWidgetSettings(Comp){return function(props){return React.createElement(Comp,_extends({widgetSettings:{}},props));};}};});jest.mock('@shopgate/engage/components',function(){return{SurroundPortals:function SurroundPortals(_ref){var children=_ref.children;return children;},I18n:{Text:function Text(){return'I18n.Text';}},Button:function Button(){return'Button';}};});describe('Filter: <ApplyButton />',function(){it('should render as activated',function(){var wrapper=shallow(React.createElement(ApplyButton,{onClick:function onClick(){}})).dive();expect(wrapper).toMatchSnapshot();});it('should render as deactivated',function(){var wrapper=shallow(React.createElement(ApplyButton,{disabled:true,onClick:function onClick(){}})).dive();expect(wrapper).toMatchSnapshot();});it('should handle clicks',function(){var wrapper=shallow(React.createElement(ApplyButton,{onClick:clickMock})).dive();expect(wrapper).toMatchSnapshot();wrapper.find('Button').simulate('click');expect(clickMock).toHaveBeenCalled();});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';var wrapper=css({display:'flex'});var button=css({padding:'0 !important'}).toString();export default{wrapper:wrapper,button:button};
@@ -0,0 +1,7 @@
1
+ import React,{memo}from'react';import PropTypes from'prop-types';import{I18n,Button,SurroundPortals}from'@shopgate/engage/components';import{PORTAL_FILTER_RESET_BUTTON}from'@shopgate/engage/filter/constants';import styles from"./style";/**
2
+ * The filter reset button component.
3
+ * @param {Object} props The component props.
4
+ * @param {boolean} props.disabled Whether the button is disabled
5
+ * @param {Function} props.onClick Click handler for the button
6
+ * @returns {JSX.Element}
7
+ */var FilterResetButton=function FilterResetButton(_ref){var disabled=_ref.disabled,onClick=_ref.onClick;return React.createElement(SurroundPortals,{portalName:PORTAL_FILTER_RESET_BUTTON,portalProps:{disabled:disabled,onClick:onClick}},React.createElement("div",{className:styles},React.createElement(Button,{flat:true,type:"primary",onClick:onClick,disabled:disabled,testId:"clearAllButton"},React.createElement(I18n.Text,{string:"filter.reset"}))));};FilterResetButton.defaultProps={disabled:false};export default memo(FilterResetButton);
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import ResetButton from"./index";var clickMock=jest.fn();jest.mock('@shopgate/engage/components');describe('Filter: <ResetButton />',function(){it('should render as activated',function(){var wrapper=shallow(React.createElement(ResetButton,{onClick:function onClick(){}}));expect(wrapper).toMatchSnapshot();});it('should render as deactivated',function(){var wrapper=shallow(React.createElement(ResetButton,{disabled:true,onClick:function onClick(){}}));expect(wrapper).toMatchSnapshot();});it('should handle clicks',function(){var wrapper=shallow(React.createElement(ResetButton,{onClick:clickMock}));expect(wrapper).toMatchSnapshot();wrapper.find('Button').simulate('click');expect(clickMock).toHaveBeenCalled();});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export default css({marginTop:4,marginBottom:40,textAlign:'right'});
@@ -0,0 +1,7 @@
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,{Fragment,PureComponent}from'react';import PropTypes from'prop-types';import*as styles from"./style";/**
2
+ * The filter selected component.
3
+ */var Selected=/*#__PURE__*/function(_PureComponent){_inherits(Selected,_PureComponent);function Selected(){_classCallCheck(this,Selected);return _possibleConstructorReturn(this,_getPrototypeOf(Selected).apply(this,arguments));}_createClass(Selected,[{key:"getItems",/**
4
+ * @returns {Array}
5
+ */value:function getItems(){var _this$props=this.props,selected=_this$props.selected,values=_this$props.values;return values.reduce(function(prevValues,value){if(selected.includes(value.id)){prevValues.push(value.label);}return prevValues;},[]);}/**
6
+ * @returns {JSX}
7
+ */},{key:"render",value:function render(){if(!this.props.selected||this.props.selected.length===0){return null;}var items=this.getItems();return React.createElement(Fragment,null,items.map(function(item,index){return React.createElement(Fragment,{key:item},React.createElement("span",{className:styles.elipsed},item),index<items.length-1?React.createElement("span",{className:styles.comma},", "):'');}));}}]);return Selected;}(PureComponent);_defineProperty(Selected,"defaultProps",{selected:null});export default Selected;
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import Selected from"./index";var values=[{id:'foo',label:'fooLabel'},{id:'bar',label:'barLabel'}];describe('Filter: <Selected />',function(){it('should not render without selected',function(){var wrapper=shallow(React.createElement(Selected,{values:values}));expect(wrapper).toMatchSnapshot();});it('should render with selected',function(){var wrapper=shallow(React.createElement(Selected,{values:values,selected:['foo']}));expect(wrapper).toMatchSnapshot();});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export var item=css({whiteSpace:'nowrap',flexShrink:0,flexGrow:0,alignSelf:'flex-end'});export var elipsed=css({maxWidth:'95%',overflow:'hidden',textAlign:'right',textOverflow:'ellipsis',whiteSpace:'nowrap'});export var comma=css({' + span':{marginLeft:'0.65ch'}});
@@ -0,0 +1,7 @@
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 classNames from'classnames';import*as styles from"./style";/**
2
+ * The toggle component.
3
+ */var Toggle=/*#__PURE__*/function(_PureComponent){_inherits(Toggle,_PureComponent);function Toggle(){_classCallCheck(this,Toggle);return _possibleConstructorReturn(this,_getPrototypeOf(Toggle).apply(this,arguments));}_createClass(Toggle,[{key:"render",/**
4
+ * @returns {JSX}
5
+ */value:function render(){var _this$props=this.props,label=_this$props.label,selected=_this$props.selected;return React.createElement("div",{className:styles.toggle},React.createElement("span",{className:this.className},label),selected&&React.createElement("span",{className:styles.selected},selected));}},{key:"className",/**
6
+ * @returns {string}
7
+ */get:function get(){var _classNames;var open=this.props.open;return classNames((_classNames={},_defineProperty(_classNames,styles.label,true),_defineProperty(_classNames,styles.open,open),_defineProperty(_classNames,styles.closed,!open),_classNames));}}]);return Toggle;}(PureComponent);_defineProperty(Toggle,"defaultProps",{open:false,selected:null});export default Toggle;
@@ -0,0 +1 @@
1
+ import React from'react';import{render}from'enzyme';import Toggle from"./index";describe('<Toggle />',function(){it('should render without selected',function(){var wrapper=render(React.createElement(Toggle,{label:"somelabel"}));expect(wrapper).toMatchSnapshot();});it('should render without selected as open',function(){var wrapper=render(React.createElement(Toggle,{label:"somelabel",open:true}));expect(wrapper).toMatchSnapshot();});it('should render with selected',function(){var wrapper=render(React.createElement(Toggle,{label:"somelabel",selected:"Some, Thing, Selected"}));expect(wrapper).toMatchSnapshot();});it('should render with selected as open',function(){var wrapper=render(React.createElement(Toggle,{label:"somelabel",selected:"Some, Thing, Selected",open:true}));expect(wrapper).toMatchSnapshot();});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export var toggle=css({display:'flex',flexFlow:'row no-wrap',alignContent:'stretch',alignItems:'flex-start'});export var label=css({whiteSpace:'no-wrap',flexShrink:0,flexGrow:1,textAlign:'left',maxWidth:'50%',minWidth:'35%',paddingRight:'16px'});export var selected=css({display:'flex',flexFlow:'row wrap',flexGrow:1,justifyContent:'flex-end',minWidth:'50%',maxWidth:'65%'});export var closed=css({fontWeight:'normal'});export var open=css({fontWeight:'bold'});
@@ -0,0 +1,7 @@
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 classNames from'classnames';import*as styles from"./style";/**
2
+ * The value button component.
3
+ */var ValueButton=/*#__PURE__*/function(_PureComponent){_inherits(ValueButton,_PureComponent);function ValueButton(){_classCallCheck(this,ValueButton);return _possibleConstructorReturn(this,_getPrototypeOf(ValueButton).apply(this,arguments));}_createClass(ValueButton,[{key:"render",/**
4
+ * @returns {JSX}
5
+ */value:function render(){var _this$props=this.props,label=_this$props.label,id=_this$props.id,onClick=_this$props.onClick,isActive=_this$props.isActive;return React.createElement("button",{className:this.className,value:id,onClick:onClick,"data-test-id":id,type:"button",role:"checkbox","aria-checked":isActive},label);}},{key:"className",/**
6
+ * @returns {string}
7
+ */get:function get(){var _classNames;var isActive=this.props.isActive;return classNames((_classNames={},_defineProperty(_classNames,styles.inactive,!isActive),_defineProperty(_classNames,styles.active,isActive),_classNames));}}]);return ValueButton;}(PureComponent);_defineProperty(ValueButton,"defaultProps",{id:null,label:null,isActive:false,onClick:function onClick(){}});export default ValueButton;
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import ValueButton from"./index";var onClick=jest.fn();describe('<ValueButton />',function(){it('should render as inactive',function(){var wrapper=shallow(React.createElement(ValueButton,{id:"someid",label:"somelabel"}));expect(wrapper).toMatchSnapshot();});it('should render as active',function(){var wrapper=shallow(React.createElement(ValueButton,{id:"someid",label:"somelabel",isActive:true}));expect(wrapper).toMatchSnapshot();});it('should handle click event',function(){var wrapper=shallow(React.createElement(ValueButton,{id:"someid",label:"somelabel",onClick:onClick}));wrapper.simulate('click');expect(wrapper).toMatchSnapshot();expect(onClick).toHaveBeenCalledTimes(1);});});
@@ -0,0 +1,2 @@
1
+ import{css}from'glamor';import{themeColors}from'@shopgate/pwa-common/helpers/config';export var inactive=css({border:"1px solid ".concat(themeColors.darkGray),borderRadius:2,color:'inherit',height:42,marginLeft:8,marginBottom:8,maxWidth:'100%',minWidth:42,outline:0,overflow:'hidden',padding:'0 8px',textOverflow:'ellipsis',whiteSpace:'nowrap',transition:'color 100ms cubic-bezier(0.25, 0.1, 0.25, 1), border-color 100ms cubic-bezier(0.25, 0.1, 0.25, 1)',willChange:'color, border-color'});export var active=css(inactive,{// Before the custom properties the accent color was used for this class.
2
+ borderColor:"var(--color-primary, ".concat(themeColors.accent,")"),color:"var(--color-primary, ".concat(themeColors.accent,")")});
@@ -0,0 +1,12 @@
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 _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);}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 _getPrototypeOf(o){_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf:function _getPrototypeOf(o){return o.__proto__||Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _assertThisInitialized(self){if(self===void 0){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}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{Accordion,SurroundPortals}from'@shopgate/engage/components';import{i18n}from'@shopgate/engage/core';import{FilterItem}from'@shopgate/engage/filter';import{PORTAL_FILTER_SELECTOR}from'@shopgate/engage/filter/constants';import ValueButton from"./components/ValueButton";import Toggle from"./components/Toggle";import Selected from"./components/Selected";import*as styles from"./style";/**
2
+ * The selector component.
3
+ */var Selector=/*#__PURE__*/function(_PureComponent){_inherits(Selector,_PureComponent);function Selector(){var _getPrototypeOf2;var _this;_classCallCheck(this,Selector);for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++){args[_key]=arguments[_key];}_this=_possibleConstructorReturn(this,(_getPrototypeOf2=_getPrototypeOf(Selector)).call.apply(_getPrototypeOf2,[this].concat(args)));_defineProperty(_assertThisInitialized(_this),"state",{selected:_this.props.selected||[]});_defineProperty(_assertThisInitialized(_this),"handleClick",function(event){var value=event.target.value;var selected=_this.state.selected;var _this$props=_this.props,id=_this$props.id,multi=_this$props.multi,onChange=_this$props.onChange;var newSelected=[].concat(selected,[value]);// If in single select mode, only allow one selected value.
4
+ if(!multi&&selected.length===1){newSelected=[value];}// If the clicked value was already selected, remove it again.
5
+ if(selected.includes(value)){newSelected=selected.filter(function(item){return item!==value;});}// Set it if it wasn't selected already.
6
+ _this.setState({selected:newSelected});onChange(id,newSelected);});_defineProperty(_assertThisInitialized(_this),"handlePortalChange",function(updatedId){_this.handleClick({target:{value:updatedId}});});_defineProperty(_assertThisInitialized(_this),"renderLabel",function(props){var _this$props2=_this.props,label=_this$props2.label,values=_this$props2.values;var selected=_this.state.selected;return React.createElement(Toggle,_extends({},props,{label:label,selected:React.createElement(Selected,{values:values,selected:selected})}));});return _this;}_createClass(Selector,[{key:"UNSAFE_componentWillReceiveProps",/**
7
+ * @param {Object} nextProps The new incoming props.
8
+ */value:function UNSAFE_componentWillReceiveProps(_ref){var selected=_ref.selected;if(selected!==this.state.selected){this.setState({selected:selected});}}/**
9
+ * @param {SyntheticEvent} event The button click event.
10
+ */},{key:"render",/**
11
+ * @returns {JSX}
12
+ */value:function render(){var _this2=this;var _this$props3=this.props,values=_this$props3.values,id=_this$props3.id,label=_this$props3.label,multi=_this$props3.multi;var selected=this.state.selected;return React.createElement(SurroundPortals,{portalName:PORTAL_FILTER_SELECTOR,portalProps:{filter:{id:id,label:label,values:values,isMultiSelect:multi},selectedValueIds:selected,onChange:this.handlePortalChange}},React.createElement(FilterItem,null,React.createElement(Accordion,{renderLabel:this.renderLabel,testId:id,handleLabel:i18n.text('filter.filter_by',{label:label})},React.createElement("div",{className:styles.content},values.map(function(value){return React.createElement(ValueButton,{key:value.id,id:value.id,label:value.label,isActive:selected&&selected.includes(value.id),onClick:_this2.handleClick});})))));}}]);return Selector;}(PureComponent);_defineProperty(Selector,"defaultProps",{multi:false,onChange:function onChange(){},selected:null});export default Selector;
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import Selector from"./index";jest.mock('@shopgate/engage/core',function(){return{hasWebBridge:function hasWebBridge(){return false;},i18n:{text:function text(string){return string;}}};});jest.mock('@shopgate/engage/components',function(){return{Accordion:function Accordion(_ref){var children=_ref.children;return children;}};});jest.mock('@shopgate/engage/filter',function(){return{FilterItem:function FilterItem(_ref2){var children=_ref2.children;return children;}};});var values=[{id:'foo',label:'fooLabel'},{id:'bar',label:'barLabel'}];describe('Filter: <Selector />',function(){it('should render with minimum props',function(){var wrapper=shallow(React.createElement(Selector,{id:"foo",label:"bar",values:values}));expect(wrapper).toMatchSnapshot();});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export var content=css({marginLeft:-8,marginBottom:-8});
@@ -0,0 +1,6 @@
1
+ import React,{Fragment}from'react';import PropTypes from'prop-types';import{SurroundPortals,ResponsiveContainer}from'@shopgate/engage/components';import{useFilterPage}from'@shopgate/engage/filter/hooks';import{PORTAL_FILTER_PRICE_RANGE,PORTAL_FILTER_PAGE_CONTENT,FILTER_TYPE_RANGE,FILTER_TYPE_MULTISELECT,PriceSlider}from'@shopgate/engage/filter';import Selector from"./components/Selector";import ApplyButton from"./components/ApplyButton";import ResetButton from"./components/ResetButton";/**
2
+ * The FilterPageContent component renders all filters for the filter page.
3
+ * @param {Object} props The component props.
4
+ * @param {React.ComponentType} props.AppBarComponent The component to be rendered as the app bar
5
+ * @returns {JSX.Element}
6
+ */var FilterPageContent=function FilterPageContent(_ref){var AppBarComponent=_ref.AppBarComponent;var _useFilterPage=useFilterPage(),apiFilters=_useFilterPage.apiFilters,resetPossible=_useFilterPage.resetPossible,hasChanged=_useFilterPage.hasChanged,applyFilters=_useFilterPage.applyFilters,resetAllFilters=_useFilterPage.resetAllFilters,getSelectedFilterValues=_useFilterPage.getSelectedFilterValues,updateSelectedFilterValues=_useFilterPage.updateSelectedFilterValues;return React.createElement(SurroundPortals,{portalName:PORTAL_FILTER_PAGE_CONTENT},AppBarComponent&&React.createElement(AppBarComponent,{title:"titles.filter",right:React.createElement(ApplyButton,{disabled:!hasChanged,onClick:applyFilters})}),apiFilters.map(function(filter){var portalProps={filter:filter};var value=getSelectedFilterValues(filter.id);if(filter.type===FILTER_TYPE_RANGE){return React.createElement(Fragment,{key:filter.id},React.createElement(SurroundPortals,{portalName:PORTAL_FILTER_PRICE_RANGE,portalProps:portalProps},React.createElement(PriceSlider,{id:filter.id,key:filter.id,min:filter.minimum,max:filter.maximum,onChange:updateSelectedFilterValues,value:value})));}return React.createElement(Selector,{id:filter.id,key:filter.id,label:filter.label,values:filter.values,multi:filter.type===FILTER_TYPE_MULTISELECT,onChange:updateSelectedFilterValues,selected:value});}),React.createElement(ResponsiveContainer,{breakpoint:"<sm",appAlways:true},React.createElement(ResetButton,{disabled:!resetPossible,onClick:resetAllFilters})));};FilterPageContent.defaultProps={AppBarComponent:null};export default FilterPageContent;
@@ -0,0 +1,13 @@
1
+ import React from'react';import PropTypes from'prop-types';import{FilterPageProvider}from"../../providers";// eslint-disable-next-line no-unused-vars, import/named
2
+ import{RouteFilters}from"../../providers/FilterPageProvider.context";import Content from"../FilterPageContent";/**
3
+ * The FilterPageContent component
4
+ * @param {Object} props The component props
5
+ * @param {RouteFilters} [props.activeFilters] Object with the active filters for a filtered product
6
+ * list
7
+ * @param {string} [props.parentRouteId] Id of the route with the product list that's supposed to be
8
+ * filtered
9
+ * @param {string} [props.categoryId] A category to be used for filter selection from Redux
10
+ * @param {string} [props.searchPhrase] A search phrase to be used for filter selection from Redux
11
+ * @param {React.ComponentType} [props.AppBarComponent] The component to be rendered as the app bar
12
+ * @returns {JSX.Element}
13
+ */var FilterPageContentWithProvider=function FilterPageContentWithProvider(_ref){var activeFilters=_ref.activeFilters,categoryId=_ref.categoryId,searchPhrase=_ref.searchPhrase,parentRouteId=_ref.parentRouteId,AppBarComponent=_ref.AppBarComponent;return React.createElement(FilterPageProvider,{activeFilters:activeFilters,categoryId:categoryId,searchPhrase:searchPhrase,parentRouteId:parentRouteId},React.createElement(Content,{AppBarComponent:AppBarComponent}));};FilterPageContentWithProvider.defaultProps={activeFilters:null,categoryId:null,searchPhrase:null,parentRouteId:null,AppBarComponent:null};export default FilterPageContentWithProvider;
@@ -1,7 +1,7 @@
1
1
  function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import React,{memo,useState,useEffect,useRef}from'react';import PropTypes from'prop-types';import appConfig from'@shopgate/pwa-common/helpers/config';import{I18n}from'@shopgate/engage/components';import{i18n}from'@shopgate/engage/core';import styles from"../../style";var currency=appConfig.currency;/**
2
2
  * The filter price range slider label component.
3
3
  * @param {Object} props The component props.
4
- * @returns {JSX}
4
+ * @returns {JSX.Element}
5
5
  */function Label(props){var priceLength=props.priceLength,priceMax=props.priceMax,priceMin=props.priceMin,onChange=props.onChange;var _useState=useState(priceMin),_useState2=_slicedToArray(_useState,2),minValue=_useState2[0],setMinValue=_useState2[1];var _useState3=useState(priceMax),_useState4=_slicedToArray(_useState3,2),maxValue=_useState4[0],setMaxValue=_useState4[1];var _useState5=useState(0),_useState6=_slicedToArray(_useState5,2),minOffset=_useState6[0],setMinOffset=_useState6[1];var _useState7=useState(0),_useState8=_slicedToArray(_useState7,2),maxOffset=_useState8[0],setMMaxOffset=_useState8[1];var minRef=useRef(null);var maxRef=useRef(null);// Set new values, when prices change from outside.
6
6
  useEffect(function(){setMinValue(priceMin);setMaxValue(priceMax);},[priceMin,priceMax]);// Store the leftOffset when the reference changes.
7
7
  useEffect(function(){setMinOffset(minRef.current.offsetLeft);setMMaxOffset(maxRef.current.offsetLeft);},[minRef,maxRef]);/**
@@ -3,7 +3,7 @@ function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="s
3
3
  */var PriceSlider=/*#__PURE__*/function(_PureComponent){_inherits(PriceSlider,_PureComponent);/**
4
4
  * The constructor.
5
5
  * @param {Object} props The component props.
6
- */function PriceSlider(props){var _this;_classCallCheck(this,PriceSlider);_this=_possibleConstructorReturn(this,_getPrototypeOf(PriceSlider).call(this,props));_defineProperty(_assertThisInitialized(_this),"onChange",function(value){var roundedValue=[Math.floor(value[0]),Math.ceil(value[1])];_this.setState({value:value});_this.props.onChange(_this.props.id,roundedValue);});var initialValue=props.value||[props.min,props.max];_this.state={value:initialValue};return _this;}/**
6
+ */function PriceSlider(props){var _this;_classCallCheck(this,PriceSlider);_this=_possibleConstructorReturn(this,_getPrototypeOf(PriceSlider).call(this,props));_defineProperty(_assertThisInitialized(_this),"onChange",function(value){var roundedValue=[Math.floor(value[0]),Math.ceil(value[1])];_this.setState({value:value});_this.props.onChange(_this.props.id,roundedValue);});var initialValue=[props.min,props.max];if(Array.isArray(props.value)&&props.value.length>0){initialValue=props.value;}_this.state={value:initialValue};return _this;}/**
7
7
  * Updates the value state.
8
8
  * @param {Object} nextProps The next component props.
9
9
  */_createClass(PriceSlider,[{key:"UNSAFE_componentWillReceiveProps",value:function UNSAFE_componentWillReceiveProps(nextProps){if(!isEqual(nextProps.value,this.props.value)){this.setState({value:nextProps.value});}}/**
@@ -1 +1 @@
1
- export{SORT_ORDER_RELEVANCE,SORT_ORDER_PRICE_ASC,SORT_ORDER_PRICE_DESC,SORT_ORDER_NAME_ASC,SORT_ORDER_NAME_DESC,SORT_ORDER_RANK_ASC,SORT_ORDER_RANK_DESC,SORT_SCOPE_CATEGORY,SORT_SCOPE_SEARCH}from"./sort";
1
+ export*from'@shopgate/pwa-common-commerce/filter/constants/index';export*from'@shopgate/pwa-common-commerce/filter/constants/Pipelines';export*from'@shopgate/pwa-common-commerce/filter/constants/Portals';export{SORT_ORDER_RELEVANCE,SORT_ORDER_PRICE_ASC,SORT_ORDER_PRICE_DESC,SORT_ORDER_NAME_ASC,SORT_ORDER_NAME_DESC,SORT_ORDER_RANK_ASC,SORT_ORDER_RANK_DESC,SORT_SCOPE_CATEGORY,SORT_SCOPE_SEARCH}from"./sort";
@@ -0,0 +1 @@
1
+ export{default as buildInitialFilters}from"./buildInitialFilters";export{default as buildUpdatedFilters}from"./buildUpdatedFilters";
@@ -0,0 +1,5 @@
1
+ import{useContext}from'react';import FilterPageProvider from"../providers/FilterPageProvider.context";// Adding a return type would break type inference
2
+ // eslint-disable-next-line valid-jsdoc
3
+ /**
4
+ * Returns the value of the filter page provider state.
5
+ */export var useFilterPage=function useFilterPage(){return useContext(FilterPageProvider);};
@@ -1,4 +1,4 @@
1
1
  import{useContext}from'react';import SortProvider from"../providers/SortProvider.context";/**
2
2
  * Returns the value of the sort provider state.
3
3
  * @returns {Object}
4
- */export var useSort=function useSort(){return useContext(SortProvider);};
4
+ */export var useSort=function useSort(){return useContext(SortProvider);};export*from"./filterPage";
package/filter/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  /** @module filter */ // ACTIONS
2
- export{default as fetchFilters}from'@shopgate/pwa-common-commerce/filter/actions/fetchFilters';// CONSTANTS
3
- export*from'@shopgate/pwa-common-commerce/filter/constants/index';export*from'@shopgate/pwa-common-commerce/filter/constants/Pipelines';export*from'@shopgate/pwa-common-commerce/filter/constants/Portals';// SELECTORS
2
+ export{default as fetchFilters}from'@shopgate/pwa-common-commerce/filter/actions/fetchFilters';export*from"./constants";// SELECTORS
4
3
  export*from'@shopgate/pwa-common-commerce/filter/selectors';// STREAMS
5
4
  export*from'@shopgate/pwa-common-commerce/filter/streams';// COMPONENTS
6
5
  export{default as FilterItem}from"./components/FilterItem";export{default as PriceSlider}from"./components/PriceSlider";// HELPERS
7
- export{default as buildInitialFilters}from"./helpers/buildInitialFilters";export{default as buildUpdatedFilters}from"./helpers/buildUpdatedFilters";export{SORT_ORDER_RELEVANCE,SORT_ORDER_PRICE_ASC,SORT_ORDER_PRICE_DESC,SORT_ORDER_NAME_ASC,SORT_ORDER_NAME_DESC,SORT_ORDER_RANK_ASC,SORT_ORDER_RANK_DESC,SORT_SCOPE_CATEGORY,SORT_SCOPE_SEARCH}from"./constants";export{makeExtendedSortOptionsSupported,makeGetDefaultSortOrder}from"./selectors";export{SortProvider}from"./providers";export{withSort}from"./hocs";export{useSort}from"./hooks";
6
+ export{default as buildInitialFilters}from"./helpers/buildInitialFilters";export{default as buildUpdatedFilters}from"./helpers/buildUpdatedFilters";export{makeExtendedSortOptionsSupported,makeGetDefaultSortOrder}from"./selectors";export{SortProvider}from"./providers";export{withSort}from"./hocs";export{useSort}from"./hooks";
@@ -0,0 +1,54 @@
1
+ import{createContext}from'react';import noop from'lodash/noop';/**
2
+ * @typedef {Object} APIFilterValue
3
+ * @property {string} id Filter value id
4
+ * @property {string} label Filter value label
5
+ * @property {number} hits Number of hits for the filter value
6
+ */export{};/**
7
+ * @typedef {Object} APIFilter
8
+ * @property {string} id Filter id
9
+ * @property {string} label Filter label
10
+ * @property {"range"|"multiselect"|"single_select"} type Filter type
11
+ * @property {string} [source] Filter source
12
+ * @property {number} [minimum] Minimum value for a range filter
13
+ * @property {number} [maximum] Maximum value for a range filter
14
+ * @property {APIFilterValue[]} values
15
+ */export{};/**
16
+ * @typedef {Object} RouteFilterValue
17
+ * @property {string} id Filter value id
18
+ * @property {string} label Filter value label
19
+ */ /**
20
+ * @typedef {Object} RouteFilter
21
+ * @property {string} id Filter id
22
+ * @property {string} label Filter label
23
+ * @property {string} source Filter source
24
+ * @property {"range"|"multiselect"|"single_select"} type Filter type
25
+ * @property {RouteFilterValue[]} values Selected values for the filter
26
+ */ /**
27
+ * @typedef {Object.<string, RouteFilter>} RouteFilters
28
+ * Object with the active filters for a route with filtered product list
29
+ */export{};/**
30
+ * @callback GetSelectedFilterValuesFn
31
+ * @param {string} filterId The id of the filter
32
+ */ /**
33
+ * @callback UpdateSelectedFilterValuesFn
34
+ * @param {string} filterId The id of the filter to be updated
35
+ * @param {string[]} selectedValues The updated selected values
36
+ * @returns {void}
37
+ */ /**
38
+ * @typedef {Object} FilterPageContext
39
+ * @property {boolean} hasChanged Whether the filter selection has changed since the filters page
40
+ * was opened
41
+ * @property {boolean} resetPossible Whether a reset of the active filters is possible
42
+ * @property {APIFilter[]} apiFilters List of available filters from the API
43
+ * @property {RouteFilters} filters Object that represents the current state of all filters
44
+ * @property {function():void} resetAllFilters Resets all filters which have been changed by the
45
+ * user
46
+ * @property {function():void} resetChangedFilters Resets all filters which have been changed by the
47
+ * user since the filters page was opened
48
+ * @property {function():void} applyFilters Applies the current filter selection to the parent route
49
+ * with a product list to be filtered
50
+ * @property {GetSelectedFilterValuesFn} getSelectedFilterValues Retrieves a list of currently
51
+ * selected values for a filter
52
+ * @property {UpdateSelectedFilterValuesFn} updateSelectedFilterValues Updates the selection for a
53
+ * filter
54
+ */ /** @type {import('react').Context<FilterPageContext>} */var context=createContext({hasChanged:false,resetPossible:false,apiFilters:[],filters:{},resetAllFilters:noop,resetChangedFilters:noop,applyFilters:noop,getSelectedFilterValues:noop,updateSelectedFilterValues:noop});export default context;
@@ -0,0 +1,98 @@
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 _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}function _toPropertyKey(arg){var key=_toPrimitive(arg,"string");return _typeof(key)==="symbol"?key:String(key);}function _toPrimitive(input,hint){if(_typeof(input)!=="object"||input===null)return input;var prim=input[Symbol.toPrimitive];if(prim!==undefined){var res=prim.call(input,hint||"default");if(_typeof(res)!=="object")return res;throw new TypeError("@@toPrimitive must return a primitive value.");}return(hint==="string"?String:Number)(input);}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;}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);}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import React,{useMemo,useState,useEffect,useCallback}from'react';import PropTypes from'prop-types';import{connect}from'react-redux';import debounce from'lodash/debounce';import isEqual from'lodash/isEqual';import{router}from'@shopgate/engage/core';import{getFiltersByHash}from'@shopgate/engage/filter';// eslint-disable-next-line no-unused-vars, import/named
2
+ import Context,{APIFilter,RouteFilters}from"./FilterPageProvider.context";import{buildInitialFilters,buildUpdatedFilters}from"../helpers";/**
3
+ * @param {Object} state The application state.
4
+ * @param {Object} props The component props.
5
+ * @returns {Object}
6
+ */var mapStateToProps=function mapStateToProps(state,props){return{filters:getFiltersByHash(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.filters&&next.filters||!isEqual(prev.filters,next.filters)){return false;}return true;};/**
11
+ * The FilterPageProvider component provides all relevant data and callbacks to represent and modify
12
+ * the current state of the "filter" page.
13
+ * @param {Object} props Provider props
14
+ * @param {APIFilter[]} props.filters Array of available filters
15
+ * @param {RouteFilters} props.activeFilters Object with the active filters for a filtered product
16
+ * list
17
+ * @param {string} props.parentRouteId Id of the route with the product list that's supposed to be
18
+ * filtered
19
+ * @param {Function} [props.onApply] Callback invoked when users pressed the apply button
20
+ * @param {string} [props.categoryId] A category to be used for filter selection from Redux
21
+ * @param {string} [props.searchPhrase] A search phrase to be used for filter selection from Redux
22
+ * @param {NodeList} children Provider children
23
+ * @returns {JSX.Element}
24
+ */var FilterPageProvider=function FilterPageProvider(_ref){var filtersProp=_ref.filters,activeFiltersProp=_ref.activeFilters,parentRouteId=_ref.parentRouteId,onApply=_ref.onApply,children=_ref.children;var _useState=useState(activeFiltersProp||{}),_useState2=_slicedToArray(_useState,2),currentFilters=_useState2[0],setCurrentFilters=_useState2[1];/**
25
+ * Storage that hosts an object that represents the initial state of the filters page.
26
+ * It's created from the "filters" array that contains all available filters, and the
27
+ * "activeFilters" object that represents filters with an active value selection.
28
+ */var _useState3=useState(buildInitialFilters(filtersProp,activeFiltersProp)),_useState4=_slicedToArray(_useState3,2),initialFilters=_useState4[0],setInitialFilters=_useState4[1];/**
29
+ * Storage that hosts an object that represents the a partial state of the filters page with
30
+ * all filters that where modified since the filters page was opened.
31
+ */var _useState5=useState({}),_useState6=_slicedToArray(_useState5,2),changedFilters=_useState6[0],setChangedFilters=_useState6[1];// Object that represents the current state of all filters
32
+ var mergedFilters=useMemo(function(){return _extends({},initialFilters,{},changedFilters);},[changedFilters,initialFilters]);/**
33
+ * Effect that updates the "initialFilters" state when it doesn't have content yet
34
+ */useEffect(function(){setInitialFilters(function(currentState){if(Object.keys(currentState).length>0){return currentState;}return buildInitialFilters(filtersProp,activeFiltersProp);});},[activeFiltersProp,filtersProp]);/**
35
+ * Whether a reset of the active filters is possible.
36
+ *
37
+ * Reset is possible whenever filters where selected by the user before, or when filters where
38
+ * modified since the filters page was opened.
39
+ * @type {boolean}
40
+ */var resetPossible=useMemo(function(){return!!(Object.keys(currentFilters).length||Object.keys(changedFilters).length);},[changedFilters,currentFilters]);/**
41
+ * Whether the filter selection has changed since the filters page was opened
42
+ * @type {boolean}
43
+ */var hasChanged=useMemo(function(){return Object.keys(changedFilters).length>0||!!(Object.keys(currentFilters).length===0&&activeFiltersProp);},[activeFiltersProp,changedFilters,currentFilters]);/**
44
+ * Retrieves a list of currently selected values for a filter
45
+ * @callback getSelectedFilterValues
46
+ * @param {string} filterId The id of the filter
47
+ * @returns {string[]}
48
+ */var getSelectedFilterValues=useCallback(/**
49
+ * @param {string} filterId The id of the filter
50
+ * @returns {string[]}
51
+ */function(filterId){var _initialFilters$filte;var value=changedFilters[filterId]?changedFilters[filterId].value:((_initialFilters$filte=initialFilters[filterId])===null||_initialFilters$filte===void 0?void 0:_initialFilters$filte.value)||[];return value.map(function(entry){return entry.id||entry;});},[changedFilters,initialFilters]);/**
52
+ * Resets all filters which have been changed by the user
53
+ */var resetAllFilters=useCallback(function(){setInitialFilters(buildInitialFilters(filtersProp,{}));setCurrentFilters({});setChangedFilters({});},[filtersProp]);/**
54
+ * Resets all filters which have been changed by the user since the filters page was opened
55
+ */var resetChangedFilters=useCallback(function(){setChangedFilters({});},[]);/**
56
+ * Adds or updates the selection for a changed filter
57
+ * @callback updateChangedFilterInternal
58
+ * @param {string} filterId The id of the filter to be updated
59
+ * @param {string[]} selectedValues The updated selected values
60
+ */var updateChangedFilterInternal=useCallback(/**
61
+ * @param {string} filterId The id of the filter to be updated
62
+ * @param {string[]} selectedValues The updated selected values
63
+ */function(filterId,selectedValues){setChangedFilters(function(currentState){return _extends({},currentState,_defineProperty({},filterId,selectedValues));});},[]);/**
64
+ * Removes a changed filter
65
+ * @callback removeChangedFilterInternal
66
+ * @param {string} filterId The id of the filter to be updated
67
+ * @param {string[]} selectedValues The updated selected values
68
+ */var removeChangedFilterInternal=useCallback(/**
69
+ * @param {string} filterId The id of the filter to be removed
70
+ */function(filterId){setChangedFilters(function(currentState){// Separate the given id from the other set filters.
71
+ var removed=currentState[filterId],remainingFilters=_objectWithoutProperties(currentState,[filterId].map(_toPropertyKey));return remainingFilters;});},[]);/**
72
+ * Updates the selection for a filter
73
+ *
74
+ * @param {string} filterId The id of the filter to be updated
75
+ * @param {string[]} selectedValues The updated selected values
76
+ */var updateSelectedFilterValues=useCallback(debounce(/**
77
+ * @param {string} filterId The id of the filter to be updated
78
+ * @param {string[]} selectedValues The updated selected values
79
+ */function(filterId,selectedValues){// Retrieve data of filter to be updated from the filters array.
80
+ var filter=filtersProp.find(function(entry){return entry.id===filterId;});// Retrieve the values for the updated filter that where set when the filter page was opened
81
+ var initialValues=initialFilters[filterId].value;// Prepare the update payload
82
+ var stateValue=[].concat(selectedValues);/**
83
+ * No initial values where set for this filter, and the update contains no values. So we
84
+ * can remove the filter from the changedFilters storage.
85
+ */if(initialValues.length===0&&selectedValues.length===0){removeChangedFilterInternal(filterId);return;}/**
86
+ * When the filter update would recreate the state that the filter initially had, we
87
+ * remove the filter from the changedFilters storage.
88
+ *
89
+ * That enables proper behavior for the "reset" and "update" button states.
90
+ */if(initialValues.length!==0&&selectedValues.length!==0){if(initialValues.every(function(initial,i){return initial===selectedValues[i];})){removeChangedFilterInternal(filterId);return;}}if(Array.isArray(filter.values)){/**
91
+ * The selectedValues array only contains a list of ids.
92
+ * For the getProducts request that's dispatched after the current filter selection was
93
+ * applied, id and label is required at the filter values level.
94
+ */stateValue=selectedValues.map(function(valueId){var match=filter.values.find(function(entry){return entry.id===valueId;});return{id:match.id,label:match.label};});}updateChangedFilterInternal(filterId,_extends({id:filterId,type:filter.type,label:filter.label,value:stateValue},filter.source&&{source:filter.source}));},50),[filtersProp,initialFilters,removeChangedFilterInternal,updateChangedFilterInternal]);/**
95
+ * Applies the current filter selection to the parent route with a product list to be filtered
96
+ */var applyFilters=useCallback(function(){var filters=buildUpdatedFilters(currentFilters,changedFilters);router.update(parentRouteId,{filters:filters});onApply(filters);},[changedFilters,currentFilters,onApply,parentRouteId]);var value=useMemo(function(){return{resetPossible:resetPossible,hasChanged:hasChanged,apiFilters:filtersProp||[],filters:mergedFilters,resetAllFilters:resetAllFilters,resetChangedFilters:resetChangedFilters,getSelectedFilterValues:getSelectedFilterValues,updateSelectedFilterValues:updateSelectedFilterValues,applyFilters:applyFilters};},[hasChanged,resetPossible,filtersProp,mergedFilters,resetAllFilters,resetChangedFilters,getSelectedFilterValues,updateSelectedFilterValues,applyFilters]);return React.createElement(Context.Provider,{value:value},children);};FilterPageProvider.defaultProps={children:null,activeFilters:null,parentRouteId:null,filters:null,onApply:function onApply(){return setTimeout(router.pop,250);}};/**
97
+ * @type FilterPageProvider
98
+ */export default connect(mapStateToProps,null,null,{areStatePropsEqual:areStatePropsEqual})(FilterPageProvider);
@@ -1 +1 @@
1
- export{default as SortProvider}from"./SortProvider";
1
+ export{default as SortProvider}from"./SortProvider";export{default as FilterPageProvider}from"./FilterPageProvider";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/engage",
3
- "version": "7.12.7-beta.1",
3
+ "version": "7.12.7-beta.3",
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.12.7-beta.1",
20
- "@shopgate/pwa-common-commerce": "7.12.7-beta.1",
21
- "@shopgate/pwa-core": "7.12.7-beta.1",
22
- "@shopgate/pwa-ui-ios": "7.12.7-beta.1",
23
- "@shopgate/pwa-ui-material": "7.12.7-beta.1",
24
- "@shopgate/pwa-ui-shared": "7.12.7-beta.1",
19
+ "@shopgate/pwa-common": "7.12.7-beta.3",
20
+ "@shopgate/pwa-common-commerce": "7.12.7-beta.3",
21
+ "@shopgate/pwa-core": "7.12.7-beta.3",
22
+ "@shopgate/pwa-ui-ios": "7.12.7-beta.3",
23
+ "@shopgate/pwa-ui-material": "7.12.7-beta.3",
24
+ "@shopgate/pwa-ui-shared": "7.12.7-beta.3",
25
25
  "@stripe/react-stripe-js": "^1.1.2",
26
26
  "@stripe/stripe-js": "^1.3.1",
27
27
  "@virtuous/conductor": "~2.5.0",