[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/utils/normalize.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { pathOr } from 'ramda'

export const DEFAULT_WIDTH = 'auto'
export const DEFAULT_HEIGHT = 'auto'
export const MAX_WIDTH = 3000
export const MAX_HEIGHT = 4000

/**
 * Having the url below as base for the LEGACY file manager,
 * https://storecomponents.vteximg.com.br/arquivos/ids/155472/Frame-3.jpg?v=636793763985400000
 * the following regex will match https://storecomponents.vteximg.com.br/arquivos/ids/155472
 *
 * Also matches urls with defined sizes like:
 * https://storecomponents.vteximg.com.br/arquivos/ids/155473-160-auto
 * @type {RegExp}
 *
 * On the new vtex.file-manager isn't necessary replace the URL, just add the param on the querystring, like:
 * "?width=WIDTH&height=HEIGHT&aspect=true"
 *
 */
const baseUrlRegex = new RegExp(/.+ids\/(\d+)/)

const httpRegex = new RegExp(/http:\/\//)

function toHttps(url) {
  return url.replace(httpRegex, 'https://')
}

function cleanImageUrl(imageUrl) {
  const result = baseUrlRegex.exec(imageUrl)
  if (result.length > 0) return result[0]
}

function replaceLegacyFileManagerUrl(imageUrl, width, height) {
  const legacyUrlPattern = '/arquivos/ids/'
  const isLegacyUrl = imageUrl.includes(legacyUrlPattern)
  if (!isLegacyUrl) return imageUrl
  return `${cleanImageUrl(imageUrl)}-${width}-${height}`
}

export function changeImageUrlSize(
  imageUrl,
  width = DEFAULT_WIDTH,
  height = DEFAULT_HEIGHT
) {
  if (!imageUrl) return
  typeof width === 'number' && (width = Math.min(width, MAX_WIDTH))
  typeof height === 'number' && (height = Math.min(height, MAX_HEIGHT))

  const normalizedImageUrl = replaceLegacyFileManagerUrl(
    imageUrl,
    width,
    height
  )
  const queryStringSeparator = normalizedImageUrl.includes('?') ? '&' : '?'

  return `${normalizedImageUrl}${queryStringSeparator}width=${width}&height=${height}&aspect=true`
}

function findAvailableProduct(item) {
  return item.sellers.find(
    ({ commertialOffer = {} }) => commertialOffer.AvailableQuantity > 0
  )
}

const defaultImage = { imageUrl: '', imageLabel: '' }
const defaultReference = { Value: '' }
const defaultSeller = { commertialOffer: { Price: 0, ListPrice: 0 } }

const resizeImage = (url, imageSize) =>
  changeImageUrlSize(toHttps(url), imageSize)

export function mapCatalogProductToProductSummary(product, imageSize = 500) {
  if (!product) return null
  const normalizedProduct = { ...product }
  const items = normalizedProduct.items || []
  const sku = items.find(findAvailableProduct) || items[0]
  if (sku) {
    const [seller = defaultSeller] = pathOr([], ['sellers'], sku)
    const [referenceId = defaultReference] = pathOr([], ['referenceId'], sku)
    const catalogImages = pathOr([], ['images'], sku)
    const normalizedImages = catalogImages.map(image => ({
      ...image,
      imageUrl: resizeImage(image.imageUrl, imageSize),
    }))
    const [image = defaultImage] = normalizedImages
    normalizedProduct.sku = {
      ...sku,
      seller,
      referenceId,
      image,
      images: normalizedImages,
    }
  }
  return normalizedProduct
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/utils/attachmentHelper.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { pathOr } from 'ramda'

export const CHOICE_TYPES = {
  SINGLE: 'SINGLE',
  MULTIPLE: 'MULTIPLE',
  TOGGLE: 'TOGGLE',
}

export const getProductPrice = product =>
  pathOr(0, ['sku', 'seller', 'commertialOffer', 'Price'], product)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/utils/displayButtonTypes.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { values, map } from 'ramda'

const displayButtonTypes = {
  DISPLAY_ALWAYS: {
    name: 'admin/editor.productSummary.displayBuyButton.option.always',
    value: 'displayButtonAlways',
  },
  DISPLAY_ON_HOVER: {
    name: 'admin/editor.productSummary.displayBuyButton.option.hover',
    value: 'displayButtonHover',
  },
  DISPLAY_NONE: {
    name: 'admin/editor.productSummary.displayBuyButton.option.none',
    value: 'displayButtonNone',
  },
}

export function getDisplayButtonNames() {
  return map(opt => opt.name, values(displayButtonTypes))
}

export function getDisplayButtonValues() {
  return map(opt => opt.value, values(displayButtonTypes))
}

export default displayButtonTypes

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/utils/propTypes.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import { CHOICE_TYPES } from './attachmentHelper'

export const addedOptionShape = PropTypes.shape({
  item: PropTypes.shape({
    name: PropTypes.string.isRequired,
    sellingPrice: PropTypes.number.isRequired,
    quantity: PropTypes.number.isRequired,
  }),
  normalizedQuantity: PropTypes.number,
  extraQuantity: PropTypes.number,
  choiceType: PropTypes.oneOf([
    CHOICE_TYPES.SINGLE,
    CHOICE_TYPES.MULTIPLE,
    CHOICE_TYPES.TOGGLE,
  ]).isRequired,
})

export const removedOptionShape = PropTypes.shape({
  removedQuantity: PropTypes.number.isRequired,
  initialQuantity: PropTypes.number.isRequired,
  name: PropTypes.string.isRequired,
})

export const productShape = PropTypes.shape({
  /** Product's id */
  productId: PropTypes.string.isRequired,
  /** Product's link text */
  linkText: PropTypes.string.isRequired,
  /** Product's name */
  productName: PropTypes.string.isRequired,
  /** Product's brand */
  brand: PropTypes.string,
  /** Product's brand id */
  brandId: PropTypes.number,
  /** Product's SKU */
  sku: PropTypes.shape({
    /** SKU name */
    name: PropTypes.string.isRequired,
    /** SKU id */
    itemId: PropTypes.string.isRequired,
    /** SKU Image to be shown */
    image: PropTypes.shape({
      /** Image URL */
      imageUrl: PropTypes.string.isRequired,
      /** Image tag as string */
      imageTag: PropTypes.string,
    }).isRequired,
    /** SKU seller */
    seller: PropTypes.shape({
      /** Seller id */
      sellerId: PropTypes.string,
      /** Seller comertial offer */
      commertialOffer: PropTypes.shape({
        /** SKU installments */
        Installments: PropTypes.arrayOf(
          PropTypes.shape({
            /** Installment value */
            Value: PropTypes.number.isRequired,
            /** Interest rate (zero if interest-free) */
            InterestRate: PropTypes.number.isRequired,
            /** Calculated total value */
            TotalValuePlusInterestRate: PropTypes.number,
            /** Number of installments */
            NumberOfInstallments: PropTypes.number.isRequired,
            /** Installments offer name */
            Name: PropTypes.string,
          })
        ),
        /** Selling Price */
        Price: PropTypes.number.isRequired,
        /** List Price */
        ListPrice: PropTypes.number.isRequired,
      }).isRequired,
    }).isRequired,
  }).isRequired,
  /** Product's collections */
  productClusters: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
    })
  ),
  /** Contains relevant assembly options information */
  assemblyOptions: PropTypes.shape({
    added: PropTypes.arrayOf(addedOptionShape),
    removed: PropTypes.arrayOf(removedOptionShape),
    parentPrice: PropTypes.number,
  }),
  /** Quantity of item in Minicart */
  quantity: PropTypes.number,
})

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryContext.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { createContext } from 'react'

const ProductSummaryContext = createContext(0)

const OriginalConsumer = ProductSummaryContext.Consumer
ProductSummaryContext.Consumer = function WrappedConsumer(props) {
  console.error(
    "If you are seeing this, a component it's using ProductSummaryContext from vtex.product-summary, which is deprecated. Please see the issue https://github.com/vtex-apps/store-issues#28 on how to migrate to the new component."
  )

  return <OriginalConsumer {...props} />
}

export default ProductSummaryContext

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummary.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useCallback, useMemo, useEffect } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { pathOr, path } from 'ramda'
import { useInView } from 'react-intersection-observer'
import { Link } from '../../../../../vtex.render-runtime'
import ProductListContext from '../../ProductListContext/ProductListContext'
import ProductSummaryContext from './ProductSummaryContext'
import ProductSummaryContextApp from '../../ProductSummaryContext/ProductSummaryContext'
import ProductContextProvider from '../../ProductContext/ProductContextProvider'
import { productShape } from '../utils/propTypes'
import { mapCatalogProductToProductSummary } from '../utils/normalize'
import useCssHandles from '../../CssHandles/useCssHandles'

const {
  ProductSummaryProvider,
  useProductSummaryDispatch,
  useProductSummary } = ProductSummaryContextApp
const PRODUCT_SUMMARY_MAX_WIDTH = 300
const CSS_HANDLES = ['container', 'containerNormal', 'element', 'clearLink']

const ProductSummaryCustom = ({
  product,
  actionOnClick,
  children,
  containerRef,
}) => {
  const { isLoading, isHovering, selectedItem, query } = useProductSummary()
  const dispatch = useProductSummaryDispatch()
  const handles = useCssHandles(CSS_HANDLES)

  /*
    Use ProductListContext to send pixel events.
    Beware that productListDispatch could be undefined if
    this component is not wrapped by a <ProductListContextProvider/>.
    In that case we don't need to send events.
  */
  const { useProductListDispatch } = ProductListContext
  const productListDispatch = useProductListDispatch()
  const [inViewRef, inView] = useInView({
    // Triggers the event when the element is 75% visible
    threshold: 0.75,
    triggerOnce: true,
  })
  useEffect(() => {
    if (inView) {
      productListDispatch &&
        productListDispatch({
          type: 'SEND_IMPRESSION',
          args: { product: product },
        })
    }
  }, [productListDispatch, inView, product])

  useEffect(() => {
    if (product) {
      dispatch({
        type: 'SET_PRODUCT',
        args: { product },
      })
    }
  }, [product, dispatch])

  const handleMouseLeave = useCallback(() => {
    dispatch({
      type: 'SET_HOVER',
      args: { isHovering: false },
    })
  }, [dispatch])

  const handleMouseEnter = useCallback(() => {
    dispatch({
      type: 'SET_HOVER',
      args: { isHovering: true },
    })
  }, [dispatch])

  const handleItemsStateUpdate = useCallback(
    isLoading => {
      dispatch({
        type: 'SET_LOADING',
        args: { isLoading },
      })
    },
    [dispatch]
  )

  const oldContextProps = useMemo(
    () => ({
      product,
      isLoading,
      isHovering,
      handleItemsStateUpdate: handleItemsStateUpdate,
    }),
    [product, isLoading, isHovering, handleItemsStateUpdate]
  )

  const containerClasses = classNames(
    handles.container,
    handles.containerNormal,
    'overflow-hidden br3 h-100 w-100 flex flex-column justify-between center tc'
  )

  const summaryClasses = classNames(
    handles.element,
    'pointer pt3 pb4 flex flex-column h-100'
  )

  const linkClasses = classNames(handles.clearLink, 'h-100 flex flex-column')

  const skuId = pathOr(
    path(['sku', 'itemId'], product),
    ['itemId'],
    selectedItem
  )

  return (
    <ProductSummaryContext.Provider value={oldContextProps}>
      <ProductContextProvider product={product} query={{ skuId }}>
        <section
          className={containerClasses}
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
          style={{ maxWidth: PRODUCT_SUMMARY_MAX_WIDTH }}
          // If containerRef is passed, it should be used
          ref={containerRef || inViewRef}
        >
          <Link
            className={linkClasses}
            page="store.product"
            params={{
              slug: product && product.linkText,
              id: product && product.productId,
            }}
            query={query}
            onClick={actionOnClick}
          >
            <article className={summaryClasses}>{children}</article>
          </Link>
        </section>
      </ProductContextProvider>
    </ProductSummaryContext.Provider>
  )
}

ProductSummaryCustom.propTypes = {
  /** Product that owns the informations */
  product: productShape,
  /** Function that is executed when a product is clicked */
  actionOnClick: PropTypes.func,
  children: PropTypes.node,
  containerRef: PropTypes.oneOfType([
    // Either a function
    PropTypes.func,
    // Or the instance of a DOM native element
    PropTypes.shape({ current: PropTypes.instanceOf(PropTypes.Element) }),
  ]),
}

function ProductSummaryWrapper(props) {
  return (
    <ProductSummaryProvider {...props}>
      <ProductSummaryCustom {...props} />
    </ProductSummaryProvider>
  )
}

ProductSummaryWrapper.getSchema = () => {
  return {
    title: 'admin/editor.productSummary.title',
    description: 'admin/editor.productSummary.description',
  }
}

// This function is public available to be used only by vtex.shelf and vtex.search-result.
// We do not garantee this API will not change and might happen breaking change anytime.
ProductSummaryWrapper.mapCatalogProductToProductSummary = mapCatalogProductToProductSummary

export default ProductSummaryWrapper

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductListEventCaller.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import useProductImpression from '../../ProductListContext/useProductImpression'

const ProductListEventCaller = () => {
  useProductImpression()
  return null
}

export default ProductListEventCaller

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/__tests__/ProductSummary.test.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import ProductSummary from '../ProductSummaryCustom'

describe('<ProductSummary /> component', () => {
  it(`should parse a product succesfully and get sku as the first with available quantity`, () => {
    const product = {
      productId: '123456789',
      linkText: 'linkText',
      productName: 'productName',
      items: [
        {
          itemId: '1',
          name: 'item 1',
          sellers: [
            {
              sellerId: '1',
              commertialOffer: {
                AvailableQuantity: 0,
                Price: 10,
              },
            },
          ],
          images: [
            {
              imageUrl: 'image1',
              imageLabel: null,
            },
            {
              imageUrl: 'image2',
              imageLabel: null,
            },
          ],
        },
        {
          itemId: '2',
          name: 'item 2',
          sellers: [
            {
              sellerId: '1',
              commertialOffer: {
                AvailableQuantity: 3,
                Price: 15,
              },
            },
          ],
          images: [
            {
              imageUrl: 'image1',
              imageLabel: null,
            },
            {
              imageUrl: 'image2',
              imageLabel: null,
            },
          ],
        },
      ],
      productClusters: [
        {
          name: 'name',
        },
      ],
      quantity: 1,
    }
    const result = ProductSummary.mapCatalogProductToProductSummary(product)
    expect(result).toBeDefined()
    expect(result.sku.seller.sellerId).toBe('1')
    expect(result.sku.image).toBeDefined()
    expect(result.sku.itemId).toBe('2')
  })
  it(`should not break ProductSummary getSchema`, () => {
    expect(ProductSummary.getSchema).toEqual(expect.any(Function))
  })
})

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/__tests__/ProductSummaryLegacy.test.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { render } from '@vtex/test-tools/react'
import fs from 'fs'

import ProductSummary from '../legacy/index'

describe('<ProductSummary /> component', () => {
  // TODO: Remove this later when we have a better way to resolve contentSchemas.json at test-tools
  const rawData = fs.readFileSync('../store/contentSchemas.json')
  const contentSchema = JSON.parse(rawData)
  const buyButtonText =
    contentSchema.definitions.ProductSummary.properties.buyButtonText.default

  const props = {
    runtime: { hints: {} },
    buyButtonText,
    product: {
      productId: '123456789',
      linkText: 'linkText',
      productName: 'productName',
      sku: {
        name: 'name',
        itemId: 'itemId',
        image: {
          imageUrl: '',
        },
        seller: {
          sellerId: 'sellerId',
          commertialOffer: {
            Installments: [
              {
                Value: 1,
                InterestRate: 1,
                NumberOfInstallments: 1,
              },
            ],
            Price: 1,
            ListPrice: 1,
          },
        },
      },
      productClusters: [
        {
          name: 'name',
        },
      ],
      quantity: 1,
    },
  }

  function renderComponent(customProps) {
    return render(<ProductSummary {...props} {...customProps} />)
  }

  it('should match the snapshot for normal mode', () => {
    const { asFragment } = renderComponent({ displayMode: 'normal' })
    expect(asFragment()).toMatchSnapshot()
  })

  it('should match the snapshot for small mode', () => {
    const { asFragment } = renderComponent({ displayMode: 'small' })
    expect(asFragment()).toMatchSnapshot()
  })

  it('should match the snapshot for inline normal mode', () => {
    const { asFragment } = renderComponent({ displayMode: 'inline' })
    expect(asFragment()).toMatchSnapshot()
  })

  it('should match the snapshot for inline price mode', () => {
    const { asFragment } = renderComponent({ displayMode: 'inlinePrice' })
    expect(asFragment()).toMatchSnapshot()
  })

  it('should render buy button in inline, small and normal mode', () => {
    const { getByText, rerender, container } = renderComponent({
      displayMode: 'normal',
    })
    expect(getByText('Buy')).toBeTruthy()

    rerender(<ProductSummary {...props} displayMode="small" />)
    expect(getByText('Buy')).toBeTruthy()

    rerender(<ProductSummary {...props} displayMode="inline" />)
    expect(getByText('Buy')).toBeTruthy()

    rerender(<ProductSummary {...props} displayMode="inlinePrice" />)
    expect(container.querySelector('.buyButtonContainer')).toBeFalsy()
  })

  it('should render quantity stepper only in inline price mode', () => {
    const { container, rerender } = renderComponent({ displayMode: 'normal' })
    expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()

    rerender(<ProductSummary {...props} displayMode="inlinePrice" />)
    expect(container.querySelector('.quantityStepperContainer')).toBeTruthy()

    rerender(<ProductSummary {...props} displayMode="small" />)
    expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()

    rerender(<ProductSummary {...props} displayMode="inline" />)
    expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()
  })

  it(`should not break Shelf getSchema`, () => {
    expect(ProductSummary.getSchema).toEqual(expect.any(Function))
  })

  describe('Site editor editable', () => {
    it('should export getSchema and return object with title', () => {
      const schema = ProductSummary.schema || ProductSummary.getSchema({})
      expect(schema).toEqual(
        expect.objectContaining({ title: expect.any(String) })
      )
    })
  })
})

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryNormal.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import { path } from 'ramda'
import classNames from 'classnames'
import { ExtensionPoint, Link } from '../../../../../../vtex.render-runtime'

import AttachmentList from './AttachmentList'
import ProductImage from './ProductImage'
import ProductSummaryBuyButton from './ProductSummaryBuyButton'
import ProductSummaryPrice from './ProductSummaryPrice'
import ProductSummaryName from './ProductSummaryName'
import ProductSummaryDescription from './ProductSummaryDescription'

import productSummary from '../../productSummary.css'

class ProductSummaryNormal extends Component {
  render() {
    const {
      product,
      showBorders,
      showDescription,
      handleMouseEnter,
      handleMouseLeave,
      actionOnClick,
      imageProps,
      nameProps,
      priceProps,
      buyButtonProps,
    } = this.props

    const containerClasses = classNames(
      productSummary.container,
      productSummary.containerNormal,
      'overflow-hidden br3 h-100 w-100 flex flex-column justify-between center tc'
    )

    const summaryClasses = classNames(
      `${productSummary.element} pointer pt3 pb4 flex flex-column h-100`,
      {
        'bb b--muted-4 mh2 mt2': showBorders,
      }
    )

    const nameClasses = {
      containerClass: `flex items-start ${productSummary.nameContainer} justify-center pv6`,
      brandNameClass: 't-body',
    }

    const priceClasses = {
      containerClass: classNames(
        'flex flex-column justify-end items-center relative',
        {
          [`${productSummary.priceContainer} pv5`]: !showBorders,
        }
      ),
      sellingPriceClass: 'dib ph2 t-body t-heading-5-ns',
    }

    const buyButtonClasses = {
      containerClass: `${productSummary.buyButtonContainer} pv3 w-100 db`,
    }

    const descriptionClasses = `${productSummary.description} c-muted-2 t-small`

    return (
      <section
        className={containerClasses}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
      >
        <div className={`${productSummary.addToListBtn} absolute z-1 mt3`}>
          <ExtensionPoint
            id="addon-summary-btn"
            product={{
              skuId: path(['sku', 'itemId'], product),
              productId: path(['productId'], product),
              quantity: 1,
            }}
          />
        </div>
        <Link
          className={`${productSummary.clearLink} h-100 flex flex-column`}
          page={'store.product'}
          params={{
            slug: product && product.linkText,
            id: product && product.productId,
          }}
          onClick={actionOnClick}
        >
          <article className={summaryClasses}>
            <div className={`${productSummary.imageContainer} db w-100 center`}>
              <ProductImage {...imageProps} />
            </div>
            <div
              className={`${productSummary.information} h-100 flex flex-column justify-between`}
            >
              <ProductSummaryName {...nameProps} {...nameClasses} />
              <AttachmentList product={product} />
              {showDescription && (
                <ProductSummaryDescription
                  description={product.description}
                  descriptionClasses={descriptionClasses}
                />
              )}
              <div>
                <ProductSummaryPrice {...priceProps} {...priceClasses} />
              </div>
            </div>
          </article>
          <ProductSummaryBuyButton {...buyButtonProps} {...buyButtonClasses} />
        </Link>
      </section>
    )
  }
}

export default ProductSummaryNormal

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummarySmall.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import { path } from 'ramda'
import classNames from 'classnames'
import { Link } from '../../../../../../vtex.render-runtime'

import AttachmentList from './AttachmentList'
import ProductImage from './ProductImage'
import ProductSummaryBuyButton from './ProductSummaryBuyButton'
import ProductSummaryPrice from './ProductSummaryPrice'
import ProductSummaryName from './ProductSummaryName'

import styles from '../../productSummary.css'

class ProductSummarySmall extends Component {
  render() {
    const {
      product,
      showBorders,
      handleMouseEnter,
      handleMouseLeave,
      actionOnClick,
      imageProps,
      nameProps,
      priceProps,
      buyButtonProps,
    } = this.props

    const containerClasses = classNames(
      styles.container,
      styles.containerSmall,
      'overflow-hidden br3 h-100 flex flex-column justify-between center tc'
    )

    const summaryClasses = classNames(
      styles.element,
      'pointer pt3 pb4 flex flex-column',
      {
        'bb b--muted-4 mh2 mt2': showBorders,
      }
    )

    const nameClasses = {
      containerClass: `flex items-start ${styles.nameContainer} justify-center pv5 t-mini pb2`,
      brandNameClass: 't-body t-mini',
    }

    const priceClasses = {
      containerClass: classNames('flex flex-column justify-end items-center', {
        [`${styles.priceContainer} pv5`]: !showBorders,
      }),
      sellingPriceClass: 'dib ph2 t-body t-heading-5-ns',
    }

    const buyButtonClasses = {
      containerClass: `${styles.buyButtonContainer} pv3 w-100 dn`,
    }

    return (
      <section
        className={containerClasses}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
      >
        <Link
          className={`${styles.clearLink} flex flex-column`}
          page={'store.product'}
          params={{ slug: path(['linkText'], product) }}
          onClick={actionOnClick}
        >
          <article className={summaryClasses}>
            <div className={`${styles.imageContainer} db w-100 center`}>
              <ProductImage {...imageProps} />
            </div>
            <div className={styles.information}>
              <ProductSummaryName {...nameProps} {...nameClasses} />
              <AttachmentList product={product} />
              <div>
                <ProductSummaryPrice {...priceProps} {...priceClasses} />
              </div>
            </div>
          </article>
          <ProductSummaryBuyButton {...buyButtonProps} {...buyButtonClasses} />
        </Link>
      </section>
    )
  }
}

export default ProductSummarySmall

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryInlinePrice.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import classNames from 'classnames'
import { Link } from '../../../../../../vtex.render-runtime'

import AttachmentList from './AttachmentList'
import ProductImage from './ProductImage'
import ProductQuantityStepper from './ProductQuantityStepper'
import ProductSummaryPrice from './ProductSummaryPrice'
import ProductSummaryName from './ProductSummaryName'

import styles from '../../productSummary.css'

const ProductSummaryInlinePrice = ({
  product,
  showBorders,
  handleMouseEnter,
  handleMouseLeave,
  handleItemsStateUpdate,
  actionOnClick,
  imageProps,
  nameProps,
  priceProps,
  showQuantitySelector,
  priceAlignLeft,
  muted,
  index,
}) => {
  const containerClasses = classNames(
    styles.container,
    styles.containerInline,
    'br3 h-100 w-100'
  )

  const summaryClasses = classNames(
    `${styles.element} pointer ph2 pt3 pb4 flex flex-column h-100`,
    {
      'bb b--muted-4 mh2 mh3-ns mt2': showBorders,
    }
  )

  const nameClasses = {
    containerClass: classNames(
      'flex items-start justify-left tl w-90 t-mini pb2',
      { 'c-muted-1': muted }
    ),
    brandNameClass: classNames('t-body', {
      'c-muted-1': muted,
      'c-on-base': !muted,
    }),
    skuNameClass: classNames('t-small', {
      'c-muted-2': muted,
    }),
  }

  const priceClasses = {
    containerClass: classNames('flex flex-column nr1 h1', {
      'items-start': priceAlignLeft,
      'items-end': !priceAlignLeft,
      [`${styles.priceContainer} pv5`]: !showBorders,
    }),
    sellingPriceClass: classNames('dib ph2 t-body t-heading-5-ns', {
      'c-muted-1': muted,
    }),
  }

  return (
    <section
      className={containerClasses}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      <article className={summaryClasses}>
        <Link
          className={`${styles.clearLink} flex h-100`}
          page="store.product"
          params={{
            slug: product && product.linkText,
            id: product && product.productId,
          }}
          onClick={actionOnClick}
        >
          <div className={`${styles.imageContainer} db h-100`}>
            <ProductImage {...imageProps} />
          </div>
          <div className={`${styles.information} w-70 pb2 ph3`}>
            <ProductSummaryName {...nameProps} {...nameClasses} />
            <AttachmentList product={product} />
            <div className="mv3 nr2">
              <div
                onClick={e => {
                  e.preventDefault()
                  // Stop propagation so it doesn't trigger the Link component above
                  e.stopPropagation()
                }}
                className={`flex justify-end nr4 mb2 ${styles.quantityStepperContainer}`}
              >
                {showQuantitySelector && (
                  <ProductQuantityStepper
                    product={product}
                    onUpdateItemsState={handleItemsStateUpdate}
                    index={index}
                  />
                )}
              </div>
              <ProductSummaryPrice {...priceProps} {...priceClasses} />
            </div>
          </div>
        </Link>
      </article>
    </section>
  )
}

export default ProductSummaryInlinePrice

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryName.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { path } from 'ramda'
import ProductName from '../../../StoreComponents/ProductName'

import { productShape } from '../../utils/propTypes'

const ProductSummaryName = ({
  product,
  showFieldsProps,
  containerClass,
  brandNameClass,
  skuNameClass,
}) => {
  const productName = path(['productName'], product)
  const skuName = path(['sku', 'name'], product)
  const brandName = path(['brand'], product)

  return (
    <div className={containerClass}>
      <ProductName
        className="overflow-hidden c-on-base"
        brandNameClass={brandNameClass}
        skuNameClass={skuNameClass}
        loaderClass="pt5 overflow-hidden"
        name={productName}
        skuName={skuName}
        brandName={brandName}
        {...showFieldsProps}
      />
    </div>
  )
}

ProductSummaryName.propTypes = {
  /** Product that owns the informations */
  product: productShape,
  /** Name schema props */
  showFieldsProps: PropTypes.object,
  /** Styles used in the container div */
  containerClass: PropTypes.string,
  /** Styles used in the brand name */
  brandNameClass: PropTypes.string,
}

export default ProductSummaryName

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryPrice.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { path, prop } from 'ramda'

import Spinner from '../../../Styleguide/Spinner'
import ProductPrice from '../../../StoreComponents/ProductPrice'

import { productShape } from '../../utils/propTypes'

const ProductSummaryPrice = ({
  product,
  showListPrice,
  showLabels,
  showInstallments,
  labelSellingPrice,
  labelListPrice,
  isLoading,
  containerClass,
  sellingPriceClass,
}) => {
  const commertialOffer = path(['sku', 'seller', 'commertialOffer'], product)

  if (isLoading) {
    return (
      <div className="flex items-end justify-end w-100 h1 pr6">
        <Spinner size={20} />
      </div>
    )
  }

  const sellingPrice = prop('Price', commertialOffer)

  return (
    <div className={containerClass}>
      {sellingPrice !== 0 && (
        <ProductPrice
          className="flex flex-column justify-start"
          listPriceContainerClass="pv1 normal c-muted-2"
          listPriceLabelClass="dib strike t-small t-mini"
          listPriceClass="dib ph2 strike t-small-ns t-mini"
          sellingPriceContainerClass="pt1 pb3 c-on-base"
          sellingPriceLabelClass="dib"
          sellingPriceClass={sellingPriceClass}
          savingsContainerClass="t-small-ns c-muted-2"
          savingsClass="dib"
          interestRateClass="dib pl2"
          installmentContainerClass="t-small-ns c-muted-2"
          listPrice={prop('ListPrice', commertialOffer)}
          sellingPrice={prop('Price', commertialOffer)}
          installments={prop('Installments', commertialOffer)}
          showListPrice={showListPrice}
          showLabels={showLabels}
          showInstallments={showInstallments}
          labelSellingPrice={labelSellingPrice}
          labelListPrice={labelListPrice}
        />
      )}
    </div>
  )
}

ProductSummaryPrice.propTypes = {
  /** Product that owns the informations */
  product: productShape,
  /** Set the product list price's visibility */
  showListPrice: PropTypes.bool,
  /** Set pricing labels' visibility */
  showLabels: PropTypes.bool,
  /** Set installments' visibility */
  showInstallments: PropTypes.bool,
  /** Text of selling Price's label */
  labelSellingPrice: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  /** Text of selling Price's label */
  labelListPrice: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  /** Defines if the loading spinner is shown */
  isLoading: PropTypes.bool,
  /** Styles used in the container div */
  containerClass: PropTypes.string,
  /** Styles used in the selling price */
  sellingPriceClass: PropTypes.string,
}

export default ProductSummaryPrice

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryDescription.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'

const MAX_SIZE_DESCRIPTION = 120

const ProductSummaryDescription = ({ descriptionClasses, description }) => {
  if (!description) return <Fragment />

  const descriptionTruncated =
    description.length > MAX_SIZE_DESCRIPTION
      ? `${description.substring(0, MAX_SIZE_DESCRIPTION)}...`
      : description

  return <span className={descriptionClasses}>{descriptionTruncated}</span>
}

ProductSummaryDescription.propTypes = {
  /** Styles used in the description */

  descriptionClasses: PropTypes.string.isRequired,
  /** Description of the product */

  description: PropTypes.string,
}

export default ProductSummaryDescription

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryBuyButton.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import BuyButton from '../../../StoreComponents/BuyButton'
import { equals, path } from 'ramda'
import classNames from 'classnames'
import IOMessage from '../../../NativeTypes/IOMessage'
import { useRuntime } from '../../../../../../vtex.render-runtime'

import displayButtonTypes from '../../utils/displayButtonTypes'
import productSummary from '../../productSummary.css'

const ProductSummaryBuyButton = ({
  product,
  displayBuyButton,
  isOneClickBuy,
  buyButtonText,
  isHovering,
  containerClass,
}) => {
  const {
    hints: { mobile },
  } = useRuntime()

  const hoverBuyButton =
    equals(displayBuyButton, displayButtonTypes.DISPLAY_ALWAYS.value) ||
    !equals(displayBuyButton, displayButtonTypes.DISPLAY_ON_HOVER.value) ||
    (isHovering && !mobile)

  const showBuyButton =
    !equals(displayBuyButton, displayButtonTypes.DISPLAY_NONE.value) &&
    !(
      equals(displayBuyButton, displayButtonTypes.DISPLAY_ON_HOVER.value) &&
      mobile
    )

  const buyButtonClasses = classNames(
    `${productSummary.buyButton} center mw-100`,
    {
      [productSummary.isHidden]: !hoverBuyButton,
    }
  )

  // TODO: change ProductSummaryContext to have `selectedSku` field instead of `sku`
  const selectedItem = product.sku
  const selectedSeller = path(['seller'], selectedItem)
  const isAvailable =
    selectedSeller &&
    selectedSeller.commertialOffer &&
    selectedSeller.commertialOffer.AvailableQuantity > 0
  const skuItems = BuyButton.mapCatalogItemToCart({
    product,
    selectedItem,
    selectedSeller,
    selectedQuantity: 1,
  })

  return (
    showBuyButton && (
      <div className={containerClass}>
        <div className={buyButtonClasses}>
          <BuyButton
            available={isAvailable}
            skuItems={skuItems}
            isOneClickBuy={isOneClickBuy}
          >
            <IOMessage id={buyButtonText} />
          </BuyButton>
        </div>
      </div>
    )
  )
}

export default ProductSummaryBuyButton

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductQuantityStepper.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import { compose, path } from 'ramda'
import PropTypes from 'prop-types'
import NumericStepper from '../../../Styleguide/NumericStepper'
import withToast from '../../../Styleguide/withToast'
import PixelContext from '../../../PixelContext/PixelContext'
import { debounce } from 'debounce'
import { injectIntl } from 'react-intl'
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

import { productShape } from '../../utils/propTypes'

const { Pixel } = PixelContext
const UPDATE_ITEMS_MUTATION = gql`
  mutation updateItemsStepper($items: [MinicartItem]) {
    updateItems(items: $items) @client
  }
`

const UPDATE_LOCAL_ITEMS_MUTATION = gql`
  mutation updateLocalItems($items: [MinicartItem]) {
    updateLocalItems(items: $items) @client
  }
`

class ProductQuantityStepper extends Component {
  static propTypes = {
    product: productShape.isRequired,
    onUpdateItemsState: PropTypes.func.isRequired,
    showToast: PropTypes.func,
    minicartItems: PropTypes.array,
    updateItems: PropTypes.func.isRequired,
    updateLocalItems: PropTypes.func.isRequired,
    push: PropTypes.func.isRequired,
    index: PropTypes.number,
  }

  state = {
    quantity: this.props.product.quantity,
    canIncrease: true,
  }

  pushPixelCartEvents = ({ isAdditionOfProd, product }) => {
    const updatedProduct = {
      skuId: path(['sku', 'itemId'], product),
      variant: path(['sku', 'name'], product),
      price: path(['assemblyOptions', 'parentPrice'], product),
      name: path(['productName'], product),
      quantity: path(['quantity'], product),
      productRefId: product.productRefId,
      brand: product.brand,
      category: product.category,
    }
    if (isAdditionOfProd) {
      this.props.push({
        event: 'addToCart',
        items: [updatedProduct],
      })
    } else {
      // removal of product
      this.props.push({
        event: 'removeFromCart',
        items: [updatedProduct],
      })
    }
  }

  componentDidUpdate = prevProps => {
    const {
      product: { quantity: prevQuantity },
    } = prevProps
    const {
      product: { quantity },
      showToast,
      intl,
    } = this.props
    if (prevQuantity !== quantity) {
      this.pushPixelCartEvents({
        isAdditionOfProd: prevQuantity < quantity,
        product: this.props.product,
      })
      const canIncrease = quantity === this.state.quantity
      this.setState({ quantity, canIncrease })
      if (!canIncrease) {
        showToast({
          message: intl.formatMessage({
            id: 'store/productSummary.quantity-error',
          }),
        })
      }
    }
  }

  handleOnChange = e => {
    e.stopPropagation()
    e.preventDefault()
    this.props.onUpdateItemsState(true)
    this.setState({ quantity: e.value }, () =>
      this.debouncedUpdate(this.state.quantity)
    )
  }

  updateItemQuantity = async quantity => {
    const { product, updateItems, updateLocalItems, index } = this.props
    this.setState({ canIncrease: true })
    const {
      sku: { itemId: id, seller = {} },
      cartIndex,
    } = product
    try {
      if (cartIndex != null) {
        await updateItems([
          {
            id,
            quantity,
            seller: seller.sellerId,
            index: cartIndex,
          },
        ])
      } else {
        await updateLocalItems([
          {
            id,
            quantity,
            seller: seller.sellerId,
            index,
          },
        ])
      }
    } catch (err) {
      // gone wrong, rollback to old quantity value
      console.error(err)
    }
    this.props.onUpdateItemsState(false)
  }

  debouncedUpdate = debounce(this.updateItemQuantity, 1000)

  render() {
    return (
      <NumericStepper
        lean
        size="small"
        value={this.state.quantity}
        minValue={1}
        maxValue={this.state.canIncrease ? undefined : this.state.quantity}
        onChange={this.handleOnChange}
      />
    )
  }
}

const withUpdateItemsMutation = graphql(UPDATE_ITEMS_MUTATION, {
  props: ({ mutate }) => ({
    updateItems: items => mutate({ variables: { items } }),
  }),
})

const withUpdateLocalItemsMutation = graphql(UPDATE_LOCAL_ITEMS_MUTATION, {
  props: ({ mutate }) => ({
    updateLocalItems: items => mutate({ variables: { items } }),
  }),
})

export default compose(
  Pixel,
  injectIntl,
  withToast,
  withUpdateItemsMutation,
  withUpdateLocalItemsMutation
)(ProductQuantityStepper)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductSummaryInline.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import classNames from 'classnames'
import { Link } from '../../../../../../vtex.render-runtime'

import AttachmentList from './AttachmentList'
import ProductImage from './ProductImage'
import ProductSummaryBuyButton from './ProductSummaryBuyButton'
import ProductSummaryPrice from './ProductSummaryPrice'
import ProductSummaryName from './ProductSummaryName'

import productSummary from '../../productSummary.css'

class ProductSummaryInline extends Component {
  render() {
    const {
      product,
      showBorders,
      handleMouseEnter,
      handleMouseLeave,
      actionOnClick,
      imageProps,
      nameProps,
      priceProps,
      buyButtonProps,
    } = this.props

    const containerClasses = classNames(
      productSummary.container,
      productSummary.containerInlinePrice,
      'overflow-hidden br3 h-100 w-100'
    )

    const summaryClasses = classNames(
      `${productSummary.element} ${productSummary.clearLink} pointer pt3 pb4 flex flex-column`,
      {
        'bb b--muted-4 mh2 mh3-ns mt2': showBorders,
      }
    )

    const nameClasses = {
      containerClass: 'flex items-start justify-left tl w-90 t-mini pb2',
      brandNameClass: 't-body c-on-base',
    }

    const priceClasses = {
      containerClass: classNames('flex flex-column nr1', {
        [`${productSummary.priceContainer}`]: !showBorders,
      }),
      sellingPriceClass: 'dib ph2 t-body t-heading-5-ns',
    }

    const buyButtonClasses = {
      containerClass: `${productSummary.buyButtonContainer} pt3 w-100`,
    }

    return (
      <section
        className={containerClasses}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
      >
        <Link
          className={summaryClasses}
          page={'store.product'}
          params={{
            slug: product && product.linkText,
            id: product && product.productId,
          }}
          onClick={actionOnClick}
        >
          <article className="flex">
            <div className={`${productSummary.imageContainer} db w-70`}>
              <ProductImage {...imageProps} />
            </div>
            <div
              className={`${productSummary.information} w-80 pb2 pl3 flex flex-wrap flex-column justify-between`}
            >
              <div className="flex flex-column">
                <ProductSummaryName {...nameProps} {...nameClasses} />
                <AttachmentList product={product} />
                <div className="nr2">
                  <ProductSummaryPrice {...priceProps} {...priceClasses} />
                </div>
              </div>
              <div className="flex flex-column-reverse">
                <ProductSummaryBuyButton
                  {...buyButtonProps}
                  {...buyButtonClasses}
                />
              </div>
            </div>
          </article>
        </Link>
      </section>
    )
  }
}

export default ProductSummaryInline

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/AttachmentList.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { productShape } from '../../utils/propTypes'
import { pathOr, reject } from 'ramda'

import RemovedAttachmentsList from '../../components/ProductSummaryAttachmentList/RemovedAttachmentsList'
import AddedAttachmentsList from '../../components/ProductSummaryAttachmentList/AddedAttachmentsList'

import styles from '../../productSummary.css'

const itemShouldHide = ({ item, extraQuantity }) =>
  extraQuantity === 0 && item.sellingPriceWithAssemblies === 0

const AttachmentList = ({ product }) => {
  const addedOptions = pathOr([], ['assemblyOptions', 'added'], product)
  const removedOptions = pathOr([], ['assemblyOptions', 'removed'], product)

  const filteredOption = reject(itemShouldHide, addedOptions)

  if (filteredOption.length === 0 && removedOptions.length === 0) {
    return null
  }

  return (
    <div className={`${styles.attachmentListContainer} pv2`}>
      <AddedAttachmentsList
        addedOptions={filteredOption}
      />
      <RemovedAttachmentsList removedOptions={removedOptions} />
    </div>
  )
}

AttachmentList.propTypes = {
  product: productShape,
}

export default AttachmentList

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/legacy/components/ProductImage.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useState } from 'react'
import { path, pathOr, compose } from 'ramda'
import PropTypes from 'prop-types'
import CollectionBadges from '../../../StoreComponents/CollectionBadges'
import DiscountBadge from '../../../StoreComponents/DiscountBadge'
import classNames from 'classnames'

import ImagePlaceholder from '../../components/ProductSummaryImage/ImagePlaceholder'

import { productShape } from '../../utils/propTypes'

import productSummary from '../../productSummary.css'

const maybeBadge = ({ listPrice, price, label }) => shouldShow => component => {
  if (shouldShow) {
    return (
      <DiscountBadge listPrice={listPrice} sellingPrice={price} label={label}>
        {component}
      </DiscountBadge>
    )
  }
  return component
}

const maybeCollection = ({ productClusters }) => shouldShow => component => {
  if (shouldShow && productClusters && productClusters.length > 0) {
    const collections = productClusters.map(cl => cl.name)
    return (
      <CollectionBadges collectionBadgesText={collections}>
        {component}
      </CollectionBadges>
    )
  }
  return component
}

const ProductImage = ({
  product,
  showBadge,
  badgeText,
  showCollections,
  displayMode,
}) => {
  const [error, setError] = useState(false)
  if (!path(['sku', 'image', 'imageUrl'], product) || error) {
    return <ImagePlaceholder cssHandle={productSummary.imagePlaceholder} />
  }

  const {
    productClusters,
    productName: name,
    sku: {
      image: { imageUrl },
    },
  } = product

  const imageClassName = classNames({
    [productSummary.imageNormal]: displayMode !== 'inline',
    [productSummary.imageInline]: displayMode === 'inline',
  })

  const commertialOffer = pathOr(
    {},
    ['sku', 'seller', 'commertialOffer'],
    product
  )

  const withBadge = maybeBadge({
    listPrice: commertialOffer.ListPrice,
    price: commertialOffer.Price,
    label: badgeText,
  })
  const withCollection = maybeCollection({ productClusters })
  const img = (
    <img
      className={imageClassName}
      src={imageUrl}
      alt={name}
      onError={() => setError(true)}
    />
  )

  return compose(
    withBadge(showBadge),
    withCollection(showCollections)
  )(img)
}

ProductImage.propTypes = {
  /** Product that owns the informations */
  product: productShape,
  /** Set the discount badge's visibility */
  showBadge: PropTypes.bool,
  /** Text shown on badge */
  badgeText: PropTypes.string,
  /** Defines if the collection badges are shown */
  showCollections: PropTypes.bool,
  /** Display mode of the summary */
  displayMode: PropTypes.string,
}

export default ProductImage

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryBuyButton/ProductSummaryBuyButton.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import BuyButton from '../../../StoreComponents/BuyButton'
import { withRuntimeContext } from '../../../../../../vtex.render-runtime'
import { equals, path } from 'ramda'
import classnames from 'classnames'
import IOMessage from '../../../NativeTypes/IOMessage'

import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp
import displayButtonTypes, {
  getDisplayButtonNames,
  getDisplayButtonValues,
} from '../../utils/displayButtonTypes'

import productSummary from '../../productSummary.css'
import useCssHandles from '../../../CssHandles/useCssHandles'

const ALWAYS_GO_TO_PRODUCT = 'alwaysGoToProduct'
const DEFAULT_BUTTON_BEHAVIOR = 'default'
const BUY_BUTTON_BEHAVIOR_OPTIONS = [
  ALWAYS_GO_TO_PRODUCT,
  DEFAULT_BUTTON_BEHAVIOR,
]
const CSS_HANDLES = ['buyButton', 'buyButtonContainer']

const ProductSummaryBuyButton = ({
  displayBuyButton,
  isOneClickBuy,
  buyButtonText,
  customToastURL,
  runtime: {
    hints: { mobile },
  },
  buyButtonBehavior,
  isHovering,
}) => {
  const { product, selectedItem, selectedQuantity } = useProductSummary()
  const handles = useCssHandles(CSS_HANDLES)

  const hoverBuyButton =
    equals(displayBuyButton, displayButtonTypes.DISPLAY_ALWAYS.value) ||
    !equals(displayBuyButton, displayButtonTypes.DISPLAY_ON_HOVER.value) ||
    (isHovering && !mobile)

  const showBuyButton =
    !equals(displayBuyButton, displayButtonTypes.DISPLAY_NONE.value) &&
    !(
      equals(displayBuyButton, displayButtonTypes.DISPLAY_ON_HOVER.value) &&
      mobile
    )

  const buyButtonClasses = classnames(
    handles.buyButton,
    'center mw-100',
    {
      [productSummary.isHidden]: !hoverBuyButton,
    }
  )

  const containerClass = classnames(
    handles.buyButtonContainer,
    'pv3 w-100 db'
  )

  const selectedSeller = path(['seller'], selectedItem)
  const isAvailable =
    selectedSeller &&
    selectedSeller.commertialOffer &&
    selectedSeller.commertialOffer.AvailableQuantity > 0
  const skuItems = BuyButton.mapCatalogItemToCart({
    product,
    selectedItem,
    selectedSeller,
    selectedQuantity,
  })

  const { items = [] } = product
  // if the item is not available the behavior is just show the disabled BuyButton,
  // but you still can go to the product page clicking in the summary
  const shouldBeALink =
    (items.length !== 1 || buyButtonBehavior !== DEFAULT_BUTTON_BEHAVIOR) &&
    isAvailable

  return (
    showBuyButton && (
      <div
        className={containerClass}
        data-testid="product-summary__buy-button-container"
      >
        <div className={buyButtonClasses}>
          <BuyButton
            skuItems={skuItems}
            available={isAvailable}
            isOneClickBuy={isOneClickBuy}
            customToastURL={customToastURL}
            shouldAddToCart={!shouldBeALink}
          >
            <IOMessage id={buyButtonText} />
          </BuyButton>
        </div>
      </div>
    )
  )
}

ProductSummaryBuyButton.propTypes = {
  /** Runtime context */
  runtime: PropTypes.shape({
    hints: PropTypes.shape({
      /** Indicates if is on a mobile device */
      mobile: PropTypes.bool,
    }),
  }),
  /** What the buy button should do when you click it, if you pass default it will add to cart only if there is only one SKU of that product */
  buyButtonBehavior: PropTypes.oneOf(BUY_BUTTON_BEHAVIOR_OPTIONS),
  /** Should redirect to checkout after clicking on buy */
  isOneClickBuy: PropTypes.bool,
  /** Custom buy button text */
  buyButtonText: PropTypes.string,
  /** Defines the display mode of buy button */
  displayBuyButton: PropTypes.oneOf(getDisplayButtonValues()),
  /** A custom URL for the `VIEW CART` button inside the toast created by BuyButton */
  customToastURL: PropTypes.string,
}

ProductSummaryBuyButton.defaultProps = {
  displayBuyButton: displayButtonTypes.DISPLAY_ALWAYS.value,
  isOneClickBuy: false,
  buyButtonBehavior: DEFAULT_BUTTON_BEHAVIOR,
}

ProductSummaryBuyButton.getSchema = () => {
  return {
    title: 'admin/editor.productSummaryBuyButton.title',
    type: 'object',
    properties: {
      isOneClickBuy: {
        type: 'boolean',
        title: 'admin/editor.productSummary.isOneClickBuy.title',
        default: false,
        isLayout: true,
      },
      displayBuyButton: {
        title: 'admin/editor.productSummary.displayBuyButton.title',
        type: 'string',
        enum: getDisplayButtonValues(),
        enumNames: getDisplayButtonNames(),
        default: displayButtonTypes.DISPLAY_ALWAYS.value,
        isLayout: true,
      },
    },
  }
}

export default withRuntimeContext(ProductSummaryBuyButton)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryBrand/ProductSummaryBrand.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import ProductBrand from '../../../StoreComponents/ProductBrand'

import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp

const DISPLAY_MODE = {
  LOGO: 'logo',
  TEXT: 'text',
}

const ProductSummaryBrand = ({
  displayMode,
  fallbackToText,
  height,
  excludeBrands,
  logoWithLink,
}) => {
  const { product } = useProductSummary()
  return (
    <ProductBrand
      displayMode={displayMode}
      fallbackToText={fallbackToText}
      height={height}
      excludeBrands={excludeBrands}
      logoWithLink={logoWithLink}
      brandName={product.brand}
      brandId={product.brandId}
    />
  )
}

ProductSummaryBrand.propTypes = {
  /** Whether it should be displayed as a logo or as a text */
  displayMode: PropTypes.oneOf(Object.values(DISPLAY_MODE)),
  /** Whether it should display the name of the brand if there is no logo */
  fallbackToText: PropTypes.bool,
  /** List of brands that should be hidden, if any */
  excludeBrands: PropTypes.arrayOf(
    PropTypes.oneOfType([PropTypes.number, PropTypes.string])
  ),
  /** Height of the logo */
  height: PropTypes.number,
  /** If the logo should have a link*/
  logoWithLink: PropTypes.bool,
}

export default ProductSummaryBrand
```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryImage/ImagePlaceholder.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'

const ImagePlaceholder = ({ cssHandle }) => (
  <div className="relative">
    <div className={`${cssHandle} absolute w-100 h-100 contain bg-center`} />
    <svg
      width="100%"
      height="100%"
      viewBox="0 0 512 512"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      data-testid="image-placeholder"
    >
      <rect width="512" height="512" fill="#F2F2F2" />
      <rect
        x="183.857"
        y="180.2"
        width="144.286"
        height="150.474"
        stroke="#CACBCC"
        strokeWidth="2"
      />
      <path d="M183.78 303.688H328.214" stroke="#CACBCC" strokeWidth="2" />
      <path
        d="M205.082 279.563L223.599 240.507L242.116 260.035L269.892 220.979L306.926 279.563H205.082Z"
        stroke="#CACBCC"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="M252.225 213.939C252.225 219.822 247.66 224.52 242.114 224.52C236.569 224.52 232.004 219.822 232.004 213.939C232.004 208.057 236.569 203.359 242.114 203.359C247.66 203.359 252.225 208.057 252.225 213.939Z"
        stroke="#CACBCC"
        strokeWidth="2"
      />
    </svg>
  </div>
)

export default ImagePlaceholder

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryImage/ProductImage.test.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { render, fireEvent } from '@vtex/test-tools/react'
import ProductImage from './ProductImage'
import { ProductSummaryProvider } from 'vtex.product-summary-context/ProductSummaryContext'

test('should show placeholder on error', () => {
  const productName = 'Ball'
  const mock = {
    product: {
      productName,
      sku: { image: { imageUrl: 'foo' } },
    },
  }

  const { getByAltText, getByTestId } = render(
    <ProductSummaryProvider value={mock}>
      <ProductImage />
    </ProductSummaryProvider>
  )

  const image = getByAltText(productName)

  fireEvent.error(image)
  expect(getByTestId('image-placeholder')).toBeDefined()
})

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryImage/ProductImage.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { pathOr, compose } from 'ramda'
import CollectionBadges from '../../../StoreComponents/CollectionBadges'
import DiscountBadge from '../../../StoreComponents/DiscountBadge'
import classNames from 'classnames'
import useDevice from '../../../DeviceDetector/useDevice'
import useResponsiveValues from '../../../ResponsiveValues/useResponsiveValues'
import useCssHandles from '../../../CssHandles/useCssHandles'
import applyModifiers from '../../../CssHandles/applyModifiers'

import ImagePlaceholder from './ImagePlaceholder'

import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'

import productSummary from '../../productSummary.css'

import { changeImageUrlSize } from '../../utils/normalize'

const { useProductSummary } = ProductSummaryContextApp
const CSS_HANDLES = ['image', 'imageContainer', 'product', 'imagePlaceholder']

const maybeBadge = ({ listPrice, price, label }) => shouldShow => component => {
  if (shouldShow) {
    return (
      <DiscountBadge listPrice={listPrice} sellingPrice={price} label={label}>
        {component}
      </DiscountBadge>
    )
  }
  return component
}

const maybeCollection = ({ productClusters }) => shouldShow => component => {
  if (shouldShow && productClusters && productClusters.length > 0) {
    const collections = productClusters.map(cl => cl.name)
    return (
      <CollectionBadges collectionBadgesText={collections}>
        {component}
      </CollectionBadges>
    )
  }
  return component
}

const findImageByLabel = (images, selectedLabel) => {
  if (!selectedLabel) {
    return null
  }
  return images.find(({ imageLabel }) => imageLabel === selectedLabel)
}

const Image = ({ src, width, height, onError, alt, className }) => {
  const { isMobile } = useDevice()

  const dpi = window.devicePixelRatio || (isMobile ? 2 : 1)

  const shouldResize = !!(width || height)

  return (
    <img
      src={
        shouldResize ? changeImageUrlSize(src, width * dpi, height * dpi) : src
      }
      style={
        shouldResize
          ? {
              width: '100%',
              height,
              objectFit: 'contain',
              maxHeight: 'unset',
              maxWidth: width,
            }
          : null
      }
      loading={shouldResize ? 'lazy' : 'auto'}
      alt={alt}
      className={className}
      onError={onError}
    />
  )
}

const ProductImageContent = ({
  product,
  onError,
  hasError,
  showBadge,
  badgeText,
  displayMode,
  mainImageLabel,
  hoverImageLabel,
  showCollections,
  width: widthProp,
  height: heightProp,
}) => {
  const { productClusters, productName: name } = product || {}

  const sku = product && product.sku

  const { isMobile } = useDevice()
  const handles = useCssHandles(CSS_HANDLES)

  const [width, height] = [
    // fallsback to the other remaining value, if not defined
    parseFloat(widthProp || heightProp || 0),
    parseFloat(heightProp || widthProp || 0),
  ]

  const legacyContainerClasses = classNames(
    productSummary.imageStackContainer,
    productSummary.hoverEffect
  )

  const containerClassname = classNames(
    'dib relative',
    handles.imageContainer,
    legacyContainerClasses
  )

  if (!sku || hasError) {
    return (
      <div className={containerClassname}>
        <ImagePlaceholder cssHandle={handles.productImage} />
      </div>
    )
  }

  const images = pathOr([], ['images'], sku)
  const hoverImage = findImageByLabel(images, hoverImageLabel)

  let imageUrl = pathOr({}, ['image', 'imageUrl'], sku)
  if (mainImageLabel) {
    const mainImage = findImageByLabel(images, mainImageLabel)
    if (mainImage) {
      imageUrl = mainImage.imageUrl
    }
  }

  const legacyImageClasses = classNames({
    [productSummary.imageNormal]: displayMode !== 'inline',
    [productSummary.imageInline]: displayMode === 'inline',
  })

  // TODO: change ProductSummaryContext to have `selectedSku` field instead of `sku`
  const commertialOffer = pathOr(
    {},
    ['sku', 'seller', 'commertialOffer'],
    product
  )

  const withBadge = maybeBadge({
    listPrice: commertialOffer.ListPrice,
    price: commertialOffer.Price,
    label: badgeText,
  })

  const withCollection = maybeCollection({ productClusters })

  const imageClassname = classNames(legacyImageClasses, handles.image)

  const hoverImageClassname = classNames(
    'w-100 h-100 dn absolute top-0 left-0 z-999',
    applyModifiers(handles.image, 'hover'),
    legacyImageClasses,
    productSummary.hoverImage
  )

  const img = (
    <div className={containerClassname}>
      <Image
        src={imageUrl}
        width={width}
        height={height}
        alt={name}
        className={imageClassname}
        onError={onError}
      />
      {hoverImage && !isMobile && (
        <Image
          src={hoverImage.imageUrl}
          width={width}
          height={height}
          alt={name}
          className={hoverImageClassname}
          onError={onError}
        />
      )}
    </div>
  )

  return compose(
    withBadge(showBadge),
    withCollection(showCollections)
  )(img)
}

const ProductImage = ({
  showBadge,
  badgeText,
  displayMode,
  mainImageLabel,
  hoverImageLabel,
  showCollections,
  width: widthProp,
  height: heightProp,
}) => {
  const { product } = useProductSummary()

  const { widthProp: width, heightProp: height } = useResponsiveValues({
    widthProp,
    heightProp,
  })

  const [error, setError] = useState(false)

  const imageClassName = classNames(productSummary.imageContainer, {
    'db w-100 center': displayMode !== 'inline',
  })

  return (
    <div className={imageClassName}>
      <ProductImageContent
        width={width}
        height={height}
        hasError={error}
        product={product}
        badgeText={badgeText}
        showBadge={showBadge}
        displayMode={displayMode}
        onError={() => setError(true)}
        mainImageLabel={mainImageLabel}
        hoverImageLabel={hoverImageLabel}
        showCollections={showCollections}
      />
    </div>
  )
}

ProductImage.propTypes = {
  /** Set the discount badge's visibility */
  showBadge: PropTypes.bool,
  /** Text shown on badge */
  badgeText: PropTypes.string,
  /** Defines if the collection badges are shown */
  showCollections: PropTypes.bool,
  /** Display mode of the summary */
  displayMode: PropTypes.oneOf(['normal', 'inline']),
  hoverImageLabel: PropTypes.string,
  mainImageLabel: PropTypes.string,
  width: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
  height: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
}

ProductImage.defaultProps = {
  showBadge: true,
  showCollections: false,
  displayMode: 'normal',
  hoverImageLabel: '',
  mainImageLabel: '',
}

ProductImage.getSchema = () => {
  return {
    title: 'admin/editor.productSummaryImage.title',
    description: 'admin/editor.productSummaryImage.description',
    type: 'object',
    properties: {
      showBadge: {
        type: 'boolean',
        title: 'admin/editor.productSummary.showBadge.title',
        default: ProductImage.defaultProps.showBadge,
        isLayout: true,
      },
      showCollections: {
        type: 'boolean',
        title: 'admin/editor.productSummary.showCollections.title',
        default: ProductImage.defaultProps.showCollections,
        isLayout: true,
      },
      displayMode: {
        title: 'admin/editor.productSummary.displayMode.title',
        type: 'string',
        enum: ['normal', 'inline'],
        default: ProductImage.defaultProps.displayMode,
        isLayout: true,
      },
      hoverImageLabel: {
        title: 'admin/editor.productSummaryImage.hoverImageLabel.title',
        type: 'string',
        default: '',
        isLayout: false,
      },
    },
  }
}

export default ProductImage

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryName/ProductSummaryName.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { path } from 'ramda'
import ProductName from '../../../StoreComponents/ProductName'
import useCssHandles from '../../../CssHandles/useCssHandles'

import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp

const CSS_HANDLES = [
  'nameContainer',
  'nameWrapper',
  'brandName',
  'skuName',
  'productReference',
  'productNameLoader',
]

const ProductSummaryName = ({ showFieldsProps }) => {
  const { product } = useProductSummary()
  const handles = useCssHandles(CSS_HANDLES)
  const productName = path(['productName'], product)
  // TODO: change ProductSummaryContext to have `selectedSku` field instead of `sku`
  const skuName = path(['sku', 'name'], product)
  const brandName = path(['brand'], product)

  const containerClasses = `${handles.nameContainer} flex items-start justify-center pv6`
  const wrapperClasses = `${handles.nameWrapper} overflow-hidden c-on-base f5`
  const brandNameClasses = `${handles.brandName} t-body`
  const skuNameClasses = `${handles.skuName} t-small`
  const loaderClasses = `${handles.productNameLoader} pt5 overflow-hidden`

  return (
    <div className={containerClasses}>
      <ProductName
        className={wrapperClasses}
        brandNameClass={brandNameClasses}
        skuNameClass={skuNameClasses}
        loaderClass={loaderClasses}
        productReferenceClass={handles.productReference}
        name={productName}
        skuName={skuName}
        brandName={brandName}
        {...showFieldsProps}
      />
    </div>
  )
}

ProductSummaryName.defaultProps = {
  showFieldsProps: {
    showProductReference: false,
    showBrandName: false,
    showSku: false,
  },
}

ProductSummaryName.propTypes = {
  /** Name schema props */
  showFieldsProps: PropTypes.object,
}

ProductSummaryName.getSchema = () => {
  return {
    title: 'admin/editor.productSummaryName.title',
    type: 'object',
    properties: {
      showFieldsProps: ProductName.schema,
    },
  }
}

export default ProductSummaryName

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryPrice/ProductSummaryPrice.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { path, prop, flatten, pluck } from 'ramda'
import classNames from 'classnames'
import Spinner from '../../../Styleguide/Spinner'
import ProductPrice from '../../../StoreComponents/ProductPrice'
import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'

import useCssHandles from '../../../CssHandles/useCssHandles'

const { useProductSummary } = ProductSummaryContextApp
const CSS_HANDLES = [
  'priceContainer',
  'productPriceClass',
  'listPriceContainer',
  'listPriceLabel',
  'listPrice',
  'sellingPriceContainer',
  'sellingPriceLabel',
  'sellingPrice',
  'savingsContainer',
  'savings',
  'interestRate',
  'installmentContainer',
  'listPriceRange',
  'sellingPriceRange',
  'priceLoading',
]

const isAvailableProduct = price => price !== 0

const getPrices = (product, attribute) => {
  if (!product || (!product.items && !product.priceRange)) {
    return []
  }
  if (product.priceRange) {
    const values = product.priceRange[attribute]
    return values ? [values.lowPrice, values.highPrice] : []
  }

  // No priceRange resolver provided, use sku information
  const sellers = flatten(pluck('sellers', product.items))
  const offerAttribute = attribute === 'sellingPrice' ? 'Price' : 'ListPrice'
  const prices = sellers.map(path(['commertialOffer', offerAttribute]))
  const availableProductsPrices = prices.filter(isAvailableProduct)
  return availableProductsPrices
}

const ProductSummaryPrice = ({
  showListPrice,
  showSellingPriceRange,
  showLabels,
  showInstallments,
  showDiscountValue,
  labelSellingPrice,
  labelListPrice,
  showBorders,
  showListPriceRange,
}) => {
  const { product, isLoading } = useProductSummary()
  const handles = useCssHandles(CSS_HANDLES)
  // TODO: change ProductSummaryContext to have `selectedSku` field instead of `sku`
  const commertialOffer = path(['sku', 'seller', 'commertialOffer'], product)

  if (isLoading) {
    return (
      <div
        className={`${handles.priceLoading} flex items-end justify-end w-100 h1 pr6`}
      >
        <Spinner size={20} />
      </div>
    )
  }

  const priceClasses = {
    containerClass: classNames('flex flex-column justify-end items-center', {
      [`${handles.priceContainer} pv5`]: !showBorders,
    }),
    sellingPriceClass: `${handles.sellingPrice} dib ph2 t-body t-heading-5-ns`,
  }

  const sellingPriceList = showSellingPriceRange
    ? getPrices(product, 'sellingPrice')
    : []
  const listPriceList = showListPriceRange
    ? getPrices(product, 'listPrice')
    : []
  const sellingPrice = prop('Price', commertialOffer)

  return (
    <div className={priceClasses.containerClass}>
      {sellingPrice !== 0 && (
        <ProductPrice
          className={`${handles.productPriceClass} flex flex-column justify-start`}
          listPriceContainerClass={`${handles.listPriceContainer} pv1 normal c-muted-2`}
          listPriceLabelClass={`${handles.listPriceLabel} dib strike t-small t-mini`}
          listPriceClass={`${handles.listPrice} dib ph2 strike t-small-ns t-mini`}
          sellingPriceContainerClass={`${handles.sellingPriceContainer} pt1 pb3 c-on-base`}
          sellingPriceLabelClass={`${handles.sellingPriceLabel} dib`}
          sellingPriceClass={priceClasses.sellingPriceClass}
          savingsContainerClass={`${handles.savingsContainer} t-small-ns c-muted-2`}
          savingsClass={`${handles.savings} dib`}
          interestRateClass={`${handles.interestRate} dib pl2`}
          installmentContainerClass={`${handles.installmentContainer} t-small-ns c-muted-2`}
          listPrice={prop('ListPrice', commertialOffer)}
          sellingPriceList={sellingPriceList}
          listPriceRangeClass={`${handles.listPriceRange} dib ph2 t-small-ns strike`}
          sellingPriceRangeClass={`${handles.sellingPriceRange} dib ph2 t-small-ns`}
          sellingPrice={prop('Price', commertialOffer)}
          installments={prop('Installments', commertialOffer)}
          showListPrice={showListPrice}
          showSellingPriceRange={showSellingPriceRange}
          showLabels={showLabels}
          showInstallments={showInstallments}
          labelSellingPrice={labelSellingPrice}
          labelListPrice={labelListPrice}
          listPriceList={listPriceList}
          showListPriceRange={showListPriceRange}
          showSavings={showDiscountValue}
        />
      )}
    </div>
  )
}

ProductSummaryPrice.propTypes = {
  /** Set the product selling price range visibility */
  showSellingPriceRange: PropTypes.bool,
  /** Set the product list price's visibility */
  showListPrice: PropTypes.bool,
  /** Set the product list price range visibility */
  showListPriceRange: PropTypes.bool,
  /** Set pricing labels' visibility */
  showLabels: PropTypes.bool,
  /** Set installments' visibility */
  showInstallments: PropTypes.bool,
  /** Set savings' visibility*/
  showDiscountValue: PropTypes.bool,
  /** Text of selling Price's label */
  labelSellingPrice: PropTypes.string,
  /** Text of list Price's label */
  labelListPrice: PropTypes.string,
  /** Set installments' visibility */
  showBorders: PropTypes.bool,
}

ProductSummaryPrice.defaultProps = {
  showSellingPriceRange: false,
  showDiscountValue: false,
  showListPriceRange: false,
  showListPrice: true,
  showInstallments: true,
  showLabels: true,
  labelSellingPrice: '',
  labelListPrice: '',
  showBorders: false,
}

ProductSummaryPrice.schema = {
  title: 'admin/editor.productSummaryPrice.title',
  description: 'admin/editor.productSummaryPrice.description',
  type: 'object',
  properties: {
    showListPrice: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showListPrice.title',
      default: ProductSummaryPrice.defaultProps.showListPrice,
      isLayout: true,
    },
    showSellingPriceRange: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showSellingPriceRange.title',
      default: ProductSummaryPrice.defaultProps.showSellingPriceRange,
      isLayout: true,
    },
    showListPriceRange: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showListPriceRange.title',
      default: ProductSummaryPrice.defaultProps.showListPrice,
      isLayout: true,
    },
    showInstallments: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showInstallments.title',
      default: ProductSummaryPrice.defaultProps.showInstallments,
      isLayout: true,
    },
    showDiscountValue: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showDiscountValue.title',
      default: ProductSummaryPrice.defaultProps.showDiscountValue,
    },
    showLabels: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showLabels.title',
      default: ProductSummaryPrice.defaultProps.showLabels,
      isLayout: true,
    },
    showBorders: {
      type: 'boolean',
      title: 'admin/editor.productSummaryPrice.showBorders.title',
      default: ProductSummaryPrice.defaultProps.showBorders,
      isLayout: true,
    },
  },
}

export default ProductSummaryPrice

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryAddToListButton/ProductSummaryAddToListButton.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useMemo } from 'react'
import { ExtensionPoint } from '../../../../../../vtex.render-runtime'
import { path } from 'ramda'
import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp
import useCssHandles from '../../../CssHandles/useCssHandles'

// TODO: change ProductSummaryContext to have `selectedSku` field instead of `sku`
const getSkuId = path(['sku', 'itemId'])
const getProductId = path(['productId'])
const CSS_HANDLES = ['addToListBtn']

// This avoids triggering the link to the product page
const captureClick = e => {
  e.preventDefault()
  e.stopPropagation()
}

function ProductSummaryAddToListButton() {
  const handles = useCssHandles(CSS_HANDLES)
  const productContext = useProductSummary()

  const skuId = getSkuId(productContext.product)
  const productId = getProductId(productContext.product)

  const productProp = useMemo(
    () => ({
      skuId,
      productId,
      quantity: 1,
    }),
    [skuId, productId]
  )

  return (
    <div
      role="button"
      tabIndex="-1"
      onKeyDown={() => {}}
      className={`${handles.addToListBtn} absolute z-1`}
      onClick={captureClick}
    >
      <ExtensionPoint id="addon-summary-btn" product={productProp} />
    </div>
  )
}

export default ProductSummaryAddToListButton

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryDescription/ProductSummaryDescription.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment } from 'react'

import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp
import useCssHandles from '../../../CssHandles/useCssHandles'

const MAX_SIZE_DESCRIPTION = 120
const CSS_HANDLES = ['description']

const ProductSummaryDescription = () => {
  const {
    product: { description },
  } = useProductSummary()
  const handles = useCssHandles(CSS_HANDLES)

  if (!description) return <Fragment />

  const descriptionClasses = `${handles.description} c-muted-2 t-small`

  const descriptionTruncated =
    description.length > MAX_SIZE_DESCRIPTION
      ? `${description.substring(0, MAX_SIZE_DESCRIPTION)}...`
      : description

  return <span className={descriptionClasses}>{descriptionTruncated}</span>
}

export default ProductSummaryDescription

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummarySpecificationBadges/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'

import BaseSpecificationBadges from '../../../ProductSpecificationBadges/BaseSpecificationBadges'
import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp

const ProductSummarySpecificationBadges = ({
  specificationGroupName,
  visibleWhen,
  specificationsOptions,
  specificationName,
  displayValue,
  orientation,
}) => {
  const { product } = useProductSummary()
  return (
    <BaseSpecificationBadges
      product={product}
      visibleWhen={visibleWhen}
      specificationsOptions={specificationsOptions}
      specificationName={specificationName}
      displayValue={displayValue}
      orientation={orientation}
      specificationGroupName={specificationGroupName}
    />
  )
}

ProductSummarySpecificationBadges.schema = {
  ...BaseSpecificationBadges.schema,
  title: 'admin/editor.product-summary-specification-badges.title',
}

export default ProductSummarySpecificationBadges

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryAttachmentList/AttachmentChildren.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import AddedAttachmentsList from './AddedAttachmentsList'
import RemovedAttachmentsList from './RemovedAttachmentsList'

import useCssHandles from '../../../CssHandles/useCssHandles'

const CSS_HANDLES = ['attachmentChildrenContainer']

const AttachmentChildren = ({ addedOptions, removedOptions }) => {
  const handles = useCssHandles(CSS_HANDLES)
  if (addedOptions.length === 0 && removedOptions.length === 0) {
    return null
  }

  return (
    <div className={`${handles.attachmentChildrenContainer} ml3`}>
      <AddedAttachmentsList addedOptions={addedOptions} showItemPrice={false} />
      <RemovedAttachmentsList removedOptions={removedOptions} />
    </div>
  )
}

export default AttachmentChildren

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryAttachmentList/AttachmentItem.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { memo } from 'react'
import { string, number, object, bool } from 'prop-types'
import ProductPrice from '../../../StoreComponents/ProductPrice'
import { reject } from 'ramda'

import useCssHandles from '../../../CssHandles/useCssHandles'
import AttachmentChildren from './AttachmentChildren'

const CSS_HANDLES = ['attachmentItemContainer', 'attachmentItem', 'attachmentItemProductText']

const itemShouldHide = ({ item, extraQuantity }) =>
  extraQuantity === 0 && item.sellingPriceWithAssemblies === 0

const AttachmentItem = ({
  productText,
  price,
  assemblyOptions,
  showItemPrice,
}) => {
  const handles = useCssHandles(CSS_HANDLES)
  const childrenAdded = (assemblyOptions && assemblyOptions.added) || []
  const childrenRemoved = (assemblyOptions && assemblyOptions.removed) || []
  const filteredChildrenAdded = reject(itemShouldHide, childrenAdded)
  const parentColor =
    filteredChildrenAdded.length > 0 || childrenRemoved.length > 0
      ? 'c-on-base'
      : 'c-muted-2'

  return (
    <div className={`${handles.attachmentItemContainer} flex flex-column pv1`}>
      <div className={`${handles.attachmentItem} flex items-center justify-between`}>
        <span className={`${handles.attachmentItemProductText} t-small ${parentColor} tl pr3`}>{productText}</span>
        {price != null && showItemPrice && price > 0 && (
          <ProductPrice
            sellingPrice={price}
            sellingPriceContainerClass="c-on-base"
            sellingPriceLabelClass="dib"
            sellingPriceClass="dib t-small c-muted-2"
            showListPrice={false}
            showLabels={false}
            showInstallments={false}
          />
        )}
      </div>
      <AttachmentChildren
        addedOptions={filteredChildrenAdded}
        removedOptions={childrenRemoved}
      />
    </div>
  )
}

AttachmentItem.propTypes = {
  productText: string.isRequired,
  price: number,
  assemblyOptions: object,
  showItemPrice: bool,
}

export default memo(AttachmentItem)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryAttachmentList/RemovedAttachmentsList.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment } from 'react'
import { injectIntl } from 'react-intl'
import { arrayOf } from 'prop-types'

import AttachmentItem from './AttachmentItem'

import { removedOptionShape } from '../../utils/propTypes'

const wasCompletelyRemoved = ({ removedQuantity, initialQuantity }) =>
  removedQuantity === 1 && removedQuantity === initialQuantity

const formatAttachmentName = (missingOption, intl) => {
  const { name, removedQuantity } = missingOption
  if (wasCompletelyRemoved(missingOption)) {
    return intl.formatMessage(
      { id: 'store/productSummary.missingOptionName' },
      { name }
    )
  }

  const extraParams = {
    sign: '-',
    name,
    quantity: removedQuantity,
  }
  return intl.formatMessage(
    { id: 'store/productSummary.attachmentName' },
    extraParams
  )
}

const RemovedAttachmentsList = ({ removedOptions, intl }) => {
  if (removedOptions.length === 0) {
    return null
  }

  return (
    <Fragment>
      {removedOptions.map(removedOption => {
        const productText = formatAttachmentName(removedOption, intl)
        return <AttachmentItem productText={productText} key={productText} />
      })}
    </Fragment>
  )
}

RemovedAttachmentsList.propTypes = {
  removedOptions: arrayOf(removedOptionShape).isRequired
}

export default injectIntl(RemovedAttachmentsList)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryAttachmentList/AttachmentList.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { pathOr, reject } from 'ramda'

import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummary } = ProductSummaryContextApp

import RemovedAttachmentsList from './RemovedAttachmentsList'
import AddedAttachmentsList from './AddedAttachmentsList'

import useCssHandles from '../../../CssHandles/useCssHandles'

const CSS_HANDLES = ['attachmentListContainer']

const itemShouldHide = ({ item, extraQuantity }) =>
  extraQuantity === 0 && item.sellingPriceWithAssemblies === 0

const AttachmentList = () => {
  const { product } = useProductSummary()
  const handles = useCssHandles(CSS_HANDLES)
  const addedOptions = pathOr([], ['assemblyOptions', 'added'], product)
  const removedOptions = pathOr([], ['assemblyOptions', 'removed'], product)

  const filteredOption = reject(itemShouldHide, addedOptions)

  if (filteredOption.length === 0 && removedOptions.length === 0) {
    return null
  }

  return (
    <div className={`${handles.attachmentListContainer} pv2`}>
      <AddedAttachmentsList addedOptions={filteredOption} />
      <RemovedAttachmentsList removedOptions={removedOptions} />
    </div>
  )
}

export default AttachmentList

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummaryAttachmentList/AddedAttachmentsList.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment } from 'react'
import { arrayOf, bool } from 'prop-types'
import { FormattedMessage } from 'react-intl'

import AttachmentItem from './AttachmentItem'

import { CHOICE_TYPES } from '../../utils/attachmentHelper'

import { addedOptionShape } from '../../utils/propTypes'

const formatAttachmentName = option => (
  <FormattedMessage
    id="store/productSummary.attachmentName"
    values={{
      sign: '+',
      name: option.item.name,
      quantity: option.normalizedQuantity,
    }}
  />
)

const AddedAttachmentsList = ({ addedOptions, showItemPrice }) => {
  if (addedOptions.length === 0) {
    return null
  }
  return (
    <Fragment>
      {addedOptions.map(option => {
        const isMultiple = option.choiceType === CHOICE_TYPES.MULTIPLE
        const productText = isMultiple
          ? formatAttachmentName(option)
          : option.item.name
        return (
          <AttachmentItem
            productText={productText}
            price={
              option.item.sellingPriceWithAssemblies * option.normalizedQuantity
            }
            key={`${option.item.name}-${option.choiceType}`}
            assemblyOptions={option.item.assemblyOptions}
            showItemPrice={showItemPrice}
          />
        )
      })}
    </Fragment>
  )
}

AddedAttachmentsList.defaultProps = {
  showItemPrice: true,
}

AddedAttachmentsList.propTypes = {
  addedOptions: arrayOf(addedOptionShape).isRequired,
  showItemPrice: bool,
}

export default AddedAttachmentsList

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/ProductSummary/components/ProductSummarySKUSelector/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { head } from 'ramda'
import SKUSelector from '../../../StoreComponents/SKUSelector'
import useCssHandles from '../../../CssHandles/useCssHandles'
import ProductSummaryContextApp from '../../../ProductSummaryContext/ProductSummaryContext'
const { useProductSummaryDispatch, useProductSummary } = ProductSummaryContextApp

const CSS_HANDLES = ['SKUSelectorContainer']

function ProductSummarySKUSelector(props) {
  const stopBubblingUp = e => {
    e.preventDefault()
    e.stopPropagation()
  }
  const dispatch = useProductSummaryDispatch()
  const { product } = useProductSummary()

  const handleSKUSelected = skuId => {
    const selectedItem =
      product.items && product.items.find(item => item.itemId === skuId)

    const sku = {
      ...selectedItem,
      image: head(selectedItem.images),
      seller: head(selectedItem.sellers),
    }

    const newProduct = {
      ...product,
      selectedItem,
      sku,
    }

    dispatch({
      type: 'SET_PRODUCT',
      args: { product: newProduct },
    })

    dispatch({
      type: 'SET_PRODUCT_QUERY',
      args: { query: `skuId=${skuId}` },
    })
  }

  const handles = useCssHandles(CSS_HANDLES)
  return (
    // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
    <div
      onClick={stopBubblingUp}
      className={handles.SKUSelectorContainer}
    >
      <SKUSelector onSKUSelected={handleSKUSelected} {...props} />
    </div>
  )
}

export default ProductSummarySKUSelector

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/Minicart/typings/OrderForm.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface OrderFormContext {
  orderForm: OrderForm
  loading: boolean
}

interface OrderFormItem {
  additionalInfo: ItemAdditionalInfo
  availability: string
  detailUrl: string
  id: string
  imageUrl: string
  listPrice: number
  measurementUnit: string
  name: string
  price: number
  productId: string
  quantity: number
  sellingPrice: number
  skuName: string
  skuSpecifications: SKUSpecification[]
  uniqueId: string
  productCategories: Record<string, string>
  productCategoryIds: string
  productRefId: string
}

interface ItemAdditionalInfo {
  brandName: string
}

interface SKUSpecification {
  fieldName: string
  fieldValues: string[]
}

interface OrderForm {
  id: string
  items: OrderFormItem[]
  marketingData: MarketingData
  totalizers: Totalizer[]
  value: number
  messages: OrderFormMessages
}

interface MarketingData {
  coupon: string
}

interface Totalizer {
  id: string
  name: string
  value: number
}

interface OrderFormMessages {
  couponMessages: Message[]
  generalMessages: Message[]
}

interface Message {
  code: string
  status: string
  text: string
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/monobloco/components/new/Minicart/typings/vtex.order-items.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.order-items'
declare module 'vtex.order-items/*'

```