{"version":3,"file":"grouped-category-97388a91.js","sources":["../../../client/src/javascripts/customer_pages/_grouped-category/calendar-dates.js","../../../client/src/javascripts/customer_pages/_grouped-category/price-and-product-create.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/_common/grouped-category-base.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/calendar-start-date-selector.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/designer.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter-comparison.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter-nothing-selectable.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter-selectors-mixin.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter-color-criteron.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter-image-criteron.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter-text-criteron.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filter.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/filters.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/button-option.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/button-option-selector.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/button-option-selectors.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/option-selector.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/option-selectors.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-description.jsx","../../../client/src/javascripts/customer_pages/_utils/tools/image-tools.js","../../../client/src/javascripts/customer_pages/_grouped-category/folded-card-product-image.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/metallic-card-product-image.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-image.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-image-thumbnail.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-video.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-images.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-not-available.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/product-flags.jsx","../../../client/src/javascripts/customer_pages/_grouped-category/grouped-category.jsx"],"sourcesContent":["const defaultDates = [\n {\n from: {day: 1, month: 10},\n to: {day: 31, month: 12},\n defaultsTo: { month: 1, year: 1 }\n },\n {\n from: {day: 1, month: 1},\n to: {day: 31, month: 1},\n defaultsTo: { month: 1, year: 0 }\n },\n {\n from: {day: 1, month: 2},\n to: {day: 31, month: 9},\n defaultsTo: { month: 13, year: 0 } // 13 indicates next month\n }\n];\nconst backDates = [{\n from: {day: 1, month: 1},\n to: {day: 30, month: 6},\n earliest: { month: 1, year: 0 }\n }, {\n from: {day: 1, month: 7},\n to: {day: 31, month: 12},\n earliest: { month: 7, year: 0 }\n }\n];\nconst forwardDate = {month: 1, year: 5};\n\nconst CalendarDates = {\n todayDate: new Date(),\n\n getOptions() {\n // Generate Month Options\n const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n const { earliest } = this.findPeriod(backDates);\n let monthOptions = [];\n for (let i = earliest.year; i <= forwardDate.year; i++) {\n const startMonth = (i === earliest.year) ? earliest.month - 1 : 0;\n const noOfMonths = (i === forwardDate.year) ? forwardDate.month : 12;\n\n for (let j = startMonth; j < noOfMonths; j++) {\n const date = new Date(this.todayDate.getFullYear() + i, j);\n monthOptions.push(\n {\n label: `${ monthNames[date.getMonth()]}, ${ date.getFullYear() }`,\n value: date.getTime()\n }\n );\n }\n }\n\n return monthOptions;\n },\n\n getDefaultValue() {\n // Get Default Starting Date\n const { defaultsTo: { year, month } } = this.findPeriod(defaultDates);\n const defaultMonth = month <= 12 ? month - 1 : this.todayDate.getMonth() + (month - 12);\n const defaultTimeStamp = (new Date(this.todayDate.getFullYear() + year, defaultMonth)).getTime();\n\n return this.getOptions().find((mO) =>\n mO.value === defaultTimeStamp\n );\n },\n findPeriod(periodsArray) {\n return periodsArray.find((period) => {\n return (\n (period.from.month - 1) <= CalendarDates.todayDate.getMonth() &&\n (period.from.day) <= CalendarDates.todayDate.getDate() &&\n (period.to.month - 1) >= CalendarDates.todayDate.getMonth() &&\n (period.to.day) >= CalendarDates.todayDate.getDate()\n );\n }) || periodsArray[0];\n }\n}\n\nexport default CalendarDates;\n","import createReactClass from 'create-react-class';\n'use strict';\n\n// Import Libraries\nimport React from 'react';\nimport classNames from 'classnames';\n// Import JSX Modules\nimport Price from './price';\nimport ProgressButton from '../_utils/progress-button';\n// Import JS Modules\nimport { PrismUI, builderDispatch } from '../_utils/ui';\nimport genericHelpers from '../_utils/generic-helpers';\nimport translate from '../_utils/tools/translate';\nimport Currency from '../_utils/tools/currency';\nimport QuantityPricingTools from './quantity-pricing-tools';\nimport UrlBuilder from '../_utils/url-building';\n\n// -----------------------------------------------------------\n// PriceAndProductCreate\n// -----------------------------------------------------------\nvar PriceAndProductCreate = createReactClass({\n render() {\n if (this.props.products.length === 0)\n return null;\n\n const { product, $price } = (() => {\n if (this.props.products.length === 1) {\n const [product] = this.props.products;\n\n return {\n product,\n $price: this.renderPrice(product, true)\n };\n }\n\n const product = this.productWithMinimumPrice();\n\n return {\n product,\n $price: this.renderPrice(product)\n };\n })();\n\n const $quantityDropdown = (() => {\n if (product.show_quantity_dropdown) {\n return (\n
\n
\n
\n { this.renderQuantityDropdown(product) }\n
\n
\n
\n );\n }\n })();\n\n const action = this.action(product);\n\n return (\n
\n { $quantityDropdown }\n
\n

\n { $price }\n

\n
\n { this.renderCreateNow(action, $price) }\n
\n );\n },\n\n renderCreateNow(action, price) {\n const isMobile = (() => {\n if (typeof document !== 'undefined') {\n return document.documentElement.clientWidth < 768;\n }\n \n return false;\n })();\n\n if (isMobile) {\n return (\n
\n
\n
\n { price }\n
\n
\n
\n {\n \n { this.renderProgressButtonLabel(action) }\n \n }\n
\n
\n );\n } else {\n return (\n
\n {\n \n { this.renderProgressButtonLabel(action) }\n \n }\n
\n );\n }\n },\n\n renderProgressButtonLabel(action) {\n return /^\\/product\\/add/.test(action) ? `Add to ${ translate('Cart') }` : 'Create Now';\n },\n\n renderQuantityDropdown(product) {\n const {copies} = this.props;\n\n return (\n
\n \n
\n \n
\n {\n (new QuantityPricingTools(product)).generateOptions().map(({product, quantity, unitPrice, cost}) => {\n const active = copies == quantity;\n\n return (\n \n );\n })\n }\n
\n
\n
\n );\n },\n\n renderPrice(product, displayWas) {\n const copies = this.props.copies;\n\n const { price, includeFrom } = (() => {\n const options = this.productOptions(product).filter(option => option.affectsPrice);\n\n if (options.length === 1) {\n const [option] = options;\n\n return {\n price: option.minimumPrice * copies,\n includeFrom: option.priceIsFrom\n };\n }\n\n const price = (() => {\n if (product.show_quantity_dropdown) {\n return (new QuantityPricingTools(product)).getUnitPriceForQuantity(copies) * copies;\n }\n\n return product.minimum_price;\n })();\n\n return {\n price,\n includeFrom: this.shouldDisplayFrom()\n };\n })();\n\n const wasPrice = (() => {\n if (!displayWas) {\n return;\n }\n\n const wasPrice = (product.was_price || []).reduce((memo, wp) => {\n if (wp.quantity <= copies) {\n return Object.assign({}, wp, {value: wp.value * copies});\n }\n\n return memo;\n }, {});\n\n if (genericHelpers.isWasPriceValid({ was_price: wasPrice, price })) {\n return wasPrice.value;\n }\n })();\n\n return (\n \n );\n },\n\n shouldDisplayFrom() {\n const productPrice = this.props.products[0].minimum_price;\n for (let i = 0; i < this.props.products.length; i++) {\n let product = this.props.products[i];\n if ((product.price_is_from) || (productPrice !== product.minimum_price)) {\n return true;\n }\n }\n return false;\n },\n\n productWithMinimumPrice() {\n return this.props.products.reduce((memo, product) => {\n return memo.minimum_price < product.minimum_price ? memo : product;\n });\n },\n\n action(product) {\n // Determines the Create Now button action\n const params = {\n theme: this.props.theme,\n copies: this.props.copies,\n selected_delivery_option: this.props.deliveryOption && this.props.deliveryOption.key\n };\n\n if (this.props.variantName) {\n params.variant_name = this.props.variantName;\n }\n\n if (this.props.selectedDeliveryOptions) {\n params.selected_delivery_option = this.props.selectedDeliveryOptions\n }\n\n if (product.is_calendar && this.props.calendar_start_date) {\n const date = new Date(this.props.calendar_start_date);\n params.yearSel = date.getFullYear();\n params.monthSel = date.getMonth() + 1;\n }\n\n this.productOptions(product).forEach(option => {\n params['custom_' + option.key] = option.value.toLowerCase();\n });\n\n const queryString = UrlBuilder.buildURLQuery(params);\n if (product.action.includes('?')) {\n return product.action + '&' + UrlBuilder.buildURLQuery(params);\n }\n\n return product.action + '?' + queryString;\n },\n\n productOptions(product) {\n return product.options.map(option => {\n const key = option.id,\n value = (this.props.options[key] && this.props.options[key].value) || option.options[0].value,\n subOption = option.options.find(option => option.value == value);\n\n return {\n key,\n value,\n affectsPrice: option.affects_price,\n minimumPrice: subOption.minimum_price,\n priceIsFrom: subOption.price_is_from\n };\n });\n },\n\n handleCopiesChanged(value) {\n builderDispatch.dispatch({\n type: PrismUI.EVENT_QUANTITY_CHANGED,\n value\n });\n }\n});\n\nexport default PriceAndProductCreate;\n","import React from 'react';\n\n// Import JS Modules\nimport PropTypes from 'prop-types';\nimport parseQueryString from '../../_utils/parse-query-string';\nimport UrlBuilder from '../../_utils/url-building';\nimport setCanonicalUrl from '../../_utils/tools/canonical-url';\nimport merge from 'lodash/merge';\nimport QuantityPricingTools from '../quantity-pricing-tools';\nimport PriceAndProductCreate from '../price-and-product-create';\n\nclass GroupedCategoryBase extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.productAndFilters = React.createRef();\n\n this.state = {\n filters: {},\n options: {},\n copies: this.getInitialCopies(this.props.data.products),\n };\n }\n\n componentDidMount() {\n this.setDefaultFilters();\n }\n\n getCurrentProductIdAccordingToUrl = () => {\n return parseInt(parseQueryString().product, 10);\n };\n\n getCurrentShelfFiltersFromUrl = () => {\n // Try to map Shelf Filters to Item's\n // If a map fails, the corresponding filter will be unselected\n return Object.entries(parseQueryString()).reduce(\n (filters, [key, value]) => {\n value = value.replace(/\\\"/g, '');\n\n const product = this.props.data.products.find(\n p => (p.filters[key] || '').replace(/\\\"/g, '') === value\n );\n\n if (product) {\n filters[key] = product.filters[key];\n }\n\n return filters;\n },\n {}\n );\n };\n\n getDefaultFilters = () => {\n const defaultFilters = {};\n this.props.data.filters\n .filter(function(filter) {\n return filter.options.some(option => option.default === true);\n })\n .forEach(function(filter) {\n const defaultOptionTitle =\n (filter.options || {}).find(option => option.default === true) || {};\n if (Object.keys(defaultOptionTitle).length > 0) {\n defaultFilters[filter.title] = defaultOptionTitle.title;\n }\n });\n return defaultFilters;\n };\n\n setDefaultFilters = (\n productId = this.getCurrentProductIdAccordingToUrl()\n ) => {\n const productFilters = (() => {\n const product = this.props.data.products.find(p => p.id == productId);\n\n if (product) {\n return product.filters;\n }\n })();\n\n const mergedFilters = merge(\n this.getDefaultFilters(),\n this.getCurrentShelfFiltersFromUrl()\n );\n\n this.setState({\n filters: productFilters || mergedFilters,\n });\n\n const { canonical_url_parameters: canonicalUrlParameters } = this.props;\n\n setCanonicalUrl(window, canonicalUrlParameters);\n };\n\n getInitialCopies = products => {\n const currentProductId = this.getCurrentProductIdAccordingToUrl();\n const product =\n products.find(prod => prod.id === currentProductId) || products[0];\n\n if (!product) return;\n\n const [theme] = product.themes,\n defaultCopies = product.set_copies && theme && theme.default_copies;\n\n return (\n defaultCopies ||\n new QuantityPricingTools(product).currentOrFirstAvailableCopies(1)\n );\n };\n\n handleCreateNowClick = (e, button) => {\n const currentProducts = this.getCurrentProducts();\n\n if (currentProducts.length > 1) {\n e.preventDefault();\n\n this.productAndFilters.current.scrollIntoView({ behavior: 'smooth', block: 'start' });\n\n this.setState(\n {\n validateOptionsChosen: true,\n },\n () => {\n button.reset();\n }\n );\n }\n };\n\n getCurrentProducts = () => {\n const { filters } = this.state;\n let { products } = this.props.data;\n\n for (const filter in filters) {\n products = products.filter(\n product =>\n product.filters[filter] === filters[filter] &&\n product.delivery_options.length\n );\n }\n\n return products;\n };\n\n handleOptionChange = (name, value, asset) => {\n this.setState({\n options: {\n ...this.state.options,\n [name]: {\n value: value,\n asset: asset\n }\n },\n });\n };\n\n handleFilterCriteronSelected = (title, criteron) => {\n this.setState({\n filters: {\n ...this.state.filters,\n [title]: criteron,\n },\n options: {}\n });\n };\n\n setInnerHtmlDescription(description) {\n return (\n \n );\n }\n\n renderPriceAndProductCreate = (\n currentProducts,\n selectedTheme,\n calendarStartDate = null,\n copies,\n options,\n variantName,\n selectedDeliveryOptions\n ) => {\n return (\n \n );\n };\n\n setPageAttributesForProduct = (...currentProductParams) => {\n\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // dont' start manipulating the push state until we've seen the default product\n this.pushUrlState.call(\n this,\n !this.defaultProductHasBeenSeen,\n ...currentProductParams\n );\n this.defaultProductHasBeenSeen = true;\n };\n\n pushUrlState = (\n firstTime,\n currentProduct,\n selectedTheme,\n defaultDesignCode,\n variantName,\n selectedDeliveryOptions\n ) => {\n if (\n window.history &&\n (this.getCurrentProductIdAccordingToUrl() != currentProduct.id ||\n firstTime)\n ) {\n // url doesn't match the current product\n const params = {\n product: currentProduct.slug || currentProduct.id, // || currentProduct.id for zero-downtime only\n theme: selectedTheme && selectedTheme.name,\n ...(defaultDesignCode && { design_code: defaultDesignCode }),\n };\n\n if (variantName) {\n params.variant_name = variantName\n }\n\n if (selectedDeliveryOptions) {\n params.selected_delivery_options = selectedDeliveryOptions\n }\n\n // We want to persist certain params for tracking / analytics purposes\n const queryParams = parseQueryString();\n const whitelistedParamsRegex = /^utm_.*$|^veh$|^adid$/;\n\n for (const key in queryParams) {\n if (key.match(whitelistedParamsRegex)) {\n params[key] = queryParams[key];\n }\n }\n\n const path = `${window.location.origin +\n window.location.pathname}?${UrlBuilder.buildURLQuery(params)}`;\n if (firstTime) {\n window.history.replaceState(\n {\n product_id: currentProduct.id,\n },\n '',\n path\n );\n } else {\n window.history.pushState(\n {\n product_id: currentProduct.id,\n },\n '',\n path\n );\n }\n }\n const { canonical_url_parameters: canonicalUrlParameters } = this.props;\n\n setCanonicalUrl(window, canonicalUrlParameters);\n };\n\n handlePopState = (e) => {\n const { state } = e;\n if (state) {\n this.setDefaultFilters(state.product_id);\n }\n };\n\n handlePageShow(e) {\n let historyTraversal =\n e.persisted ||\n (typeof window.performance != 'undefined' &&\n window.performance.getEntriesByType('navigation')[0].type ===\n 'back_forward');\n if (historyTraversal) {\n window.location.reload(true);\n }\n }\n}\n\nGroupedCategoryBase.propTypes = {\n canonical_url_parameters: PropTypes.arrayOf(PropTypes.string),\n};\n\nGroupedCategoryBase.defaultProps = {\n canonical_url_parameters: [],\n};\n\nexport default GroupedCategoryBase;\n\n","'use strict';\n\n// Import Libraries\nimport React from 'react';\n// Import JSX Modules\nimport Select from '../_utils/select-wrapper';\nimport CalendarDates from './calendar-dates';\n\nexport default class CalendarStartDateSelector extends React.Component {\n constructor(props) {\n super(props);\n this.monthOptions = CalendarDates.getOptions();\n this.handleChange = this.handleChange.bind(this);\n }\n render() {\n const selectedOption = this.monthOptions.find((mO) => mO.value === this.props.value) || CalendarDates.getDefaultValue();\n\n return (\n
\n
\n \n { selectedOption.label }\n
\n \n
\n );\n};\n\n\nexport default OptionSelector;\n","'use strict';\n\n// Import Libraries\nimport React from 'react';\n// Import JSX Modules\nimport OptionSelector from './option-selector';\n\n// -----------------------------------------------------------\n// OptionSelectors\n// -----------------------------------------------------------\nconst OptionSelectors = ({options, selected, onChange}) => {\n return (\n
\n {\n (options || []).map((option, i) => {\n return ;\n })\n }\n
\n );\n};\n\nexport default OptionSelectors;\n","'use strict';\n\n// Import Libraries\nimport React from 'react';\nimport PropTypes from 'prop-types';\n// Import JSX Modules\nimport PricesTable from './prices-table';\n\n// -----------------------------------------------------------\n// ProductDescription\n// -----------------------------------------------------------\nconst ProductDescription = ({currentProduct, products, deliveryOptions}, {showPricesTable, description}) => {\n description = (currentProduct && currentProduct.description) || description;\n\n if (showPricesTable) {\n return (\n
\n
\n
\n
\n \n
\n
\n
\n );\n }\n\n if (description) {\n return (\n
\n
\n
\n
\n
\n );\n }\n\n return null;\n};\n\nProductDescription.contextTypes = {\n description: PropTypes.string,\n showPricesTable: PropTypes.bool\n}\n\nexport default ProductDescription;\n","export const calculateDimensions = (url) => new Promise((resolve, reject) => {\n const image = new Image();\n\n image.src = url;\n image.onload = () => {\n resolve({\n width: image.width,\n height: image.height,\n });\n };\n\n image.onerror = () => reject();\n});\n","'use strict';\n\n// Import Libraries\nimport React from 'react';\nimport classNames from 'classnames';\n// Import JSX Modules\nimport Spinner from '../_utils/spinner';\nimport { calculateDimensions } from '../_utils/tools/image-tools';\n// -----------------------------------------------------------\n// FoldedCardProductImage\n// -----------------------------------------------------------\nexport default class FoldedCardProductImage extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.state = {};\n }\n\n componentDidMount() {\n this.updateImageDimensions();\n }\n\n componentDidUpdate(prevProps) {\n if (prevProps.url != this.props.url) {\n this.updateImageDimensions();\n }\n }\n\n render() {\n if (!this.state.loaded) {\n return ;\n }\n\n const backgroundImages = ['url('+this.props.url+')'],\n backgroundSizes = [],\n class_names = ['product-image-selected', 'folded-card'],\n ratio = this.state.height / this.state.width;\n\n if (ratio <= 1) {\n class_names.push('landscape');\n backgroundImages.push('url(/stylesheets/walmart/images/fake_folded_card_backs/landscape.png)');\n backgroundSizes.push('93% auto');\n backgroundSizes.push('7% ' + (((ratio * 100) - 10) * 1.6) + '%');\n } else {\n class_names.push('portrait');\n backgroundImages.push('url(/stylesheets/walmart/images/fake_folded_card_backs/portrait.png)');\n backgroundSizes.push('auto 92%');\n backgroundSizes.push(((1 / ratio) * 92 )+ '% 7%');\n }\n\n return (\n
\n
\n );\n }\n\n updateImageDimensions() {\n calculateDimensions(this.props.url).then(({ height, width }) => {\n this.setState({\n height,\n width,\n loaded: true\n });\n }).catch(() => {\n this.setState({\n loaded: false\n });\n });\n }\n}\n","'use strict';\n\n// Import Libraries\nimport React from 'react';\n// Import JS Modules\nimport classNames from 'classnames';\nimport { calculateDimensions } from '../_utils/tools/image-tools';\n// Import JSX Modules\nimport Spinner from '../_utils/spinner';\n\n// -----------------------------------------------------------\n// MetallicCardProductImage\n// -----------------------------------------------------------\nclass MetallicCardProductImage extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.state = {\n loaded: false\n };\n }\n\n componentDidMount() {\n this.updateImageDimensions();\n }\n\n render() {\n if (!this.state.loaded) {\n return ;\n }\n\n const { width, height } = this.state;\n let portraitClassName;\n\n if (height > width && height > 640) {\n portraitClassName = 'contain-portrait-height';\n } else if (height > width) {\n portraitClassName = 'contain-portrait';\n }\n\n return (\n
\n \n
\n );\n }\n\n updateImageDimensions() {\n calculateDimensions(this.props.url).then(({ height, width }) => {\n this.setState({\n height,\n width,\n loaded: true\n });\n }).catch(() => {\n this.setState({\n loaded: false\n });\n });\n }\n}\n\nexport default MetallicCardProductImage;\n","import React, { useEffect, useState } from 'react';\nimport classNames from 'classnames';\nimport screenAndStyle from '../_utils/screen-and-style';\nimport { calculateDimensions } from '../_utils/tools/image-tools';\nimport Spinner from '../_utils/spinner';\n\nconst maskSrc = (isScalloped, portrait) => {\n const edge = isScalloped ? 'scallop' : 'elegant';\n const orientation = portrait ? 'portrait' : 'landscape';\n const ext = screenAndStyle.isSafari() || screenAndStyle.isEdge() ? '.png' : '.svg';\n\n return `/stylesheets/walmart/images/scalloped_edges_and_elegant_corners/5x7_${edge}_mask_${orientation}${ext}`;\n};\n\nconst RenderNormal = ({ url, alt, isCard, isRounded, dimensions, onLoad }) => {\n const { width, height } = dimensions;\n\n return (\n
\n \n
\n );\n};\n\nconst RenderMasked = ({ portrait, isScalloped, url }) => {\n const getPortraitDimensions = () => {\n return portrait\n ? { paddingTop: '97%', width: '71.5%' }\n : { paddingTop: '71.5%', width: '100%' };\n };\n\n const { paddingTop, width } = getPortraitDimensions();\n const maskedSrc = maskSrc(isScalloped, portrait);\n\n return (\n \n );\n};\nconst RenderCustomisationOverlay = ({url, optionAsset}) => {\n return (\n \n );\n};\nconst ProductImage = ({ url, alt, isCard, isRounded, isElegant, isScalloped, optionAsset }) => {\n const [dimensions, setDimensions] = useState({ height: 0, width: 0 });\n const [loaded, setLoaded] = useState(false);\n const [portrait, setPortrait] = useState(false);\n let mounted = false;\n\n useEffect(() => {\n mounted = true;\n\n if (!loaded) {\n updateImageDimensions(url);\n }\n\n return () => {\n mounted = false;\n }\n }, [loaded, url]);\n\n const updateImageDimensions = (url) => {\n calculateDimensions(url)\n .then(({ height, width }) => {\n if (mounted) {\n setDimensions({ height, width });\n setLoaded(true);\n setPortrait(height > width);\n }\n })\n .catch(() => {\n if (mounted) {\n setLoaded(false);\n }\n });\n };\n\n const renderTemplate = () => {\n if (optionAsset) {\n return \n } else if (isElegant || isScalloped) {\n return \n } else {\n return updateImageDimensions(url)}/>\n }\n }\n\n if (loaded) {\n return renderTemplate();\n } else {\n return ;\n }\n};\n\nexport default ProductImage;\n","'use strict';\n\n// Import Libraries\nimport React from 'react';\n// Import JS Modules\nimport classNames from 'classnames';\n// Import JSX Modules\nimport ProductImage from './product-image';\n\n// -----------------------------------------------------------\n// ProductImageThumbnail\n// -----------------------------------------------------------\nconst ProductImageThumbnail = props => {\n const thumbnailUrl = (() => {\n let urlParts = props.thumbnail.split('/');\n\n urlParts[urlParts.length - 1] = urlParts[urlParts.length - 1].replace(\n /^_hd_product/,\n '_hd_thm_product'\n );\n\n return urlParts.join('/');\n })();\n\n return (\n \n \n
\n );\n\n function handleClick() {\n props.onClick(props.index);\n }\n\n function onKeyPressed(event) {\n if (event.keyCode === 13) {\n props.onClick(props.index);\n }\n }\n};\n\nexport default ProductImageThumbnail;\n","import React from 'react';\n\n// -----------------------------------------------------------\n// ProductVideo\n// -----------------------------------------------------------\nconst ProductVideo = (props) => {\n return (\n