{"version":3,"file":"static/js/1d5951df5db64f705a92.bundle.js","mappings":"+IAEO,MAAMA,EAAqBA,CAACC,EAAyBC,EAAiBC,KAAgB,IAAAC,EAYzF,MAJY,GAPc,WAAWH,EAAQI,eAAeC,oBAKZ,QAAlCF,EAAGH,EAAQI,eAAeE,gBAAQ,IAAAH,EAAAA,EAAI,MAEHF,EAC5CM,KAAIC,GAAKC,EAAOD,KAChBE,QAAOC,GAAKA,EAAEC,OAAS,IACvBC,KAAK,QAAQX,KAIhBO,EAAUK,GACCA,EACRC,cACAC,QAAQ,6BAA8B,KACtCA,QAAQ,OAAQ,KAChBA,QAAQ,KAAM,IACdA,QAAQ,KAAM,K,iICMjB,MAAOC,EASTC,YAAYC,EAAmCC,EAAmCC,EAAmBC,GAO9F,KAAAC,mBAAqB,IAAc,qBAEnC,KAAAC,YAAc,IACjB,IAAGC,EAAAA,EAAAA,eAAc,qBAAsBC,KAAKN,gBAAgBM,KAAKP,OAAOQ,SAASD,KAAKL,aAAaK,KAAKJ,SAErG,KAAAM,cAAgB,IAAiB,cAXpCF,KAAKP,OAASA,GAAU,GACxBO,KAAKN,YAAcA,EACnBM,KAAKL,UAAYA,EACjBK,KAAKJ,OAASA,GAiBtB,MA0FA,GAAeO,EAAAA,EAAAA,IAA2B,CACtCC,GAAI,+DACJC,OAxDWC,MAAOC,EAAgCjC,KAClD,MAAM,OAAEmB,EAAM,UAAEE,EAAS,YAAED,GAAgBa,EAC3C,IAAIC,EACJ,IACIA,QAA0BC,EAAAA,EAAAA,cAAa,CAAEC,cAAepC,GAAWqB,EAAWD,EAAYiB,WAC5F,MAAAC,IAGF,GAAIJ,EAAmB,KAAAK,EACnB,IAAIC,EACJ,IACIA,GAAaC,EAAAA,EAAAA,mBAAkBP,EAAmBlC,GAClD,MAAMK,EAAkBL,EAAQI,eAAeC,gBAE3CmC,EADAA,GAAcnC,EACD,WAAWA,IAAkBmC,IAAaE,yBAE1CC,EAEnB,MAAAC,GACEJ,OAAaG,EAGjB,IAAIE,EAAgC,QAApBN,EAAGL,SAAiB,IAAAK,GAAqB,QAArBA,EAAjBA,EAAmBO,2BAAmB,IAAAP,GAAgC,QAAhCA,EAAtCA,EAAwCQ,MAAKC,GAAiB,UAAXA,EAAGC,aAAgB,IAAAV,GAAO,QAAPA,EAAtEA,EAAwEW,aAAK,IAAAX,OAAA,EAA7EA,EAA+EY,YAClG,IAAKN,EACD,IACIA,OA9CQb,OACpBhC,EACAoD,EACAf,EACAgB,KAEA,MAAMC,QAA0BC,EAAAA,EAAAA,yBAC5B,CAAEnB,cAAepC,EAASwD,oBAAqB,IAC/CJ,EACAf,EACAgB,GAGJ,IAAK,MAAMI,KAAoBH,EAC3B,GAA8B,UAA1BG,EAAiBC,KACjB,OAAOD,EAAiBE,WA+BCC,CAAgB5D,EAASqB,EAAWD,EAAYiB,UAAWjB,EAAYiC,WAC9F,MAAAQ,GACEhB,OAAeF,EAIvB,MAAO,CACHhB,MAAOO,EAAkBwB,KACzBI,YAAa5B,EAAkB6B,YAC/BC,iBAAiBC,EAAAA,EAAAA,kBAAiB/B,EAAkBgC,gBAAiB9C,GACrE+C,aAAc3B,EACd4B,WAAYjD,GAAUA,EAAOiD,WAC7B/C,UAAWa,EAAkBmC,SAC7BC,MAAOpC,EAAkBqC,cACzB1B,aAAAA,GAID,OAAI1B,EACA,CACHQ,MAAOR,EAAOQ,MACdmC,YAAa3C,EAAO2C,YACpBE,gBAAiB7C,EAAOqD,cAAgBrD,EAAOqD,aAAaC,IAC5DL,WAAYjD,GAAUA,EAAOiD,YAG9B,IAMPnC,MA7FiByC,IACjB,MAAMrD,GAAYsD,EAAAA,EAAAA,qCAAoCD,GAEtD,GAAIrD,EACA,OAAO,IAAIJ,EACoByD,EAAKvD,OAChCuD,EAAKtE,eAAegB,aACnBC,EACDqD,EAAKtE,eAAekB,QAG5B,MAAM,IAAIsD,MAAM,qG,kGCnDpB,MAAMC,UAA2BC,EAAAA,cACtBC,SAAM,IAAAC,EAAAC,EACT,QAAkDtC,IAA9CjB,KAAKwD,MAAMC,KAAKC,mBAAmBC,OACnC,MAAM,IAAIT,MAAM,uFAEpB,IACIO,MACIC,oBACIC,QAAQ,MAAE1D,EAAK,YAAEmC,EAAW,SAAEwB,EAAQ,gBAAEtB,EAAe,WAAEI,MAGjE1C,KAAKwD,MAET,MAAM,OACF/D,EAAM,QACNnB,EACAmF,MACIC,oBACIC,QAAQ,aAAElB,EAAY,UAAE9C,EAAS,aAAEwB,EAAY,MAAEyB,MAGzD5C,KAAKwD,MAGHK,EAAc5D,EACd6D,EAAqB1B,EACrB2B,EAAkBzB,EAGxBrC,EAAQR,EAAOQ,OAASA,EACxBmC,EAAc3C,EAAO2C,aAAeA,EACpCwB,EAAWnE,EAAOmE,UAAYA,EAC9BtB,EAAmB7C,EAAOqD,cAAgBrD,EAAOqD,aAAaC,KAAQT,EACtEI,EAAajD,EAAOiD,YAAcA,EAElC,MAAMsB,GAAyB3F,EAAAA,EAAAA,GAAmBC,EAAQ2F,cAAe,CAAM,QAANX,EAACrD,SAAK,IAAAqD,EAAAA,EAAI,IAAK,GAAG3D,QAAkB8C,EAG7G,IAAIyB,EAAYlE,KAAKmE,oBAAoBlE,EAAO3B,GAAWA,EAAQ8F,SAAW9F,EAAQ8F,QAAQC,KAK9F,OAJIH,IAAcA,EAAUI,SAAS,eACjCJ,GAAa,cAIbd,EAAAA,cAAAA,EAAAA,SAAA,KACIA,EAAAA,cAACmB,EAAAA,GAAe,KACXL,GAAad,EAAAA,cAAA,aAAQc,GACrB9B,GAAegB,EAAAA,cAAA,QAAMoB,KAAK,cAAcC,QAASrC,IACjDwB,GAAYR,EAAAA,cAAA,QAAMoB,KAAK,WAAWC,QAASb,KAC3Cc,EAGAV,GAA0BZ,EAAAA,cAAA,QAAMuB,IAAI,YAAYC,KAAMZ,IACtDtB,GAAcU,EAAAA,cAAA,QAAMuB,IAAI,gBAAgBC,KAAMlC,MAEjDjD,EAAOoF,mBACL7E,KAAK8E,uBACDjB,EACAC,EACAC,EACAtB,EACA9C,EACAiD,EACuB,QADlBW,EACLjF,EAAQ8F,QAAQW,eAAO,IAAAxB,OAAA,EAAvBA,EAAyByB,SACzB7D,IAEN1B,EAAOwF,eAAiBjF,KAAKkF,cAAclB,EAAwBE,EAAW9B,EAAaE,IAC3F7C,EAAO0F,oBAAsBnF,KAAKoF,mBAAmBlB,EAAW9B,EAAaE,IAYnF4C,cACJG,EACApF,EACAmC,EACAE,GAEA,MAAM1C,EAASI,KAAKwD,MAAMlF,QAAQ8F,QAAQxE,OAC1C,OACIwD,EAAAA,cAACmB,EAAAA,GAAe,KACXc,GAAOjC,EAAAA,cAAA,QAAMkC,SAAS,SAASb,QAASY,IACzCjC,EAAAA,cAAA,QAAMkC,SAAS,YAAYb,QAAS7E,IACnCK,GAASmD,EAAAA,cAAA,QAAMkC,SAAS,WAAWb,QAASxE,IAC5CmC,GAAegB,EAAAA,cAAA,QAAMkC,SAAS,iBAAiBb,QAASrC,IACxDE,GAAmBc,EAAAA,cAAA,QAAMkC,SAAS,WAAWb,QAASnC,IACvDc,EAAAA,cAAA,QAAMkC,SAAS,UAAUb,QAAQ,YACjCrB,EAAAA,cAAA,QAAMkC,SAAS,eAAeb,QAAQ,aAiB1CK,uBACJjB,EACAzB,EACAE,EACAG,EACA9C,EACAiD,EACA2C,EACApE,GAGA,MAAMqE,EAAkBC,KAAKC,UAAU,CACnC,WAAY,oBACZ,QAAS,UACTlB,KAAMX,EACNzB,YAAAA,EACAuD,MAAOrD,EACPsD,IAAKjG,EACLkG,MAAO,CACH,QAAS,QACTrB,KAAMrD,GAEV2E,OAAQ,CACJ,QAAS,QACTT,IAAK5C,EACLsD,cAAeR,EACf3C,MAAAA,KAGR,OACIQ,EAAAA,cAACmB,EAAAA,GAAe,KACZnB,EAAAA,cAAA,4BAAwB,UAAU4C,KAAK,sBAAsBC,wBAAyB,CAAEC,OAAQV,MAWpGJ,mBACJnF,EACAmC,EACAE,GAEA,OACIc,EAAAA,cAACmB,EAAAA,GAAe,KACXtE,GAASmD,EAAAA,cAAA,QAAMoB,KAAK,gBAAgBC,QAASxE,IAC7CmC,GAAegB,EAAAA,cAAA,QAAMoB,KAAK,sBAAsBC,QAASrC,IACzDE,GAAmBc,EAAAA,cAAA,QAAMoB,KAAK,gBAAgBC,QAASnC,IACxDc,EAAAA,cAAA,QAAMoB,KAAK,eAAeC,QAAQ,YAClCrB,EAAAA,cAAA,QAAMoB,KAAK,eAAeC,QAAQ,kBAClCrB,EAAAA,cAAA,QAAMoB,KAAK,kBAAkBC,QAAQ,mBAUzCN,oBAAoBlE,EAA2BoE,GAC9CpE,IACDA,EAAQ,IAEZ,MAAMkG,EAAenG,KAAKwD,MAAM/D,OAChC,GAAI0G,GAAgBA,EAAaC,wBAC7B,OAAOnG,EAEX,MAAMoG,EAAYhC,GAAOA,EAAIiC,SAU7B,OATID,IACIA,EAAUE,kBACVtG,EAAQ,GAAGoG,EAAUE,kBAAkBtG,KAEvCoG,EAAUG,kBACVvG,EAAQ,GAAGA,IAAQoG,EAAUG,oBAI9BvG,GAIf,W,+lBCxNA,MAAMwG,EAAU,CAAEC,QAAS,GAAIC,YAAa,IAwCvCF,EAAQC,QAAQ,wBAA0B,CACvCE,EAAGA,IAAMC,EAAQ,MACjBC,MAAO,qBACPC,GAAI,CAAC,CAACvC,KAAK,qBAAuBwC,KAAK,2DAA4DC,MAAO,IAE1GC,KAAK,EACLC,GAAI,YACJC,EAAG,uBACHtI,EAAG,YAEHuI,IAAK,GAGLC,GAAI,oCAlC4BC,EAACC,EAAqBC,KAUlD,GADAhB,EAAQE,YAAYa,GAAuBC,GACtChB,EAAQE,YAAYa,GAAqBE,QAC1C,MAAM,IAAIxE,MAAM,oBAAsBsE,EAAsB,mCAEhEf,EAAQE,YAAYa,GAAqBE,QAAQC,UAAUC,eAAiBJ,EACxEf,EAAQE,YAAYa,GAAqBE,QAAQC,UAAUvH,KAC3DqG,EAAQE,YAAYF,EAAQE,YAAYa,GAAqBE,QAAQC,UAAUvH,IAAMoH,IA0BzFD,CAF4B,2DACXV,EAAQ,MAMjCgB,OAAOC,aAAeD,OAAOC,cAAgB,GAC7CD,OAAOC,aAAapB,QAAOqB,EAAAA,EAAA,GACpBF,OAAOC,aAAapB,SAAW,IAC/BD,EAAQC,SAGXmB,OAAOC,aAAanB,YAAWoB,EAAAA,EAAA,GAC5BF,OAAOC,aAAanB,aAAe,IACnCF,EAAQE,c,mBCzEnBqB,EAAOC,QAAU7E,O,oBCAjB4E,EAAOC,QAAUC,W","sources":["webpack://henrys-ecommerce/./src/common/utilities/createCanonicalUrl.ts?7ccf","webpack://henrys-ecommerce/./src/modules/product-page-summary/product-page-summary.action.ts?e077","webpack://henrys-ecommerce/./src/modules/product-page-summary/product-page-summary.tsx?f297","webpack://henrys-ecommerce/./lib/product-page-summary/module-registration.js?deb5","webpack://henrys-ecommerce/external var \"React\"?0d3b","webpack://henrys-ecommerce/external var \"ReactDOM\"?853b"],"sourcesContent":["import { IActionContext } from '@msdyn365-commerce/core';\r\n\r\nexport const createCanonicalUrl = (context: IActionContext, paths: string[], page: string) => {\r\n let canonicalDomainHost = `https://${context.requestContext.canonicalDomain}`;\r\n if (process.env.NODE_ENV === 'development') {\r\n canonicalDomainHost = '';\r\n }\r\n\r\n const sitePath = context.requestContext.sitePath ?? '';\r\n\r\n const url = `${canonicalDomainHost}${sitePath}/${paths\r\n .map(p => toSlug(p))\r\n .filter(s => s.length > 0)\r\n .join('/')}/${page}`;\r\n return url;\r\n};\r\n\r\nconst toSlug = (text: string) => {\r\n const slug = text\r\n .toLowerCase()\r\n .replace(/[^A-Za-z\\u00C0-\\u017F0-9]/g, '-')\r\n .replace(/--+/g, '-')\r\n .replace(/^-/, '')\r\n .replace(/-$/, '');\r\n\r\n return slug;\r\n};\r\n","/*--------------------------------------------------------------\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\n/* eslint-disable no-duplicate-imports */\r\nimport {\r\n CacheType,\r\n createObservableDataAction,\r\n IAction,\r\n IActionContext,\r\n IActionInput,\r\n ICommerceApiSettings,\r\n ICreateActionContext\r\n} from '@msdyn365-commerce/core';\r\nimport { getAttributeValuesAsync, getByIdAsync } from '@msdyn365-commerce/retail-proxy/dist/DataActions/ProductsDataActions.g';\r\nimport {\r\n buildCacheKey,\r\n generateImageUrl,\r\n getProductUrlSync,\r\n getSelectedProductIdFromActionInput\r\n} from '@msdyn365-commerce-modules/retail-actions';\r\n\r\nimport { IPageSummaryData } from '@msdyn365-commerce-modules/page-summary';\r\nimport { IProductPageSummaryConfig } from './product-page-summary.props.autogenerated';\r\n\r\n/**\r\n * Product Page Summary Input\r\n */\r\nexport class ProductPageSummaryInput implements IActionInput {\r\n public apiSettings: ICommerceApiSettings;\r\n\r\n public config: IProductPageSummaryConfig;\r\n\r\n public productId: number;\r\n\r\n public locale: string;\r\n\r\n constructor(config: IProductPageSummaryConfig, apiSettings: ICommerceApiSettings, productId: number, locale: string) {\r\n this.config = config || {};\r\n this.apiSettings = apiSettings;\r\n this.productId = productId;\r\n this.locale = locale;\r\n }\r\n\r\n public getCacheObjectType = (): string => 'ProductPageSummary';\r\n\r\n public getCacheKey = (): string =>\r\n `${buildCacheKey('ProductPageSummary', this.apiSettings)}-${this.config.title}-${this.productId}-${this.locale}`;\r\n\r\n public dataCacheType = (): CacheType => 'application';\r\n}\r\n\r\nexport interface IProductPageSummary extends IPageSummaryData {\r\n price?: number;\r\n productId?: number;\r\n productBrand?: string;\r\n}\r\n\r\nconst createInput = (args: ICreateActionContext) => {\r\n const productId = getSelectedProductIdFromActionInput(args);\r\n\r\n if (productId) {\r\n return new ProductPageSummaryInput(\r\n args.config,\r\n args.requestContext.apiSettings,\r\n +productId,\r\n args.requestContext.locale\r\n );\r\n }\r\n throw new Error('Unable to create ProductPageSummaryAction input, no productId found on module config or query');\r\n};\r\n\r\n// Checks product attributes for the presence of brand attribute to extract the brand name for product metadata\r\nconst getProductBrand = async (\r\n context: IActionContext,\r\n recordId: number,\r\n channelId: number,\r\n catalogId: number\r\n): Promise => {\r\n const productAttributes = await getAttributeValuesAsync(\r\n { callerContext: context, queryResultSettings: {} },\r\n recordId,\r\n channelId,\r\n catalogId\r\n );\r\n\r\n for (const productAttribute of productAttributes) {\r\n if (productAttribute.Name === 'Brand') {\r\n return productAttribute.TextValue;\r\n }\r\n }\r\n return;\r\n};\r\n\r\nconst action = async (input: ProductPageSummaryInput, context: IActionContext): Promise => {\r\n const { config, productId, apiSettings } = input;\r\n let simpleProductData;\r\n try {\r\n simpleProductData = await getByIdAsync({ callerContext: context }, productId, apiSettings.channelId);\r\n } catch {\r\n // Do nothing, if there's an error we fall back to values defined from config\r\n }\r\n if (simpleProductData) {\r\n let productUrl: string | undefined;\r\n try {\r\n productUrl = getProductUrlSync(simpleProductData, context);\r\n const canonicalDomain = context.requestContext.canonicalDomain;\r\n if (productUrl && canonicalDomain) {\r\n productUrl = `https://${canonicalDomain}${productUrl}`.toLocaleLowerCase();\r\n } else {\r\n productUrl = undefined;\r\n }\r\n } catch {\r\n productUrl = undefined;\r\n }\r\n\r\n let productBrand = simpleProductData?.ExtensionProperties?.find(ep => ep.Key === 'Brand')?.Value?.StringValue;\r\n if (!productBrand) {\r\n try {\r\n productBrand = await getProductBrand(context, productId, apiSettings.channelId, apiSettings.catalogId);\r\n } catch {\r\n productBrand = undefined;\r\n }\r\n }\r\n\r\n return {\r\n title: simpleProductData.Name,\r\n description: simpleProductData.Description,\r\n sharingImageUrl: generateImageUrl(simpleProductData.PrimaryImageUrl, apiSettings),\r\n canonicalUrl: productUrl,\r\n faviconUrl: config && config.faviconUrl,\r\n productId: simpleProductData.RecordId,\r\n price: simpleProductData.AdjustedPrice,\r\n productBrand\r\n };\r\n\r\n // If the action fails fallback to values defined from config\r\n } else if (config) {\r\n return {\r\n title: config.title,\r\n description: config.description,\r\n sharingImageUrl: config.sharingImage && config.sharingImage.src,\r\n faviconUrl: config && config.faviconUrl\r\n };\r\n }\r\n return {};\r\n};\r\n\r\nexport default createObservableDataAction({\r\n id: '@msdyn365-commerce-modules/page-summary/product-page-summary',\r\n action: >action,\r\n input: createInput\r\n});\r\n","/*--------------------------------------------------------------\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\n/* eslint-disable no-duplicate-imports */\r\nimport { IAny, IGeneric } from '@msdyn365-commerce/core';\r\nimport { HtmlHeadInclude } from '@msdyn365-commerce/core';\r\nimport * as React from 'react';\r\n\r\nimport { IProductPageSummaryData } from './product-page-summary.data';\r\nimport { IProductPageSummaryProps } from './product-page-summary.props.autogenerated';\r\nimport { createCanonicalUrl } from '../../common/utilities/createCanonicalUrl';\r\n\r\n/**\r\n *\r\n * ProductPageSummary component.\r\n * @extends {React.PureComponent}\r\n */\r\nclass ProductPageSummary extends React.PureComponent> {\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 let {\r\n data: {\r\n productPageSummary: {\r\n result: { title, description, keywords, sharingImageUrl, faviconUrl }\r\n }\r\n }\r\n } = this.props;\r\n\r\n const {\r\n config,\r\n context,\r\n data: {\r\n productPageSummary: {\r\n result: { canonicalUrl, productId, productBrand, price }\r\n }\r\n }\r\n } = this.props;\r\n\r\n // Product SEO metadata specific information - non-overridable\r\n const productName = title;\r\n const productDescription = description;\r\n const productImageUrl = sharingImageUrl;\r\n\r\n // Override values coming from data action if config values are provided\r\n title = config.title || title;\r\n description = config.description || 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 const normalizedCanonicalUrl = createCanonicalUrl(context.actionContext, [title ?? ''], `${productId}.p`) || canonicalUrl;\r\n\r\n // Construct page title with suffix and prefix if provided from app settings\r\n let pageTitle = this._constructPageTitle(title, context && context.request && context.request.app);\r\n if (pageTitle && !pageTitle.endsWith(\"| Henry's\")) {\r\n pageTitle += \" | Henry's\";\r\n }\r\n\r\n return (\r\n <>\r\n \r\n {pageTitle && {pageTitle}}\r\n {description && }\r\n {keywords && }\r\n {process.env.NODE_ENV === 'development' && (\r\n \r\n )}\r\n {normalizedCanonicalUrl && }\r\n {faviconUrl && }\r\n \r\n {!config.disableLinkedData &&\r\n this._renderProductMetadata(\r\n productName,\r\n productDescription,\r\n productImageUrl,\r\n canonicalUrl,\r\n productId,\r\n price,\r\n context.request.channel?.Currency,\r\n productBrand\r\n )}\r\n {!config.disableOgTags && this._renderOgTags(normalizedCanonicalUrl, pageTitle, description, sharingImageUrl)}\r\n {!config.disableTwitterTags && this._renderTwitterTags(pageTitle, description, sharingImageUrl)}\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(\r\n url: string | undefined,\r\n title: string | undefined,\r\n description: string | undefined,\r\n sharingImageUrl: string | undefined\r\n ): JSX.Element {\r\n const locale = this.props.context.request.locale;\r\n return (\r\n \r\n {url && }\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 /**\r\n * Constructs and renders the JSON-LD tag used to output product specific metadata used by search engine crawlers.\r\n *\r\n * @param productName Product name.\r\n * @param description Product description.\r\n * @param sharingImageUrl Primary product image url.\r\n * @param canonicalUrl Product canonical url.\r\n * @param productId Master product id.\r\n * @param price Proudct price.\r\n * @param currencyCode Current channel currency code.\r\n * @param productBrand Product brand.\r\n */\r\n private _renderProductMetadata(\r\n productName: string | undefined,\r\n description: string | undefined,\r\n sharingImageUrl: string | undefined,\r\n canonicalUrl: string | undefined,\r\n productId: number | undefined,\r\n price: number | undefined,\r\n currencyCode: string | undefined,\r\n productBrand: string | undefined\r\n ): JSX.Element {\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 '@context': 'http://schema.org',\r\n '@type': 'Product',\r\n name: productName,\r\n description,\r\n image: sharingImageUrl,\r\n sku: productId,\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\r\n }\r\n });\r\n return (\r\n \r\n