{"version":3,"file":"static/js/ea4ee7edf40518b6767f.bundle.js","mappings":"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","sources":["webpack://mattressfirm/./src/Utilities/allRegex.ts?9889","webpack://mattressfirm/./src/Utilities/constants.ts?8bdf","webpack://mattressfirm/./src/data-actions/utilities/utils.ts?7452","webpack://mattressfirm/./src/modules/mfrm-product-page-summary/mfrm-product-page-summary.tsx?52af","webpack://mattressfirm/./lib/mfrm-product-page-summary/module-registration.js?4480","webpack://mattressfirm/external var \"React\"?0d3b","webpack://mattressfirm/external var \"ReactDOM\"?853b"],"sourcesContent":["import { ICoreContext } from '@msdyn365-commerce/core';\r\nexport const emailRegex = (emailValue: string) => {\r\n // eslint-disable-next-line security/detect-unsafe-regex\r\n const validationEmail = /^[-a-z0-9!#$%&'*+/=?^_`{|}~]+(?:\\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[a-z0-9]+(?:-+[a-z0-9]+)*\\.)+(?:xn--[a-z0-9]+|[a-z]{2,16})$/i;\r\n\r\n return validationEmail.test(emailValue);\r\n};\r\n\r\n/**\r\n * Method to remove special characters for product name from product URL\r\n * @param str string\r\n * @param ctx ICoreContext\r\n * @returns string\r\n */\r\n\r\nexport const removeSpecialChars = (str: string, ctx: ICoreContext): string => {\r\n if (ctx && ctx.request.app?.config.removeSpecialCharsPDP) {\r\n return str?.replace(/[^a-zA-Z0-9- ]/g, '');\r\n }\r\n return str;\r\n};\r\n\r\n\r\n/**\r\n * Method to remove special characters for product URL's path\r\n * @param str string\r\n * @param ctx ICoreContext\r\n * @returns string\r\n */\r\n\r\nexport const removeSpecialCharsFromURLPath = (str: string, ctx: ICoreContext): string => {\r\n if (ctx && ctx.request.app?.config.removeSpecialCharsPDP) {\r\n const urlPath = decodeURIComponent(str.split('.p')[0])?.replace(/[^a-zA-Z0-9-/ ]/g, '');\r\n return `${urlPath}.p`;\r\n }\r\n return str;\r\n};\r\n\r\n// Following phone format is used on customer info section at checkout page\r\nexport const customerInfoPhoneRegex = /^\\(?([2-9][0-8][0-9])\\)?[ . ]?([2-9][0-9]{2})[\\-\\. ]?([0-9]{4})(\\s*x[0-9]+)?$/; // Valid USA number in format (xxx) xxx-xxxx\r\n\r\n/*\r\nThis regex object has 2 patterns:\r\n'nameRegex' matches names with letters, spaces, apostrophes, periods, and dashes.\r\n'addressInputRegex' matches alphanumeric characters and printable ASCII symbols.\r\n*/\r\nexport const inputRegexObj = {\r\n nameRegex: /^[\\p{L}\\s.'-]+$/u,\r\n addressInputRegex: /^[a-zA-Z0-9\\x20-\\x7E]*$/,\r\n phoneNumerRegex: customerInfoPhoneRegex\r\n};\r\n\r\n// This regex allows us to effectively validate and extract delivery messages\r\nexport const cartDeliveryMsgRegex = /[A-Za-z]{3} \\d{1,2}(?: - [A-Za-z]{3} \\d{1,2})?/;","export const variantQueryStringName = 'variantid';","/*--------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * See License.txt in the project root for license information.\r\n *--------------------------------------------------------------*/\r\n\r\nimport { IAny, ICommerceApiSettings, ICoreContext, ICreateActionContext, IGeneric, IRequestContext } from '@msdyn365-commerce/core';\r\nimport {\r\n AsyncResult, CartLine, CommerceListLine, ProductDimension,\r\n ProductDimensionType, ProductSearchResult, SimpleProduct\r\n} from '@msdyn365-commerce/retail-proxy';\r\n\r\nimport { ProductDetailsCriteria, InventoryLevels, ArrayExtensions } from '@msdyn365-commerce-modules/retail-actions';\r\nimport { variantQueryStringName } from '../../Utilities/constants';\r\n// import { parseSearchData } from '@msdyn365-commerce-modules/retail-actions/src/utilities/input-data-parser';\r\n\r\nexport const wrapInResolvedAsyncResult = (input: T | null | undefined): AsyncResult => {\r\n return >{\r\n status: 'SUCCESS',\r\n result: input,\r\n metadata: {}\r\n };\r\n};\r\n\r\nexport const wrapInRejectedAsyncResult = (input: T | null | undefined): AsyncResult => {\r\n return >{\r\n status: 'FAILED',\r\n result: input,\r\n metadata: {}\r\n };\r\n};\r\n\r\n\r\n/**\r\n * Utility function to extract the active productId in the following priority:\r\n * First query param (productId), then UrlToken (itemId), then module config.\r\n * @param inputData - The Action Input data.\r\n * @returns Productid or undefined.\r\n */\r\nexport const getSelectedProductIdFromActionInput = (inputData: ICreateActionContext>): string | undefined => {\r\n const context = inputData.requestContext;\r\n const variantId = context.app.config.queryBasedVariantSelection ? getQueryParamsFromQueryByName(context.url.requestUrl, variantQueryStringName) : undefined;\r\n\r\n if (variantId) {\r\n return variantId;\r\n } else if (context.query?.productId) {\r\n return context.query.productId;\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Exsiting code.\r\n } else if (context.urlTokens && inputData.requestContext.urlTokens.itemId && inputData.requestContext.urlTokens.pageType === 'Product') {\r\n return context.urlTokens.itemId;\r\n } else if (inputData && inputData.config && inputData.config.productId) {\r\n return inputData.config.productId;\r\n }\r\n return undefined;\r\n};\r\n\r\nexport const getQueryParamsFromQueryByName = (inputUrl: URL, queryParamName: string) => {\r\n const urlWithIgnoredCase = new URL(inputUrl.toString().toLocaleLowerCase());\r\n const urlParameters = urlWithIgnoredCase.searchParams;\r\n const value = urlParameters.get(queryParamName.trim().toLocaleLowerCase());\r\n if (!value || Number.isNaN(Number(value))) {\r\n return undefined;\r\n }\r\n return value;\r\n};\r\n/**\r\n * Generates a Image URL based on data return from retail server.\r\n * @param imageUrl The image url returned by Retail Server.\r\n * @param ctx The request context.\r\n * @param apiSettings\r\n */\r\nexport const generateImageUrl = (imageUrl: string | undefined, apiSettings: ICommerceApiSettings): string | undefined => {\r\n if (imageUrl) {\r\n // Images hosted in CMS include schema\r\n if (imageUrl.startsWith('http')) {\r\n return imageUrl;\r\n }\r\n\r\n // Images hosted in Retail Server must be encoded and joined with the base image url\r\n return apiSettings.baseImageUrl + encodeURIComponent(imageUrl);\r\n }\r\n\r\n // D365Commerce.telemetry.warning(`Unable to generate a proper Image URL for Product: ${product.RecordId}`);\r\n return undefined;\r\n\r\n};\r\n\r\n/**\r\n * Represents app configuration for dimensions.\r\n */\r\nexport interface IDimensionsConfig {\r\n dimensionsAsSwatchType?: DimensionTypes[];\r\n dimensionsInProductCard?: DimensionTypes[];\r\n inventoryLevel?: InventoryLevels;\r\n dimensionToPreSelectInProductCard?: DimensionTypes;\r\n}\r\n\r\n/**\r\n * Represents app configuration for dimensions.\r\n */\r\nexport interface IDimensionsApp {\r\n config: IDimensionsConfig;\r\n}\r\n\r\n/**\r\n * Represents product dimension types.\r\n */\r\nexport enum DimensionTypes {\r\n none = 'none',\r\n color = 'color',\r\n configuration = 'configuration',\r\n size = 'size',\r\n style = 'style'\r\n}\r\n\r\n/**\r\n * Defines display configuration types.\r\n */\r\nexport enum DimensionSwatchDisplayTypes {\r\n default = 'default',\r\n productCard = 'productCard'\r\n}\r\n\r\n/**\r\n * Checks if rendering the particular dimensions is allowed.\r\n * @param dimensionType - Dimension to be displayed.\r\n * @param context - Core application context.\r\n * @param displayType - The swatch location, the component from which it comes from.\r\n * @returns Updates the state with new product page url.\r\n */\r\nexport const checkIfShouldDisplayAsSwatch = (\r\n dimensionType: DimensionTypes,\r\n context: ICoreContext,\r\n displayType: DimensionSwatchDisplayTypes = DimensionSwatchDisplayTypes.default): boolean => {\r\n\r\n // Additional checks for the product card since it has a separate config setting.\r\n if (displayType === DimensionSwatchDisplayTypes.productCard) {\r\n const dimensionsToDisplayOnProductCard = context.app.config.dimensionsInProductCard;\r\n if (!ArrayExtensions.hasElements(dimensionsToDisplayOnProductCard) ||\r\n dimensionsToDisplayOnProductCard.includes(DimensionTypes.none) ||\r\n !dimensionsToDisplayOnProductCard.includes(dimensionType)) {\r\n return false;\r\n }\r\n }\r\n\r\n const dimensionsToDisplayAsSwatch = context.app.config.dimensionsAsSwatchType;\r\n return ArrayExtensions.hasElements(dimensionsToDisplayAsSwatch) &&\r\n !dimensionsToDisplayAsSwatch.includes(DimensionTypes.none) &&\r\n dimensionsToDisplayAsSwatch.includes(dimensionType);\r\n};\r\n\r\n/**\r\n * Generates an image URL for a swatch.\r\n * @param imageUrl - The image url returned by Retail Server.\r\n * @param apiSettings - The request context.\r\n * @returns Full image url.\r\n */\r\nexport const generateSwatchImageUrl = (imageUrl: string, apiSettings: ICommerceApiSettings): string => {\r\n if (imageUrl.startsWith('http')) {\r\n return imageUrl;\r\n }\r\n\r\n return apiSettings.baseImageUrl + encodeURIComponent(imageUrl);\r\n};\r\n\r\n/**\r\n * Generates a Image URL for a product based on data return from retail server.\r\n * @param product The Product returned by Retail Server.\r\n * @param ctx The request context.\r\n * @param apiSettings\r\n */\r\nexport const generateProductImageUrl = (\r\n product: SimpleProduct | ProductSearchResult,\r\n apiSettings: ICommerceApiSettings\r\n): string | undefined => {\r\n return generateImageUrl(product.PrimaryImageUrl, apiSettings);\r\n};\r\n\r\n/**\r\n * Creates a CartLine object from the passed data.\r\n * @param product The product.\r\n * @param quantity The quantity.\r\n * @param catalogId The catalog.\r\n */\r\nexport const buildCartLine = (product: SimpleProduct, quantity?: number, catalogId?: number): CartLine => {\r\n return {\r\n CatalogId: catalogId || 0,\r\n Description: product.Description,\r\n\r\n // TODO: Investigate this value and what it represents\r\n EntryMethodTypeValue: 3,\r\n ItemId: product.ItemId,\r\n ProductId: product.RecordId,\r\n Quantity: quantity || 1,\r\n TrackingId: '',\r\n UnitOfMeasureSymbol: product.DefaultUnitOfMeasure\r\n };\r\n};\r\n\r\n/**\r\n * Creates a CommerceListLine (also know as WishlistLine) object from the passed data.\r\n * @param productId The RecordId of the Product to be added.\r\n * @param customerId The account number of the customer.\r\n * @param wishlistId The Id of the commerce list.\r\n */\r\nexport const buildWishlistLine = (productId: number, customerId: string, wishlistId: number): CommerceListLine => {\r\n return {\r\n CommerceListId: wishlistId,\r\n ProductId: productId,\r\n CustomerId: customerId\r\n };\r\n};\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\nexport 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 * Transforms search text into the expected 'search terms' format, expected by refiner APIs.\r\n * @param searchText Free-form text used for searching for products or categories of products.\r\n */\r\nexport const ensureSearchTextIsFormedProperly = (searchText: string): string => {\r\n const prefix = searchText.startsWith('\\'') ? '' : '\\'';\r\n const suffix = searchText.endsWith('\\'') ? '' : '\\'';\r\n return `${prefix}${searchText}${suffix}`;\r\n};\r\n\r\nexport const ensureSafeSearchText = (searchText: string): string => {\r\n return searchText?.replace(/[^\\d\\sA-Za-z]+/g, '');\r\n};\r\n\r\nexport const buildCacheKey = (base: string, apiSettings: ICommerceApiSettings, locale?: string): string => {\r\n return `${base}-chanId:${apiSettings.channelId}-catId:${apiSettings.catalogId}${locale ? `-${locale}` : ''}`;\r\n};\r\n\r\nexport const buildCacheKeyWithUrlTokens = (base: string, requestContext: IRequestContext): string => {\r\n const urlTokens = requestContext.urlTokens;\r\n const defaultCacheKey = buildCacheKey(base, requestContext.apiSettings, requestContext.locale);\r\n return urlTokens ? `${defaultCacheKey}-${urlTokens.itemId}-${urlTokens.recordId}-${urlTokens.pageType}` : defaultCacheKey;\r\n};\r\n\r\n/**\r\n * Generates a key from set of arguments as inputs.\r\n *\r\n * @param args Argument list of pivots to generate key from.\r\n * @param handler Handler function for null/undefined values.\r\n */\r\n\r\ntype TKeyTypes = string | number | boolean | null | undefined;\r\ninterface IGenerateKeyOptions {\r\n separator?: string;\r\n handler?(input: null | undefined): string;\r\n}\r\nexport const generateKey = (args: TKeyTypes[], options?: IGenerateKeyOptions): string => {\r\n const { handler, separator }: IGenerateKeyOptions = { ...{ separator: '-', handler: undefined }, ...(options || {}) };\r\n return args\r\n .map(arg => {\r\n if (arg === null || arg === undefined) {\r\n if (handler) {\r\n return handler(arg);\r\n }\r\n }\r\n return arg;\r\n })\r\n .join(separator);\r\n};\r\n\r\n/**\r\n * Gets the fall back image url for a variant image.\r\n * @param itemId Item id of a product.\r\n * @param apiSettings Api setting from request context.\r\n */\r\nexport const getFallbackImageUrl = (itemId: string | undefined, apiSettings: ICommerceApiSettings): string | undefined => {\r\n if (!itemId) {\r\n return '';\r\n }\r\n\r\n const parsedItemId = itemId.trim().split(' ')[0];\r\n\r\n const productUrl = `Products/${parsedItemId}_000_001.png`;\r\n return generateImageUrl(productUrl, apiSettings);\r\n};\r\n\r\n/**\r\n * Converts retail proxy product dimension type to display dimension type.\r\n * @param productDimensionType - Product dimension type from retail proxy.\r\n * @returns Local dimension type.\r\n */\r\nexport const convertProductDimensionTypeToDimensionTypes = (productDimensionType: ProductDimensionType): DimensionTypes => {\r\n switch (productDimensionType) {\r\n case ProductDimensionType.Color:\r\n return DimensionTypes.color;\r\n case ProductDimensionType.Configuration:\r\n return DimensionTypes.configuration;\r\n case ProductDimensionType.Size:\r\n return DimensionTypes.size;\r\n case ProductDimensionType.Style:\r\n return DimensionTypes.style;\r\n default:\r\n return DimensionTypes.none;\r\n }\r\n};\r\n\r\n/**\r\n * Converts display dimension type to retail proxy product dimension type.\r\n * @param dimensionType - Local dimension type.\r\n * @returns Product dimension type from retail proxy.\r\n */\r\nexport const convertDimensionTypeToProductDimensionType = (dimensionType: DimensionTypes): ProductDimensionType => {\r\n switch (dimensionType) {\r\n case DimensionTypes.color:\r\n return ProductDimensionType.Color;\r\n case DimensionTypes.configuration:\r\n return ProductDimensionType.Configuration;\r\n case DimensionTypes.size:\r\n return ProductDimensionType.Size;\r\n case DimensionTypes.style:\r\n return ProductDimensionType.Style;\r\n default:\r\n return ProductDimensionType.None;\r\n }\r\n};\r\n\r\n/**\r\n * Sets dimensions to url.\r\n * @param inputUrl - Url to update.\r\n * @param productDimensions - Dimensions to set.\r\n */\r\nexport const setDimensionValuesToQuery = (inputUrl: URL, productDimensions: ProductDimension[]): void => {\r\n for (const dimension of productDimensions) {\r\n inputUrl.searchParams.set(\r\n convertProductDimensionTypeToDimensionTypes(dimension.DimensionTypeValue), dimension.DimensionValue?.Value ?? '');\r\n }\r\n\r\n window.history?.replaceState(window.history.state, '', inputUrl.toString()?.replace(inputUrl.host, window.location.host));\r\n};\r\n\r\n/**\r\n * Retrieves dimension value stored in url.\r\n * @param urlParameters - Url parameters.\r\n * @param productDimensionType - The dimension type to retrieve.\r\n * @returns Product dimension item.\r\n */\r\nconst parseDimensionFromUrl = (urlParameters: URLSearchParams, productDimensionType: ProductDimensionType): ProductDimension | undefined => {\r\n const localDimensionType = convertProductDimensionTypeToDimensionTypes(productDimensionType);\r\n const value = urlParameters.get(localDimensionType);\r\n if (!value) {\r\n return undefined;\r\n }\r\n return {\r\n DimensionTypeValue: productDimensionType,\r\n DimensionValue: {\r\n RecordId: 0,\r\n Value: value\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Retrieves all dimensions from URL.\r\n * @param urlParameters - Url parameters.\r\n * @returns Product dimensions stored in url.\r\n */\r\nconst parseDimensionsFromUrl = (urlParameters: URLSearchParams): ProductDimension[] => {\r\n const dimensionsToParse: ProductDimensionType[] = [\r\n ProductDimensionType.Color,\r\n ProductDimensionType.Configuration,\r\n ProductDimensionType.Size,\r\n ProductDimensionType.Style\r\n ];\r\n const parsedDimensions = dimensionsToParse.map(dimension => parseDimensionFromUrl(urlParameters, dimension));\r\n return ArrayExtensions.validValues(parsedDimensions);\r\n};\r\n\r\n/**\r\n * Utility function to extract the dimension values from input url querystring.\r\n * @param inputUrl - The request url.\r\n * @returns The selected dimension values.\r\n */\r\nexport const getDimensionValuesFromQuery = (inputUrl: URL): ProductDimension[] => {\r\n const urlWithIgnoredCase = new URL(inputUrl.toString().toLocaleLowerCase());\r\n const urlParameters = urlWithIgnoredCase.searchParams;\r\n const dimensions: ProductDimension[] = parseDimensionsFromUrl(urlParameters);\r\n return dimensions;\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/* eslint-disable no-duplicate-imports */\r\nimport * as React from 'react';\r\n\r\nimport { HtmlHeadInclude, IAny, ICoreContext, IGeneric } from '@msdyn365-commerce/core';\r\nimport { IMfrmProductPageSummaryData } from './mfrm-product-page-summary.data';\r\nimport { IMfrmProductPageSummaryProps } from './mfrm-product-page-summary.props.autogenerated';\r\nimport { SimpleProduct } from '@msdyn365-commerce/retail-proxy';\r\nimport { removeSpecialCharsFromURLPath } from '../../Utilities/allRegex';\r\n/**\r\n *\r\n * ProductPageSummary component\r\n * @extends {React.PureComponent}\r\n */\r\nclass ProductPageSummary extends React.PureComponent> {\r\n constructor(props: any) {\r\n super(props);\r\n }\r\n\r\n public render(): JSX.Element {\r\n if (this.props.data.productPageSummary.result === undefined) {\r\n throw new Error('PageSummaryData input to page-summary is undefined. Unable to generate page-summary');\r\n }\r\n const {\r\n config,\r\n context,\r\n data\r\n } = this.props;\r\n let { data: { productPageSummary: { result: {\r\n title,\r\n description,\r\n keywords,\r\n sharingImageUrl,\r\n faviconUrl\r\n } } } } = this.props;\r\n\r\n // Product SEO metadata specific information - non-overridable\r\n const productName = title;\r\n\r\n // Override values coming from data action if config values are provided\r\n title = config.title?.split('').join(productName) || title;\r\n description = config.description?.split('').join(productName) || description;\r\n keywords = config.keywords || keywords;\r\n sharingImageUrl = (config.sharingImage && config.sharingImage.src) || sharingImageUrl;\r\n faviconUrl = config.faviconUrl || faviconUrl;\r\n\r\n // Construct page title with suffix and prefix if provided from app settings\r\n const pageTitle = this._constructPageTitle(title, context && context.request && context.request.app);\r\n const url = context.request.url.requestUrl;\r\n const urlParams = new URLSearchParams(url.search);\r\n const variantid = urlParams.get('variantid') ? `?variantid=${urlParams.get('variantid')}` : null;\r\n const canonicalUrl = `${url.origin}${removeSpecialCharsFromURLPath(url?.pathname, context)}${variantid ? variantid : ''}`;\r\n return (\r\n \r\n \r\n {pageTitle && {pageTitle}}\r\n {description && }\r\n {keywords && }\r\n {canonicalUrl && }\r\n {faviconUrl && }\r\n {this._renderProductMetadata(context, data)}\r\n {!config.disableOgTags && this._renderOgTags(pageTitle, description, sharingImageUrl)}\r\n {!config.disableTwitterTags && this._renderTwitterTags(pageTitle, description, sharingImageUrl)}\r\n \r\n \r\n );\r\n }\r\n\r\n /**\r\n * Renders the facebook and other social media specific metadata tags\r\n *\r\n * @param title Page title\r\n * @param description Product description\r\n * @param sharingImageUrl Primary product image url\r\n */\r\n private _renderOgTags(title: string | undefined, description: string | undefined, sharingImageUrl: string | undefined): JSX.Element {\r\n return (\r\n <>\r\n {title && }\r\n {description && }\r\n {sharingImageUrl && }\r\n \r\n \r\n );\r\n }\r\n\r\n /**\r\n * Constructs and renders the JSON-LD tag used to output product specific metadata used by search engine crawlers\r\n * also known as: SEO Schema\r\n *\r\n * @param context used to get currency\r\n * @param data the resulting data gathered from coresponding action file.\r\n */\r\n private _renderProductMetadata(context: ICoreContext, data: IMfrmProductPageSummaryData): JSX.Element {\r\n if (!data.productPageSummary.result || !data.product.result || !context.request.channel?.Currency) {\r\n throw new Error(\"Missing data required to build SEO schema.\");\r\n }\r\n\r\n const variantRecordId = data.product.result.RecordId;\r\n const currentVariant = data.productRetailId.result?.find((variant: SimpleProduct) => variant.RecordId === variantRecordId);\r\n const retailVariantId: string | undefined = currentVariant?.ExtensionProperties?.find(item => item.Key === 'RetailVariantId')?.Value?.StringValue;\r\n const {\r\n title,\r\n description,\r\n sharingImageUrl,\r\n canonicalUrl,\r\n variantId,\r\n price,\r\n productBrand,\r\n itemCondition,\r\n priceValidUntil,\r\n isOutOfStockArray,\r\n gtinArray\r\n } = data.productPageSummary.result;\r\n const currencyCode = context.request.channel.Currency;\r\n\r\n const isOutOfStockValue = isOutOfStockArray?.find(it => it.key === `${variantRecordId}`)?.value || null;\r\n const isOutOfStock = isOutOfStockValue === null ? undefined : parseInt(isOutOfStockValue, 10);\r\n const availability = isOutOfStock === undefined || isNaN(isOutOfStock) ?\r\n undefined : isOutOfStock ? \"OutOfStock\" : \"InStock\";\r\n\r\n const gtinValue = gtinArray?.find(it => it.key === `${retailVariantId}`)?.value || null;\r\n const gtin = gtinValue === null ? undefined : parseInt(gtinValue, 10) || undefined;\r\n\r\n // Construct the JSON-LD data that contains the product metadata information used by search enginge crawlers\r\n const productMetaData = JSON.stringify({\r\n // tslint:disable-next-line:no-http-string\r\n '@context': 'http://schema.org',\r\n '@type': 'Product',\r\n '@id': canonicalUrl,\r\n name: title,\r\n description: description,\r\n image: sharingImageUrl,\r\n sku: variantId?.toString(),\r\n gtin12: gtin?.toString(),\r\n itemCondition: itemCondition,\r\n brand: {\r\n '@type': 'Brand',\r\n name: productBrand\r\n },\r\n offers: {\r\n '@type': 'Offer',\r\n url: canonicalUrl,\r\n priceCurrency: currencyCode,\r\n price: price,\r\n priceValidUntil: priceValidUntil,\r\n availability: availability\r\n }\r\n });\r\n\r\n return (\r\n <>\r\n {/* tslint:disable:react-no-dangerous-html - intentionally setting inner html with only data action output (no unsanizted user input)*/}\r\n