{"version":3,"file":"static/js/f29a87a636e5defab7de.bundle.js","mappings":"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","sources":["webpack://united-malt/./src/actions/shared-availability-state.ts?3c71","webpack://united-malt/./src/actions/get-related-products-minimal.ts?b166","webpack://united-malt/./src/modules/substitute-products/actions/get-substitute-products.ts?f34e","webpack://united-malt/./src/modules/substitute-products/substitute-products.tsx?9eb2","webpack://united-malt/./src/modules/substitute-products/substitute-products.view.tsx?3520","webpack://united-malt/./lib/substitute-products/module-registration.js?8b54","webpack://united-malt/external var \"React\"?0d3b","webpack://united-malt/external var \"ReactDOM\"?853b"],"sourcesContent":["//==============================================================================\r\n// Extremely simple shared state\r\n//\r\n// This version allows sharing of availability information across modules\r\n//==============================================================================\r\nimport * as Msdyn365 from '@msdyn365-commerce/core';\r\n\r\n//==============================================================================\r\n//==============================================================================\r\n\r\n//==========================================================\r\n// Input Action\r\n//==========================================================\r\nexport class SharedAvailabilityInput implements Msdyn365.IActionInput {\r\n\r\n //----------------------------------------------------------\r\n // Caching Stuff\r\n //----------------------------------------------------------\r\n public getCacheKey = () => `SharedAvailability`;\r\n public getCacheObjectType = () => 'SharedAvailability';\r\n public dataCacheType = (): Msdyn365.CacheType => 'request';\r\n}\r\n\r\n//==========================================================\r\n//==========================================================\r\nexport function createInput(actionContext: Msdyn365.ICreateActionContext): Msdyn365.IActionInput {\r\n return new SharedAvailabilityInput();\r\n}\r\n\r\n//==========================================================\r\n// Insanely simple class to hold a single variable\r\n//==========================================================\r\nexport class SharedAvailability {\r\n public isAvailable: Boolean = true;\r\n}\r\n\r\n//==========================================================\r\n//==========================================================\r\nexport async function sharedAvailabilityAction(input: SharedAvailabilityInput, ctx?: Msdyn365.IActionContext): Promise {\r\n return new SharedAvailability();\r\n}\r\n\r\n//==============================================================================\r\n//==============================================================================\r\nexport default Msdyn365.createObservableDataAction({\r\n action: >sharedAvailabilityAction,\r\n input: createInput\r\n});","//==============================================================================\r\n// Slightly streamlined version of get-related-products\r\n// Returns ProductSearchResults instead of FullProducts\r\n//==============================================================================\r\nimport { CacheType, createObservableDataAction, IAction, IActionContext, IActionInput, IAny, ICreateActionContext, IGeneric } from '@msdyn365-commerce/core';\r\nimport { getRelatedProductsAsync, getRelationTypesAsync } from '@msdyn365-commerce/retail-proxy/dist/DataActions/ProductsDataActions.g';\r\nimport { ProductRelationType, ProductSearchResult } from '@msdyn365-commerce/retail-proxy';\r\n\r\nimport { ProductDetailsCriteria, QueryResultSettingsProxy } from '@msdyn365-commerce-modules/retail-actions';\r\n\r\n/**\r\n * Utility function to prepare the product details criteria before getting full product:\r\n * @param inputData The Action Input data\r\n */\r\n export const getProductDetailsCriteriaFromActionInput = (inputData: ICreateActionContext>): ProductDetailsCriteria => {\r\n if (inputData && inputData.config) {\r\n return {\r\n getPrice: !inputData.config.hidePrice,\r\n getRating: !inputData.config.hideRating\r\n };\r\n }\r\n return {\r\n getPrice: true,\r\n getRating: true\r\n };\r\n};\r\n\r\n/**\r\n * GetRelatedProducts Input Action.\r\n */\r\nexport class GetRelatedProductsInput implements IActionInput {\r\n public readonly productId: number;\r\n\r\n public readonly catalogId: number;\r\n\r\n public readonly relationType: string;\r\n\r\n public ProductDetailsCriteria: ProductDetailsCriteria;\r\n\r\n public readonly queryResultSettingsProxy: QueryResultSettingsProxy;\r\n\r\n constructor(\r\n productId: number,\r\n catalogId: number,\r\n relationType: string,\r\n queryResultSettingsProxy: QueryResultSettingsProxy,\r\n criteria: ProductDetailsCriteria\r\n ) {\r\n this.productId = productId;\r\n this.catalogId = catalogId;\r\n this.relationType = relationType;\r\n this.queryResultSettingsProxy = queryResultSettingsProxy;\r\n this.ProductDetailsCriteria = criteria;\r\n }\r\n\r\n public getCacheKey = () => `${this.productId}|${this.catalogId}|${this.relationType.toLowerCase()}|${this.queryResultSettingsProxy.cacheKeyHint}|minimal`;\r\n\r\n public getCacheObjectType = () => 'GetRelatedProducts';\r\n\r\n public dataCacheType = (): CacheType => 'none';\r\n}\r\n\r\n/**\r\n * Creates the input required to make GetRelatedProducts retail api call.\r\n * @param inputData\r\n */\r\nexport const createGetRelatedProductsMinimalInput = (inputData: ICreateActionContext>): GetRelatedProductsInput => {\r\n if (inputData && inputData.requestContext && inputData.config) {\r\n const catalogId = inputData.requestContext.apiSettings.catalogId;\r\n const relationType = inputData.config.relationType;\r\n\r\n let productId = inputData.requestContext.urlTokens ? Number(inputData.requestContext.urlTokens.recordId) : 0;\r\n const productDetailsCriteria = getProductDetailsCriteriaFromActionInput(inputData);\r\n if (!relationType) {\r\n throw new Error('Input relation type is invalid.');\r\n }\r\n\r\n // Query string may override the product id from url\r\n if (inputData.requestContext.query && inputData.requestContext.query.productId) {\r\n productId = Number(inputData.requestContext.query.productId);\r\n }\r\n\r\n if (Number.isNaN(productId) || productId <= 0) {\r\n throw new Error('No valid product id available in url or query string.');\r\n }\r\n\r\n if (Number.isNaN(catalogId)) {\r\n throw new Error('Failed to cast catalog id into a number.');\r\n }\r\n\r\n const queryResultSettingsProxy = QueryResultSettingsProxy.fromInputData(inputData);\r\n\r\n return new GetRelatedProductsInput(productId, catalogId, relationType, queryResultSettingsProxy, productDetailsCriteria);\r\n }\r\n\r\n throw new Error('Invalid input data or request context');\r\n};\r\n\r\nexport function searchProductRelationType(productRelationTypes: ProductRelationType[], _productRelationType: string): number | undefined {\r\n let foundProductRelationTypeId;\r\n _productRelationType = _productRelationType.toLowerCase();\r\n productRelationTypes.forEach((productRelationType: ProductRelationType) => {\r\n if (productRelationType.Name && productRelationType.Name.toLowerCase() === _productRelationType) {\r\n foundProductRelationTypeId = productRelationType.RecordId;\r\n }\r\n });\r\n\r\n return foundProductRelationTypeId;\r\n}\r\n\r\nexport async function getRelatedProductsMinimalAction(input: GetRelatedProductsInput, ctx: IActionContext): Promise {\r\n const apiSettings = ctx.requestContext.apiSettings;\r\n const querySettings = input.queryResultSettingsProxy.QueryResultSettings;\r\n\r\n const productRelationTypes = await getRelationTypesAsync(\r\n { callerContext: ctx, queryResultSettings: querySettings },\r\n input.productId,\r\n +apiSettings.channelId,\r\n input.catalogId\r\n );\r\n if (!productRelationTypes) {\r\n ctx.trace(`[getProductRelationType] Unable to get product relation types for product ${input.productId}`);\r\n return [];\r\n }\r\n const productRelationTypeId = searchProductRelationType(productRelationTypes, input.relationType);\r\n if (!productRelationTypeId) {\r\n ctx.trace(`[getRelatedProducts] Unable to find relation type ${input.relationType} for product ${input.productId}`);\r\n return [];\r\n }\r\n\r\n return getRelatedProductsAsync(\r\n { callerContext: ctx, queryResultSettings: querySettings },\r\n input.productId,\r\n +apiSettings.channelId,\r\n input.catalogId,\r\n productRelationTypeId\r\n );\r\n}\r\n\r\n/**\r\n * The getRelatedProducts data action\r\n * Uses a productId URL Token and finds the relation types for said product\r\n * using the getRelationTypes RetailServer API, and then finds and retusn all products that\r\n * share that relation type via the getRelatedProducts RetailServer API.\r\n */\r\nexport const getRelatedProductsActionDataAction = createObservableDataAction({\r\n id: 'actions/get-related-products-minimal',\r\n action: >getRelatedProductsMinimalAction,\r\n input: createGetRelatedProductsMinimalInput\r\n});\r\n\r\nexport default getRelatedProductsActionDataAction;\r\n","//==============================================================================\r\n// Fetches a list of substitute products\r\n//\r\n// Products are sourced from a related products list\r\n// Only products with inventory available are returned\r\n//==============================================================================\r\nimport * as Msdyn365 from '@msdyn365-commerce/core';\r\nimport { ProductSearchResult } from '@msdyn365-commerce/retail-proxy';\r\n\r\nimport {\r\n ArrayExtensions,\r\n getInventoryLevelCodeFromDimensionValue,\r\n InventoryLevelValues,\r\n GetDimensionsForSelectedVariantInput,\r\n getDimensionsForSelectedVariantAction,\r\n} from '@msdyn365-commerce-modules/retail-actions';\r\n\r\nimport { createGetRelatedProductsMinimalInput, getRelatedProductsMinimalAction } from '../../../actions/get-related-products-minimal';\r\n\r\nimport { ISubstituteProductsConfig } from '../substitute-products.props.autogenerated';\r\n\r\n//==============================================================================\r\n// INTERFACES\r\n//==============================================================================\r\n\r\n//==============================================================================\r\n// FUNCTIONS\r\n//==============================================================================\r\n\r\n//==========================================================\r\n// GetSubstituteProduct Input Action\r\n//==========================================================\r\nexport class GetSubstituteProductInput implements Msdyn365.IActionInput {\r\n public readonly context: Msdyn365.ICreateActionContext;\r\n\r\n //----------------------------------------------------------\r\n //----------------------------------------------------------\r\n constructor(\r\n context: Msdyn365.ICreateActionContext,\r\n ) {\r\n this.context = context;\r\n }\r\n\r\n //----------------------------------------------------------\r\n // Caching Stuff\r\n //----------------------------------------------------------\r\n public getCacheKey = () => `${this.context.config?.productCollection || ''}|${this.context.config?.maxProductsToShow || 0}`;\r\n public getCacheObjectType = () => 'SubstituteProducts';\r\n public dataCacheType = (): Msdyn365.CacheType => 'application';\r\n}\r\n\r\n//==========================================================\r\n//==========================================================\r\nconst createSubstituteProductsInput = (actionContext: Msdyn365.ICreateActionContext): Msdyn365.IActionInput => {\r\n return new GetSubstituteProductInput(actionContext);\r\n};\r\n\r\n//==========================================================\r\n// This assumes that there are no service items and the list is unique.\r\n// This was borrowed from get-product-availabilities-wishlist-items\r\n// but the extra checks were removed since they shouldn't be\r\n// needed in this context.\r\n//==========================================================\r\nasync function getAvailabilities(productList: number[], ctx: Msdyn365.IActionContext): Promise {\r\n\r\n // Initiate a bunch of parallel requests (unfortunate!)\r\n const promises = productList.map(id => {\r\n const input = new GetDimensionsForSelectedVariantInput(id, ctx.requestContext.apiSettings.channelId);\r\n return getDimensionsForSelectedVariantAction(input, ctx);\r\n });\r\n\r\n // Wait for all requests to complete\r\n const result = await Promise.all(promises);\r\n\r\n // Convert results into a simple true/false for product availability\r\n return result.map(entry => {\r\n const dimensionValuesWithInventory = ArrayExtensions.flatten(\r\n ArrayExtensions.validValues(entry.map(value => value.dimensionValuesWithInventory)));\r\n const hasAvailableProducts = !ArrayExtensions.hasElements(dimensionValuesWithInventory) || dimensionValuesWithInventory.some(\r\n value => {\r\n const inventoryLevelCode = getInventoryLevelCodeFromDimensionValue(value, ctx.requestContext.app.config.inventoryLevel);\r\n return inventoryLevelCode !== InventoryLevelValues.outOfStock;\r\n }\r\n );\r\n\r\n return hasAvailableProducts;\r\n });\r\n}\r\n\r\n//==========================================================\r\n//==========================================================\r\nasync function getSubstituteProductsAction(input: GetSubstituteProductInput, ctx: Msdyn365.IActionContext): Promise {\r\n\r\n // If we don't have a related products list name, we can't do anything\r\n if (!input.context.config?.productCollection) {\r\n return undefined;\r\n }\r\n\r\n // // @REMOVEME/dg: DEBUG!\r\n // ctx.requestContext.app.config.enableStockCheck = true;\r\n // ctx.requestContext.app.config.inventoryLevel = 'totalAvailable';\r\n\r\n // Fetch the related products list\r\n // The get-related-products data action returns FullProduct results, which is more info than needed. Use a more lightweight solution.\r\n // @ts-expect-error\r\n input.context.config.relationType = input.context.config.productCollection;\r\n const relatedProductsInput = createGetRelatedProductsMinimalInput(input.context);\r\n let relatedProducts = await getRelatedProductsMinimalAction(relatedProductsInput, ctx);\r\n\r\n // Pull the record IDs from the related product list and truncate to a max length of maxProductsToShow\r\n const productList = relatedProducts && relatedProducts.map(entry => entry.RecordId).slice(0, input.context.config.maxProductsToShow);\r\n if (!productList || !productList.length) {\r\n return;\r\n }\r\n\r\n // Filter out products with no availability (only if inventory checking is enabled)\r\n if (ctx.requestContext.app.config.enableStockCheck) {\r\n\r\n // Fetch availability information for the products in the list\r\n const availabilities = await getAvailabilities(productList, ctx);\r\n\r\n // Filter out unavailable products\r\n relatedProducts = relatedProducts.filter((product, index) => {\r\n return availabilities[index];\r\n });\r\n }\r\n\r\n return relatedProducts;\r\n}\r\n\r\n//==============================================================================\r\n//==============================================================================\r\nexport default Msdyn365.createObservableDataAction({\r\n action: >getSubstituteProductsAction,\r\n id: 'substitute-products/GetSubstituteProducts',\r\n input: createSubstituteProductsInput\r\n});\r\n","//==============================================================================\r\n// Displays one or more substitute products if the current product is out of stock\r\n//\r\n// Design decisions:\r\n// Show if any variants are out of stock? Or just the currently selected variant?\r\n// Needs to work in conjunction with \"inventory visibility\" feature -- ensure\r\n// that one operates the data action level -- PROBABLY NOT POSSIBLE\r\n//\r\n// Start loading the products during initial client render\r\n// Toggle display based on inventory of current product\r\n// Wrap the Add to Cart component's shouldShowOutOfStock function to determine visibility\r\n// Don't emit events related to the loading checks -- leave display as-is.\r\n// For all others, use results of shouldShowOutOfStock\r\n//==============================================================================\r\nimport * as React from 'react';\r\nimport { observer } from 'mobx-react';\r\n\r\nimport { ProductSearchResult } from '@msdyn365-commerce/retail-proxy';\r\n\r\nimport { ISubstituteProductsData } from './substitute-products.data';\r\nimport { ISubstituteProductsProps } from './substitute-products.props.autogenerated';\r\n\r\n//==============================================================================\r\n// INTERFACES\r\n//==============================================================================\r\nexport interface ISubstituteProductsViewProps extends ISubstituteProductsProps {\r\n productList: SubstituteProduct[] | undefined;\r\n showSubstitute: Boolean;\r\n}\r\n\r\nexport interface SubstituteProduct {\r\n name: string;\r\n id: number;\r\n price: string | undefined;\r\n}\r\n\r\n//==============================================================================\r\n// CLASS DEFINITION\r\n//==============================================================================\r\n/**\r\n *\r\n * SubstituteProducts component\r\n * @extends {React.Component>}\r\n */\r\n@observer\r\nclass SubstituteProducts extends React.Component> {\r\n\r\n //----------------------------------------------------------\r\n //----------------------------------------------------------\r\n public render(): JSX.Element | null {\r\n\r\n const isAvailable = this.props.data.sharedAvailabilityState.result?.isAvailable;\r\n\r\n // Create the view props\r\n const viewProps: ISubstituteProductsViewProps = {\r\n ...this.props,\r\n productList: this.constructProductList(),\r\n showSubstitute: !isAvailable,\r\n };\r\n\r\n // Pass along to the view\r\n return this.props.renderView(viewProps);\r\n }\r\n\r\n //----------------------------------------------------------\r\n //----------------------------------------------------------\r\n private constructProductList(): SubstituteProduct[] | undefined {\r\n if (this.props.data.substituteProducts.result) {\r\n const output = this.props.data.substituteProducts.result.map(entry => ({\r\n name: entry.Name || '',\r\n id: entry.RecordId,\r\n price: this.formatPrice(entry),\r\n }));\r\n\r\n // Limit to requested number of entries\r\n return output.slice(0, this.props.config.maxProductsToShow);\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n //----------------------------------------------------------\r\n //----------------------------------------------------------\r\n private formatPrice(product: ProductSearchResult): string {\r\n const format = this.props.context.cultureFormatter.formatCurrency;\r\n\r\n // Determine if we should use min/max or price\r\n if (product.MinVariantPrice && product.MaxVariantPrice) {\r\n\r\n // If min and max are the same, display either one\r\n if (product.MinVariantPrice === product.MaxVariantPrice) {\r\n return format(product.MinVariantPrice);\r\n }\r\n\r\n // We have a range -- this hard-codes the format which isn't ideal!\r\n return `${format(product.MinVariantPrice)} - ${format(product.MaxVariantPrice)}`;\r\n }\r\n\r\n // If there's a price, use it\r\n if (product.Price) {\r\n return format(product.Price);\r\n }\r\n\r\n // There's no price. Use the No Price string from resources.\r\n // If would be much better to pull this from an existing module, but that's a bit challenging.\r\n return this.props.resources.priceFree;\r\n }\r\n}\r\n\r\nexport default SubstituteProducts;\r\n","//==============================================================================\r\n//==============================================================================\r\nimport * as React from 'react';\r\nimport classnames from 'classnames';\r\n\r\nimport * as Msdyn365 from '@msdyn365-commerce/core';\r\n\r\nimport { ISubstituteProductsViewProps, SubstituteProduct } from './substitute-products';\r\nimport { IHeadingData } from './substitute-products.props.autogenerated';\r\n\r\n//==============================================================================\r\n//==============================================================================\r\nconst BASE_CLASS = 'substitute-products';\r\nconst cls = (fragment: string) => `${BASE_CLASS}__${fragment}`;\r\n\r\n//==============================================================================\r\n//==============================================================================\r\n\r\n//==========================================================\r\n// Construct the header node\r\n//==========================================================\r\nfunction constructHeader(heading: IHeadingData): React.ReactNode {\r\n\r\n return heading.text && (\r\n \r\n );\r\n}\r\n\r\n//==========================================================\r\n// Constructs the list of substitutes\r\n//==========================================================\r\nfunction constructEntries(list: SubstituteProduct[]): React.ReactNode {\r\n\r\n // Create 1 or more entries -- we checked for 0 entries externally\r\n return list.map(entry => (\r\n
\r\n {entry.name}\r\n
{entry.price}
\r\n
\r\n ));\r\n}\r\n\r\n//==========================================================\r\n// The main render function\r\n//==========================================================\r\nexport default (props: ISubstituteProductsViewProps) => {\r\n\r\n // Ensure we have something to show\r\n if (!props.productList || !props.productList.length) {\r\n return null;\r\n }\r\n\r\n return (\r\n
\r\n {props.config.heading && constructHeader(props.config.heading)}\r\n {constructEntries(props.productList)}\r\n
\r\n );\r\n};\r\n","const binding = { modules: {}, dataActions: {} };\n\n const registerActionId = (actionPath) => {\n if (binding.dataActions[actionPath] &&\n binding.dataActions[actionPath].default &&\n binding.dataActions[actionPath].default.prototype &&\n binding.dataActions[actionPath].default.prototype.id) {\n binding.dataActions[binding.dataActions[actionPath].default.prototype.id] = binding.dataActions[actionPath];\n } else {\n Object.keys(binding.dataActions[actionPath] || {}).forEach(exportName => {\n if (binding.dataActions[actionPath][exportName] &&\n binding.dataActions[actionPath][exportName].prototype &&\n binding.dataActions[actionPath][exportName].prototype.Action) {\n binding.dataActions[binding.dataActions[actionPath][exportName].prototype.id] = binding.dataActions[actionPath][exportName];\n }\n })\n }\n };\n\n const registerSanitizedActionPath = (sanitizedActionPath, dataAction) => {\n if (process.env.NODE_ENV === 'development') {\n if (!dataAction.default) {\n throw new Error('Data action path does not have a default export');\n }\n if (!(dataAction.default.prototype.id && binding.dataActions[dataAction.default.prototype.id]) || !binding.dataActions[sanitizedActionPath]) {\n binding.dataActions[sanitizedActionPath] = dataAction;\n }\n } else {\n binding.dataActions[sanitizedActionPath] = dataAction;\n if (!binding.dataActions[sanitizedActionPath].default) {\n throw new Error('Data action path ' + sanitizedActionPath + ' does not have a default export');\n }\n binding.dataActions[sanitizedActionPath].default.prototype.RegistrationId = sanitizedActionPath;\n if (binding.dataActions[sanitizedActionPath].default.prototype.id) {\n binding.dataActions[binding.dataActions[sanitizedActionPath].default.prototype.id] = sanitizedActionPath;\n }\n }\n };\n \n\n (binding.modules['substitute-products'] = {\n c: () => require('partner/modules/substitute-products/substitute-products.tsx'),\n $type: 'contentModule',\n da: [{name:'sharedAvailabilityState', path:'actions/shared-availability-state', runOn: 0},{name:'substituteProducts', path:'modules/substitute-products/actions/get-substitute-products', runOn: 1}],\n \n iNM: false,\n ns: '__local__',\n n: 'substitute-products',\n p: '__local__',\n \n pdp: '',\n \n \n md: 'src/modules/substitute-products'\n });\n \n\n {\n const sanitizedActionPath = 'actions/shared-availability-state';\n let dataAction = require('partner/actions/shared-availability-state');\n registerSanitizedActionPath(sanitizedActionPath, dataAction);\n }\n \n\n {\n const sanitizedActionPath = 'modules/substitute-products/actions/get-substitute-products';\n let dataAction = require('partner/modules/substitute-products/actions/get-substitute-products');\n registerSanitizedActionPath(sanitizedActionPath, dataAction);\n }\n \n\n \n window.__bindings__ = window.__bindings__ || {};\n window.__bindings__.modules = {\n ...window.__bindings__.modules || {},\n ...binding.modules\n };\n \n window.__bindings__.dataActions = {\n ...window.__bindings__.dataActions || {},\n ...binding.dataActions\n };\n export const viewDictionary = {};\n viewDictionary['__local__|__local__|modules|substitute-products|substitute-products'] = {\n c: () => require('partner/modules/substitute-products/substitute-products.view.tsx'),\n cn: '__local__-__local__-substitute-products'\n };\nwindow.__bindings__ = window.__bindings__ || {};\nwindow.__bindings__.viewDictionary = {\n ...window.__bindings__.viewDictionary || {},\n ...viewDictionary\n };","module.exports = React;","module.exports = ReactDOM;"],"names":["SharedAvailabilityInput","constructor","getCacheKey","getCacheObjectType","dataCacheType","createInput","actionContext","SharedAvailability","isAvailable","async","sharedAvailabilityAction","input","ctx","Msdyn365","action","GetRelatedProductsInput","productId","catalogId","relationType","queryResultSettingsProxy","criteria","this","toLowerCase","cacheKeyHint","ProductDetailsCriteria","createGetRelatedProductsMinimalInput","inputData","requestContext","config","apiSettings","urlTokens","Number","recordId","productDetailsCriteria","getPrice","hidePrice","getRating","hideRating","getProductDetailsCriteriaFromActionInput","Error","query","isNaN","QueryResultSettingsProxy","fromInputData","getRelatedProductsMinimalAction","querySettings","QueryResultSettings","productRelationTypes","getRelationTypesAsync","callerContext","queryResultSettings","channelId","trace","productRelationTypeId","_productRelationType","foundProductRelationTypeId","forEach","productRelationType","Name","RecordId","searchProductRelationType","getRelatedProductsAsync","createObservableDataAction","id","GetSubstituteProductInput","context","_this$context$config","_this$context$config2","productCollection","maxProductsToShow","_input$context$config","relatedProductsInput","relatedProducts","productList","map","entry","slice","length","app","enableStockCheck","availabilities","promises","GetDimensionsForSelectedVariantInput","getDimensionsForSelectedVariantAction","Promise","all","dimensionValuesWithInventory","ArrayExtensions","flatten","validValues","value","hasElements","some","getInventoryLevelCodeFromDimensionValue","inventoryLevel","InventoryLevelValues","outOfStock","getAvailabilities","filter","product","index","SubstituteProducts","React","render","_this$props$data$shar","props","data","sharedAvailabilityState","result","viewProps","_objectSpread","constructProductList","showSubstitute","renderView","substituteProducts","name","price","formatPrice","format","cultureFormatter","formatCurrency","MinVariantPrice","MaxVariantPrice","Price","resources","priceFree","__decorate","observer","BASE_CLASS","cls","fragment","className","classnames","hidden","heading","text","tag","key","href","binding","modules","dataActions","registerSanitizedActionPath","sanitizedActionPath","dataAction","default","prototype","RegistrationId","c","require","$type","da","path","runOn","iNM","ns","n","p","pdp","md","window","__bindings__","viewDictionary","cn","module","exports","ReactDOM"],"sourceRoot":""}