[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/global.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface MinicartProps {
  variation: MinicartVariationType
  openOnHover: boolean
  linkVariationUrl: string
  maxDrawerWidth: number | string
  drawerSlideDirection: SlideDirectionType
}

type SlideDirectionType =
  | 'horizontal'
  | 'vertical'
  | 'rightToLeft'
  | 'leftToRight'
type MinicartVariationType = 'popup' | 'drawer' | 'link'

```


[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/css.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  const css: Record<string, string>
  export default css
}

```


[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.pixel-manager.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.pixel-manager'
declare module 'vtex.pixel-manager/*'

```


[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/legacy/minicart.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
.container {
}
.label {
}
.itemImage {
}
.item {
}
.itemContainer {
}
.itemDeleteIcon {
}
.itemDeleteIcon {
}
.itemDeleteIconLoader {
}
.content {
}
.contentDiscount {
}
.contentPrice {
}
.itemName {
}
.itemNameLarge {
}
.itemFooter {
}
.imgContainer {
}
.itemRemoveBtn {
}
.sidebarScrim {
}
.sidebarHeader {
}

.contentSmall {
  max-height: 383px;
}

.contentLarge {
  max-height: stretch;
}

.badge {
  top: -0.7rem;
  right: -0.8rem;
}

.arrowUp {
  right: 7px;
}

.box {
  width: 364px;
  top: 100%;
}

.itemImageLoader {
  width: 100%;
  height: 100%;
}

.contentFooter {
}

.footerSpacer {
}

.footerShippingPriceContainer {
}

.footerShippingPriceLabelContainer {
}

.popupContentContainer {
}

.popupChildrenContainer {
}

.sidebarRightCaretContainer {
}

.sidebarItemQuantityContainer {
}

.labelDiscountText{
}

@media only screen and (max-width: 40rem) {
  body.sidebarOpen {
    overflow: hidden;
  }
}

@media only screen and (min-width: 40em) {
  .sidebar {
    width: 340px;
  }
}

```


[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/components/DrawerMode.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import useCssHandles from '../../CssHandles/useCssHandles'
import Drawer from '../../Drawer/Drawer'

import MinicartIconButton from './MinicartIconButton'

const DRAWER_CLOSE_ICON_HEIGHT = 58
const CSS_HANLDES = ['minicartSideBarContentWrapper']

interface Props {
  maxDrawerWidth: number | string
  drawerSlideDirection: SlideDirectionType
}

const DrawerMode: FC<Props> = ({
  maxDrawerWidth,
  drawerSlideDirection,
  children,
}) => {
  const handles = useCssHandles(CSS_HANLDES)

  return (
    <Drawer
      maxWidth={maxDrawerWidth}
      slideDirection={drawerSlideDirection}
      customIcon={<MinicartIconButton />}
    >
      <div
        className={`${handles.minicartSideBarContentWrapper} w-100 h-100`}
        style={{
          height: window.innerHeight - DRAWER_CLOSE_ICON_HEIGHT,
        }}
      >
        {children}
      </div>
    </Drawer>
  )
}

export default DrawerMode

```


[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/components/Popup.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import React, { FC } from 'react'
import Overlay from '../../ReactPortal/Overlay'
import useCssHandles from '../../CssHandles/useCssHandles'

import { useMinicartState, useMinicartDispatch } from '../MinicartContext'
import MinicartIconButton from './MinicartIconButton'
import styles from '../styles.css'

const CSS_HANDLES = [
  'popupWrapper',
  'popupContentContainer',
  'arrowUp',
  'popupChildrenContainer',
]

const PopupMode: FC = ({ children }) => {
  const {
    open,
    hasBeenOpened,
    openBehavior,
    openOnHoverProp,
  } = useMinicartState()
  const dispatch = useMinicartDispatch()
  const handles = useCssHandles(CSS_HANDLES)

  const handleClick = () => {
    if (openOnHoverProp) {
      dispatch({ type: 'SET_OPEN_BEHAVIOR', value: 'hover' })
    }
    dispatch({ type: 'CLOSE_MINICART' })
  }
  const handleMouseLeave = () => {
    dispatch({ type: 'CLOSE_MINICART' })
  }

  return (
    <div onMouseLeave={openBehavior === 'hover' ? handleMouseLeave : undefined}>
      <MinicartIconButton />
      {open && (
        <Overlay>
          {openBehavior === 'click' && (
            <div
              className="fixed top-0 left-0 w-100 h-100"
              onClick={handleClick}
            />
          )}
          <div
            className={`${handles.popupWrapper} ${styles.popupBoxPosition} absolute z-max flex flex-column`}
          >
            <div
              className={`${handles.popupContentContainer} w-100 shadow-3 bg-base`}
            >
              <div
                className={`${handles.arrowUp} ${styles.popupArrowUp} absolute top-0 bg-base h1 w1 pa4 rotate-45`}
              />
              <div
                className={`${handles.popupChildrenContainer} mt3 bg-base relative flex flex-column ph5 pv3`}
              >
                {hasBeenOpened && children}
              </div>
            </div>
          </div>
        </Overlay>
      )}
    </div>
  )
}

export default PopupMode

```


[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/components/MinicartIconButton.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import ButtonWithIcon from '../../Styleguide/ButtonWithIcon'
import IconCart from '../../StoreIcons/IconCart'
import useCssHandles from '../../CssHandles/useCssHandles'
import OrderFormOrder from '../../OrderManager/OrderForm'

import { useMinicartDispatch, useMinicartState } from '../MinicartContext'
import styles from '../styles.css'

const { useOrderForm } = OrderFormOrder

const CSS_HANDLES = ['minicartIconContainer', 'minicartQuantityBadge'] as const

const MinicartIconButton = () => {
  const { orderForm, loading }: OrderFormContext = useOrderForm()
  const handles = useCssHandles(CSS_HANDLES)
  const { open, openBehavior, openOnHoverProp } = useMinicartState()
  const dispatch = useMinicartDispatch()
  const itemQuantity = loading ? 0 : orderForm.items.length

  const handleClick = () => {
    if (openOnHoverProp) {
      if (openBehavior === 'hover') {
        dispatch({
          type: 'SET_OPEN_BEHAVIOR',
          value: 'click',
        })
        return
      }
      dispatch({ type: 'CLOSE_MINICART' })
      dispatch({
        type: 'SET_OPEN_BEHAVIOR',
        value: 'hover',
      })
      return
    }
    dispatch({ type: open ? 'CLOSE_MINICART' : 'OPEN_MINICART' })
  }

  return (
    <ButtonWithIcon
      icon={
        <span className={`${handles.minicartIconContainer} gray relative`}>
          <IconCart />
          {itemQuantity > 0 && (
            <span
              style={{ userSelect: 'none' }}
              className={`${handles.minicartQuantityBadge} ${styles.minicartQuantityBadgeDefault} c-on-emphasis absolute t-mini bg-emphasis br4 w1 h1 pa1 flex justify-center items-center lh-solid`}
            >
              {itemQuantity}
            </span>
          )}
        </span>
      }
      variation="tertiary"
      onMouseEnter={
        openBehavior === 'hover'
          ? () => dispatch({ type: 'OPEN_MINICART' })
          : undefined
      }
      onClick={handleClick}
    />
  )
}

export default MinicartIconButton

```


[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/modules/useCartIdPixel.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useEffect } from 'react'
import { usePixel } from '../../PixelContext/PixelContext'

const useCartIdPixel = (orderFormId?: string) => {
  const { push } = usePixel()

  useEffect(() => {
    if (!orderFormId) {
      return
    }

    push({
      event: 'cartId',
      cartId: orderFormId,
    } as any)
  }, [push, orderFormId])
}

export default useCartIdPixel

```


[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/modules/pixelHelper.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
export function mapCartItemToPixel(item: CartItem | any): PixelCartItem {
  return {
    skuId: item.id,
    variant: item.skuName,
    price: item.sellingPrice,
    name: getNameWithoutVariant(item),
    quantity: item.quantity,
    productRefId: item.productRefId,
    brand: item.additionalInfo ? item.additionalInfo.brandName : '',
    category: productCategory(item),
    detailUrl: item.detailUrl,
    imageUrl: item.imageUrls
      ? fixUrlProtocol(item.imageUrls.at3x)
      : item.imageUrl ?? '',
  }
}

export function mapBuyButtonItemToPixel(item: BuyButtonItem): PixelCartItem {
  // Change this `/Apparel & Accessories/Clothing/Tops/`
  // to this `Apparel & Accessories/Clothing/Tops`
  const category = item.category ? item.category.slice(1, -1) : ''

  return {
    skuId: item.id,
    variant: item.skuName,
    price: item.sellingPrice,
    name: item.name,
    quantity: item.quantity,
    productRefId: item.productRefId,
    brand: item.brand,
    category,
    detailUrl: item.detailUrl,
    imageUrl: item.imageUrl,
  }
}

/**
 * URL comes like "//storecomponents.vteximg.com.br/arquivos/ids/155491"
 * this function guarantees it comes with protocol in it.
 */
function fixUrlProtocol(url: string) {
  if (!url || url.indexOf('http') === 0) {
    return url
  }

  return `https:${url}`
}

/**
 * Remove the variant from the end of the name.
 * Ex: from "Classic Shoes Pink" to "Classic Shoes"
 */
function getNameWithoutVariant(item: CartItem) {
  if (!item.name.includes(item.skuName)) {
    return item.name
  }

  const leadingSpace = 1
  const variantLength = leadingSpace + item.skuName.length

  return item.name.slice(0, item.name.length - variantLength)
}

function productCategory(item: CartItem) {
  try {
    const categoryIds = item.productCategoryIds.split('/').filter(c => c.length)
    const category = categoryIds.map(id => item.productCategories[id]).join('/')

    return category
  } catch {
    return ''
  }
}

interface PixelCartItem {
  skuId: string
  variant: string
  price: number
  name: string
  quantity: number
  productRefId: string
  brand: string
  category: string
  detailUrl: string
  imageUrl: string
}

interface BuyButtonItem {
  id: string
  skuName: string
  sellingPrice: number
  name: string
  quantity: number
  productRefId: string
  brand: string
  category: string
  detailUrl: string
  imageUrl: string
}

interface CartItem {
  id: string
  skuName: string
  sellingPrice: number
  name: string
  quantity: number
  productRefId: string
  additionalInfo: {
    brandName: string
  }
  productCategoryIds: string
  productCategories: Record<string, string>
  detailUrl: string
  // Field from the usual orderForm API
  imageUrl?: string
  // Field from the order-manager orderForm API
  imageUrls?: {
    at1x: string
    at2x: string
    at3x: 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/modules/debouncedPixelHook.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useRef } from 'react'
import { usePixel } from '../../PixelContext/PixelContext'
import debounce from 'debounce'

export default function useDebouncedPush() {
  const { push } = usePixel()
  const debouncedPush = useRef<(param: object) => void>(debounce(push, 600))

  return debouncedPush.current
}

```


[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/modules/checkoutHook.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import CheckoutUtils from '../../CheckoutResources/Utils'
const { useCheckoutURL } = CheckoutUtils
import { useRuntime } from '../../../../../vtex.render-runtime'

export default function useCheckout() {
  const { url: checkoutUrl, major } = useCheckoutURL()
  const { navigate } = useRuntime()

  const goToCheckout = (url: string) => {
    if (major > 0 && url === checkoutUrl) {
      navigate({ to: url })
    } else {
      window.location.href = url
    }
  }

  return goToCheckout
}

```


[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/legacy/utils/itemsHelper.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
const isParentItem = ({ parentItemIndex, parentAssemblyBinding }) =>
  parentItemIndex == null && parentAssemblyBinding == null

export const shouldShowItem = item => !!item.quantity && isParentItem(item)

```


[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/legacy/utils/propTypes.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'

export const MiniCartPropTypes = {
  /* Set the minicart type */
  type: PropTypes.oneOf(['popup', 'sidebar']),
  /* Set the content visibility */
  hideContent: PropTypes.bool,
  /* Label that will appear when the minicart is empty */
  labelMiniCartEmpty: PropTypes.string,
  /* Finish shopping button label */
  labelButtonFinishShopping: PropTypes.string,
  linkButtonFinishShopping: PropTypes.string,
  /* Icon's classnames */
  iconClasses: PropTypes.string,
  /* Icon's size */
  iconSize: PropTypes.number,
  /* Icon's label */
  iconLabel: PropTypes.object,
  /* Label's classnames */
  labelClasses: PropTypes.string,
  /* Set the discount visibility */
  showDiscount: PropTypes.bool,
  /* Set the shipping fee visibility */
  showShippingCost: PropTypes.bool,
}

```


[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/legacy/utils/urlHelpers.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
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:\/\//)

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

export 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`
}

```


[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/legacy/localState/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { head, mergeDeepRight, values } from 'ramda'
import { loader } from 'graphql.macro'

const updateOrderFormShipping = loader('../../../StoreResources/mutations/updateOrderFormShipping.gql')
const updateOrderFormCheckin = loader('../../../StoreResources/mutations/updateOrderFormCheckin.gql')
const fullMinicartQuery = loader('./graphql/fullMinicartQuery.gql')

export const ITEMS_STATUS = {
  NONE: 'NONE',
  MODIFIED: 'MODIFIED',
  LOCAL_ITEM: 'LOCAL_ITEM',
}

export default function(client) {
  const replayOrderFormServerMutation = mutation => async (
    _,
    variables,
    { cache }
  ) => {
    const response = await client.mutate({
      variables,
      mutation,
    })

    const updatedOrderForm = head(values(response.data))

    const data = cache.readQuery({ query: fullMinicartQuery })

    const orderForm = JSON.stringify(
      mergeDeepRight(JSON.parse(data.minicart.orderForm), updatedOrderForm)
    )
    cache.writeQuery({
      query: fullMinicartQuery,
      data: {
        ...data,
        minicart: {
          __typename: 'Minicart',
          ...data.minicart,
          orderForm,
        },
      },
    })
    return orderForm
  }

  const resolvers = {
    Mutation: {
      addToCart: (_, { items }, { cache }) => {
        const data = cache.readQuery({ query: fullMinicartQuery })

        const cartItems = JSON.parse(data.minicart.items)
        const newItems = items.filter(
          item =>
            !cartItems.find(
              cartItem =>
                cartItem.id === item.id && cartItem.seller === item.seller
            )
        )

        const writeItems = cartItems.concat(
          newItems.map(item => ({
            ...item,
            localStatus: navigator.onLine
              ? ITEMS_STATUS.MODIFIED
              : ITEMS_STATUS.LOCAL_ITEM,
          }))
        )

        cache.writeQuery({
          query: fullMinicartQuery,
          data: {
            ...data,
            minicart: {
              __typename: 'Minicart',
              ...data.minicart,
              items: JSON.stringify(writeItems),
            },
          },
        })

        return writeItems
      },
      updateItems: (_, { items: newItems }, { cache }) => {
        const data = cache.readQuery({ query: fullMinicartQuery })

        const cartItems = JSON.parse(data.minicart.items)

        // Items provided to this function MUST have a valid index property
        const cleanNewItems = newItems.filter(({ index }) => index != null)
        const items = [...cartItems]

        for (const newItem of cleanNewItems) {
          const { index } = newItem
          const prevItem = cartItems[index]
          items[index] = mergeDeepRight(prevItem, {
            ...newItem,
            localStatus: ITEMS_STATUS.MODIFIED,
          })
        }

        const newCartItems = items.filter(Boolean)

        cache.writeQuery({
          query: fullMinicartQuery,
          data: {
            ...data,
            minicart: {
              __typename: 'Minicart',
              ...data.minicart,
              items: JSON.stringify(newCartItems),
            },
          },
        })
        return newCartItems
      },
      updateLocalItems: (_, { items }, { cache }) => {
        const data = cache.readQuery({ query: fullMinicartQuery })

        const itemsToRemove = items.filter(({ quantity }) => quantity === 0)
        const itemsToUpdate = items.filter(({ quantity }) => quantity > 0)

        const updatedItems = JSON.parse(data.minicart.items)
          .map((item, index) => {
            const updateItem = itemsToUpdate.find(
              updateItem => updateItem.index === index
            )

            if (updateItem) {
              return {
                ...item,
                ...updateItem,
              }
            }

            return item
          })
          .filter(
            (_, index) =>
              itemsToRemove.findIndex(
                removedItem => removedItem.index === index
              ) === -1
          )

        cache.writeQuery({
          query: fullMinicartQuery,
          data: {
            ...data,
            minicart: {
              __typename: 'Minicart',
              ...data.minicart,
              items: JSON.stringify(updatedItems),
            },
          },
        })

        return updatedItems
      },
      updateOrderForm: (
        _,
        { orderForm, forceUpdateItems = false },
        { cache }
      ) => {
        const data = cache.readQuery({ query: fullMinicartQuery })

        const prevItems = JSON.parse(data.minicart.items)
        const orderFormItems = (orderForm.items || []).map(item => ({
          ...item,
          localStatus: ITEMS_STATUS.NONE,
        }))

        const currentItems = forceUpdateItems
          ? prevItems.map(item => ({
              ...item,
              localStatus:
                item.localStatus === ITEMS_STATUS.MODIFIED
                  ? ITEMS_STATUS.NONE
                  : item.localStatus,
            }))
          : prevItems

        const updatedItems = [
          ...orderFormItems,
          ...currentItems.filter(
            ({ localStatus }) => localStatus !== ITEMS_STATUS.NONE
          ),
        ]

        cache.writeQuery({
          query: fullMinicartQuery,
          data: {
            ...data,
            minicart: {
              __typename: 'Minicart',
              ...data.minicart,
              orderForm: JSON.stringify(orderForm),
              items: JSON.stringify(updatedItems),
            },
          },
        })

        return orderForm
      },
      updateLocalItemStatus: (_, __, { cache }) => {
        const data = cache.readQuery({ query: fullMinicartQuery })
        const prevItems = JSON.parse(data.minicart.items)

        const updatedItems = prevItems.map(item => ({
          ...item,
          localStatus:
            item.localStatus === ITEMS_STATUS.LOCAL_ITEM
              ? ITEMS_STATUS.MODIFIED
              : item.localStatus,
        }))

        cache.writeQuery({
          query: fullMinicartQuery,
          data: {
            ...data,
            minicart: {
              __typename: 'Minicart',
              ...data.minicart,
              items: JSON.stringify(updatedItems),
            },
          },
        })

        return true
      },
      updateOrderFormShipping: replayOrderFormServerMutation(
        updateOrderFormShipping
      ),
      updateOrderFormCheckin: replayOrderFormServerMutation(
        updateOrderFormCheckin
      ),
      setMinicartOpen: (_, { isOpen }, { cache }) => {
        const data = cache.readQuery({ query: fullMinicartQuery })
        cache.writeQuery({
          query: fullMinicartQuery,
          data: {
            ...data,
            minicart: {
              __typename: 'Minicart',
              ...data.minicart,
              isOpen,
            },
          },
        })
        return true
      },
    },
  }

  const initialState = {
    minicart: {
      __typename: 'Minicart',
      items: '[]',
      orderForm: null,
      isOpen: false,
    },
  }

  return { resolvers, initialState }
}

```


[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/legacy/components/Popup.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import Overlay from '../../../ReactPortal/Overlay'

import minicart from '../minicart.css'

const boxPositionStyle = {
  right: -40,
}

/**
 * Pop-up component.
 */
const Popup = ({ children, onOutsideClick }) => {
  return (
    <Overlay>
      <div
        className="fixed top-0 left-0 w-100 h-100"
        onClick={onOutsideClick}
      />
      <div
        className={`${minicart.box} dn db-ns absolute z-max flex flex-colunm`}
        style={boxPositionStyle}
      >
        <div className={`${minicart.popupContentContainer} shadow-3`}>
          <div
            className={`${minicart.arrowUp} absolute top-0 shadow-3 bg-base h1 w1 pa4 rotate-45`}
          />
          <div
            className={`${minicart.popupChildrenContainer} mt3 bg-base relative flex flex-column`}
          >
            {children}
          </div>
        </div>
      </div>
    </Overlay>
  )
}

Popup.propTypes = {
  /* The pop-up's content */
  children: PropTypes.object,
  /* Offset width to set the arrow position */
  buttonOffsetWidth: PropTypes.number,
  /* Function to be called when click occurs outside the popup */
  onOutsideClick: PropTypes.func,
}

export default Popup

```


[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/legacy/components/MiniCartFooter.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment, memo } from 'react'
import classNames from 'classnames'
import ProductPrice from '../../../StoreComponents/ProductPrice'
import Button from '../../../Styleguide/Button'
import Spinner from '../../../Styleguide/Spinner'
import { FormattedMessage } from 'react-intl'
import PropTypes from 'prop-types'
import { useRuntime, ExtensionPoint } from '../../../../../../vtex.render-runtime'

import { MiniCartPropTypes } from '../utils/propTypes'
import minicart from '../minicart.css'

const MiniCartFooter = ({
  shippingCost,
  isSizeLarge,
  isUpdating,
  totalValue,
  buttonLabel,
  buttonLink,
  showDiscount,
  discount,
  labelDiscount,
  showShippingCost,
}) => {
  const { rootPath = '' } = useRuntime()
  const handleClickButton = () => window.location.assign(rootPath + buttonLink)

  const priceAndDiscountClasses = classNames(
    `${minicart.contentDiscount} w-100 flex justify-end items-center mb3`,
    {
      pv3: isSizeLarge,
    }
  )

  const checkoutButtonClasses = classNames({
    'bb bw4 bw2-m b--transparent': isSizeLarge,
  })

  const shouldShowShippingCost = showShippingCost && shippingCost > 0

  const footerClasses = classNames(
    `${minicart.contentFooter} w-100 bg-base pa4 pv5 flex flex-column items-end`,
    {
      'bt b--muted-3': shouldShowShippingCost || isSizeLarge,
    }
  )

  return (
    <Fragment>
      {shouldShowShippingCost && (
        <div
          className={`${minicart.footerShippingPriceContainer} flex items-center justify-between ma5`}
        >
          <div
            className={`${minicart.footerShippingPriceLabelContainer} t-body c-muted-1`}
          >
            <FormattedMessage id="store/minicart.shipping-cost" />
          </div>
          <ProductPrice
            sellingPriceClass="t-heading-5-ns b c-on-base ph2 dib"
            sellingPrice={shippingCost}
            showLabels={false}
            showListPrice={false}
          />
        </div>
      )}
      <div
        className={minicart.footerSpacer}
        style={{
          marginTop: 'auto',
        }}
      />
      <ExtensionPoint id="sandbox" />
      <div className={footerClasses}>
        {!isUpdating && showDiscount && discount > 0 && (
          <div className={priceAndDiscountClasses}>
            <span
              className={`${minicart.labelDiscountText} ttl c-action-primary`}
            >
              {labelDiscount}
            </span>
            <ProductPrice
              sellingPriceClass="c-action-primary t-body ph2 dib"
              sellingPrice={discount}
              listPrice={discount}
              showLabels={false}
              showListPrice={false}
            />
          </div>
        )}
        <div className={`${minicart.contentPrice} mb3`}>
          {isUpdating ? (
            <Spinner size={18} />
          ) : (
            <ProductPrice
              sellingPriceClass="t-heading-5-ns c-on-base b ph2 dib"
              sellingPrice={totalValue}
              listPrice={totalValue}
              showLabels={false}
              showListPrice={false}
            />
          )}
        </div>
        <div className={checkoutButtonClasses}>
          <Button variation="primary" size="small" onClick={handleClickButton}>
            {buttonLabel}
          </Button>
        </div>
      </div>
    </Fragment>
  )
}

MiniCartFooter.propTypes = {
  shippingCost: PropTypes.number,
  isSizeLarge: PropTypes.bool,
  isUpdating: PropTypes.bool,
  totalValue: PropTypes.number.isRequired,
  buttonLink: PropTypes.string,
  buttonLabel: PropTypes.string.isRequired,
  showDiscount: MiniCartPropTypes.showDiscount,
  discount: PropTypes.number,
  labelDiscount: PropTypes.string,
  showShippingCost: MiniCartPropTypes.showShippingCost,
}

export default memo(MiniCartFooter)

```


[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/legacy/components/Sidebar.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import IconCaret from '../../../StoreIcons/IconCaret'
import IconCart from '../../../StoreIcons/IconCart'
import { injectIntl } from 'react-intl'
import OutsideClickHandler from 'react-outside-click-handler'
import Animation from '../../../StoreComponents/Animation'
import classNames from 'classnames'
import Overlay from '../../../ReactPortal/Overlay'

import minicart from '../minicart.css'

const OPEN_SIDEBAR_CLASS = minicart.sidebarOpen

/* SideBar component */
class Sidebar extends Component {
  updateComponent() {
    if (this.props.isOpen) {
      document.body.classList.add(OPEN_SIDEBAR_CLASS)
    } else {
      document.body.classList.remove(OPEN_SIDEBAR_CLASS)
    }
  }

  componentDidMount() {
    this.updateComponent()
  }

  componentDidUpdate() {
    this.updateComponent()
  }

  componentWillUnmount() {
    document.body.classList.remove(OPEN_SIDEBAR_CLASS)
  }

  render() {
    const {
      isOpen,
      onOutsideClick,
      intl,
      iconSize,
      quantity,
      iconsProps,
    } = this.props

    if (typeof document === 'undefined') {
      return null
    }

    const scrimClasses = classNames(
      `${minicart.sidebarScrim} fixed dim bg-base--inverted top-0 left-0 z-9999 w-100 vh-100 o-40`,
      {
        dn: !isOpen,
      }
    )

    return (
      <Overlay fullWidth>
        <OutsideClickHandler onOutsideClick={onOutsideClick}>
          <div
            style={{ willChange: 'opacity' }}
            className={scrimClasses}
            onClick={onOutsideClick}
          />

          <Animation
            className={`${minicart.sidebar} w-80 w-auto-ns h-100 fixed top-0 right-0 z-9999 bg-base shadow-2 flex flex-column`}
            isActive={isOpen}
            type="drawerLeft"
          >
            <div
              className={`${minicart.sidebarHeader} pointer flex flex-row items-center pa5 h3 bg-base w-100 z-max bb b--muted-3 bw1`}
            >
              <div
                className={`${minicart.sidebarRightCaretContainer} c-muted-1 pa4 flex items-center`}
                onClick={onOutsideClick}
              >
                <IconCaret orientation="right" size={17} {...iconsProps} />
              </div>
              <div
                className={`${minicart.sidebarItemQuantityContainer} relative c-muted-1`}
              >
                <IconCart size={iconSize} {...iconsProps} />
                {quantity > 0 && (
                  <span
                    className={`${minicart.badge} c-on-emphasis absolute t-mini bg-emphasis br4 w1 h1 pa1 flex justify-center items-center lh-solid`}
                  >
                    {quantity}
                  </span>
                )}
              </div>
              <span
                className={`${minicart.label} dn-m db-l t-action--small pl${
                  quantity > 0 ? '6' : '4'
                } c-muted-1`}
              >
                {intl.formatMessage({ id: 'store/sidebar-title' })}
              </span>
            </div>
            {this.props.children}
          </Animation>
        </OutsideClickHandler>
      </Overlay>
    )
  }
}

Sidebar.propTypes = {
  /* Set the sideBar visibility */
  isOpen: PropTypes.bool,
  /* Sidebar content */
  children: PropTypes.object.isRequired,
  /* Function to be called when click in the close sidebar button or outside the sidebar */
  onOutsideClick: PropTypes.func,
  /* Items quantity */
  quantity: PropTypes.number.isRequired,
  /* Cart icon size */
  iconSize: PropTypes.number,
  /** Props to passed to icons from store-icons */
  iconsProps: PropTypes.shape({
    viewBox: PropTypes.string,
    size: PropTypes.number,
  }),
}

export default injectIntl(Sidebar)

```


[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/legacy/components/MiniCartContent.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import { reduceBy, values, clone, find, propEq, compose } from 'ramda'
import React, { Component, Fragment } from 'react'
import { graphql } from 'react-apollo'
import { injectIntl } from 'react-intl'
import classNames from 'classnames'

import { withPixel } from '../../../PixelContext/PixelContext'

import ButtonWithIcon from '../../../Styleguide/ButtonWithIcon'
import Spinner from '../../../Styleguide/Spinner'
import IconDelete from '../../../StoreIcons/IconDelete'

import { MiniCartPropTypes } from '../utils/propTypes'
import { toHttps, changeImageUrlSize } from '../utils/urlHelpers'
import { mapCartItemToPixel } from '../../modules/pixelHelper'

import { ITEMS_STATUS } from '../localState/index'
import styles from '../minicart.css'
import MiniCartFooter from './MiniCartFooter'

import ProductSummary from '../../../ProductSummary/ProductSummaryLegacy'
import { loader } from 'graphql.macro'

const updateItemsMutation = loader('../localState/graphql/updateItemsMutation.gql')
const updateLocalItemsMutation = loader('../localState/graphql/updateLocalItemsMutation.gql')

/**
 * Minicart content component
 */

class MiniCartContent extends Component {
  static propTypes = {
    /* Set the mini cart content size */
    isSizeLarge: PropTypes.bool,
    /** Define a function that is executed when the item is clicked */
    onClickAction: PropTypes.func,
    /* Update Items mutation */
    updateItems: PropTypes.func.isRequired,
    updateLocalItems: PropTypes.func.isRequired,
    /* Determines if the orderform is updating */
    updatingOrderForm: PropTypes.bool,
    /* Reused props */
    orderForm: PropTypes.object,
    loading: PropTypes.bool,
    labelMiniCartEmpty: MiniCartPropTypes.labelMiniCartEmpty,
    linkButton: MiniCartPropTypes.linkButtonFinishShopping,
    labelButton: MiniCartPropTypes.labelButtonFinishShopping,
    showDiscount: MiniCartPropTypes.showDiscount,
    showShippingCost: MiniCartPropTypes.showShippingCost,
    itemsToShow: PropTypes.arrayOf(PropTypes.object),
    /* Pixel push */
    push: PropTypes.func.isRequired,
    /** Props to passed to icons from store-icons */
    iconsProps: PropTypes.shape({
      viewBox: PropTypes.string,
      size: PropTypes.number,
    }),
  }

  state = { isUpdating: [] }

  sumItemsPrice = items =>
    items.reduce(
      (sum, { sellingPrice, quantity }) => sum + sellingPrice * quantity,
      0
    )

  getGroupedItems = () =>
    values(
      reduceBy(
        (acc, item) =>
          acc ? { ...acc, quantity: acc.quantity + item.quantity } : item,
        undefined,
        item => item.id,
        this.props.orderForm.items
      )
    )

  getShippingCost = orderForm => {
    const totalizer = find(propEq('id', 'Shipping'))(orderForm.totalizers || [])
    return (totalizer && totalizer.value / 100) || 0
  }

  calculateDiscount = items =>
    items.reduce(
      (sum, { listPrice, sellingPrice, quantity }) =>
        sum + (listPrice - sellingPrice) * quantity,
      0
    )

  handleItemRemoval = async (item, index) => {
    const { updateItems, updateLocalItems } = this.props
    const updatedItems = [
      {
        id: item.id,
        index: item.cartIndex != null ? item.cartIndex : index,
        quantity: 0,
      },
    ]

    try {
      if (item.cartIndex != null) {
        await updateItems(updatedItems)
      } else {
        await updateLocalItems(updatedItems)
      }

      this.props.push({
        event: 'removeFromCart',
        items: [mapCartItemToPixel(item)],
      })
    } catch (error) {
      // TODO: Toast error message
      console.error(error)
    }
  }

  updateItemLoad = (itemId, newStatus) => {
    const isUpdating = clone(this.state.isUpdating)
    isUpdating[itemId] = newStatus
    this.setState({ isUpdating })
  }

  calculateTotalValue = orderForm =>
    this.getShippingCost(orderForm)
      ? orderForm.value
      : this.sumItemsPrice(orderForm.items)

  getItemCategory = item => {
    if (!item.productCategoryIds || !item.productCategories) {
      return ''
    }

    return item.productCategoryIds
      .split('/')
      .reduce((acc, id) => acc.concat(item.productCategories[id]), [])
      .join('/')
      .slice(1, -1)
  }

  createProductShapeFromItem = item => {
    return {
      productName: item.name,
      brand: item.additionalInfo ? item.additionalInfo.brandName : undefined,
      category: this.getItemCategory(item),
      productRefId: item.productRefId,
      linkText: item.detailUrl.replace(/^\//, '').replace(/\/p$/, ''),
      sku: {
        seller: {
          commertialOffer: {
            Price: item.sellingPriceWithAssemblies * item.quantity,
            ListPrice: item.listPrice,
          },
          sellerId: item.seller,
        },
        name: item.skuName,
        itemId: item.id,
        image: {
          imageUrl: changeImageUrlSize(toHttps(item ? item.imageUrl : ''), 240),
        },
      },
      assemblyOptions: item.assemblyOptions,
      quantity: item.quantity,
      cartIndex: item.cartIndex,
    }
  }

  get isUpdating() {
    const { isUpdating } = this.state
    const {
      orderForm: { items },
      updatingOrderForm,
    } = this.props
    return (
      updatingOrderForm ||
      items.some(item => item.quantity === 0) ||
      isUpdating.some(status => status)
    )
  }

  renderWithoutItems = label => (
    <div
      className={`${styles.item} pa9 flex items-center justify-center relative bg-base`}
    >
      <span className="t-body">{label}</span>
    </div>
  )

  renderMiniCartWithItems = (
    orderForm,
    itemsToShow,
    label,
    labelDiscount,
    showDiscount,
    onClickAction,
    isUpdating,
    isSizeLarge,
    showShippingCost,
    iconsProps,
    productSummaryProps
  ) => {
    const MIN_ITEMS_TO_SCROLL = 2

    const classes = classNames(`${styles.content} overflow-x-hidden pa1`, {
      [`${styles.contentSmall} bg-base`]: !isSizeLarge,
      [`${styles.contentLarge}`]: isSizeLarge,
      'overflow-y-scroll':
        itemsToShow.length > MIN_ITEMS_TO_SCROLL && !isSizeLarge,
    })

    return (
      <Fragment>
        <div className={classes}>
          {itemsToShow.map((item, index) => (
            <Fragment key={item.id}>
              <section className={`${styles.itemContainer} relative flex`}>
                <div
                  className={`${styles.itemDeleteIcon} fr absolute top-0 right-0`}
                >
                  {isUpdating[item.id] ? (
                    <div className={`${styles.itemDeleteIconLoader} ma4`}>
                      <Spinner size={18} />
                    </div>
                  ) : (
                    <ButtonWithIcon
                      icon={
                        <IconDelete
                          size={15}
                          activeClassName="c-muted-2"
                          {...iconsProps}
                        />
                      }
                      variation="tertiary"
                      onClick={() => this.handleItemRemoval(item, index)}
                    />
                  )}
                </div>
                <ProductSummary
                  showBorders
                  product={this.createProductShapeFromItem(item)}
                  name={item.name}
                  displayMode="inlinePrice"
                  showListPrice={false}
                  showBadge={false}
                  showInstallments={false}
                  showLabels={false}
                  actionOnClick={onClickAction}
                  muted={item.localStatus !== ITEMS_STATUS.NONE}
                  index={index}
                  {...(productSummaryProps? productSummaryProps : {})}
                />
                {/* <ExtensionPoint
                  id="product-summary"
                  showBorders
                  product={this.createProductShapeFromItem(item)}
                  name={item.name}
                  displayMode="inlinePrice"
                  showListPrice={false}
                  showBadge={false}
                  showInstallments={false}
                  showLabels={false}
                  actionOnClick={onClickAction}
                  muted={item.localStatus !== ITEMS_STATUS.NONE}
                  index={index}
                /> */}
              </section>
            </Fragment>
          ))}
        </div>
        <MiniCartFooter
          shippingCost={this.getShippingCost(orderForm)}
          isUpdating={this.isUpdating}
          totalValue={this.calculateTotalValue(orderForm)}
          discount={this.calculateDiscount(orderForm.items)}
          buttonLink={this.props.linkButton}
          buttonLabel={label}
          isSizeLarge={isSizeLarge}
          labelDiscount={labelDiscount}
          showDiscount={showDiscount}
          showShippingCost={showShippingCost}
        />
      </Fragment>
    )
  }

  renderLoading = () => (
    <div
      className={`${styles.item} pa4 flex items-center justify-center relative bg-base`}
    >
      <Spinner />
    </div>
  )

  render() {
    const {
      itemsToShow,
      labelMiniCartEmpty,
      labelButton,
      intl,
      showDiscount,
      onClickAction,
      isSizeLarge,
      showShippingCost,
      orderForm,
      loading,
      iconsProps,
      productSummaryProps,
    } = this.props
    const { isUpdating } = this.state

    if (loading) {
      return this.renderLoading()
    }

    if (!orderForm || !itemsToShow.length) {
      const label =
        labelMiniCartEmpty || intl.formatMessage({ id: 'store/minicart-empty' })
      return this.renderWithoutItems(label)
    }

    const label =
      labelButton ||
      intl.formatMessage({ id: 'store/finish-shopping-button-label' })
    const labelDiscount = intl.formatMessage({
      id: 'store/minicart-content-footer-discount',
    })

    return this.renderMiniCartWithItems(
      orderForm,
      itemsToShow,
      label,
      labelDiscount,
      showDiscount,
      onClickAction,
      isUpdating,
      isSizeLarge,
      showShippingCost,
      iconsProps,
      productSummaryProps
    )
  }
}

const withUpdateItemsMutation = graphql(updateItemsMutation, {
  name: 'updateItems',
  props: ({ updateItems }) => ({
    updateItems: items => updateItems({ variables: { items } }),
  }),
})

const withUpdateLocalItemsMutation = graphql(updateLocalItemsMutation, {
  name: 'updateLocalItems',
  props: ({ updateLocalItems }) => ({
    updateLocalItems: items => updateLocalItems({ variables: { items } }),
  }),
})

export default compose(
  injectIntl,
  withUpdateItemsMutation,
  withUpdateLocalItemsMutation,
  withPixel
)(MiniCartContent)

```


[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/legacy/__tests__/MiniCart.test.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { render, fireEvent, wait } from '@vtex/test-tools/react'
import { orderForm as orderFormQuery } from 'vtex.store-resources/Queries'

import orderForm from '../__mocks__/orderForm'
import emptyOrderForm from '../__mocks__/emptyOrderForm'
import MiniCart from '../../index'

const mocks = [
  {
    request: {
      query: orderFormQuery,
    },
    result: {
      data: {
        orderForm,
      },
    },
  },
]

const emptyMock = [
  {
    request: {
      query: orderFormQuery,
    },
    result: {
      data: {
        orderForm: emptyOrderForm,
      },
    },
  },
]

describe('<MiniCart />', () => {
  beforeEach(() => {
    jest.useFakeTimers()
  })

  it('should render popup onClick', async () => {
    const { getByText, baseElement } = render(
      <MiniCart type="popup" hideContent={false} />
    )

    await wait(() => {
      jest.runAllTimers()
    })

    let box = baseElement.querySelector('.box')
    let sidebar = baseElement.querySelector('.sidebar')

    // Expect box be null before click
    expect(box).toBeNull()
    // Sidebar should not exist before and after click
    expect(sidebar).toBeNull()

    await wait(() => {
      fireEvent.click(getByText(/button test/i))
    })

    await wait(() => {
      jest.runAllTimers()
    })

    box = baseElement.querySelector('.box')
    sidebar = baseElement.querySelector('.sidebar')

    // Expect Minicart Popup redered
    expect(box).toBeDefined()
    expect(box).not.toBeNull()
    // Expect sidebar still not rendered
    expect(sidebar).toBeNull()
  })

  it('should display sidebar onClick', async () => {
    const { getByText, baseElement } = render(
      <MiniCart type="sidebar" hideContent={false} />
    )

    await wait(() => {
      jest.runAllTimers()
    })

    let box = baseElement.querySelector('.box')
    let sidebar = baseElement.querySelector('.sidebarScrim.dn')

    // Expect box be null before and after click
    expect(box).toBeNull()
    // Sidebar should have diplay none class before click
    expect(sidebar).toBeDefined()
    expect(sidebar).not.toBeNull()

    await wait(() => {
      fireEvent.click(getByText(/button test/i))
    })

    await wait(() => {
      jest.runAllTimers()
    })

    box = baseElement.querySelector('.box')
    sidebar = baseElement.querySelector('.sidebarScrim.dn')

    // Expect sidebar dont have display none after click
    expect(sidebar).toBeNull()
    expect(box).toBeNull()
  })

  it('should match the snapshot in popup mode', async () => {
    const leftClick = { button: 0 }

    const { getByText, asFragment } = render(
      <MiniCart type="popup" hideContent={false} />,
      { graphql: { mocks } }
    )

    await wait(() => {
      jest.runAllTimers()
    })

    await wait(() => {
      fireEvent.click(getByText(/button test/i), leftClick)
    })

    await wait(() => {
      jest.runAllTimers()
    })

    expect(asFragment()).toMatchSnapshot()
  })

  it('should match the snapshot in sidebar mode', async () => {
    const { baseElement } = render(
      <MiniCart type="sidebar" hideContent={false} />,
      { graphql: { mocks } }
    )

    await wait(async () => {
      jest.runAllTimers()
    })

    expect(baseElement).toMatchSnapshot()
  })

  it('should be editable in Site Editor', () => {
    const schema = MiniCart.schema || MiniCart.getSchema({})
    expect(schema).toEqual(
      expect.objectContaining({ title: expect.any(String) })
    )
  })

  it('should not show item quantity if there are no items in cart', async () => {
    const { queryByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showTotalItemsQty={false} />,
      { graphql: { mocks: emptyMock } }
    )

    await wait(() => {
      jest.runAllTimers()
    })

    expect(queryByTestId('item-qty')).toBeNull()
  })

  it('should show the quantity of different items in cart', async () => {
    const { getByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showTotalItemsQty={false} />,
      { graphql: { mocks } }
    )

    await wait(() => {
      jest.runAllTimers()
    })

    expect(getByTestId('item-qty').textContent).toBe('1')
  })

  it('should show the total quantity of items in cart', async () => {
    const { getByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showTotalItemsQty />,
      { graphql: { mocks } }
    )

    await wait(() => {
      jest.runAllTimers()
    })

    expect(getByTestId('item-qty').textContent).toBe('2')
  })

  it('should not show price if showPrice is false', async () => {
    const { queryByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showPrice={false} />,
      { graphql: { mocks } }
    )
    await wait(() => {
      jest.runAllTimers()
    })
    expect(queryByTestId('total-price')).toBeNull()
  })

  it('should not show price if there are no items in the cart', async () => {
    const { queryByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showPrice />,
      { graphql: { mocks: emptyMock } }
    )
    await wait(() => {
      jest.runAllTimers()
    })

    expect(queryByTestId('total-price')).toBeNull()
  })

  it('should show price if there are items in the cart', async () => {
    const { getByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showPrice />,
      { graphql: { mocks } }
    )
    await wait(() => {
      jest.runAllTimers()
    })
    expect(getByTestId('total-price')).toBeInTheDocument()
  })

  it('should not show price if showPrice is false', async () => {
    const { queryByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showPrice={false} />,
      { graphql: { mocks } }
    )
    await wait(() => {
      jest.runAllTimers()
    })
    expect(queryByTestId('total-price')).toBeNull()
  })

  it('should show price if there are items in the cart', async () => {
    const { getByTestId } = render(
      <MiniCart type="sidebar" hideContent={false} showPrice />,
      { graphql: { mocks } }
    )

    await wait(() => {
      jest.runAllTimers()
    })

    expect(getByTestId('total-price')).toBeInTheDocument()
  })
})

```


[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/legacy/__tests__/localState.test.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import gql from 'graphql-tag'
import { loader } from 'graphql.macro'

import createLocalState from '../localState/index'
import { ITEMS_STATUS } from '../localState'
const addToCartMutation = loader('../localState/graphql/addToCartMutation.gql')
const updateItemsMutation = loader('../localState/graphql/updateItemsMutation.gql')

describe('Local State', () => {
  let cache, client

  beforeEach(() => {
    cache = new InMemoryCache()
    client = new ApolloClient({
      link: ApolloLink.empty(),
      cache,
    })

    const { resolvers, initialState } = createLocalState(client)

    client.addResolvers(resolvers)
    cache.writeData({ data: initialState })
  })

  it('should append new items to end of cart', async () => {
    const items = [
      {
        id: '100',
        name: 'Chiclete',
        imageUrl: 'imageUrl',
        detailUrl: '/chiclete/p',
        skuName: 'chiclete',
        quantity: 1,
        sellingPrice: 0,
        listPrice: 0,
        parentItemIndex: null,
        parentAssemblyBinding: null,
        assemblyOptions: {
          added: [],
          removed: [],
          parentPrice: 0,
        },
      },
      {
        id: '101',
        name: 'Chiclete de menta',
        imageUrl: 'imageUrl',
        detailUrl: '/chiclete-de-menta/p',
        skuName: 'chiclete de menta',
        quantity: 1,
        sellingPrice: 0,
        listPrice: 0,
        parentItemIndex: null,
        parentAssemblyBinding: null,
        assemblyOptions: {
          added: [],
          removed: [],
          parentPrice: 0,
        },
      },
    ]

    await client.mutate({ mutation: addToCartMutation, variables: { items } })

    const queryResult = client.readQuery({
      query: gql`
        query {
          minicart @client {
            items
          }
        }
      `,
    })

    const cacheItems = JSON.parse(queryResult.minicart.items)

    // assert that the cache items contains all items of the mutation
    expect(cacheItems).toEqual(
      expect.arrayContaining(items.map(expect.objectContaining))
    )

    cacheItems.forEach(item => {
      expect(item).toHaveProperty('localStatus', ITEMS_STATUS.MODIFIED)
    })
  })

  it('should update quantity of item in cart', async () => {
    const item = {
      id: '100',
      name: 'Chiclete',
      imageUrl: 'imageUrl',
      detailUrl: '/chiclete/p',
      skuName: 'chiclete',
      quantity: 1,
      sellingPrice: 0,
      listPrice: 0,
      parentItemIndex: null,
      parentAssemblyBinding: null,
      assemblyOptions: {
        added: [],
        removed: [],
        parentPrice: 0,
      },
    }

    cache.writeData({
      data: {
        minicart: {
          __typename: 'Minicart',
          items: JSON.stringify([item]),
        },
      },
    })

    const updateItemsPayload = [{ index: 0, quantity: 2, id: item.id }]

    await client.mutate({
      mutation: updateItemsMutation,
      variables: { items: updateItemsPayload },
    })

    const queryResult = client.readQuery({
      query: gql`
        query {
          minicart @client {
            items
          }
        }
      `,
    })

    const cacheItems = JSON.parse(queryResult.minicart.items)

    expect(cacheItems).toEqual(
      expect.arrayContaining(
        updateItemsPayload.map(item =>
          expect.objectContaining({
            id: item.id,
            localStatus: ITEMS_STATUS.MODIFIED,
          })
        )
      )
    )

    expect(cacheItems).toEqual(
      expect.arrayContaining(
        updateItemsPayload.map(item =>
          expect.objectContaining({ id: item.id, quantity: item.quantity })
        )
      )
    )
  })

  it('should update quantity of more than one item in cart', async () => {
    const items = [
      {
        id: '100',
        name: 'Chiclete',
        imageUrl: 'imageUrl',
        detailUrl: '/chiclete/p',
        skuName: 'chiclete',
        quantity: 1,
        sellingPrice: 0,
        listPrice: 0,
        parentItemIndex: null,
        parentAssemblyBinding: null,
        assemblyOptions: {
          added: [],
          removed: [],
          parentPrice: 0,
        },
      },
      {
        id: '101',
        name: 'Chiclete de menta',
        imageUrl: 'imageUrl',
        detailUrl: '/chiclete-de-menta/p',
        skuName: 'chiclete de menta',
        quantity: 1,
        sellingPrice: 0,
        listPrice: 0,
        parentItemIndex: null,
        parentAssemblyBinding: null,
        assemblyOptions: {
          added: [],
          removed: [],
          parentPrice: 0,
        },
      },
    ]

    cache.writeData({
      data: {
        minicart: {
          __typename: 'Minicart',
          items: JSON.stringify(items),
        },
      },
    })

    const updateItemsPayload = [
      { index: 0, quantity: 2, id: items[0].id },
      { index: 1, quantity: 9, id: items[1].id },
    ]

    await client.mutate({
      mutation: updateItemsMutation,
      variables: { items: updateItemsPayload },
    })

    const queryResult = client.readQuery({
      query: gql`
        query {
          minicart @client {
            items
          }
        }
      `,
    })

    const cacheItems = JSON.parse(queryResult.minicart.items)

    expect(cacheItems).toEqual(
      expect.arrayContaining(
        updateItemsPayload.map(item =>
          expect.objectContaining({
            id: item.id,
            localStatus: ITEMS_STATUS.MODIFIED,
          })
        )
      )
    )

    expect(cacheItems).toEqual(
      expect.arrayContaining(
        updateItemsPayload.map(item =>
          expect.objectContaining({ id: item.id, quantity: item.quantity })
        )
      )
    )
  })
})

```


[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/legacy/hooks/useMarketingSessionParams.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { useEffect, useState } from 'react'

import { path, pathOr } from 'ramda'

const getUtmParams = (publicFields) => ({
  source: path(['utm_source', 'value'], publicFields),
  medium: path(['utm_medium', 'value'], publicFields),
  campaign: path(['utm_campaign', 'value'], publicFields),
})

const getUtmiParams = (publicFields) => ({
  campaign: path(['utmi_cp', 'value'], publicFields),
  page: path(['utmi_p', 'value'], publicFields),
  part: path(['utmi_pc', 'value'], publicFields),
})

const getSessionPromiseFromWindow = () =>
    !window.__RENDER_8_SESSION__ || !window.__RENDER_8_SESSION__.sessionPromise
      ? Promise.resolve(null)
      : window.__RENDER_8_SESSION__.sessionPromise

const useMarketingSessionParams = () => {
  const [utmParams, setUtmParams] = useState(undefined)
  const [utmiParams, setUtmiParams] = useState(undefined)

  useEffect(() => {
    getSessionPromiseFromWindow().then(data => {
      const publicFields = pathOr({}, ['response', 'namespaces', 'public'], data)
      if (Object.keys(publicFields).length === 0) {
        return
      }

      setUtmParams(getUtmParams(publicFields))
      setUtmiParams(getUtmiParams(publicFields))
    }).catch(() => {
      // Do nothing!
    })
  }, [])

  return { utmParams, utmiParams }
}

export default useMarketingSessionParams

```


[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/legacy/localState/graphql/updateLocalItemStatusMutation.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updateLocalItemStatus {
  updateLocalItemStatus @client
}

```


[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/legacy/localState/graphql/addToCartMutation.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation addToCart($items: [MinicartItem]) {
  addToCart(items: $items) @client
}

```


[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/legacy/localState/graphql/updateLocalItemsMutation.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation UpdateLocalItems($items: [MinicartItem]) {
  updateLocalItems(items: $items) @client
}

```


[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/legacy/localState/graphql/fullMinicartQuery.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
query {
  minicart @client {
    items
    orderForm
    isOpen
  }
}

```


[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/legacy/localState/graphql/minicartOrderFormQuery.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
query orderFormLocal {
  minicart @client {
    orderForm
  }
}

```


[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/legacy/localState/graphql/updateOrderFormMutation.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updateOrderForm(
  $orderForm: [OrderForm]
  $forceUpdateItems: Boolean = false
) {
  updateOrderForm(orderForm: $orderForm, forceUpdateItems: $forceUpdateItems)
    @client
}

```


[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/legacy/localState/graphql/updateItemsMutation.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updateItemsLocal($items: [MinicartItem]) {
  updateItems(items: $items) @client
}

```


[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/legacy/localState/graphql/setMinicartOpenMutation.gql from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation setMinicartOpen($isOpen: Boolean!) {
  setMinicartOpen(isOpen: $isOpen) @client
}

```


[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/legacy/__tests__/hooks/useMarketingSessionParams.test.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { renderHook, wait } from '@vtex/test-tools/react'
import useMarketingSessionParams from '../../hooks/useMarketingSessionParams'

const fakeSessionWithData = {
  response: {
    namespaces: {
      public: {
        ['utm_source']: {
          value: 'utmSource'
        },
        ['utm_medium']: {
          value: 'utmMedium'
        },
        ['utm_campaign']: {
          value: 'utmCampaign'
        },
        ['utmi_cp']: {
          value: 'utmiCampaign'
        },
        ['utmi_p']: {
          value: 'utmiPage'
        },
        ['utmi_pc']: {
          value: 'utmiPart'
        },
      }
    }
  }
}

const fakeSessionNoData = {
  response: {
    namespaces: {
      public: {}
    }
  }
}

it('if session has correct data, get and format input correctly', async () => {
  window.__RENDER_8_SESSION__ = {}
  window.__RENDER_8_SESSION__.sessionPromise = new Promise(resolve => resolve(fakeSessionWithData))
  const { result } = renderHook(() => useMarketingSessionParams())

  await wait()

  const { utmParams, utmiParams } = result.current
  expect(utmParams).toMatchObject({
    source: 'utmSource',
    medium: 'utmMedium',
    campaign: 'utmCampaign',
  })
  expect(utmiParams).toMatchObject({
    campaign: 'utmiCampaign',
    page: 'utmiPage',
    part: 'utmiPart',
  })
})

it('if session does not have data, leave object as undefined', async () => {
  window.__RENDER_8_SESSION__ = {}
  window.__RENDER_8_SESSION__.sessionPromise = new Promise(resolve => resolve(fakeSessionNoData))
  const { result } = renderHook(() => useMarketingSessionParams())

  await wait()

  const { utmParams, utmiParams } = result.current
  expect(utmParams).toBe(undefined)
  expect(utmiParams).toBe(undefined)
})

it('if session promise rejects, everything still works, response is undefined', async () => {
  window.__RENDER_8_SESSION__ = {}
  window.__RENDER_8_SESSION__.sessionPromise = new Promise((_, reject) => reject())
  const { result } = renderHook(() => useMarketingSessionParams())

  await wait()

  const { utmParams, utmiParams } = result.current
  expect(utmParams).toBe(undefined)
  expect(utmiParams).toBe(undefined)
})

```


[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/StoreIcons/typings/global.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface IconProps {
  readonly id: string
  readonly handle?: string
  readonly isActive?: boolean
  readonly size?: number
  readonly viewBox?: string
  readonly activeClassName?: string
  readonly mutedClassName?: string
}

interface EnhancedIconProps extends IconProps {
  readonly orientation?: string
  readonly state?: string
  readonly shape?: string
  readonly type?: string
}

interface CaretProps extends EnhancedIconProps {
  readonly thin?: boolean
}

interface Enhancement {
  id: string
  modifier: 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/StoreIcons/utils/helpers.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { contains, find, propEq } from 'ramda'
import { ORIENTATIONS, SHAPES, STATES, TYPES } from './enhancements'

/**
 * Get the modifer from any collection matching the rule collection{id, modifier}
 * @param {*} id
 * @param {*} collection
 */
export const getModifier = (collection: Enhancement[], id?: string) => {
  const foundItem = find(propEq('id', id), collection) as any
  return !!foundItem ? foundItem.modifier : id
}

/**
 * Get a subset of the collections with given ids (passed with commas)
 * @param {*} tokens
 * @param {*} collection
 */
export const getSubset = (tokens: string, collection: Enhancement[]) => {
  const ids = tokens.split(',').join('')
  return collection.filter((item: any) => contains(item.id, ids))
}

/**
 * Get enhancement modifier
 * @param enhancementList list of enhancements
 * @param enhancement desired enhancement
 * @param supported all supported enhancement list
 */
export const getEnhancement = (
  enhancementList: Enhancement[],
  enhancement?: string,
  supported?: string
) => {
  const supportedEnhancements = !!supported
    ? getSubset(supported, enhancementList)
    : enhancementList
  const modifier = getModifier(supportedEnhancements, enhancement)
  return modifier
}

/**
 * Get orientation modifier
 * @param orientation desired orientation
 * @param supported suported orientations
 */
export const getOrientation = (orientation?: string, supported?: string) =>
  getEnhancement(ORIENTATIONS, orientation, supported)

/**
 * Get type modifier
 * @param type desired type
 * @param supported suported types
 */
export const getType = (type?: string, supported?: string) =>
  getEnhancement(TYPES, type, supported)

/**
 * Get state modifier
 * @param state desirend state
 * @param supported suported states
 */
export const getState = (state?: string, supported?: string) =>
  getEnhancement(STATES, state, supported)

/**
 * Get shape modifier
 * @param size icon size
 * @param background background color
 * @param shape desired shape
 * @param supported suported shapes
 */
export const getShape = (
  size: number,
  background: string,
  shape?: string,
  supported?: string
) => {
  const REDUCTION_PERCENTAGE = 0.4
  const getReduction = (size: number) => size * REDUCTION_PERCENTAGE
  const modifiers = getEnhancement(SHAPES, shape, supported)
  const reduction = getReduction(size)
  const padding = reduction / 2
  const reducedIconSize = size - reduction

  const wrapperProps = [
    { className: `${modifiers} flex` },
    { style: { padding, backgroundColor: background } },
  ]

  return { wrapperProps, reducedIconSize }
}

```


[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/StoreIcons/utils/enhancements.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const SHAPES = [
  {
    id: 'square',
    modifier: 'br1',
  },
  {
    id: 'rounded',
    modifier: 'br3',
  },
  {
    id: 'circle',
    modifier: 'br-100',
  },
]

export const ORIENTATIONS = [
  {
    id: 'up',
    modifier: '--up',
  },
  {
    id: 'down',
    modifier: '--down',
  },
  {
    id: 'right',
    modifier: '--right',
  },
  {
    id: 'left',
    modifier: '--left',
  },
]

export const STATES = [
  {
    id: 'on',
    modifier: '--on',
  },
  {
    id: 'off',
    modifier: '--off',
  },
]

export const TYPES = [
  {
    id: 'filled',
    modifier: '--filled',
  },
  {
    id: 'outline',
    modifier: '--outline',
  },
  {
    id: 'line',
    modifier: '--line',
  },
]

```


[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/StoreIcons/components/Icon.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import useCssHandles from '../../CssHandles/useCssHandles'

import Use from './Use'
import Svg from './Svg'

import './icon.global.css'

const CSS_HANDLES = [
  'arrowBackIcon',
  'assistantSalesIcon',
  'caretIcon',
  'cartIcon',
  'checkIcon',
  'closeIcon',
  'deleteIcon',
  'equalsIcon',
  'eyeSightIcon',
  'filterIcon',
  'globeIcon',
  'gridIcon',
  'heartIcon',
  'homeIcon',
  'inlineGridIcon',
  'locationInputIcon',
  'locationMarkerIcon',
  'menuIcon',
  'minusIcon',
  'plusIcon',
  'profileIcon',
  'removeIcon',
  'searchIcon',
  'singleGridIcon',
  'socialIcon',
  'starIcon',
  'swapIcon',
] as const

const Icon = ({
  id,
  handle,
  isActive,
  size,
  viewBox,
  activeClassName,
  mutedClassName,
}: IconProps) => {
  const handles = useCssHandles(CSS_HANDLES)

  return (
    <Svg
      fill="none"
      width={size}
      height={size}
      viewBox={viewBox}
      className={`${
        isActive ? activeClassName || '' : mutedClassName || ''
      } ${handles[handle] || ''}`}
    >
      <Use id={id} />
    </Svg>
  )
}

Icon.defaultProps = {
  isActive: true,
  size: 16,
  viewBox: '0 0 16 16',
}

export default Icon

```


[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/StoreIcons/components/Use.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface Props {
  id: string
}

const Use = ({ id }: Props) => <use href={`#${id}`} xlinkHref={`#${id}`} />

export default Use

```


[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/StoreIcons/components/Svg.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactNode } from 'react'

interface Props {
  readonly fill?: string
  readonly width?: number
  readonly height?: number
  readonly viewBox?: string
  readonly className?: string
  readonly xmlns?: string
  readonly xmlnsXlink?: string
  readonly children?: ReactNode
}

const Svg = ({ children, ...props }: Props) => <svg {...props}>{children}</svg>

Svg.defaultProps = {
  xmlns: 'http://www.w3.org/2000/svg',
  xmlnsXlink: 'http://www.w3.org/1999/xlink',
}

export default Svg

```


[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/StoreIcons/components/icon.global.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
@keyframes sti-loading-rotate {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

.sti-loading-rotate {
  transform-origin: 50px 50px;
  animation: sti-loading-rotate 0.7s infinite linear;
}

```


[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/StoreIcons/__tests__/Svg.test.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { render } from '@vtex/test-tools/react'
import Svg from '../components/Svg'

describe('Svg', () => {
  it('should match snapshot', () => {
    const component = render(
      <Svg fill="black">
        <path />
      </Svg>
    ).asFragment()
    expect(component).toMatchSnapshot()
  })
})

```


[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/StoreIcons/__tests__/Icon.test.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

import Icon from '../components/Icon'

describe('Icon', () => {
  it('should match snapshot', () => {
    const component = render(<Icon id="tst-snapshot" size={20} />).asFragment()
    expect(component).toMatchSnapshot()
  })
})

```


[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/StoreIcons/__tests__/Use.test.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { render } from '@vtex/test-tools/react'
import Use from '../components/Use'

describe('Use', () => {
  it('should match snapshot', () => {
    const component = render(
      <svg>
        <Use id="tst-snapshot" />
      </svg>
    ).asFragment()
    expect(component).toMatchSnapshot()
  })
})

```


[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/StoreIcons/__tests__/Enhancements.test.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import {
  getSubset,
  getShape,
  getOrientation,
  getState,
  getType,
} from '../utils/helpers'
import { SHAPES, ORIENTATIONS } from '../utils/enhancements'

describe('Enhancements', () => {
  it('should allow supported enhancements', () => {
    const shapes = getSubset('square', SHAPES)
    const orientations = getSubset('down, right', ORIENTATIONS)

    expect(shapes).toEqual([
      {
        id: 'square',
        modifier: 'br1',
      },
    ])

    expect(orientations).toEqual([
      {
        id: 'down',
        modifier: '--down',
      },
      {
        id: 'right',
        modifier: '--right',
      },
    ])
  })

  it('should get the correct shape', () => {
    const square = getShape(16, 'red', 'square')
    const rounded = getShape(20, 'green', 'rounded')
    const circle = getShape(24, 'blue', 'circle')

    expect(square.reducedIconSize).toBeLessThan(16)
    expect(rounded.reducedIconSize).toBeLessThan(20)
    expect(circle.reducedIconSize).toBeLessThan(24)

    expect(square.wrapperProps).toHaveLength(2)
    expect(rounded.wrapperProps).toHaveLength(2)
    expect(circle.wrapperProps).toHaveLength(2)

    expect(square.wrapperProps[0].className).toContain('br1')
    expect(rounded.wrapperProps[0].className).toContain('br3')
    expect(circle.wrapperProps[0].className).toContain('br-100')

    expect(square.wrapperProps[1].style!.backgroundColor).toEqual('red')
    expect(rounded.wrapperProps[1].style!.backgroundColor).toEqual('green')
    expect(circle.wrapperProps[1].style!.backgroundColor).toEqual('blue')
  })

  it('should get the correct orientation', () => {
    const up = getOrientation('up')
    const down = getOrientation('down')
    const left = getOrientation('left')
    const right = getOrientation('right')

    expect(up).toEqual('--up')
    expect(down).toEqual('--down')
    expect(left).toEqual('--left')
    expect(right).toEqual('--right')
  })

  it('should get the correct state', () => {
    const on = getState('on')
    const off = getState('off')

    expect(on).toEqual('--on')
    expect(off).toEqual('--off')
  })

  it('should get the correct type', () => {
    const filled = getType('filled')
    const outline = getType('outline')
    const line = getType('line')

    expect(filled).toEqual('--filled')
    expect(outline).toEqual('--outline')
    expect(line).toEqual('--line')
  })
})

```


[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/StoreIcons/testUtils/setupTests.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
// react-testing-library renders your components to document.body,
// this will ensure they're removed after each test.
import 'react-testing-library/cleanup-after-each'

// this adds jest-dom's custom assertions
import 'jest-dom/extend-expect'

```


[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/Slider/utils/resolveSlidesNumber.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
/**
 * This function returns the number of slides to show depending on the size of the window.
 * If you pass a number it just returns that number.
 * If you pass an object it will return the number of slides of the closest breakpoint to the size of the window.
 * If you pass for example
 * perPage = {
 *   400: 2,
 *   1000: 3
 * }
 *
 * If the size of the window is something between 400px and 999px if will return 2,
 * if it is 1000px or bigger, it will return 3, and if it is smaller than 400px it
 * will return the default value; that is, 1.
 * @param {number|object} perPage
 * @param {number|undefined} minPerPage
 */
function resolveSlidesNumber(minPerPage, perPage, isMobile) {
  let result = minPerPage || 1
  if (typeof perPage === 'number') {
    result = perPage
  } else if (typeof perPage === 'object') {
    const innerWidth = window && window.innerWidth

    /** If it's on SSR, use placeholder screen sizes to get an approximate
     * guess of how many items are displayed per page */
    const windowSize = innerWidth || (isMobile ? 320 : 1024)

    for (const viewport in perPage) {
      if (windowSize >= viewport) {
        result = perPage[viewport]
      }
    }
  }
  return result < minPerPage ? minPerPage : result
}

export default resolveSlidesNumber

```


[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/Slider/utils/index.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
export function setStyle(target, styles) {
  Object.keys(styles).forEach(attr => {
    target.style[attr] = styles[attr]
  })
}

function getZeroOrString(num = 0) {
  return num === 0 ? num : `${num}%`
}

export function getTranslateProperty(x = 0, y = 0, z = 0) {
  return {
    transform: `translate3d(${getZeroOrString(x)}, ${getZeroOrString(
      y
    )}, ${getZeroOrString(z)})`,
    WebkitTransform: `translate3d(${getZeroOrString(x)}, ${getZeroOrString(
      y
    )}, ${getZeroOrString(z)})`,
  }
}

export function getStylingTransition(easing, duration = 0) {
  return {
    WebkitTransition: `all ${duration}ms ${easing}`,
    transition: `all ${duration}ms ${easing}`,
  }
}

export const constants = {
  defaultResizeDebounce: 250,
  defaultTransitionDuration: 250,
  NAVIGATION_PAGE: 'page',
}

```


[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/Slider/components/styles.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
.slideImg {
  margin-right: -50%;
  transform: translate(-50%, -50%);
  left: 50%;
  top: 50%;
}

.dotsContainer {
  margin-right: -50%;
  transform: translate(-50%, 0);
  left: 50%;
}

.arrowContainer {
  top: 50%;
  transform: translate(0, -50%);
}

.sliderFrame {
  will-change: transform;
}

```


[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/Slider/components/Dots.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import debounce from 'debounce'
import EventListener from 'react-event-listener'
import { constants } from '../utils'
import resolveSlidesNumber from '../utils/resolveSlidesNumber'
import styles from './styles.css'

class Dots extends PureComponent {
  static propTypes = {
    /** Classes to style the elements fo the component */
    classes: PropTypes.shape({
      root: PropTypes.string,
      dot: PropTypes.string,
      activeDot: PropTypes.string,
      notActiveDot: PropTypes.string,
    }),
    /** Current slide on the screen, if you have perPage > 1, then the current slide is the most left slide on the screen */
    currentSlide: PropTypes.number,
    /** Extra props to be applied to the dot element */
    dotProps: PropTypes.object,
    /** The size of the dots, can be a number (in this case it will use px unit), or a string (you have to pass the number with the unit e.g '3rem') */
    dotSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /** Tag to be rendered in the dot element */
    dotTag: PropTypes.string,
    /** If the slides should be looping */
    loop: PropTypes.bool,
    /** Function to change the currentSlide */
    onChangeSlide: PropTypes.func.isRequired,
    /** This prop works the same way the minPerPage of Slider and this component should receive the same value of Slider */
    minPerPage: PropTypes.number,
    /** This prop works the same way the perPage of Slider and this component should receive the same value of Slider */
    perPage: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
    /** Debounce time in milliseconds. */
    resizeDebounce: PropTypes.number,
    /** Tag of root element of the component to be rendered */
    rootTag: PropTypes.string,
    /** Total value of sliders that will be rendered */
    totalSlides: PropTypes.number.isRequired,
    /** If this flag is true, then every dot represent a page of slides (e.g. if perPage = 2 and you have 4 elements,
     * then you have 2 dots), if false, then it will render a dot to every slide */
    showDotsPerPage: PropTypes.bool,
  }

  static defaultProps = {
    classes: {
      root: '',
      dot: '',
      activeDot: '',
      notActiveDot: '',
    },
    dotTag: 'li',
    loop: false,
    perPage: 1,
    rootTag: 'ul',
    showDotsPerPage: false,
    resizeDebounce: constants.defaultResizeDebounce,
  }

  constructor(props) {
    super(props)

    this.handleResize = debounce(this._setPerPageOnResize, props.resizeDebounce)
  }

  get slideIndeces() {
    const { showDotsPerPage, totalSlides } = this.props
    return this.perPage
      ? [
          ...Array(
            showDotsPerPage
              ? Math.ceil(totalSlides / this.perPage)
              : totalSlides
          ).keys(),
        ]
      : []
  }

  get selectedDot() {
    const { showDotsPerPage, currentSlide, loop } = this.props
    const realCurrentSlide = loop ? currentSlide - this.perPage : currentSlide
    return showDotsPerPage
      ? Math.floor(realCurrentSlide / this.perPage)
      : realCurrentSlide
  }

  handleDotClick = index => {
    const { showDotsPerPage, onChangeSlide, loop } = this.props
    const slideToGo = showDotsPerPage ? index * this.perPage : index
    onChangeSlide(loop ? slideToGo + this.perPage : slideToGo)
  }

  componentWillUnmount() {
    this.handleResize.clear()
  }

  _setPerPageOnResize = () => {
    const { minPerPage, perPage } = this.props
    this.perPage = resolveSlidesNumber(minPerPage, perPage)
    this.forceUpdate()
  }

  render() {
    const {
      rootTag: RootTag,
      dotTag: DotTag,
      classes: classesProp,
      dotProps,
      minPerPage,
      perPage,
      totalSlides,
      dotSize,
    } = this.props

    const classes = {
      ...Dots.defaultProps.classes,
      ...classesProp,
    }

    if (totalSlides < 2) {
      return null
    }

    if (!this.perPage) {
      this.perPage = resolveSlidesNumber(minPerPage, perPage)
    }

    return (
      <RootTag
        className={classnames(
          styles.dotsContainer,
          classes.root,
          'absolute ma0 pa0 dib list'
        )}
      >
        <EventListener target="window" onResize={this.handleResize} />
        {this.slideIndeces.map(i => {
          const dotClasses = classnames(classes.dot, 'dib', {
            [classes.activeDot]: i === this.selectedDot,
            [classes.notActiveDot]: i !== this.selectedDot,
          })

          return (
            <DotTag
              className={dotClasses}
              key={i}
              onClick={() => this.handleDotClick(i)}
              {...{ style: { height: dotSize, width: dotSize } }}
              {...dotProps}
            />
          )
        })}
      </RootTag>
    )
  }
}

export default Dots

```


[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/Slider/components/Slide.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { PureComponent } from 'react'
import EventListener from 'react-event-listener'
import classnames from 'classnames'
import PropTypes from 'prop-types'
import debounce from 'debounce'
import styles from './styles.css'
import { constants } from '../utils'

class SlideComponent extends PureComponent {
  constructor(props) {
    super(props)
    this.imgRef = React.createRef()
    this.handleResize = debounce(() => {
      setTimeout(() => {
        this.fit()
      }, props.sliderTransitionDuration)
    }, props.resizeDebounce)

    this.state = {
      firstRender: true
    }
  }

  componentDidMount() {
    this.ensureImageCover()
    this.setState({ firstRender: false })
  }

  componentDidUpdate() {
    this.ensureImageCover()
  }

  componentWillUnmount() {
    this.handleResize.clear()
  }

  fit = () => {
    const { current: imgElement } = this.imgRef

    if (!imgElement || !imgElement.complete) {
      return
    }

    const imgAspectRatio = imgElement.width / imgElement.height
    const parentAspectRatio = imgElement.parentNode.offsetWidth / imgElement.parentNode.offsetHeight

    if (imgAspectRatio > parentAspectRatio) {
      imgElement.classList.remove('w-100')
      imgElement.classList.add('h-100')
    } else {
      imgElement.classList.remove('h-100')
      imgElement.classList.add('w-100')
    }
    imgElement.removeEventListener('load', this.fit)
  }

  ensureImageCover = () => {
    const { current: imgElement } = this.imgRef
    if (!imgElement || !this.props.fitImg) {
      return
    }

    if (imgElement.complete) {
      this.fit()
    } else {
      imgElement.addEventListener('load', this.fit)
    }
  }

  render() {
    const {
      children,
      className,
      tag: RootComponent,
      fitImg,
      innerRef,
      resizeDebounce,
      defaultWidth,
      style,
      sliderTransitionDuration,
      ...rootProps
    } = this.props

    return (
      <RootComponent
        ref={innerRef}
        className={classnames(className, 'inline-flex h-100 relative overflow-hidden')}
        style={{ ...style }}
        {...rootProps}
      >
        <EventListener target="window" onResize={this.handleResize} />
        {React.Children.map(children, child => {
          if (!React.isValidElement(child)) {
            return null
          }
          if (fitImg && child.type === 'img') {
            return React.cloneElement(child, {
              ref: this.imgRef,
              className: classnames(styles.slideImg, child.props.className, 'absolute')
            })
          }

          return child
        })}
      </RootComponent>
    )
  }
}

const renderForwardRef = (props, ref) => <SlideComponent innerRef={ref} {...props} />

renderForwardRef.displayName = 'Slide'

const Slide = React.forwardRef(renderForwardRef)

Slide.propTypes = {
  /** Node to render */
  children: PropTypes.node.isRequired,
  /** Classes to pass to root of slider */
  className: PropTypes.string,
  /** Default width of root in px */
  defaultWidth: PropTypes.number,
  /** Tag to be rendered in root element */
  tag: PropTypes.string,
  /** If the slide component should try to fit the img (only works if children is an img element) */
  fitImg: PropTypes.bool,
  /** Time of debounce of resize event listener */
  resizeDebounce: PropTypes.number,
  /** Duration of transition passed to Slider (must be the same), if nothing is passed to any of the components
   * it will apply the same default value
   */
  sliderTransitionDuration: PropTypes.number
}

Slide.defaultProps = {
  tag: 'li',
  fitImg: true,
  resizeDebounce: constants.defaultResizeDebounce,
  sliderTransitionDuration: constants.defaultTransitionDuration
}

export default Slide

```


[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/Slider/components/SliderContainer.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

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

class SliderContainerComponent extends PureComponent {
  intervalRef = null

  setNewInterval = () => {
    const { autoplay, autoplayInterval, onNextSlide } = this.props

    if (
      !autoplay ||
      typeof autoplayInterval !== 'number' ||
      autoplayInterval === 0
    ) {
      return
    }

    if (this.intervalRef) {
      clearInterval(this.intervalRef)
    }

    this.intervalRef = setInterval(() => {
      onNextSlide && onNextSlide()
    }, autoplayInterval)
  }

  componentDidMount() {
    if (this.props.autoplay && this.props.autoplayInterval > 0) {
      this.setNewInterval()
    }
  }

  componentWillUnmount() {
    clearInterval(this.intervalRef)
  }

  eventProcedure = (e, eventCallback, clearOnPause = true) => {
    const { pauseOnHover } = this.props
    if (pauseOnHover) {
      clearOnPause ? clearInterval(this.intervalRef) : this.setNewInterval()
    }
    if (eventCallback) {
      eventCallback(e)
    }
  }

  onTouchStart = e => {
    this.eventProcedure(e, this.props.onTouchStart)
  }

  onTouchEnd = e => {
    this.eventProcedure(e, this.props.onTouchEnd, false)
  }

  onMouseEnter = e => {
    this.eventProcedure(e, this.props.onMouseEnter)
  }

  onMouseLeave = e => {
    this.eventProcedure(e, this.props.onMouseLeave, false)
  }

  render() {
    const {
      className,
      children,
      tag: RootTag,
      innerRef,
      onMouseEnter,
      onMouseLeave,
      onTouchStart,
      onTouchEnd,
      onNextSlide,
      pauseOnHover,
      autoplay,
      autoplayInterval,
      ...otherProps
    } = this.props

    return (
      <RootTag
        ref={innerRef}
        className={classnames(className, 'relative')}
        onMouseEnter={this.onMouseEnter}
        onMouseLeave={this.onMouseLeave}
        onTouchStart={this.onTouchStart}
        onTouchEnd={this.onTouchEnd}
        {...otherProps}
      >
        {children}
      </RootTag>
    )
  }
}

const renderForwardRef = (props, ref) => (
  <SliderContainerComponent innerRef={ref} {...props} />
)
renderForwardRef.displayName = 'SliderContainer'
const SliderContainer = React.forwardRef(renderForwardRef)

SliderContainer.propsTypes = {
  /** If the slider should be passing automatically */
  autoplay: PropTypes.boolean,
  /** Time in milliseconds of the interval to pass from a slider to the next one */
  autoplayInterval: PropTypes.number,
  /** Children of the component to render */
  children: PropTypes.node.isRequired,
  /** Classes to be applied to the root element */
  className: PropTypes.string,
  /** Function to go to the next slide */
  onNextSlide: PropTypes.func,
  /** If the interval should not be executed if the mouse is on the component */
  pauseOnHover: PropTypes.boolean,
  /** Tag to render the component */
  tag: PropTypes.string,
}

SliderContainer.defaultProps = {
  autoplay: false,
  autoplayInterval: 5000,
  pauseOnHover: true,
  tag: 'div',
}

export default SliderContainer

```