{"version":3,"file":"productMediaGallery.fd6e7ff2a2382adb26f1.js","sources":["webpack:///./Source/FECOM.Web.UI/Scripts/apps/product/productPageApi.ts","webpack:///./Source/FECOM.Web.UI/Scripts/components/ProductMediaGallery.tsx","webpack:///./Source/FECOM.Web.UI/Scripts/components/ResponsiveProductImage.tsx"],"sourcesContent":["import { InStockNotificationRequest } from './../../types/generated';\r\n\r\nexport const apiPathProducts = '/umbraco/surface/productssurface/';\r\nexport const apiPathUser = '/umbraco/surface/usersurface/';\r\nexport const apiPathInStock = '/umbraco/surface/instocknotificationsurface/';\r\nexport const apiPathBasket = '/umbraco/surface/basketsurface/';\r\n\r\nconst fetchBaseConfig: RequestInit = {\r\n credentials: 'same-origin',\r\n headers: {\r\n 'content-type': 'application/json',\r\n accept: 'application/json'\r\n }\r\n};\r\n\r\nexport function getProductDataByVariants() {\r\n console.log('do something');\r\n}\r\n\r\nexport const getIsFavourite = (catalogueRef?: string | null) => {\r\n const path = `${apiPathProducts}GetProductIsFavourite/?catalogueRef=${catalogueRef}`;\r\n\r\n return fetch(path, fetchBaseConfig).then((response) => {\r\n return response.json();\r\n });\r\n};\r\n\r\nexport const getIsDownloadUser = () => {\r\n const path = `${apiPathUser}GetIsDownloadUser`;\r\n\r\n return fetch(path, fetchBaseConfig).then((response) => {\r\n return response.json();\r\n });\r\n};\r\n\r\nexport const registerForInStockNotification = (\r\n form: Partial\r\n) => {\r\n const path = `${apiPathInStock}RegisterForInStockNotification`;\r\n const data = { ...form };\r\n const config: RequestInit = {\r\n ...fetchBaseConfig,\r\n body: JSON.stringify(data),\r\n method: 'POST'\r\n };\r\n\r\n return fetch(path, config).then((response) => {\r\n return response.json();\r\n });\r\n};\r\n\r\nexport const getProductByProductId = (productId: number) => {\r\n const path = `${apiPathProducts}GetProductByProductId/?productId=${productId}`;\r\n\r\n return fetch(path, fetchBaseConfig).then((response) => {\r\n return response.json();\r\n });\r\n};\r\n\r\nexport const getProductQuantityInBasket = (catalogueRef: string) => {\r\n const path = `${apiPathBasket}GetProductQuantityInBasket/?catalogueRef=${catalogueRef}`;\r\n\r\n return fetch(path, fetchBaseConfig).then((response) => {\r\n return response.json();\r\n });\r\n};\r\n","/* eslint-disable react-hooks/exhaustive-deps */ //todo\r\n\r\nimport { useState, useEffect, lazy, Suspense } from 'react';\r\n// import { JsonView } from './JsonView';\r\nimport {\r\n ProductMediaItemViewModel,\r\n ProductImageViewModel,\r\n ProductMediaType\r\n} from '../types/generated';\r\nimport canUseDOM from '../utilities/canUseDOM';\r\nimport { ResponsiveProductImage } from './ResponsiveProductImage';\r\n\r\nimport ImageGallery from 'react-image-gallery';\r\nimport Loader from './Loader';\r\nimport ProductsILove from '../apps/product/components/ProductsILove';\r\n\r\nconst Modal = lazy(\r\n () =>\r\n import(\r\n /* webpackChunkName: \"reactResponsiveModal\" */ 'react-responsive-modal'\r\n )\r\n);\r\nconst Player = lazy(\r\n () => import(/* webpackChunkName: \"reactPlayer\" */ 'react-player')\r\n);\r\n\r\nexport interface ProductMediaGalleryProps {\r\n primaryImageUrl: string;\r\n images: ProductImageViewModel[];\r\n videos: ProductMediaItemViewModel[];\r\n thumbnailPosition?: 'top' | 'right' | 'bottom' | 'left';\r\n catRef?: string;\r\n isCssFavouritesEnabled?: boolean;\r\n isVariant?: boolean;\r\n}\r\n\r\nexport interface ImageSizes {\r\n [size: string]: string | number;\r\n}\r\n\r\nconst lightboxImageSizes = {\r\n //xs: 360,\r\n sm: 480,\r\n md: 800,\r\n //lg: 800,\r\n xl: 1200\r\n // xxl: 1200\r\n};\r\n\r\nconst imageSizes: ImageSizes = {\r\n //xs: 360,\r\n sm: 508,\r\n md: 338,\r\n //lg: 338,\r\n xl: 578\r\n //xxl: 578\r\n};\r\n\r\nconst smallImageSizes = {\r\n xs: 70,\r\n // sm: 480,\r\n // md: 270,\r\n lg: 83\r\n // xl: 445,\r\n};\r\n\r\ninterface CarouselItem {\r\n url: string;\r\n type: 'video' | 'image';\r\n}\r\n\r\nexport default function ProductMediaGallery({\r\n primaryImageUrl,\r\n images,\r\n videos,\r\n thumbnailPosition,\r\n catRef,\r\n isCssFavouritesEnabled,\r\n isVariant\r\n}: ProductMediaGalleryProps) {\r\n const [slideIndex, setSlideIndex] = useState(0);\r\n const [isLightboxOpen, setIsLightboxOpen] = useState(false);\r\n\r\n function preloadPrimaryImage(imageUrl: string = '') {\r\n if (canUseDOM()) {\r\n for (const size in imageSizes) {\r\n const link = window.document.createElement('link');\r\n const head = window.document.getElementsByTagName('head')[0];\r\n\r\n link.rel = 'preload';\r\n link.as = 'image';\r\n link.href = encodeURI(\r\n `${imageUrl}?width=${imageSizes[size]}&height=${imageSizes[size]}&quality=75 1x&scale=UpscaleCanvas&anchor=MiddleCenter`\r\n );\r\n\r\n head.appendChild(link);\r\n }\r\n }\r\n }\r\n\r\n useEffect(() => {\r\n // console.log('checking slide index:', slideIndex)\r\n setSlideIndex(0);\r\n\r\n preloadPrimaryImage(primaryImageUrl);\r\n }, [primaryImageUrl, images.length, videos.length]);\r\n\r\n const items: CarouselItem[] = [\r\n {\r\n url: primaryImageUrl,\r\n type: 'image'\r\n },\r\n ...videos.map((video) => {\r\n const item: CarouselItem = {\r\n url: video.value || '',\r\n type: 'video'\r\n };\r\n return item;\r\n }),\r\n ...images\r\n .map((image) => {\r\n const item: CarouselItem = {\r\n url: image.name || '',\r\n type: 'image'\r\n };\r\n return item;\r\n })\r\n .filter((item) => item.url !== primaryImageUrl) // may need to add filter to remove blank URLS\r\n ];\r\n\r\n function toggleLightbox() {\r\n setIsLightboxOpen(!isLightboxOpen);\r\n }\r\n\r\n const pageGallery = (\r\n {\r\n setSlideIndex(currentIndex);\r\n }}\r\n showNav={true}\r\n showFullscreenButton={false}\r\n showBullets={false}\r\n showPlayButton={false}\r\n onClick={toggleLightbox}\r\n items={items.map((item) => ({\r\n original: item.url,\r\n thumbnail: item.url\r\n }))}\r\n showThumbnails={items.length > 1}\r\n thumbnailPosition={thumbnailPosition}\r\n renderThumbInner={(item) => {\r\n // add a check for video\r\n if (item.original && item.original.includes('vimeo.')) {\r\n return (\r\n \r\n );\r\n }\r\n\r\n if (item.original && item.original.includes('.youtube.')) {\r\n return (\r\n \r\n );\r\n }\r\n\r\n return (\r\n
\r\n \r\n
\r\n );\r\n }}\r\n renderItem={(item) => {\r\n // add a check for video\r\n if (item.original && item.original.includes('vimeo.')) {\r\n return (\r\n
\r\n \r\n \r\n
\r\n );\r\n }\r\n if (item.original && item.original.includes('.youtube.')) {\r\n return (\r\n
\r\n \r\n \r\n
\r\n );\r\n }\r\n\r\n return (\r\n
\r\n \r\n {!isVariant && (\r\n \r\n )}\r\n \r\n
\r\n );\r\n }}\r\n renderLeftNav={(\r\n onClick: React.MouseEventHandler,\r\n disabled?: boolean\r\n ) => (\r\n
\r\n \r\n Go to the previous slide\r\n \r\n
\r\n )}\r\n renderRightNav={(\r\n onClick: React.MouseEventHandler,\r\n disabled?: boolean\r\n ) => (\r\n
\r\n \r\n Go to the next slide\r\n \r\n
\r\n )}\r\n />\r\n );\r\n\r\n return (\r\n
\r\n {pageGallery}\r\n\r\n }>\r\n \r\n {\r\n setSlideIndex(currentIndex);\r\n }}\r\n showNav={true}\r\n showFullscreenButton={false}\r\n showBullets={false}\r\n showPlayButton={false}\r\n onClick={toggleLightbox}\r\n showThumbnails={false}\r\n items={items.map((item) => ({\r\n original: item.url\r\n }))}\r\n renderItem={(item) => {\r\n // add a check for video\r\n if (\r\n item.original &&\r\n (item.original.includes('vimeo.') ||\r\n item.original.includes('.youtube.'))\r\n ) {\r\n return (\r\n }>\r\n
\r\n \r\n
\r\n
\r\n );\r\n }\r\n\r\n return (\r\n \r\n );\r\n }}\r\n renderThumbInner={() => null}\r\n />\r\n \r\n
\r\n
\r\n );\r\n}\r\n\r\ninterface VideoThumbnailProps {\r\n videoUrl: string;\r\n videoType: ProductMediaType;\r\n isThumb?: boolean;\r\n}\r\n\r\nconst VideoThumbnail = ({\r\n videoUrl,\r\n videoType,\r\n isThumb = false\r\n}: VideoThumbnailProps) => {\r\n // if required we can determine type from the url\r\n\r\n const [thumbnail, setThumbnail] = useState('');\r\n\r\n useEffect(() => {\r\n if (videoType === ProductMediaType.vimeo) {\r\n // do vimeo thing\r\n if (canUseDOM()) {\r\n fetch(`https://vimeo.com/api/oembed.json?url=${videoUrl}`)\r\n .then((res) => res.json())\r\n .then((data) => {\r\n if (data && data.thumbnail_url) {\r\n const thumbSize = isThumb ? '_70x70.' : '_320x320.';\r\n const thumb = data.thumbnail_url.replace(\r\n /(_[0-9x]*\\.)/g,\r\n thumbSize\r\n );\r\n setThumbnail(thumb);\r\n }\r\n });\r\n }\r\n }\r\n }, []); // shouldn't need to retrigger this\r\n\r\n if (videoType === ProductMediaType.youTube) {\r\n // do youTube thing\r\n const id = videoUrl.split('?v=')[1];\r\n\r\n return (\r\n \r\n );\r\n }\r\n\r\n return ;\r\n};\r\n\r\nconst ExpandNotice = () => (\r\n
\r\n Click to Expand\r\n
\r\n);\r\n\r\ninterface VideoPlaceholderProps {\r\n src: string;\r\n}\r\nconst VideoPlaceholder = ({ src: thumbnailUrl }: VideoPlaceholderProps) => {\r\n return (\r\n
\r\n
\r\n {thumbnailUrl && (\r\n \r\n )}\r\n
\r\n
\r\n );\r\n};\r\n","import * as React from 'react';\r\n\r\nexport interface ResponsiveProductImageProps {\r\n src: string;\r\n srcMobile?: string;\r\n xs?: number;\r\n sm?: number;\r\n md?: number;\r\n lg?: number;\r\n xl?: number;\r\n xxl?: number;\r\n alt?: string;\r\n className?: string;\r\n}\r\n\r\ntype MediaSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';\r\n\r\ninterface Size {\r\n name: MediaSize;\r\n size?: number;\r\n}\r\ninterface FilledSize {\r\n name: MediaSize;\r\n size: number;\r\n}\r\n\r\nconst mediaQueries = {\r\n xs: '(max-width: 575px)',\r\n sm: '(min-width: 576px)',\r\n md: '(min-width: 768px)',\r\n lg: '(min-width: 992px)',\r\n xl: '(min-width: 1200px)',\r\n xxl: '(min-width: 1500px)'\r\n};\r\n\r\nexport function ResponsiveProductImage({\r\n xs,\r\n sm,\r\n md,\r\n lg,\r\n xl,\r\n xxl,\r\n src,\r\n srcMobile,\r\n alt = '',\r\n className\r\n}: ResponsiveProductImageProps) {\r\n const mobileImageSrc = srcMobile || src;\r\n\r\n const sizes: Size[] = [];\r\n\r\n if (xs) {\r\n sizes.push({ name: 'xs', size: xs });\r\n }\r\n if (sm) {\r\n sizes.push({ name: 'sm', size: sm });\r\n }\r\n if (md) {\r\n sizes.push({ name: 'md', size: md });\r\n }\r\n if (lg) {\r\n sizes.push({ name: 'lg', size: lg });\r\n }\r\n if (xl) {\r\n sizes.push({ name: 'xl', size: xl });\r\n }\r\n if (xxl) {\r\n sizes.push({ name: 'xxl', size: xxl });\r\n }\r\n\r\n let lastSize = 0;\r\n let imageUrlWebP: string;\r\n let sourceTypeWebP: string;\r\n\r\n const filledSizes: FilledSize[] = sizes\r\n .map(({ name, size }) => {\r\n if (!size) {\r\n return { name, size: lastSize };\r\n }\r\n\r\n lastSize = size;\r\n return { name, size };\r\n })\r\n .reverse();\r\n\r\n var isWebP = (window as { [key: string]: any })['isWebP'];\r\n if (isWebP) {\r\n imageUrlWebP = 'format=webp&';\r\n sourceTypeWebP = 'image/webp';\r\n }\r\n const handleOnDragStart = (e: React.DragEvent) =>\r\n e.preventDefault();\r\n\r\n return (\r\n
\r\n \r\n {filledSizes.map(({ name, size }) => {\r\n const sizedSrc =\r\n name === 'xs' || name === 'sm' ? mobileImageSrc : src;\r\n\r\n // URL encode to avoid milions of errors in console\r\n var firstImageUrl = encodeURI(\r\n `${sizedSrc}?${imageUrlWebP}width=${size}&height=${size}&quality=75 1x&scale=UpscaleCanvas&anchor=MiddleCenter`\r\n );\r\n var secondImageUrl = encodeURI(\r\n `${sizedSrc}?${imageUrlWebP}width=${size * 2}&height=${\r\n size * 2\r\n }&quality=75 2x&scale=UpscaleCanvas&anchor=MiddleCenter`\r\n );\r\n\r\n const srcSet = `${firstImageUrl}, ${secondImageUrl}`;\r\n\r\n return (\r\n \r\n );\r\n })}\r\n \r\n \r\n
\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAFA;AAFA;AAQA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AAHA;AACA;AAKA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjEA;AAAA;AAEA;AACA;AACA;AAKA;AACA;AAEA;AACA;AACA;;;AAEA;AACA,uXAEA;AAFA;AAKA;AACA,mMAAA;AAAA;AAiBA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AASA;AACA;AACA;AACA;AACA;AACA;AALA;AAaA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAFA;AAKA;AACA;AACA;AAFA;AAIA;AACA;AAGA;AACA;AACA;AAFA;AAIA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAFA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AAEA;AADA;AADA;AAOA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAFA;AADA;AAQA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAFA;AADA;AAQA;AACA;AACA;AACA;AAEA;AACA;AAFA;AAOA;AACA;AAFA;AAPA;AAiBA;AACA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAHA;AAKA;AAAA;AAAA;AALA;AADA;AAJA;AAcA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAHA;AAKA;AAAA;AAAA;AALA;AADA;AAJA;AA3GA;AACA;AA2HA;AACA;AAGA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AADA;AALA;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AADA;AAAA;AAGA;AACA;AACA;AAKA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AALA;AADA;AADA;AAYA;AACA;AACA;AAEA;AACA;AAFA;AAMA;AACA;AAAA;AAAA;AA7CA;AAdA;AADA;AAHA;AAqEA;AACA;AAOA;AAIA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AADA;AAMA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AADA;AADA;AACA;AAQA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAHA;AAFA;AADA;AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrZA;;;AA0BA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AASA;AAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AAMA;AAEA;AAGA;AACA;AACA;AAJA;AAOA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AAdA;AA1BA;AADA;AA8CA;;;;A","sourceRoot":""}