{"version":3,"file":"static/js/fa2ffd94c053e47a84ef.bundle.js","mappings":"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","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