@shopgate/pwa-common-commerce
Version:
Commerce library for the Shopgate Connect PWA.
31 lines • 15.1 kB
JavaScript
import _regeneratorRuntime from"@babel/runtime/regenerator";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;}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value;}catch(error){reject(error);return;}if(info.done){resolve(value);}else{Promise.resolve(value).then(_next,_throw);}}function _asyncToGenerator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value);}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err);}_next(undefined);});};}import pipelineDependencies from'@shopgate/pwa-core/classes/PipelineDependencies';import appConfig from'@shopgate/pwa-common/helpers/config';import showModal from'@shopgate/pwa-common/actions/modal/showModal';import{appDidStart$}from'@shopgate/pwa-common/streams';import groupBy from'lodash/groupBy';import ToastProvider from'@shopgate/pwa-common/providers/toast';import{makeGetRoutePattern}from'@shopgate/engage/core/selectors';import{getLoadWishlistOnAppStartEnabled,getWishlistItemQuantityEnabled}from'@shopgate/engage/core/selectors/shopSettings';import{LoadingProvider}from'@shopgate/pwa-common/providers';import{favoritesWillEnter$,shouldFetchFreshFavorites$,addProductToFavoritesDebounced$,addProductToFavorites$,removeProductFromFavoritesDebounced$,errorFavoritesLimit$,refreshFavorites$,didReceiveFlushFavoritesBuffer$,updateProductInFavoritesDebounced$,favoritesDidAddItem$,favoritesSyncIdle$}from"../streams";import{SHOPGATE_USER_ADD_FAVORITES,SHOPGATE_USER_DELETE_FAVORITES}from"../constants/Pipelines";import addFavorites from"../actions/addFavorites";import updateFavorites from"../actions/updateFavorites";import removeFavorites from"../actions/removeFavorites";import fetchFavoritesListsWithItems from"../actions/fetchFavoritesListsWithItems";import fetchFavorites from"../actions/fetchFavorites";import{requestAddFavorites,requestRemoveFavorites,cancelRequestSyncFavorites,errorFavorites,idleSyncFavorites,requestUpdateFavorites}from"../action-creators";import{REQUEST_ADD_FAVORITES,REQUEST_REMOVE_FAVORITES,FAVORITES_LIMIT_ERROR,REQUEST_UPDATE_FAVORITES,FAVORITES_PATH}from"../constants";import{getFavoritesCount,makeGetFavoritesCountByList,makeGetProductRelativesOnFavorites,getFavoritesProducts,getUseGetFavoriteIdsPipeline}from"../selectors";import fetchFavoriteIds from"../actions/fetchFavoriteIds";/**
* @param {Function} subscribe Subscribes to an observable.
*/export default function favorites(subscribe){if(!appConfig.hasFavorites){return;}/** App start */subscribe(appDidStart$,/*#__PURE__*/function(){var _ref2=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref){var dispatch,getState,loadWishlistOnAppStartEnabled;return _regeneratorRuntime.wrap(function _callee$(_context){while(1)switch(_context.prev=_context.next){case 0:dispatch=_ref.dispatch,getState=_ref.getState;// Setup sync pipeline dependencies (concurrency to each other and themselves)
pipelineDependencies.set(SHOPGATE_USER_ADD_FAVORITES,[SHOPGATE_USER_ADD_FAVORITES,SHOPGATE_USER_DELETE_FAVORITES]);pipelineDependencies.set(SHOPGATE_USER_DELETE_FAVORITES,[SHOPGATE_USER_ADD_FAVORITES,SHOPGATE_USER_DELETE_FAVORITES]);loadWishlistOnAppStartEnabled=getLoadWishlistOnAppStartEnabled(getState());if(!(loadWishlistOnAppStartEnabled&&makeGetRoutePattern()(getState())!==FAVORITES_PATH)){_context.next=7;break;}_context.next=7;return dispatch(fetchFavoritesListsWithItems(false));case 7:case"end":return _context.stop();}},_callee);}));return function(_x){return _ref2.apply(this,arguments);};}());/** Favorites route enter */subscribe(favoritesWillEnter$,/*#__PURE__*/function(){var _ref4=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref3){var dispatch;return _regeneratorRuntime.wrap(function _callee2$(_context2){while(1)switch(_context2.prev=_context2.next){case 0:dispatch=_ref3.dispatch;_context2.next=3;return dispatch(fetchFavoritesListsWithItems(true));case 3:case"end":return _context2.stop();}},_callee2);}));return function(_x2){return _ref4.apply(this,arguments);};}());/** User login / logout */subscribe(shouldFetchFreshFavorites$,/*#__PURE__*/function(){var _ref6=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(_ref5){var dispatch;return _regeneratorRuntime.wrap(function _callee3$(_context3){while(1)switch(_context3.prev=_context3.next){case 0:dispatch=_ref5.dispatch;_context3.next=3;return dispatch(fetchFavoritesListsWithItems(true));case 3:case"end":return _context3.stop();}},_callee3);}));return function(_x3){return _ref6.apply(this,arguments);};}());subscribe(addProductToFavoritesDebounced$,function(_ref7){var _getFavoritesProducts;var action=_ref7.action,dispatch=_ref7.dispatch,getState=_ref7.getState;var state=getState();var wishlistItemQuantityEnabled=getWishlistItemQuantityEnabled(state);// Nothing to do, when the store already contains the item
var activeProductInList=(_getFavoritesProducts=getFavoritesProducts(state).byList[action.listId])===null||_getFavoritesProducts===void 0?void 0:_getFavoritesProducts.items.find(function(_ref8){var productId=_ref8.productId;return productId===action.productId;});if(activeProductInList&&!wishlistItemQuantityEnabled){// Call cancel action with "zero" count, because request was even dispatched
dispatch(cancelRequestSyncFavorites(0,action.listId));return;}var _appConfig$favorites=appConfig.favorites,_appConfig$favorites2=_appConfig$favorites===void 0?{}:_appConfig$favorites,_appConfig$favorites3=_appConfig$favorites2.limit,limit=_appConfig$favorites3===void 0?100:_appConfig$favorites3;var count=makeGetFavoritesCountByList(function(){return action===null||action===void 0?void 0:action.listId;})(state);// When the getFavorites pipeline is used to fetch favorites, the amount of items is limited
// since it returns full product entities. Hence adding more items needs to be prevented.
if(limit&&count>=limit&&!getUseGetFavoriteIdsPipeline(state)){// Dispatch a local error only, because the request to add is prevented
var error=new Error('Limit exceeded');error.code=FAVORITES_LIMIT_ERROR;dispatch(errorFavorites(action.productId,error));}else{dispatch(requestAddFavorites(action.productId,action.listId,action.quantity,action.notes,action.showToast));}});subscribe(updateProductInFavoritesDebounced$,function(_ref9){var action=_ref9.action,dispatch=_ref9.dispatch;dispatch(requestUpdateFavorites(action.productId,action.listId,action.quantity,action.notes));});subscribe(removeProductFromFavoritesDebounced$,function(_ref10){var _getFavoritesProducts2;var action=_ref10.action,dispatch=_ref10.dispatch,getState=_ref10.getState;var count=getFavoritesCount(getState());if(count>0){if(action.withRelatives){// Will only handle ids which are present in the store, no additional check needed
var allOnList=makeGetProductRelativesOnFavorites(function(){return action.listId;})(getState(),{productId:action.productId});allOnList.forEach(function(id){return dispatch(requestRemoveFavorites(id,action.listId));});return;}// Avoids trying to remove something that was already removed (incoming fetch response)
var list=getFavoritesProducts(getState()).byList[action.listId];if(!(list===null||list===void 0?void 0:list.items.find(function(_ref11){var productId=_ref11.productId;return productId===action.productId;}))){// Call cancel action with "zero" count, because request was even dispatched
dispatch(cancelRequestSyncFavorites(0,action.listId));return;}dispatch(requestRemoveFavorites(action.productId,action.listId));}else if(!((_getFavoritesProducts2=getFavoritesProducts(getState()).byList[action.listId])===null||_getFavoritesProducts2===void 0?void 0:_getFavoritesProducts2.isFetching)){// Remove should not be possible when no favorites available
// Refresh to fix inconsistencies, by dispatching an idleSync action when not fetching
dispatch(idleSyncFavorites(action.listId));}});// Catch local limit errors (backend errors are handled autonomously)
subscribe(errorFavoritesLimit$,function(_ref12){var dispatch=_ref12.dispatch;dispatch(showModal({confirm:null,dismiss:'modal.ok',title:'modal.title_error',message:'favorites.error_limit'}));});/**
* Request after N seconds since last add or remove request to make sure
* backend did actually save it
*/subscribe(refreshFavorites$,/*#__PURE__*/function(){var _ref14=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(_ref13){var dispatch,action,getState,useGetFavoriteIdsPipeline;return _regeneratorRuntime.wrap(function _callee4$(_context4){while(1)switch(_context4.prev=_context4.next){case 0:dispatch=_ref13.dispatch,action=_ref13.action,getState=_ref13.getState;if(!action.listId){_context4.next=5;break;}useGetFavoriteIdsPipeline=getUseGetFavoriteIdsPipeline(getState());if(useGetFavoriteIdsPipeline){dispatch(fetchFavoriteIds(true,action.listId));}else{dispatch(fetchFavorites(true,action.listId));}return _context4.abrupt("return");case 5:_context4.next=7;return dispatch(fetchFavoritesListsWithItems(true));case 7:case"end":return _context4.stop();}},_callee4);}));return function(_x4){return _ref14.apply(this,arguments);};}());/**
* Takes an action buffer of the request-add, request-remove and request-update favorites actions
* and triggers Pipeline requests for all of them. Errors are handled autonomously.
* After all pipeline requests are done it resets the favorite page's state to "idle".
*/subscribe(didReceiveFlushFavoritesBuffer$,/*#__PURE__*/function(){var _ref15=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6(actionBuffer){var dispatch,actions,actionsByListAndProduct,idleLists;return _regeneratorRuntime.wrap(function _callee6$(_context6){while(1)switch(_context6.prev=_context6.next){case 0:if(!(!Array.isArray(actionBuffer)||!actionBuffer.length)){_context6.next=2;break;}return _context6.abrupt("return");case 2:LoadingProvider.setLoading(FAVORITES_PATH);// All actions provide the same functionality, just take the first entry
dispatch=actionBuffer[0].dispatch;// Group all buffered actions by listId and productID
actions=actionBuffer.map(function(_ref16){var action=_ref16.action;return action;});actionsByListAndProduct=groupBy(actions,function(_ref17){var listId=_ref17.listId,productId=_ref17.productId;return"".concat(listId,"-").concat(productId,"}");});idleLists=[];_context6.next=9;return Object.values(actionsByListAndProduct).forEach(/*#__PURE__*/function(){var _ref18=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(groupedActions){var _groupedActions,_groupedActions$,_groupedActions$2,productId,listId,quantity,notes,showToast,updateActions,addActions,removeActions,_updateActions$slice3,_updateActions$slice4,lastUpdateAction,addRemoveBalance;return _regeneratorRuntime.wrap(function _callee5$(_context5){while(1)switch(_context5.prev=_context5.next){case 0:_groupedActions=_slicedToArray(groupedActions,1),_groupedActions$=_groupedActions[0],_groupedActions$2=_groupedActions$===void 0?{}:_groupedActions$,productId=_groupedActions$2.productId,listId=_groupedActions$2.listId,quantity=_groupedActions$2.quantity,notes=_groupedActions$2.notes,showToast=_groupedActions$2.showToast;updateActions=groupedActions.filter(function(action){return action.type===REQUEST_UPDATE_FAVORITES;});addActions=groupedActions.filter(function(action){return action.type===REQUEST_ADD_FAVORITES;});removeActions=groupedActions.filter(function(action){return action.type===REQUEST_REMOVE_FAVORITES;});_context5.prev=4;if(!(updateActions.length>0)){_context5.next=9;break;}_updateActions$slice3=updateActions.slice(-1),_updateActions$slice4=_slicedToArray(_updateActions$slice3,1),lastUpdateAction=_updateActions$slice4[0];_context5.next=9;return dispatch(updateFavorites(lastUpdateAction.productId,lastUpdateAction.listId,lastUpdateAction.quantity,lastUpdateAction.notes));case 9:// Sum up all adds and removes, based on sum dispatch add / remove
addRemoveBalance=addActions.length-removeActions.length;if(!(addRemoveBalance>0)){_context5.next=13;break;}_context5.next=13;return dispatch(addFavorites(productId,listId,quantity,notes,showToast));case 13:if(!(addRemoveBalance<0)){_context5.next=16;break;}_context5.next=16;return dispatch(removeFavorites(productId,listId,quantity,notes));case 16:if(!(updateActions.length===0&&addRemoveBalance===0)){_context5.next=20;break;}dispatch(cancelRequestSyncFavorites(groupedActions.length,listId));_context5.next=24;break;case 20:if(idleLists.includes(listId)){_context5.next=24;break;}idleLists.push(listId);_context5.next=24;return dispatch(idleSyncFavorites(listId));case 24:_context5.next=32;break;case 26:_context5.prev=26;_context5.t0=_context5["catch"](4);if(idleLists.includes(listId)){_context5.next=32;break;}idleLists.push(listId);_context5.next=32;return dispatch(idleSyncFavorites(listId));case 32:case"end":return _context5.stop();}},_callee5,null,[[4,26]]);}));return function(_x6){return _ref18.apply(this,arguments);};}());case 9:case"end":return _context6.stop();}},_callee6);}));return function(_x5){return _ref15.apply(this,arguments);};}());subscribe(favoritesSyncIdle$,function(){LoadingProvider.resetLoading(FAVORITES_PATH);});subscribe(addProductToFavorites$,function(_ref19){var events=_ref19.events,getState=_ref19.getState,action=_ref19.action;var loadWishlistOnAppStartEnabled=getLoadWishlistOnAppStartEnabled(getState());// When wish list loading on app start is disabled, toast is shown instantly after the add
// action was dispatched. We don't have to wait for the "debounced" action, since
// removal of wishlist items is not possible.
if(!loadWishlistOnAppStartEnabled&&(action===null||action===void 0?void 0:action.showToast)!==false){events.emit(ToastProvider.ADD,{id:'favorites.added',message:'favorites.added'});}});subscribe(favoritesDidAddItem$,function(_ref20){var events=_ref20.events,getState=_ref20.getState,action=_ref20.action;var loadWishlistOnAppStartEnabled=getLoadWishlistOnAppStartEnabled(getState());// When wish list loading on app start is enabled, toast is shown after the add action from
// the buffer system is dispatched. We wait for that since the item might have been removed
// again within the debounce time.
if(loadWishlistOnAppStartEnabled&&(action===null||action===void 0?void 0:action.showToast)!==false){events.emit(ToastProvider.ADD,{id:'favorites.added',message:'favorites.added'});}});}