{"version":3,"sources":["webpack:///./src/Frontend/app/components/product-teaser/product-teaser.tsx","webpack:///./src/Frontend/app/views/product-teaser/product-teaser-view.tsx","webpack:///./src/Frontend/app/components/anchor/anchor.tsx","webpack:///./src/Frontend/app/components/content-section/content-section.tsx","webpack:///./src/Frontend/app/components/cta-button/cta-button.tsx","webpack:///./src/Frontend/app/utils/breakpoint-utils.ts","webpack:///./src/Frontend/app/components/tag/tag.tsx","webpack:///./src/Frontend/app/utils/tracking-utils.ts","webpack:///./src/Frontend/app/components/product-image/product-image.tsx","webpack:///./src/Frontend/app/components/product-authors/product-authors.tsx","webpack:///./src/Frontend/app/components/show-more/show-more.tsx"],"names":["product","splashLabel","splashText","featuredLabel","ctaLink","autogeneratedCtaLink","enableShowMoreDescription","showMoreButton","showLessButton","props","title","authors","description","imageFallbackSrc","imageSrcSet","productId","url","baseClass","image","fallbackSrc","srcSet","sizes","alt","trackingParams","trackingList","trackingPosition","triggerOnce","ref","inView","clickTrackingEvent","className","type","href","onClick","dangerouslySetInnerHTML","__html","maxLines","minHeight","btnLabelShowMore","btnLabelShowLess","link","isLarge","render","this","contextModel","id","anchorId","hasNoMarginTop","hasNoMarginBottom","componentClasses","children","isInverted","isSecondary","breakpoints","rat","rabbit","cat","dog","wolf","lion","horse","rhino","elephant","mediaQueries","Object","keys","reduce","queryStrings","key","currentMediaQueries","handleMediaMatch","isMatching","forEach","mediaQuery","matchMedia","matches","addListener","event","tagTypeClassMap","NEWS","SPOT","BESTSELLER","BOOK_OF_THE_MONTH","UPCOMING","classModifier","rootClasses","shape","EventTypes","CurrencyCodes","TrackingDimensions","ensureDataLayer","window","dataLayer","pushEcommerenceTrackingEvent","trackingEvent","push","pushTrackingEvent","pushClickTrackingEvent","CLICK","ecommerce","click","actionField","list","products","name","position","pushDetailViewTrackingEvent","DETAIL_VIEW","detail","pushImpressionViewTrackingEvent","IMPRESSION_VIEW","impressions","map","ProductImage","loading","src","length","classes","Wrapper","lines","author","index","state","showMoreHasOverflow","showMoreIsOpen","componentDidMount","addEventListener","handleResize","bind","componentWillUnmount","removeEventListener","disableOnBreakpoint","disableOverflow","hasOverflow","childrenWrapper","clientHeight","setState","toggleMore","containerClasses","setAnimateToMinHeight","btnText","height","duration","node"],"mappings":"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","file":"24.acc7e072e165b2a7ee9a.js","sourcesContent":["import * as React from \"react\";\r\nimport { IProduct } from \"../../types/product\";\r\n// import { IButtonAddToBasketProps } from \"~/components/button-add-to-basket/button-add-to-basket\";\r\nimport CtaButton from \"../cta-button/cta-button\";\r\n// import ProductPrice, { IProductPriceProps } from \"../product-price/product-price\";\r\nimport ShowMore from \"../show-more/show-more\";\r\nimport { pushImpressionViewTrackingEvent, pushClickTrackingEvent } from \"~/utils/tracking-utils\";\r\nimport { useInView } from \"react-intersection-observer\";\r\nimport Tag from \"../tag/tag\";\r\nimport ProductAuthors from \"../product-authors/product-authors\";\r\n// import InfoSection from \"../info-section/info-section\";\r\n// import ProductDiscountSplash from \"../product-discount-splash/product-discount-splash\";\r\nimport ProductImage from \"../product-image/product-image\";\r\nimport ContentSection from \"../content-section/content-section\";\r\n\r\nexport interface IProductTeaserProps {\r\n product: IProduct;\r\n splashLabel?: string;\r\n splashText?: string;\r\n ctaLink?: string;\r\n autogeneratedCtaLink?: string;\r\n productPriceAddToBasketLabel?: string;\r\n enableShowMoreDescription?: boolean;\r\n showMoreButton?: string;\r\n showLessButton?: string;\r\n featuredLabel?: string;\r\n anchorId?: string;\r\n hasNoMarginTop?: boolean;\r\n hasNoMarginBottom?: boolean;\r\n}\r\n\r\nconst ProductTeaser: React.FC<IProductTeaserProps> = ({\r\n product,\r\n // productPriceAddToBasketLabel,\r\n // primaryPriceLabel,\r\n // secondaryPriceLabel,\r\n // addToBasketWebApiUrl,\r\n splashLabel,\r\n splashText,\r\n featuredLabel,\r\n ctaLink,\r\n autogeneratedCtaLink,\r\n enableShowMoreDescription,\r\n showMoreButton,\r\n showLessButton,\r\n ...props\r\n}) => {\r\n const {\r\n title,\r\n authors,\r\n description,\r\n imageFallbackSrc,\r\n imageSrcSet,\r\n productId,\r\n // priceType,\r\n // primaryPrice,\r\n // secondaryPrice,\r\n url\r\n // materialType,\r\n // discount\r\n } = product;\r\n const baseClass = \"product-teaser\";\r\n\r\n const image = imageFallbackSrc && imageSrcSet && (\r\n <ProductImage fallbackSrc={imageFallbackSrc} srcSet={imageSrcSet} sizes=\"240px\" alt={title} />\r\n );\r\n\r\n const trackingParams = {\r\n productId,\r\n title,\r\n trackingList: \"Product Teaser\",\r\n trackingPosition: 1\r\n };\r\n\r\n const [ref, inView] = useInView({\r\n triggerOnce: true\r\n });\r\n\r\n React.useEffect(() => {\r\n if (inView) {\r\n pushImpressionViewTrackingEvent([trackingParams]);\r\n }\r\n }, [inView]);\r\n\r\n const clickTrackingEvent = () => pushClickTrackingEvent(trackingParams);\r\n\r\n return (\r\n <ContentSection className={baseClass} type=\"full\" {...props}>\r\n <div className={`${baseClass}__inner`} ref={ref}>\r\n <div className={`${baseClass}__image-section-wrapper`}>\r\n <div className={`${baseClass}__image-section`}>\r\n {imageFallbackSrc && url && (\r\n <a href={url} onClick={clickTrackingEvent}>\r\n {image}\r\n </a>\r\n )}\r\n {imageFallbackSrc && !url && image}\r\n {(splashLabel || splashText) && (\r\n <div className={`${baseClass}__splash-wrapper`}>\r\n <div className={`${baseClass}__splash`}>\r\n {splashLabel && (\r\n <div\r\n className={`${baseClass}__splash-label`}\r\n dangerouslySetInnerHTML={{ __html: splashLabel }}\r\n />\r\n )}\r\n {splashText && (\r\n <div\r\n className={`${baseClass}__splash-text`}\r\n dangerouslySetInnerHTML={{ __html: splashText }}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n {/* {discount && <ProductDiscountSplash discount={discount} />} */}\r\n </div>\r\n </div>\r\n <div className={`${baseClass}__content-wrapper`}>\r\n {featuredLabel ? (\r\n <Tag className={`${baseClass}__featured-tag`}>{featuredLabel}</Tag>\r\n ) : null}\r\n\r\n {url ? (\r\n <h2 className={`${baseClass}__title h2-style`}>\r\n <a className=\"reset-a\" href={url} onClick={clickTrackingEvent}>\r\n {title}\r\n </a>\r\n </h2>\r\n ) : (\r\n <h2 className={`${baseClass}__title h2-style`}>{title}</h2>\r\n )}\r\n\r\n <ProductAuthors\r\n className={`${baseClass}__product-authors`}\r\n authors={authors}\r\n maxLines={2}\r\n />\r\n\r\n {/* {materialType && <div className={`${baseClass}__material-type`}>{materialType}</div>} */}\r\n {description && (\r\n <>\r\n {enableShowMoreDescription && showMoreButton && showLessButton ? (\r\n <ShowMore\r\n className={`${baseClass}__rich-text-show-more-wrapper`}\r\n minHeight={140}\r\n btnLabelShowMore={showMoreButton}\r\n btnLabelShowLess={showLessButton}\r\n >\r\n <div\r\n className=\"content-rich-text\"\r\n dangerouslySetInnerHTML={{\r\n __html: description\r\n }}\r\n />\r\n </ShowMore>\r\n ) : (\r\n <div\r\n className={`${baseClass}__rich-text content-rich-text`}\r\n dangerouslySetInnerHTML={{ __html: description }}\r\n />\r\n )}\r\n </>\r\n )}\r\n\r\n {ctaLink && <CtaButton link={ctaLink} isLarge />}\r\n {autogeneratedCtaLink && <CtaButton link={autogeneratedCtaLink} isLarge />}\r\n {/* <div className={`${baseClass}__price-wrapper`}> */}\r\n {/* <ProductPrice\r\n primaryPriceLabel={primaryPriceLabel}\r\n secondaryPriceLabel={secondaryPriceLabel}\r\n priceType={priceType}\r\n primaryPrice={primaryPrice}\r\n secondaryPrice={secondaryPrice}\r\n >\r\n {ctaLink ? (\r\n <CtaButton link={ctaLink} isLarge />\r\n ) : (\r\n <>\r\n {addToBasketWebApiUrl && (\r\n <ButtonAddToBasket\r\n addToBasketWebApiUrl={addToBasketWebApiUrl}\r\n productId={productId}\r\n trackingList=\"Product Teaser\"\r\n isLarge\r\n >\r\n {productPriceAddToBasketLabel}\r\n </ButtonAddToBasket>\r\n )}\r\n </>\r\n )}\r\n </ProductPrice> */}\r\n {/* </div> */}\r\n {/* {product.stockStatusLabel && (\r\n <InfoSection iconId=\"32_information\" label={product.stockStatusLabel} />\r\n )}\r\n {product.deliveryLabel && (\r\n <InfoSection iconId=\"32_truck-in-motion\" label={product.deliveryLabel} />\r\n )} */}\r\n </div>\r\n </div>\r\n </ContentSection>\r\n );\r\n};\r\n\r\nexport default ProductTeaser;\r\n","import * as React from \"react\";\r\nimport ProductTeaser, { IProductTeaserProps } from \"~/components/product-teaser/product-teaser\";\r\n\r\nexport interface IProductTeaserViewProps {\r\n contextModel: IProductTeaserProps;\r\n}\r\n\r\nclass ProductTeaserView extends React.PureComponent<IProductTeaserViewProps> {\r\n public render() {\r\n return <ProductTeaser {...this.props.contextModel} />;\r\n }\r\n}\r\n\r\nexport default ProductTeaserView;\r\n","import * as React from \"react\";\r\n\r\nexport interface AnchorProps {\r\n id?: string;\r\n}\r\n\r\nconst Anchor = ({ id }: AnchorProps) => {\r\n return <div className=\"anchor\" id={id} />;\r\n};\r\n\r\nexport default Anchor;\r\n","import classNames from \"classnames\";\r\nimport * as React from \"react\";\r\nimport Anchor from \"../anchor/anchor\";\r\n\r\nexport interface ContentSectionProps {\r\n className?: string;\r\n type?: \"default\" | \"full\";\r\n anchorId?: string;\r\n hasNoMarginTop?: boolean;\r\n hasNoMarginBottom?: boolean;\r\n}\r\n\r\nconst ContentSection: React.FC<ContentSectionProps> = ({\r\n className,\r\n type = \"default\",\r\n anchorId,\r\n hasNoMarginTop,\r\n hasNoMarginBottom,\r\n ...props\r\n}) => {\r\n const baseClass = \"content-section\";\r\n const componentClasses = classNames(baseClass, className, {\r\n [`${baseClass}--full`]: type === \"full\",\r\n \"anchor-wrapper\": !!anchorId,\r\n \"content-no-margin-top\": hasNoMarginTop,\r\n \"content-no-margin-bottom\": hasNoMarginBottom\r\n });\r\n return (\r\n <section className={componentClasses}>\r\n {anchorId && <Anchor id={anchorId} />}\r\n {props.children}\r\n </section>\r\n );\r\n};\r\n\r\nexport default ContentSection;\r\n","import * as React from \"react\";\r\nimport classNames from \"classnames\";\r\n\r\nexport interface ICtaButtonProps {\r\n className?: string;\r\n isLarge?: boolean;\r\n isInverted?: boolean;\r\n isSecondary?: boolean;\r\n link: string;\r\n onClick?(): void;\r\n}\r\n\r\nconst CtaButton = ({ className, isLarge, isInverted, isSecondary, link, onClick }: ICtaButtonProps) => {\r\n const baseClass = \"cta-button\";\r\n const componentClasses = classNames(className, baseClass, {\r\n [`${baseClass}--large`]: isLarge,\r\n [`${baseClass}--inverted`]: isInverted,\r\n [`${baseClass}--secondary`]: isSecondary\r\n });\r\n\r\n return <div onClick={onClick} className={componentClasses} dangerouslySetInnerHTML={{ __html: link }} />;\r\n};\r\n\r\nexport default CtaButton;\r\n","interface IBreakpoints {\r\n [key: string]: number;\r\n}\r\n\r\ninterface IMediaQueryStrings {\r\n [key: string]: string;\r\n}\r\n\r\nexport type IMatchingQueries = { [key in Breakpoints]?: boolean };\r\n\r\nexport type Breakpoints =\r\n | \"ratMin\"\r\n | \"ratMax\"\r\n | \"rabbitMin\"\r\n | \"rabbitMax\"\r\n | \"catMin\"\r\n | \"catMax\"\r\n | \"dogMin\"\r\n | \"dogMax\"\r\n | \"wolfMin\"\r\n | \"wolfMax\"\r\n | \"lionMin\"\r\n | \"horseMin\"\r\n | \"horseMax\"\r\n | \"rhinoMin\"\r\n | \"rhinoMax\"\r\n | \"elephantMin\"\r\n | \"elephantMax\";\r\n\r\nexport const breakpoints: IBreakpoints = {\r\n rat: 360,\r\n rabbit: 480,\r\n cat: 640,\r\n dog: 768,\r\n wolf: 1024,\r\n lion: 1100,\r\n horse: 1400,\r\n rhino: 1520,\r\n elephant: 1670\r\n};\r\n\r\nconst mediaQueries: IMediaQueryStrings = Object.keys(breakpoints).reduce(\r\n (queryStrings: IMediaQueryStrings, key) => {\r\n queryStrings[`${key}Min`] = `(min-width: ${breakpoints[key]}px)`;\r\n queryStrings[`${key}Max`] = `(max-width: ${breakpoints[key] - 1}px)`;\r\n return queryStrings;\r\n },\r\n {}\r\n);\r\n\r\nconst setupMediaQueryListeners = () => {\r\n Object.keys(mediaQueries).forEach((key: string) => {\r\n const mediaQuery = matchMedia(mediaQueries[key]);\r\n\r\n handleMediaMatch(mediaQuery.matches, key as Breakpoints); // Initial values\r\n mediaQuery.addListener(event => handleMediaMatch(event.matches, key as Breakpoints));\r\n });\r\n};\r\n\r\nconst currentMediaQueries: IMatchingQueries = {};\r\nconst handleMediaMatch = (isMatching: boolean, key: Breakpoints) => (currentMediaQueries[key] = isMatching);\r\n\r\nif (!__SERVER__) {\r\n setupMediaQueryListeners();\r\n}\r\n\r\nexport { currentMediaQueries };\r\n","import * as React from \"react\";\r\nimport classNames from \"classnames\";\r\nimport { ProductStatus } from \"~/types/product\";\r\n\r\nexport interface ITagProps {\r\n type?: ProductStatus;\r\n children: React.ReactNode;\r\n className?: string;\r\n shape?: \"pill\" | \"square\";\r\n}\r\n\r\nexport const tagTypeClassMap: { [key in ProductStatus]: string } = {\r\n NEWS: \"news\",\r\n SPOT: \"spot\",\r\n BESTSELLER: \"bestseller\",\r\n BOOK_OF_THE_MONTH: \"botm\",\r\n UPCOMING: \"upcoming\"\r\n};\r\n\r\nconst Tag: React.FC<ITagProps> = props => {\r\n const classModifier = props.type && tagTypeClassMap[props.type];\r\n const rootClasses = classNames(\"tag\", props.className, `tag--shape-${props.shape || \"pill\"}`, {\r\n [`tag--${classModifier}`]: props.type\r\n });\r\n\r\n return (\r\n <div className={rootClasses}>\r\n <span className=\"tag__label\">{props.children}</span>\r\n </div>\r\n );\r\n};\r\n\r\nexport default Tag;\r\n","import { MembershipType } from \"~/types/membership\";\r\nimport { IBasketProduct, IProduct } from \"~/types/product\";\r\n// import { IBasketSummationProps } from \"~/components/basket-summation/basket-summation\";\r\nimport { IProductTileProps } from \"~/components/product-tile/product-tile\";\r\n\r\nenum EventTypes {\r\n SIGNUP = \"eec.signup\",\r\n PURCHASE = \"eec.purchase\",\r\n CHECKOUT = \"eec.checkout\",\r\n ADD_TO_BASKET = \"eec.add\",\r\n REMOVE_FROM_BASKET = \"eec.remove\",\r\n CLICK = \"eec.impressionClick\",\r\n DETAIL_VIEW = \"eec.detail\",\r\n IMPRESSION_VIEW = \"eec.impressionView\",\r\n PROMO_VIEW = \"eec.promotionView\",\r\n PROMO_CLICK = \"eec.promotionClick\",\r\n VOUCHER = \"eec.voucher\"\r\n}\r\n\r\nenum CurrencyCodes {\r\n DKK = \"DKK\"\r\n}\r\n\r\nenum TrackingDimensions {\r\n CAMPAIGN_ID = \"dimension2\",\r\n MEMBERSHIP_TYPE = \"dimension3\",\r\n PAYMENT_PERIOD = \"dimension4\",\r\n DISCOUNT_SPLASH = \"dimension5\"\r\n}\r\n\r\ninterface ITrackingProduct {\r\n name?: string;\r\n id?: string;\r\n price?: number;\r\n quantity?: number;\r\n [TrackingDimensions.MEMBERSHIP_TYPE]?: MembershipType | string;\r\n [TrackingDimensions.PAYMENT_PERIOD]?: string;\r\n [TrackingDimensions.DISCOUNT_SPLASH]?: string;\r\n}\r\n\r\ninterface IProductImpression extends ITrackingProduct {\r\n list?: string;\r\n position: number | undefined;\r\n}\r\n\r\ninterface ICheckoutActionField {\r\n step: string;\r\n [TrackingDimensions.CAMPAIGN_ID]?: string;\r\n option?: string;\r\n coupon?: string;\r\n}\r\n\r\ninterface IEcommerceTrackingEvent<T> {\r\n event: EventTypes;\r\n ecommerce: T & { currencyCode?: CurrencyCodes };\r\n}\r\n\r\ninterface ITrackingEvent {\r\n event: \"trackEvent\";\r\n eventData: {\r\n category: string;\r\n action: string;\r\n label: string;\r\n };\r\n}\r\n\r\nconst mapProductsToTrackingProducts = (\r\n { title, primaryPriceNumber, productId, quantityNumber, discounts }: IBasketProduct,\r\n membershipType?: MembershipType,\r\n paymentPeriod?: string\r\n): ITrackingProduct => {\r\n const product: ITrackingProduct = {\r\n name: title,\r\n price: primaryPriceNumber,\r\n quantity: quantityNumber || 1,\r\n [TrackingDimensions.MEMBERSHIP_TYPE]: membershipType || \"\",\r\n [TrackingDimensions.PAYMENT_PERIOD]: paymentPeriod || \"\",\r\n [TrackingDimensions.DISCOUNT_SPLASH]: discounts?.map(discount => discount.label).join(\" | \") || \"\"\r\n };\r\n\r\n if (productId) {\r\n product.id = productId;\r\n }\r\n\r\n return product;\r\n};\r\n\r\nexport interface ISignupTrackingParams {\r\n campaignId?: string;\r\n membershipType?: MembershipType;\r\n currentStepIndex: number;\r\n paymentPeriod?: string;\r\n miniBasketProducts?: IBasketProduct[];\r\n}\r\n\r\ninterface ISignupTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n checkout: {\r\n actionField: ICheckoutActionField;\r\n products: ITrackingProduct[];\r\n };\r\n }> {}\r\n\r\nconst generateSignupTrackingEvent = ({\r\n membershipType,\r\n campaignId,\r\n miniBasketProducts,\r\n currentStepIndex,\r\n paymentPeriod\r\n}: ISignupTrackingParams): ISignupTrackingEvent => {\r\n const actionField: ICheckoutActionField = {\r\n step: (currentStepIndex + 1).toString(),\r\n option: currentStepIndex > 0 ? paymentPeriod : \"\"\r\n };\r\n\r\n actionField[TrackingDimensions.CAMPAIGN_ID] = campaignId || \"\";\r\n\r\n const products: ITrackingProduct[] = miniBasketProducts\r\n ? miniBasketProducts.map(product =>\r\n mapProductsToTrackingProducts(product, membershipType, paymentPeriod)\r\n )\r\n : [];\r\n\r\n const signupTrackingEvent = {\r\n event: EventTypes.SIGNUP,\r\n ecommerce: {\r\n checkout: {\r\n actionField,\r\n products\r\n }\r\n }\r\n };\r\n\r\n return signupTrackingEvent;\r\n};\r\n\r\ninterface ICheckoutTrackingParams {\r\n products?: IBasketProduct[];\r\n paymentMethod?: string;\r\n step: number;\r\n}\r\n\r\ninterface ICheckoutTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n checkout: {\r\n actionField: ICheckoutActionField;\r\n products: ITrackingProduct[];\r\n };\r\n }> {}\r\n\r\nconst generateCheckoutTrackingEvent = ({\r\n products,\r\n step,\r\n paymentMethod\r\n}: ICheckoutTrackingParams): ICheckoutTrackingEvent => {\r\n const actionField: ICheckoutActionField = {\r\n step: `${step}`\r\n };\r\n\r\n if (paymentMethod) {\r\n actionField.option = paymentMethod;\r\n }\r\n\r\n const mappedProducts: ITrackingProduct[] = products\r\n ? products.map(product => mapProductsToTrackingProducts(product))\r\n : [];\r\n\r\n return {\r\n event: EventTypes.CHECKOUT,\r\n ecommerce: {\r\n checkout: {\r\n actionField,\r\n products: mappedProducts\r\n }\r\n }\r\n };\r\n};\r\n\r\ninterface IPurchaseTrackingParams {\r\n membershipType?: MembershipType;\r\n miniBasketProducts?: IBasketProduct[];\r\n // miniBasketSummation?: IBasketSummationProps;\r\n orderId?: string;\r\n campaignId?: string;\r\n}\r\n\r\ninterface IPurchaseActionField {\r\n [TrackingDimensions.CAMPAIGN_ID]?: string;\r\n coupon?: string;\r\n revenue?: number;\r\n shipping?: number;\r\n tax?: number;\r\n id?: string;\r\n}\r\n\r\ninterface IPurchaseTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n purchase: {\r\n actionField: IPurchaseActionField;\r\n products: ITrackingProduct[];\r\n };\r\n }> {}\r\n\r\nconst generatePurchaseTrackingEvent = ({\r\n membershipType,\r\n miniBasketProducts,\r\n // miniBasketSummation,\r\n orderId,\r\n campaignId\r\n}: IPurchaseTrackingParams): IPurchaseTrackingEvent => {\r\n const actionField: IPurchaseActionField = {};\r\n\r\n if (orderId) {\r\n actionField.id = orderId;\r\n }\r\n\r\n actionField[TrackingDimensions.CAMPAIGN_ID] = campaignId || \"\";\r\n\r\n // if (miniBasketSummation) {\r\n // actionField.tax = miniBasketSummation.vatNumber;\r\n // actionField.revenue = miniBasketSummation.totalPriceNumber;\r\n\r\n // if (miniBasketSummation.shippingFee) {\r\n // actionField.shipping = miniBasketSummation.shippingFeeNumber;\r\n // }\r\n // if (miniBasketSummation.voucherDiscount) {\r\n // actionField.coupon = miniBasketSummation.voucherDiscount;\r\n // }\r\n // }\r\n\r\n const products: ITrackingProduct[] = miniBasketProducts\r\n ? miniBasketProducts.map(product => mapProductsToTrackingProducts(product, membershipType))\r\n : [];\r\n\r\n const purchaseTrackingEvent = {\r\n event: EventTypes.PURCHASE,\r\n ecommerce: {\r\n currencyCode: CurrencyCodes.DKK,\r\n purchase: {\r\n actionField,\r\n products\r\n }\r\n }\r\n };\r\n\r\n return purchaseTrackingEvent;\r\n};\r\n\r\ninterface IClickActionField {\r\n list: string;\r\n}\r\n\r\ninterface IClickTrackingParams\r\n extends Pick<IProductTileProps, \"trackingList\" | \"trackingPosition\" | \"productId\" | \"title\"> {}\r\n\r\ninterface IClickTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n click: {\r\n actionField: IClickActionField;\r\n products: IProductImpression[];\r\n };\r\n }> {}\r\n\r\nconst generateClickTrackingEvent = ({\r\n trackingList,\r\n trackingPosition,\r\n productId,\r\n title\r\n}: IClickTrackingParams): IClickTrackingEvent => {\r\n return {\r\n event: EventTypes.CLICK,\r\n ecommerce: {\r\n click: {\r\n actionField: {\r\n list: trackingList\r\n },\r\n products: [\r\n {\r\n id: productId,\r\n name: title,\r\n position: trackingPosition\r\n }\r\n ]\r\n }\r\n }\r\n };\r\n};\r\n\r\ninterface IDetailActionField {\r\n list: string;\r\n}\r\n\r\ninterface IDetailViewTrackingParams extends Pick<IProduct, \"title\" | \"productId\"> {\r\n trackingList: string;\r\n}\r\n\r\ninterface IDetailViewTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n detail: {\r\n actionField: IDetailActionField;\r\n products: ITrackingProduct[];\r\n };\r\n }> {}\r\n\r\nconst generateDetailViewTrackingEvent = ({\r\n title,\r\n productId,\r\n trackingList\r\n}: IDetailViewTrackingParams): IDetailViewTrackingEvent => {\r\n return {\r\n event: EventTypes.DETAIL_VIEW,\r\n ecommerce: {\r\n detail: {\r\n actionField: {\r\n list: trackingList\r\n },\r\n products: [\r\n {\r\n id: productId,\r\n name: title\r\n }\r\n ]\r\n }\r\n }\r\n };\r\n};\r\n\r\ninterface IBasketTrackingParams {\r\n products?: IBasketProduct[];\r\n trackingList: string;\r\n}\r\n\r\ninterface IAddToBasketTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n add: {\r\n actionField: { list: string };\r\n products: ITrackingProduct[] | undefined;\r\n };\r\n }> {}\r\n\r\nconst generateAddToBasketTrackingEvent = ({\r\n products,\r\n trackingList\r\n}: IBasketTrackingParams): IAddToBasketTrackingEvent => {\r\n const basketProducts = products && products.map(product => mapProductsToTrackingProducts(product));\r\n\r\n return {\r\n event: EventTypes.ADD_TO_BASKET,\r\n ecommerce: {\r\n add: {\r\n actionField: { list: trackingList },\r\n products: basketProducts\r\n }\r\n }\r\n };\r\n};\r\n\r\ninterface IRemoveFromBasketTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n remove: {\r\n actionField: { list: string };\r\n products: ITrackingProduct[] | undefined;\r\n };\r\n }> {}\r\n\r\nconst generateRemoveFromBasketTrackingEvent = ({\r\n products,\r\n trackingList\r\n}: IBasketTrackingParams): IRemoveFromBasketTrackingEvent => {\r\n const basketProducts = products && products.map(product => mapProductsToTrackingProducts(product));\r\n\r\n return {\r\n event: EventTypes.REMOVE_FROM_BASKET,\r\n ecommerce: {\r\n remove: {\r\n actionField: { list: trackingList },\r\n products: basketProducts\r\n }\r\n }\r\n };\r\n};\r\n\r\ninterface IVoucherTrackingParams {\r\n // summation?: IBasketSummationProps;\r\n caller: string;\r\n action: string;\r\n}\r\ninterface IVoucherTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n // summation?: IBasketSummationProps;\r\n caller: string;\r\n action: string;\r\n }> {}\r\n\r\nconst generateVoucherTrackingEvent = (props: IVoucherTrackingParams): IVoucherTrackingEvent => {\r\n return {\r\n event: EventTypes.VOUCHER,\r\n ecommerce: {\r\n // summation: props.summation,\r\n caller: props.caller,\r\n action: props.action\r\n }\r\n };\r\n};\r\n\r\ninterface IImpressionViewTrackingParams\r\n extends Required<Pick<IProductTileProps, \"trackingList\" | \"trackingPosition\" | \"productId\" | \"title\">> {}\r\n\r\ninterface IImpressionViewTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n impressions: IProductImpression[];\r\n }> {}\r\n\r\nconst generateImpressionViewTrackingEvent = (\r\n products: IImpressionViewTrackingParams[]\r\n): IImpressionViewTrackingEvent => {\r\n return {\r\n event: EventTypes.IMPRESSION_VIEW,\r\n ecommerce: {\r\n impressions: products.map(product => {\r\n return {\r\n list: product.trackingList,\r\n position: product.trackingPosition,\r\n id: product.productId,\r\n name: product.title\r\n };\r\n })\r\n }\r\n };\r\n};\r\n\r\ninterface IPromoViewTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n promoView: {\r\n promotions: Array<{\r\n id: string;\r\n name: string;\r\n creative: string;\r\n position: string;\r\n }>;\r\n };\r\n }> {}\r\n\r\nconst generatePromoViewTrackingEvent = (): IPromoViewTrackingEvent => {\r\n return {\r\n event: EventTypes.PROMO_VIEW,\r\n ecommerce: {\r\n promoView: {\r\n promotions: [\r\n {\r\n id: \"\",\r\n name: \"Splash\",\r\n creative: \"\",\r\n position: \"\"\r\n }\r\n ]\r\n }\r\n }\r\n };\r\n};\r\n\r\ninterface IPromoClickTrackingEvent\r\n extends IEcommerceTrackingEvent<{\r\n promoClick: {\r\n promotions: Array<{\r\n id: string;\r\n name: string;\r\n creative: string;\r\n position: string;\r\n }>;\r\n };\r\n }> {}\r\n\r\nconst generatePromoClickTrackingEvent = (): IPromoClickTrackingEvent => {\r\n return {\r\n event: EventTypes.PROMO_CLICK,\r\n ecommerce: {\r\n promoClick: {\r\n promotions: [\r\n {\r\n id: \"\",\r\n name: \"Splash\",\r\n creative: \"\",\r\n position: \"\"\r\n }\r\n ]\r\n }\r\n }\r\n };\r\n};\r\n\r\nconst ensureDataLayer = () => {\r\n if (typeof window === \"undefined\") {\r\n return false;\r\n }\r\n\r\n window.dataLayer = window.dataLayer || [];\r\n return true;\r\n};\r\n\r\nconst pushEcommerenceTrackingEvent = (trackingEvent: IEcommerceTrackingEvent<unknown>) => {\r\n if (ensureDataLayer()) window.dataLayer.push(trackingEvent);\r\n};\r\n\r\nexport const pushTrackingEvent = (trackingEvent: ITrackingEvent) => {\r\n if (ensureDataLayer()) window.dataLayer.push(trackingEvent);\r\n};\r\n\r\nexport const pushAddToBasketTrackingEvent = (props: IBasketTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateAddToBasketTrackingEvent(props));\r\n\r\nexport const pushRemoveFromBasketTrackingEvent = (props: IBasketTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateRemoveFromBasketTrackingEvent(props));\r\n\r\nexport const pushSignupTrackingEvent = (props: ISignupTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateSignupTrackingEvent(props));\r\n\r\nexport const pushCheckoutTrackingEvent = (props: ICheckoutTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateCheckoutTrackingEvent(props));\r\n\r\nexport const pushPurchaseTrackingEvent = (props: IPurchaseTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generatePurchaseTrackingEvent(props));\r\n\r\nexport const pushClickTrackingEvent = (props: IClickTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateClickTrackingEvent(props));\r\n\r\nexport const pushDetailViewTrackingEvent = (props: IDetailViewTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateDetailViewTrackingEvent(props));\r\n\r\nexport const pushImpressionViewTrackingEvent = (props: IImpressionViewTrackingParams[]) =>\r\n pushEcommerenceTrackingEvent(generateImpressionViewTrackingEvent(props));\r\n\r\nexport const pushPromoViewTrackingEvent = () =>\r\n pushEcommerenceTrackingEvent(generatePromoViewTrackingEvent());\r\n\r\nexport const pushPromoClickTrackingEvent = () =>\r\n pushEcommerenceTrackingEvent(generatePromoClickTrackingEvent());\r\n\r\nexport const pushVoucherTrackingEvent = (props: IVoucherTrackingParams) =>\r\n pushEcommerenceTrackingEvent(generateVoucherTrackingEvent(props));\r\n","import * as React from \"react\";\r\n\r\nexport interface ProductImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"srcSet\"> {\r\n className?: string;\r\n fallbackSrc?: string;\r\n srcSet: string;\r\n sizes?: string;\r\n loading?: React.ImgHTMLAttributes<HTMLImageElement>[\"loading\"];\r\n ref?: React.Ref<HTMLImageElement>;\r\n width?: string | number;\r\n height?: string | number;\r\n}\r\n\r\nconst ProductImage: React.FC<ProductImageProps> = React.forwardRef(\r\n ({ fallbackSrc, loading = \"lazy\", ...props }, ref) => {\r\n return <img ref={ref} src={fallbackSrc} loading={loading} {...props} />;\r\n }\r\n);\r\n\r\nexport default ProductImage;\r\n","import * as React from \"react\";\r\nimport { IProductAuthor } from \"~/types/product\";\r\nimport TruncateMarkup from \"react-truncate-markup\";\r\nimport classNames from \"classnames\";\r\n\r\ninterface IProductAuthorProps {\r\n authors?: IProductAuthor[];\r\n maxLines?: number;\r\n className?: string;\r\n}\r\n\r\nconst ProductAuthors: React.FC<IProductAuthorProps> = ({ authors, className, maxLines }) => {\r\n if (!authors?.length) {\r\n return null;\r\n }\r\n\r\n const baseClass = \"product-authors\";\r\n const classes = classNames(baseClass, className);\r\n\r\n const Wrapper: React.FC = ({ children }) =>\r\n maxLines ? (\r\n <TruncateMarkup lines={maxLines}>{children}</TruncateMarkup>\r\n ) : (\r\n <React.Fragment>{children}</React.Fragment>\r\n );\r\n\r\n return (\r\n <Wrapper>\r\n <ul className={classes}>\r\n {authors.map((author, index) => {\r\n return (\r\n <li key={index} className={`${baseClass}__item`}>\r\n {author.url ? (\r\n <a href={author.url} title={author.name}>\r\n {author.name}\r\n </a>\r\n ) : (\r\n <span>{author.name}</span>\r\n )}\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </Wrapper>\r\n );\r\n};\r\n\r\nexport default ProductAuthors;\r\n","import * as React from \"react\";\r\nimport classNames from \"classnames\";\r\nimport AnimateHeight from \"react-animate-height\";\r\nimport { currentMediaQueries, Breakpoints } from \"~/utils/breakpoint-utils\";\r\n\r\nexport interface IShowMoreProps {\r\n minHeight: number;\r\n btnLabelShowMore?: string;\r\n btnLabelShowLess?: string;\r\n className?: string;\r\n disableOnBreakpoint?: Breakpoints;\r\n}\r\ninterface IShowMoreState {\r\n showMoreHasOverflow: boolean;\r\n showMoreIsOpen: boolean;\r\n}\r\n\r\nclass ShowMore extends React.Component<IShowMoreProps, IShowMoreState> {\r\n private childrenWrapper: HTMLDivElement | null;\r\n\r\n public state = {\r\n showMoreHasOverflow: true,\r\n showMoreIsOpen: false\r\n };\r\n\r\n public componentDidMount() {\r\n window.addEventListener(\"resize\", this.handleResize.bind(this));\r\n this.handleResize();\r\n }\r\n\r\n public componentWillUnmount() {\r\n window.removeEventListener(\"resize\", this.handleResize.bind(this));\r\n }\r\n\r\n public handleResize() {\r\n const { disableOnBreakpoint, minHeight } = this.props;\r\n const disableOverflow = disableOnBreakpoint && currentMediaQueries[disableOnBreakpoint];\r\n const hasOverflow = this.childrenWrapper && this.childrenWrapper.clientHeight > minHeight;\r\n\r\n if (!disableOverflow && hasOverflow) {\r\n this.setState({ showMoreHasOverflow: true });\r\n } else {\r\n this.setState({ showMoreHasOverflow: false });\r\n }\r\n }\r\n\r\n private toggleMore() {\r\n this.setState({ showMoreIsOpen: !this.state.showMoreIsOpen });\r\n }\r\n\r\n public render() {\r\n const { className, minHeight, btnLabelShowLess, btnLabelShowMore, children } = this.props;\r\n const baseClass = \"show-more\";\r\n const containerClasses = classNames(className, baseClass, {\r\n [`${baseClass}--hasOverflow`]: this.state.showMoreHasOverflow,\r\n [`${baseClass}--isClosed`]: this.state.showMoreHasOverflow && !this.state.showMoreIsOpen\r\n });\r\n const setAnimateToMinHeight = this.state.showMoreHasOverflow && !this.state.showMoreIsOpen;\r\n const btnText = this.state.showMoreIsOpen ? btnLabelShowLess : btnLabelShowMore;\r\n\r\n return (\r\n <div className={containerClasses}>\r\n <AnimateHeight height={setAnimateToMinHeight ? minHeight : \"auto\"} duration={300}>\r\n <div ref={node => (this.childrenWrapper = node)}>{children}</div>\r\n </AnimateHeight>\r\n\r\n <button className=\"show-more-button\" onClick={() => this.toggleMore()}>\r\n {btnText}\r\n </button>\r\n </div>\r\n );\r\n }\r\n}\r\n\r\nexport default ShowMore;\r\n"],"sourceRoot":""}