{"version":3,"file":"static/js/9641c9d1f60623285132.bundle.js","mappings":"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","sources":["webpack://united-malt/./src/actions/get-localized-attributes.ts?7444","webpack://united-malt/./src/modules/pdp-attributes-localized/pdp-attributes-localized.tsx?0bc7","webpack://united-malt/./src/utilities/data-attribute-parser.ts?7345","webpack://united-malt/./lib/pdp-attributes-localized/module-registration.js?6ec4","webpack://united-malt/external var \"React\"?0d3b","webpack://united-malt/external var \"ReactDOM\"?853b"],"sourcesContent":["//==============================================================================\r\n//==============================================================================\r\nimport { CacheType, createObservableDataAction, ICommerceApiSettings, IAction, IActionContext, IActionInput, IAny, ICreateActionContext, IGeneric, getCatalogId } from '@msdyn365-commerce/core';\r\nimport { AttributeValue, ProductSearchCriteria } from '@msdyn365-commerce/retail-proxy';\r\nimport { searchByCriteriaAsync, getAttributeValuesAsync } from '@msdyn365-commerce/retail-proxy/dist/DataActions/ProductsDataActions.g';\r\nimport { getSelectedProductIdFromActionInput, buildCacheKey } from '@msdyn365-commerce-modules/retail-actions';\r\n\r\n//==========================================================\r\n//==========================================================\r\nexport class GetLocalizedAttributesInput implements IActionInput {\r\n\r\n public productId: number;\r\n\r\n public channelId: number;\r\n\r\n private apiSettings: ICommerceApiSettings;\r\n\r\n private locale: string;\r\n\r\n constructor(productId: number, channelId: number, apiSettings: ICommerceApiSettings, locale: string) {\r\n this.productId = productId;\r\n this.channelId = channelId;\r\n this.apiSettings = apiSettings;\r\n this.locale = locale;\r\n }\r\n\r\n public getCacheKey = () => buildCacheKey(`LocalAttributes-${this.productId}`, this.apiSettings, this.locale);\r\n\r\n public getCacheObjectType = () => 'LocalAttributes';\r\n\r\n public dataCacheType = (): CacheType => 'application';\r\n\r\n}\r\n\r\n//==========================================================\r\n//==========================================================\r\nexport const createGetLocalizedAttributesInput = (inputData: ICreateActionContext>): IActionInput => {\r\n\r\n const productId = getSelectedProductIdFromActionInput(inputData);\r\n if (productId) {\r\n return new GetLocalizedAttributesInput(+productId, +inputData.requestContext.apiSettings.channelId, inputData.requestContext.apiSettings, inputData.requestContext.locale);\r\n }\r\n throw new Error('No productId found on query, unable to get product attributes');\r\n\r\n};\r\n\r\n//==========================================================\r\n//==========================================================\r\nexport async function getLocalizedAttributesAction(input: GetLocalizedAttributesInput, ctx: IActionContext): Promise {\r\n\r\n const catalogId = getCatalogId(ctx.requestContext);\r\n\r\n // Build a ProductSearchCriteria object\r\n const criteria: ProductSearchCriteria = {\r\n Ids: [input.productId],\r\n IncludeProductsFromDescendantCategories: false,\r\n SkipVariantExpansion: true,\r\n IncludeAttributes: true,\r\n Context: {\r\n ChannelId: input.channelId,\r\n CatalogId: catalogId\r\n }\r\n };\r\n\r\n // Fetch search results containing attribute internal names\r\n const productSearchResult = await searchByCriteriaAsync({ callerContext: ctx }, criteria);\r\n const product = productSearchResult[0];\r\n\r\n // Reformat product search attributes for easier lookup\r\n const internalNameAttributeMap = {};\r\n product?.AttributeValues?.forEach(attr => {\r\n if (attr.RecordId) {\r\n internalNameAttributeMap[attr.RecordId] = attr.Name;\r\n }\r\n });\r\n\r\n const attributesWithFriendlyName = await getAttributeValuesAsync({ callerContext: ctx, queryResultSettings: {} }, product.RecordId, input.channelId, catalogId);\r\n\r\n // Combines product search attributes internal name with result\r\n attributesWithFriendlyName.forEach(attr => {\r\n if (attr.RecordId) {\r\n attr.KeyName = internalNameAttributeMap[attr.RecordId];\r\n }\r\n });\r\n\r\n return attributesWithFriendlyName;\r\n\r\n}\r\n\r\n//==============================================================================\r\n//==============================================================================\r\nexport default createObservableDataAction({\r\n action: >getLocalizedAttributesAction,\r\n id: 'get-localized-attributes',\r\n input: createGetLocalizedAttributesInput\r\n});\r\n","//==============================================================================\r\n// PDP Attributes Localized\r\n//\r\n// Renders a pre-configured list of attributes of the current page's product.\r\n// Clone of PDP Attributes module that combines friendly name and internal names\r\n// of attributes to support multi-language sites.\r\n//==============================================================================\r\nimport * as React from 'react';\r\nimport classnames from 'classnames';\r\n\r\nimport { RichTextComponent } from '@msdyn365-commerce/core';\r\nimport { Button } from '@msdyn365-commerce-modules/utilities';\r\nimport { AttributeValue, SimpleProduct, IDictionary } from '@msdyn365-commerce/retail-proxy';\r\n\r\nimport { convertProductAttributesLocalized, AttributesLocalized, CommerceValueTypes } from '../../utilities/data-attribute-parser';\r\nimport { IPdpAttributesLocalizedData } from './pdp-attributes-localized.data';\r\nimport { IAttributesData, IPdpAttributesLocalizedProps, IPdpAttributesLocalizedResources } from './pdp-attributes-localized.props.autogenerated';\r\n\r\n//==============================================================================\r\n// INTERFACES AND CONSTANTS\r\n//==============================================================================\r\n\r\n// Return type for _parseAttribute()\r\ntype ParsedAttribute> = {\r\n name: string,\r\n value: T,\r\n type: string\r\n};\r\n\r\n//==============================================================================\r\n// CLASS NAME UTILITY\r\n//==============================================================================\r\nconst BASE_CLASS = 'pdp-attributes';\r\nconst cls = (fragment: string) => `${BASE_CLASS}__${fragment}`;\r\n\r\n//==============================================================================\r\n// CLASS DEFINITION\r\n//==============================================================================\r\n/**\r\n * PdpAttributesLocalized component\r\n * @extends {React.Component>}\r\n */\r\n//==============================================================================\r\nclass PdpAttributesLocalized extends React.Component> {\r\n private combinedAttributes: AttributesLocalized | undefined;\r\n\r\n //==========================================================================\r\n // PUBLIC METHODS\r\n //==========================================================================\r\n\r\n //------------------------------------------------------\r\n // Render function\r\n //------------------------------------------------------\r\n public render(): JSX.Element {\r\n const productSimpleData = this.props.data.product.result;\r\n const productSpecificationData = this.props.data.productSpecificationData.result;\r\n\r\n return (\r\n
\r\n {productSpecificationData && productSimpleData && this._getAttributesList(productSimpleData, productSpecificationData)}\r\n
\r\n );\r\n }\r\n\r\n //==========================================================================\r\n // PRIVATE METHODS\r\n //==========================================================================\r\n\r\n //------------------------------------------------------\r\n // Gets converted attributes, combines pseudo simple\r\n // attributes, and renders attributes list\r\n //------------------------------------------------------\r\n private _getAttributesList(productSimpleData: SimpleProduct, productSpecificationData: AttributeValue[]): JSX.Element {\r\n if (!this.combinedAttributes) {\r\n const convertedAttributes = convertProductAttributesLocalized(productSpecificationData);\r\n\r\n if (convertedAttributes) {\r\n this.combinedAttributes = this._appendPseudoSimpleAttributes(productSimpleData, convertedAttributes);\r\n }\r\n }\r\n\r\n return this._renderAttributesList();\r\n }\r\n\r\n //------------------------------------------------------\r\n // Appends reformatted pseudo simple attributes to\r\n // combined attributes object\r\n //------------------------------------------------------\r\n private _appendPseudoSimpleAttributes(simpleProduct: SimpleProduct, convertedAttributes: AttributesLocalized): AttributesLocalized {\r\n this.props.config.attributes.map((attr) => {\r\n if (simpleProduct[attr.attributeName]) {\r\n convertedAttributes[attr.attributeName] = simpleProduct[attr.attributeName];\r\n convertedAttributes.meta[attr.attributeName] = 'string';\r\n }\r\n });\r\n\r\n return convertedAttributes;\r\n }\r\n\r\n //------------------------------------------------------\r\n // Returns JSX of the attribute list's render\r\n //------------------------------------------------------\r\n private _renderAttributesList(): JSX.Element {\r\n return (\r\n \r\n {this.props.config.attributes.map((attr, index) => {\r\n return (\r\n \r\n {this._renderAttribute(attr)}\r\n \r\n );\r\n })}\r\n \r\n );\r\n }\r\n\r\n //------------------------------------------------------\r\n // Returns JSX of a specific attribute's render\r\n //------------------------------------------------------\r\n private _renderAttribute(cmsAttribute: IAttributesData): JSX.Element | null {\r\n const attribute = this._parseAttribute(cmsAttribute.attributeName);\r\n\r\n // Do not render if attribute doesn't exist or has no value\r\n if (!attribute || (!attribute.value && attribute.value !== 0 && attribute.value !== false)) {\r\n return null;\r\n }\r\n\r\n // Do not render if hideFalse is checked and attribute value is false\r\n if (cmsAttribute.hideFalse && attribute.value === false) {\r\n return null;\r\n }\r\n\r\n // Pipeline for rendering based on attribute type\r\n const attributeType = {\r\n string: this._richtextRender,\r\n number: this._plaintextRender,\r\n Date: this._dateRender,\r\n boolean: this._booleanRender,\r\n url: this._urlRender\r\n };\r\n\r\n // Differentiates url type from string type\r\n let type = attribute.type;\r\n if (attribute.value?.toString().startsWith('https://' || 'http://')) {\r\n type = 'url';\r\n }\r\n\r\n // Function call to render attribute via pipeline\r\n const renderedAttribute = attributeType[type](attribute, cmsAttribute, this.props.resources);\r\n // this.props.resources is not accessible in the individual render\r\n // functions for some reason, so had to be passed through as a parameter\r\n\r\n return this._renderCell(renderedAttribute, cmsAttribute, attribute.name);\r\n }\r\n\r\n //------------------------------------------------------\r\n // Renders rich text attribute\r\n //------------------------------------------------------\r\n private _richtextRender(text: ParsedAttribute, cmsAttribute: IAttributesData): JSX.Element | null {\r\n return ;\r\n }\r\n\r\n //------------------------------------------------------\r\n // Renders plain text attribute\r\n //------------------------------------------------------\r\n private _plaintextRender(text: ParsedAttribute, cmsAttribute: IAttributesData): JSX.Element | null {\r\n return {text.value}{cmsAttribute.suffixText || ''};\r\n }\r\n\r\n //------------------------------------------------------\r\n // Renders date attribute\r\n //------------------------------------------------------\r\n private _dateRender(date: ParsedAttribute, cmsAttribute: IAttributesData): JSX.Element {\r\n return {new Date(date.value).toUTCString()}{cmsAttribute.suffixText};\r\n }\r\n\r\n //------------------------------------------------------\r\n // Renders boolean attribute\r\n //------------------------------------------------------\r\n private _booleanRender(bool: ParsedAttribute, cmsAttribute: IAttributesData, resources: IPdpAttributesLocalizedResources): JSX.Element {\r\n const booleanTrue = resources.pdpAttributes_booleanTrue;\r\n const booleanFalse = resources.pdpAttributes_booleanFalse;\r\n return (\r\n \r\n {bool.value ? booleanTrue : booleanFalse}\r\n \r\n );\r\n }\r\n\r\n //------------------------------------------------------\r\n // Renders URL attribute in the form of a CTA button\r\n //------------------------------------------------------\r\n private _urlRender(url: ParsedAttribute, cmsAttribute: IAttributesData): JSX.Element {\r\n return (\r\n \r\n );\r\n }\r\n\r\n //------------------------------------------------------\r\n // Renders div containing each attribute\r\n //------------------------------------------------------\r\n private _renderCell(cellBody: JSX.Element, cmsAttribute: IAttributesData, friendlyName: string): JSX.Element {\r\n const attributeName = cmsAttribute.labelOverride || friendlyName;\r\n\r\n return (\r\n
\r\n {!cmsAttribute.noLabel &&
{attributeName}
}\r\n
\r\n {cellBody}\r\n
\r\n
\r\n );\r\n }\r\n\r\n //------------------------------------------------------\r\n // Parses and returns the attribute value queried\r\n //------------------------------------------------------\r\n private _parseAttribute(name: string): ParsedAttribute {\r\n return {\r\n name: this.combinedAttributes![name]?.friendlyName || '',\r\n value: this.combinedAttributes![name]?.value || '',\r\n type: this.combinedAttributes!.meta[name]\r\n };\r\n }\r\n}\r\n\r\nexport default PdpAttributesLocalized;\r\n","//==============================================================================\r\n// D365 OData Attribute Parser\r\n//\r\n// In creating this, it became clear that \"attributes\" is a general term.\r\n//\r\n// Product attributes are a first-class entity. They have their own dedicated\r\n// fields and schema.\r\n//\r\n// The more generic term \"attributes\" is used as a generic extension system.\r\n// Almost every entity (including Product Attributes) has an ExtensionProperties\r\n// field for jamming extra information into. In some cases, D365 handles these\r\n// natively, such as sales order line and header attributes, or customer\r\n// attributes. Attributes using ExtensionProperties use the\r\n// CommerceProperty and CommercePropertyValue types.\r\n//\r\n// A major note about ExtensionProperty-based attributes: they have fields\r\n// for many different data types, but there's no indicator as to which\r\n// of the fields is actually used. The consumer of the data is expected to\r\n// know the data type ahead of time. In the case of D365-native attribute users\r\n// such as customers and sales orders, only the string type appears to work.\r\n//\r\n// This module includes parsers for generic ExtensionProperties-based attributes\r\n// and Product Attributes. Though different Product Attribute retail server\r\n// calls use the same AttributeValue entity to transmit the data, they appear\r\n// to return different fields from that entity. Because of this, two different\r\n// parser calls are included here. They currently share the same implementation,\r\n// but by including different call signatures we have the ability to diverge\r\n// the implementations if the need arises.\r\n//\r\n// A note about Product Attributes: These contain both a friendly name,\r\n// displayed to users in back office, and an internal name. The internal name\r\n// can be the same as the friendly name, but by convention we've been pushing\r\n// for a PascalCase scheme. At present, the searchByCriteria call returns only\r\n// the unfriendly name, and the GetAttributeValues call returns only the\r\n// friendly name. We don't have a known method of correlating the two. That may\r\n// be an argument for keeping the friendly and unfriendly names identical.\r\n//==============================================================================\r\nimport {\r\n CommerceProperty, // Generic attributes stored in ExtensionProperties\r\n CommercePropertyValue, // Generic attributes stored in AttributeValue\r\n AttributeValue, AttributeDataType, // Product attributes or Product Search Result attributes\r\n CustomerAttribute, // Customer attributes\r\n IDictionary,\r\n} from '@msdyn365-commerce/retail-proxy';\r\n\r\n//==============================================================================\r\n// INTERFACES AND CONSTANTS\r\n//==============================================================================\r\nexport type CommerceValueTypes = string | number | boolean | Date;\r\n\r\n// This is me giving up on proper typing. If doing this in TypeScript is possible, I don't know how.\r\n// For the key \"meta\", the type should be a hash of strings.\r\n// For all other keys, the type is a CommerceValueType.\r\nexport type AttributesWithMetadata = {\r\n [key: string]: CommerceValueTypes | IDictionary\r\n};\r\n\r\n// Type to support both internal and friendly name for attributes\r\nexport type AttributesLocalized = {\r\n [key: string]: {\r\n friendlyName?: string,\r\n value?: CommerceValueTypes | IDictionary\r\n }\r\n};\r\n\r\n// Return type for getTypeInfo()\r\ntype TypeData = {\r\n source: keyof AttributeValue,\r\n type: string,\r\n\r\n customerSource?: keyof CommercePropertyValue,\r\n};\r\n\r\n//==============================================================================\r\n// FUNCTIONS\r\n//==============================================================================\r\n\r\n//----------------------------------------------------------\r\n// This version handles ExtensionProperties conversion.\r\n//\r\n// While these have a bunch of potential fields, the value\r\n// is always stored within StringValue.\r\n// There isn't a data type field, so if the content wasn't\r\n// in StringValue we wouldn't know where to find it.\r\n//----------------------------------------------------------\r\nexport function convertExtensionProperties(attributeList: CommerceProperty[]): IDictionary {\r\n const output = {};\r\n\r\n attributeList.forEach(entry => {\r\n if (entry.Key) {\r\n output[entry.Key] = entry.Value?.StringValue; // Ecommerce seems to always use strings.\r\n }\r\n });\r\n\r\n return output;\r\n}\r\n\r\n//----------------------------------------------------------\r\n// For these attributes, the Name is always the friendly\r\n// name.\r\n// KeyName and ExtensionProperties aren't defined.\r\n//\r\n// These results seem to be missing CurrencyValue,\r\n// FloatValue, DateTimeOffsetValue\r\n// I don't know if those data types aren't allowed here.\r\n//\r\n// Return value: Hash of key: property values with variable\r\n// types. There is also a \"meta\" key containing a hash of\r\n// all the attribute keys and their corresponding types.\r\n//\r\n// Example:\r\n// {\r\n// flavor: 'bland',\r\n// calories: 5300,\r\n// meta: {\r\n// flavor: 'string',\r\n// calories: 'number'\r\n// }\r\n// }\r\n//----------------------------------------------------------\r\nexport function convertProductAttributes(attributeList: AttributeValue[]): AttributesWithMetadata {\r\n const output = {\r\n meta: {}\r\n };\r\n\r\n attributeList.forEach(attribute => {\r\n // These should always be present, but TypeScript insists they can be undefined.\r\n if (attribute.Name && attribute.DataTypeValue) {\r\n const typeData = getTypeInfo(attribute.DataTypeValue);\r\n output[attribute.Name] = attribute[typeData.source]; // Ecommerce seems to require strings\r\n output.meta[attribute.Name] = typeData.type;\r\n }\r\n });\r\n\r\n return output;\r\n}\r\n\r\n//----------------------------------------------------------\r\n// For these attributes, the\r\n// Name/KeyName/ExtensionProperties is always the unfriendly\r\n// name.\r\n//\r\n// These results are only missing the Swatches field.\r\n//\r\n// Though the returned value is a bit different, at present\r\n// the implementation for convertProductAttributes works for\r\n// search results.\r\n// If they diverge in the future, extend this function.\r\n//----------------------------------------------------------\r\nexport function convertSearchAttributes(attributeList: AttributeValue[]): AttributesWithMetadata {\r\n return convertProductAttributes(attributeList);\r\n}\r\n\r\n//----------------------------------------------------------\r\n// For these attributes, the Name is the friendly\r\n// name while KeyName is the internal name.\r\n//\r\n// This makes use of combined attributes containing both\r\n// internal and friendly name to support localization.\r\n//\r\n// Return value: Hash of internal name keys containing an object with both the\r\n// friendly name and attribute value There is also a \"meta\" key containing a\r\n// hash of all the attribute keys and their corresponding types.\r\n//\r\n// Example:\r\n// {\r\n// flavor: {\r\n// friendlyName: Flavor,\r\n// value: 'bland'\r\n// },\r\n// calories: {\r\n// friendlyName: Calories,\r\n// value: 5300\r\n// },\r\n// meta: {\r\n// flavor: 'string',\r\n// calories: 'number'\r\n// }\r\n// }\r\n//----------------------------------------------------------\r\nexport function convertProductAttributesLocalized(attributeList: AttributeValue[]): AttributesLocalized {\r\n const output = {\r\n meta: {}\r\n };\r\n\r\n attributeList.forEach(attribute => {\r\n if (attribute.KeyName && attribute.DataTypeValue) {\r\n const typeData = getTypeInfo(attribute.DataTypeValue);\r\n output[attribute.KeyName] = {\r\n friendlyName: attribute.Name,\r\n value: attribute[typeData.source]\r\n };\r\n output.meta[attribute.KeyName] = typeData.type;\r\n }\r\n });\r\n\r\n return output;\r\n}\r\n\r\n//----------------------------------------------------------\r\n//----------------------------------------------------------\r\nexport function convertCustomerAttributes(attributeList: CustomerAttribute[] | undefined): AttributesWithMetadata {\r\n const output = {\r\n meta: {}\r\n };\r\n\r\n attributeList?.forEach(attribute => {\r\n // These should always be present, but TypeScript insists they can be undefined.\r\n if (attribute.Name && attribute.DataTypeValue) {\r\n const typeData = getTypeInfo(attribute.DataTypeValue);\r\n output[attribute.Name] = attribute.AttributeValue && typeData.customerSource && attribute.AttributeValue[typeData.customerSource];\r\n output.meta[attribute.Name] = typeData.type;\r\n }\r\n });\r\n\r\n return output;\r\n}\r\n\r\n//----------------------------------------------------------\r\n// Finds the source field and type for an attribute\r\n//\r\n// This should probably be extended to better support\r\n// currency, which seems to be two fields glued together.\r\n//----------------------------------------------------------\r\nfunction getTypeInfo(type: AttributeDataType): TypeData {\r\n\r\n // Awkward, but this helps TypeScript enforce strict type checking\r\n type TypeMapType = {\r\n [key in AttributeDataType]: TypeData\r\n };\r\n\r\n const typeMap: TypeMapType = {\r\n [AttributeDataType.None]: {source: 'TextValue', type: 'string'}, // We need to choose something\r\n [AttributeDataType.Currency]: {source: 'CurrencyValue', type: 'number'}, // Should also include CurrencyCode, which is a string?\r\n [AttributeDataType.DateTime]: {source: 'DateTimeOffsetValue', type: 'Date'},\r\n [AttributeDataType.Decimal]: {source: 'FloatValue', type: 'number'},\r\n [AttributeDataType.Integer]: {source: 'IntegerValue', type: 'number', customerSource: 'IntegerValue'},\r\n [AttributeDataType.Text]: {source: 'TextValue', type: 'string', customerSource: 'StringValue'},\r\n [AttributeDataType.TrueFalse]: {source: 'BooleanValue', type: 'boolean', customerSource: 'BooleanValue'},\r\n [AttributeDataType.Video]: {source: 'TextValue', type: 'string'},\r\n [AttributeDataType.Image]: {source: 'TextValue', type: 'string'}\r\n };\r\n\r\n return typeMap[type];\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['pdp-attributes-localized'] = {\n c: () => require('partner/modules/pdp-attributes-localized/pdp-attributes-localized.tsx'),\n $type: 'contentModule',\n da: [{name:'product', path:'@msdyn365-commerce-modules/retail-actions/dist/lib/get-selected-variant', runOn: 0},{name:'productSpecificationData', path:'actions/get-localized-attributes', runOn: 0}],\n \n iNM: false,\n ns: '__local__',\n n: 'pdp-attributes-localized',\n p: '__local__',\n \n pdp: '',\n \n \n md: 'src/modules/pdp-attributes-localized'\n });\n \n\n {\n const sanitizedActionPath = '@msdyn365-commerce-modules/retail-actions/dist/lib/get-selected-variant';\n let dataAction = require('@msdyn365-commerce-modules/retail-actions/dist/lib/get-selected-variant');\n registerSanitizedActionPath(sanitizedActionPath, dataAction);\n }\n \n\n {\n const sanitizedActionPath = 'actions/get-localized-attributes';\n let dataAction = require('partner/actions/get-localized-attributes');\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 };","module.exports = React;","module.exports = ReactDOM;"],"names":["GetLocalizedAttributesInput","constructor","productId","channelId","apiSettings","locale","getCacheKey","buildCacheKey","this","getCacheObjectType","dataCacheType","createGetLocalizedAttributesInput","inputData","getSelectedProductIdFromActionInput","requestContext","Error","async","getLocalizedAttributesAction","input","ctx","_product$AttributeVal","catalogId","getCatalogId","criteria","Ids","IncludeProductsFromDescendantCategories","SkipVariantExpansion","IncludeAttributes","Context","ChannelId","CatalogId","product","searchByCriteriaAsync","callerContext","internalNameAttributeMap","AttributeValues","forEach","attr","RecordId","Name","attributesWithFriendlyName","getAttributeValuesAsync","queryResultSettings","KeyName","createObservableDataAction","action","id","BASE_CLASS","cls","fragment","PdpAttributesLocalized","React","render","productSimpleData","props","data","result","productSpecificationData","className","classnames","config","_getAttributesList","combinedAttributes","convertedAttributes","convertProductAttributesLocalized","_appendPseudoSimpleAttributes","_renderAttributesList","simpleProduct","attributes","map","attributeName","meta","index","key","_renderAttribute","cmsAttribute","_attribute$value","attribute","_parseAttribute","value","hideFalse","attributeType","string","_richtextRender","number","_plaintextRender","Date","_dateRender","boolean","_booleanRender","url","_urlRender","type","toString","startsWith","renderedAttribute","resources","_renderCell","name","text","RichTextComponent","suffixText","date","toUTCString","bool","booleanTrue","pdpAttributes_booleanTrue","booleanFalse","pdpAttributes_booleanFalse","Button","title","labelOverride","href","target","cellBody","friendlyName","noLabel","_this$combinedAttribu","_this$combinedAttribu2","convertProductAttributes","attributeList","output","DataTypeValue","typeData","getTypeInfo","source","convertCustomerAttributes","AttributeValue","customerSource","AttributeDataType","None","Currency","DateTime","Decimal","Integer","Text","TrueFalse","Video","Image","binding","modules","dataActions","registerSanitizedActionPath","sanitizedActionPath","dataAction","default","prototype","RegistrationId","c","require","$type","da","path","runOn","iNM","ns","n","p","pdp","md","window","__bindings__","_objectSpread","module","exports","ReactDOM"],"sourceRoot":""}