@shopgate/pwa-common-commerce
Version:
Commerce library for the Shopgate Connect PWA.
264 lines • 24.8 kB
JavaScript
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 _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);}import{createSelector}from'reselect';import isEqual from'lodash/isEqual';import{getCurrentState}from'@shopgate/pwa-common/selectors/router';import{logger}from'@shopgate/pwa-core/helpers';import{generateResultHash}from'@shopgate/pwa-common/helpers/redux';import{getSortOrder}from'@shopgate/pwa-common/selectors/history';import{SORT_SCOPE_CATEGORY,SORT_SCOPE_SEARCH}from'@shopgate/engage/filter/constants';import{getPreferredLocation}from'@shopgate/engage/locations/selectors';import{getIsLocationBasedShopping}from'@shopgate/engage/core/selectors/merchantSettings';import{getActiveFilters}from"../../filter/selectors";import{filterProperties}from"../helpers";/**
* Retrieves the product state from the store.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @return {Object} The product state.
*/export var getProductState=function getProductState(state){return state.product||{};};/**
* Selects all products from the store.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @return {Object} The collection of products.
*/export var getProducts=createSelector(getProductState,function(state){return state.productsById||{};});/**
* Selects the product shipping state.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object} The product shipping state.
*/export var getProductShippingState=createSelector(getProductState,function(state){return state.shippingByProductId||{};});/**
* Selects the product description state.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object} The product description state.
*/export var getProductDescriptionState=createSelector(getProductState,function(state){return state.descriptionsByProductId||{};});/**
* Selects the product properties state.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object} The product properties state.
*/export var getProductPropertiesState=createSelector(getProductState,function(state){return state.propertiesByProductId||{};});/**
* Selects the product images state.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object} The product images state.
*/export var getProductImagesState=createSelector(getProductState,function(state){return state.imagesByProductId||{};});/**
* Selects the product variants state.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object} The product variants state.
*/export var getProductVariantsState=createSelector(getProductState,function(state){return state.variantsByProductId||{};});/**
* Retrieves a product by id from state. Different to getProduct() which returns the product
* entity data if available, this selector returns the pure state entry for a given productId.
* So the expires and the isFetching property is processable.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null} The dedicated product.
*/export var getProductById=createSelector(getProducts,function(state,props){return props;},function(products,props){if(_typeof(props)!=='object'){logger.warn('Invocation of getProductById() with a productId will be deprecated soon. Please provide a props object.');return products[props]||null;}if(!props.productId){return null;}return products[props.productId]||null;});/**
* @deprecated Also exists within @shopgate/engage/product/selectors/product
*/export var getProductDataById=createSelector(getProductById,function(product){return product?product.productData:undefined;});/**
* Retrieves the id of the current selected product from the component props. When the props
* contain a variant id it will return this one instead of the product id.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @param {Object} [props] The component props.
* @return {string|null} The id of the current product.
*/export var getProductId=function getProductId(state,props){if(!state){return null;}if(typeof props==='undefined'){/**
* Before PWA 6.0 some product selectors relied on a "currentProduct" state which doesn't exist
* anymore. Their successors require a props object which contains a productId or a variantId.
* To support debugging an error will be logged, if the props are missing at invocation.
*/logger.error('getProductId() needs to be called with a props object that includes a productId.');return null;}// Since a variantId can have falsy values, we need an "undefined" check here.
if(typeof props.variantId!=='undefined'&&props.variantId!==null){return props.variantId;}return props.productId||null;};/**
* Gets the variant id out of the selector props.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @returns {string|null}
*/export var getVariantProductId=function getVariantProductId(state,props){if(typeof props==='undefined'){/**
* Before PWA 6.0 the variant selectors relied on a "currentProduct" state which doesn't exist
* anymore. Their successors require a props object which contains a variantId.
* To support debugging an error will be logged, if the props are missing at invocation.
*/logger.error('getVariantId() needs to be called with a props object that includes a variantId.');}var _ref=props||{},_ref$variantId=_ref.variantId,variantId=_ref$variantId===void 0?null:_ref$variantId;return variantId;};/**
* Checks if currently a variant is selected within the props.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @returns {boolean}
*/export var isVariantSelected=function isVariantSelected(state,props){return!!getVariantProductId(state,props);};/**
* Retrieves the product data for the passed productId from the store.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object} The current product.
*/export var getProduct=createSelector(getProducts,getProductId,function(products,productId){var _ref2=products[productId]||{},productData=_ref2.productData;return productData||null;});/**
* Retrieves the product name.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getProductName=createSelector(getCurrentState,getProduct,function(routeState,product){if(!product){if(!routeState||!routeState.title){return null;}return routeState.title;}return product.name;});/**
* Retrieves the product long name.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getProductLongName=createSelector(getCurrentState,getProduct,function(routeState,product){if(!product){if(!routeState||!routeState.title){return null;}return routeState.title;}if(!product.longName){return product.name;}return product.longName;});/**
* Retrieves the product rating.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductRating=createSelector(getProduct,function(product){if(!product){return null;}return product.rating;});/**
* Retrieves the product manufacturer.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getProductManufacturer=createSelector(getProduct,function(product){if(!product){return null;}return product.manufacturer;});/**
* Retrieves the product stock information.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductStock=createSelector(getProduct,function(product){if(!product){return null;}return product.stock;});/**
* Retrieves the product availability.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductAvailability=createSelector(getProduct,function(product){if(!product){return null;}return product.availability;});/**
* Retrieves the product flags.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductFlags=createSelector(getProduct,function(product){if(!product){return null;}return product.flags;});/**
* Retrieves the product price object.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string}
*/export var getProductPriceData=createSelector(getProduct,function(product){if(!product){return null;}return product.price;});/**
* Retrieves the product currency.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @todo Move to the price selectors
* @return {string|null}
*/export var getProductCurrency=createSelector(getProductPriceData,function(price){if(!price){return null;}return price.currency;});/**
* Retrieves the product discount.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getProductDiscount=createSelector(getProductPriceData,function(price){if(!price){return null;}return price.discount||0;});/**
* Retrieves the unit price from a product.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @todo Move to the price selectors
* @return {number|null}
*/export var getProductUnitPrice=createSelector(getProductPriceData,function(price){if(!price){return null;}return price.unitPrice;});/**
* Determines if a product has variants.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {boolean}
*/export var hasProductVariants=createSelector(getProductFlags,function(flags){if(!flags){return null;}return flags.hasVariants;});/**
* Determines if a product has variety (variants, options).
* This product can not be added to a cart. Selecting of variety should be done on PDP
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {boolean}
*/export var hasProductVariety=createSelector(getProductFlags,function(flags){if(!flags){return null;}return flags.hasVariants||flags.hasOptions;});/**
* Determines if a product is a base product.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @todo Check if returning null is correct.
* @return {boolean|null}
*/export var isBaseProduct=createSelector(getProduct,hasProductVariants,function(product,hasVariants){if(!product){return false;}/**
* Base products are simple products without variants or products with related variant products.
* At variant products the baseProductId is used to reference the base product.
*/return product.baseProductId===null||hasVariants;});/**
* Determines a baseProductId for the products which are referenced within the props.
* When a variantId is passed, the selector will return the id of the related base product.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getBaseProductId=createSelector(getProduct,function(_){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return props.productId;},function(_){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return props.variantId;},function(product,productId,variantId){if(!product){// Return the productId when both ids are present, but no variant product is available yet.
if(typeof productId!=='undefined'&&typeof variantId!=='undefined'){return productId;}return null;}// First try to determine a baseProductId for a selected product
var _product$baseProductI=product.baseProductId,baseProductId=_product$baseProductI===void 0?null:_product$baseProductI;return baseProductId||product.id;});/**
* Retrieves the base product data for the passed productId from the store.
* @deprecated Also exists within @shopgate/engage/product/selectors/product
* @param {Object} state The current application state.
* @returns {Object|null} The current product.
*/export var getBaseProduct=createSelector(getProducts,getBaseProductId,function(products,baseProductId){if(!baseProductId){return null;}var _ref3=products[baseProductId]||{},_ref3$productData=_ref3.productData,productData=_ref3$productData===void 0?null:_ref3$productData;return productData;});/**
* Determines if a base product has variants.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {boolean}
*/export var hasBaseProductVariants=createSelector(getBaseProduct,function(baseProduct){if(!baseProduct){return false;}var _baseProduct$flags=baseProduct.flags,_baseProduct$flags2=_baseProduct$flags===void 0?{}:_baseProduct$flags,_baseProduct$flags2$h=_baseProduct$flags2.hasVariants,hasVariants=_baseProduct$flags2$h===void 0?false:_baseProduct$flags2$h;return hasVariants;});/**
* Retrieves the metadata for the given product.
* @param {Object} state The current application state.
* @return {Object|null}
*/export var getProductMetadata=createSelector(getProduct,function(product){if(!product){return null;}return product.metadata;});/**
* Retrieves the metadata for the given product.
* @param {Object} state The current application state.
* @return {Object|null}
*/export var getBaseProductMetadata=createSelector(getBaseProduct,function(product){if(!product){return null;}return product.metadata;});/**
* Retrieves the shipping data for the given product.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductShipping=createSelector(getProductShippingState,getProductId,function(shipping,productId){var entry=shipping[productId];if(!entry||!entry.shipping){return null;}return entry.shipping;});export var getProductPropertiesUnfiltered=createSelector(getProductId,getProductPropertiesState,function(productId,properties){var entry=properties[productId];if(!entry||entry.isFetching||typeof entry.properties==='undefined'){return null;}return entry.properties;});/**
* Retrieves the properties for the given product.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductProperties=createSelector(getProductPropertiesState,getProductId,function(properties,productId){var entry=properties[productId];if(!entry||!entry.properties){return null;}return filterProperties(entry.properties);});/**
* Retrieves the description for the given product.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getProductDescription=createSelector(getProductDescriptionState,getProductId,function(descriptions,productId){var entry=descriptions[productId];if(!entry||typeof entry.description==='undefined'){return null;}return entry.description;});/**
* Retrieves the images for the given product. If the props contain a variantId, and the related
* product does not have images, the selector tries to pick images from its base product.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Array|null}
*/export var getProductImages=createSelector(getProductImagesState,getProductId,getBaseProductId,function(images,productId,baseProductId){var _ref4=images[productId]||{},productImages=_ref4.images,isFetching=_ref4.isFetching;if(isFetching){return null;}// If the product doesn't have images after fetching
if(baseProductId&&(!Array.isArray(productImages)||!productImages.length)){// ...check the base product.
var _ref6=images[baseProductId]||{},baseProductImages=_ref6.images;if(!Array.isArray(baseProductImages)||!baseProductImages.length){return null;}return baseProductImages;}return productImages||null;});export var getFeaturedImage=createSelector(getProduct,getBaseProduct,function(product,baseProduct){var productImage=null;var baseProductImage=null;if(product===null||product===void 0?void 0:product.featuredMedia){productImage=product.featuredMedia.type==='image'?product.featuredMedia.url:null;}if(baseProduct===null||baseProduct===void 0?void 0:baseProduct.featuredMedia){baseProductImage=baseProduct.featuredMedia.type==='image'?baseProduct.featuredMedia.url:null;}return productImage||baseProductImage||(product===null||product===void 0?void 0:product.featuredImageBaseUrl)||(product===null||product===void 0?void 0:product.featuredImageUrl);});/**
* Retrieves the product variant data.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getProductVariants=createSelector(getProductVariantsState,getBaseProductId,function(variants,baseProductId){var entry=variants[baseProductId];if(!entry||!entry.variants){return null;}return entry.variants;});/**
* Retrieves a product for the selected variant id from the store.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @returns {Object|null} The selected variant or null if none is selected
*/export var getSelectedVariant=createSelector(getProduct,isVariantSelected,function(product,selected){if(!product||!selected){return null;}return product;});/**
* Determines if a product is orderable.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {boolean}
*/export var isProductOrderable=createSelector(getProductStock,function(stockInfo){return!!(stockInfo&&stockInfo.orderable);});/**
* Retrieves the product id of a variant product. When no variantId is passed within
* the props, the selector will return NULL.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {string|null}
*/export var getVariantId=createSelector(getProduct,function(product){if(!product){return null;}var id=product.id,baseProductId=product.baseProductId;return baseProductId!==null?id:null;});/**
* Retrieves an availability object for a passed set of variant characteristics.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @return {Object|null}
*/export var getVariantAvailabilityByCharacteristics=createSelector(getProductVariants,function(state){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return props.characteristics;},function(variants,characteristics){if(!variants){return null;}var found=variants.products.find(function(product){return isEqual(product.characteristics,characteristics);});if(!found){return null;}return found.availability;});/**
* Creates a selector that determines fulfillment params for product requests
*/export var getFulfillmentParams=createSelector(getIsLocationBasedShopping,getPreferredLocation,function(isLocationBasedShopping,location){if(!isLocationBasedShopping||!location){return{};}return{locationCodes:[location.code]};});/**
* Retrieves the generated result hash for a category id or search phrase.
* @param {Object} state The current application state.
* @param {Object} props The component props.
* @returns {string|null} The result hash.
*/export var getResultHash=createSelector(function(state){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return props.categoryId;},function(state){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return props.searchPhrase;},function(state){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};return props.params;},function(state,props){return getSortOrder(state,props);},getActiveFilters,getFulfillmentParams,function(categoryId,searchPhrase,params,sort,filters,fulfillmentParams){if(categoryId){return generateResultHash(_extends({categoryId:categoryId,sort:sort},filters&&{filters:filters},{},params,{},fulfillmentParams));}if(searchPhrase){return generateResultHash(_extends({searchPhrase:searchPhrase,sort:sort},params,{},filters&&{filters:filters},{},fulfillmentParams));}return null;});/**
* Retrieves the result by hash.
* @param {Object} state The application state.
* @param {Object} props The component props.
* @returns {Object} The result.
*/export var getResultByHash=createSelector(getProductState,getResultHash,function(productState,hash){var results=productState.resultsByHash[hash];if(!results){return null;}return results;});/**
* Populates the product result object.
* @param {Object} state The application state.
* @param {Object} props The component props.
* @param {string} hash The result hash.
* @param {Object} result The result.
* @return {Object} The product result.
*/export var getPopulatedProductsResult=function getPopulatedProductsResult(state,props,hash,result){var searchPhrase=props.searchPhrase;var sort=getSortOrder(state,_extends({},props,{scope:typeof searchPhrase==='undefined'?SORT_SCOPE_CATEGORY:SORT_SCOPE_SEARCH}));var products=[];var totalProductCount=!hash?0:null;var expired=!!(result&&result.expires&&result.expires>0&&result.expires<Date.now());if(result&&result.products){totalProductCount=result.totalResultCount;products=result.products.map(function(productId){return getProductById(state,{productId:productId}).productData;});}return{products:products,totalProductCount:totalProductCount,sort:sort,hash:hash,expired:expired};};/**
* Retrieves the populated product result.
* @param {Object} state The application state.
* @param {Object} props The component props.
* @returns {Object} The product result.
*/export var getProductsResult=createSelector(function(state){return state;},function(state,props){return props;},getResultHash,getResultByHash,getPopulatedProductsResult);/**
* Selector factory which creates a selector to retrieve a product results object based on a custom
* hash string.
* @param {string} hash A resultsByHash hash string
* @returns {Function}
*/export var makeGetProductResultByCustomHash=function makeGetProductResultByCustomHash(hash){var parsedHash=JSON.parse(hash);return createSelector(function(state){return state;},function(state,props){return props;},getProductState,function(state,props,productState){var searchPhrase=props.searchPhrase;var products=[];var totalProductCount=!hash?0:null;var sort=(parsedHash===null||parsedHash===void 0?void 0:parsedHash.sort)||getSortOrder(state,_extends({},props,{scope:typeof searchPhrase==='undefined'?SORT_SCOPE_CATEGORY:SORT_SCOPE_SEARCH}));var result=productState.resultsByHash[hash];if(result&&result.products){totalProductCount=result.totalResultCount;products=result.products.map(function(productId){return getProductById(state,{productId:productId}).productData;});}return{products:products,totalProductCount:totalProductCount,sort:sort,hash:hash};});};/**
* Selector mappings for PWA < 6.0
* @deprecated
*/export var getCurrentProduct=getProduct;export var getCurrentProductId=getProductId;export var getCurrentBaseProductId=getBaseProductId;export var getCurrentBaseProduct=getBaseProduct;export var getCurrentProductStock=getProductStock;export var getProductStockInfo=getProductStock;export var getProductBasePrice=getProductUnitPrice;export var isOrderable=isProductOrderable;