[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 shelf/messages/es.json from the shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.shelf.title": "Vitrina",
  "admin/editor.shelf.description": "Una vitrina con una colección de productos",
  "admin/editor.shelf.category.title": "Id de la Categoría",
  "admin/editor.shelf.category.description": "Para subcategorías, utilice \"/\" (por ejemplo: 1/2/3)",
  "admin/editor.shelf.collection.title": "Colección",
  "admin/editor.shelf.orderBy.title": "Ordenación de la Lista",
  "admin/editor.shelf.hideUnavailableItems": "Ocultar artículos no disponibles",
  "admin/editor.shelf.hideOutOfStockItems": "Ocultar ítems sin stock",
  "admin/editor.shelf.skusFilter": "Filtro de SKUs",
  "admin/editor.shelf.skusFilter.description": "¡Establecer el primer iten disponible agiliza su consulta!",
  "admin/editor.shelf.skusFilter.none": "Ninguno",
  "admin/editor.shelf.skusFilter.all-available": "Todos disponibles",
  "admin/editor.shelf.skusFilter.first-available": "Primero disponible",
  "admin/editor.shelf.maxItems.title": "Cantidad máxima de Elementos",
  "admin/editor.shelf.itemsPerPage.title": "Productos por Página (web)",
  "admin/editor.shelf.gap.title": "Brecha entre los elementos",
  "admin/editor.shelf.scrollType.title": "Tipo de Desplazamiento",
  "admin/editor.shelf.arrows.title": "Dardos (web)",
  "admin/editor.shelf.titleText.title": "Texto del Título",
  "admin/editor.shelf.titleText.showTitle": "Exibir título del vitrina",
  "admin/editor.shelf.specificationFilters.title": "Filtros de especificación",
  "admin/editor.shelf.specificationFilters.item.title": "Elemento de filtro de especificación",
  "admin/editor.shelf.specificationFilters.item.id.title": "ID del filtro de especificación",
  "admin/editor.shelf.specificationFilters.item.value.title": "Valor del filtro de especificación",
  "admin/editor.shelf.gapType.none": "Ninguno",
  "admin/editor.shelf.gapType.small": "Pequeño",
  "admin/editor.shelf.gapType.medium": "Medio",
  "admin/editor.shelf.gapType.large": "Grande",
  "admin/editor.shelf.orderType.sales": "Ventas",
  "admin/editor.shelf.orderType.priceDesc": "Precio, descendiendo",
  "admin/editor.shelf.orderType.priceAsc": "Precio, ascendente",
  "admin/editor.shelf.orderType.nameAsc": "Nombre, ascendente",
  "admin/editor.shelf.orderType.nameDesc": "Nombre, descendiendo",
  "admin/editor.shelf.orderType.releaseDate": "Fecha de lanzamiento",
  "admin/editor.shelf.orderType.discount": "Descuento",
  "admin/editor.shelf.orderType.relevance": "Relevancia",
  "admin/editor.shelf.scrollType.byPage": "Por Página",
  "admin/editor.shelf.scrollType.oneByOne": "Uno a Uno",
  "admin/editor.shelf.advanced-properties.title": "Configuraciones avanzadas",
  "admin/editor.shelf.advanced-properties.tracking-id.title": "Nombre del estante en el GTM",
  "admin/editor.shelf.advanced-properties.tracking-id.description": "Nombre para mostrar en Google Analytics. Se no se agrega nada, se utilizará el nombre del bloque del estante",
  "admin/editor.relatedProducts.title": "Productos Relacionados",
  "admin/editor.relatedProducts.description": "Una vitrina de productos relacionados para mostrar recomendaciones de vista",
  "admin/editor.relatedProducts.recommendation": "Recomendaciones",
  "admin/editor.relatedProducts.recommendation.description": "Qué recomendaciones se mostrará",
  "admin/editor.relatedProducts.similars": "Productos similares",
  "admin/editor.relatedProducts.view": "Quién vio esto, también vio...",
  "admin/editor.relatedProducts.buy": "Quién compró esto, también compró...",
  "admin/editor.relatedProducts.accessories": "Productos de accesorios",
  "admin/editor.relatedProducts.viewAndBought": "Quien vio esto, también compró ...",
  "admin/editor.relatedProducts.suggestions": "Sugerencias",
  "admin/editor.relatedProducts.groupBy.title": "Agrupar",
  "admin/editor.relatedProducts.groupBy.description": "Agrupar lista de recomendaciones",
  "admin/editor.relatedProducts.groupBy.product": "Productos",
  "admin/editor.relatedProducts.groupBy.none": "No agrupar",
  "store/shelf.title": "Mejores Productos",
  "admin/editor.shelf-properties.title.title": "Título",
  "admin/editor.shelf-properties.title.description": "Título del estante",
  "admin/editor.shelf-properties.show-title.title": "Mostrar título",
  "admin/editor.shelf-properties.show-title.description": "Si debe mostrar el título del vitrina",
  "admin/editor.shelf-properties.min-items-per-page.title": "Artículos mínimos por página",
  "admin/editor.shelf-properties.min-items-per-page.description": "La cantidad mínima de elementos que deben estar en la pantalla al mismo tiempo (ejemplo 1/2/3)",
  "admin/editor.shelf-properties.items-per-page.title": "Artículos por ventana de diapositivas",
  "admin/editor.shelf-properties.items-per-page.description": "La cantidad de elementos que deberían estar en la pantalla al mismo tiempo (ejemplo 1/2/3)",
  "admin/editor.shelf-properties.arrows.title": "Mostrar flechas",
  "admin/editor.shelf-properties.arrows.description": "Si debe mostrar las flechas para controlar el vitrina",
  "admin/editor.shelf-properties.autoplay.title": "Reproducción automática",
  "admin/editor.shelf-properties.autoplay.description": "Si pasar diapositivas automáticamente",
  "admin/editor.shelf-properties.navigation-step.title": "Paso de navegación",
  "admin/editor.shelf-properties.navigation-step.description": "Cuántos elementos debe pasar cuando se hace clic en las flechas. Puede pasar un número o puede passar \"page\" 9sin las comillas) para pasar todos los elementos de la ventana"
}

```


[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 shelf/docs/README.md from the shelf VTEX app.

[Assistant]
Here's the implementation:

```markdown
📢 Use this project, [contribute](https://github.com/vtex-apps/shelf) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).

# Shelf

>⚠ With the goal of displaying a flexible product list, the `shelf` and `shelf.relatedProducts` blocks are deprecated and now configured using the [Product Summary List](https://developers.vtex.com/docs/guides/vtex-product-summary-productsummarylist), the [Product Summary Shelf](https://developers.vtex.com/docs/guides/vtex-product-summary), and the [Slider Layout](https://developers.vtex.com/docs/guides/vtex-slider-layout) blocks. To learn how to configure it, please refer to [Building a Shelf](https://developers.vtex.com/docs/guides/vtex-io-documentation-building-a-shelf).

The Shelf app displays a list of products on your store pages, helping you build your shop window and work on your visual merchandising.

![shelf](https://cdn.jsdelivr.net/gh/vtexdocs/dev-portal-content@main/images/vtex-shelf-0.png)

## Configuration

1. Add the `shelf` app to your theme dependencies in the `manifest.json` file:

```json
  "dependencies": {
    "vtex.shelf": "1.x",
  }
```

Now, you can use all the blocks exported by the `shelf` app. See the full list below:

| Block name | Description |
| -  | - |
| `shelf` | ![https://img.shields.io/badge/-Deprecated-red](https://img.shields.io/badge/-Deprecated-red) Renders a list of products in the store home page. |
| `shelf.relatedProducts` | ![https://img.shields.io/badge/-Deprecated-red](https://img.shields.io/badge/-Deprecated-red) Renders a list of related products in the product details page. |

2. Declare the `shelf.relatedProduct` in the product template (`store.product`) using its props. For example:

```json
{
  "store.product": {
    "children": [
      "breadcrumb",
      "flex-layout.row#main",
      "shelf.relatedProducts"
    ]
  }
}
```

>⚠ Warning
>
> Note that for hiding unavailable/out-of-stock items, there are 2 different props: `hideUnavailableItems` and `hideOutOfStockItems`. They do the same thing, but each is used by a different component: `Shelf` and `RelatedProducts`, respectively.

### Shelf

| Prop name        | Type                | Description                                                                                | Default value                     |
| ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- |
| `category` | `String`              | The category ID |
| `collection` | `String`              | The collection ID |
| `orderBy` | `Enum`              | `OrderByTopSaleDESC`, `OrderByPriceDESC`, `OrderByPriceASC`, `OrderByNameASC`, `OrderByNameDESC`, `OrderByReleaseDateDESC`, `OrderByBestDiscountDESC` |
| `hideUnavailableItems` | `Boolean` | Whether out of stock items should be hidden (`true`) or not (`false`) | `false` |
| `paginationDotsVisibility` | `Enum`              | `visible`, `hidden`, `mobileOnly`, `desktopOnly` |
| `productList`    | `ProductListSchema` | Product list schema. See `ProductListSchema`                                                                                | -                                 |
| `trackingId` | `String`              | Name to show in the Google Analytics. If nothing is passed it will use the name of the block instead |
| `maxItems` | `Number`              | Max items |

### RelatedProducts

| Prop name | Type | Description | Default value |
| -  | -  | -  | - |
| `recommendation` | `enum` | Type of recommendations that will be displayed on the shelf. Possible values: `similars`, `suggestions`, and `accessories` (these depend on the product information given in the Admin Catalog); and `view`, `buy`, and `viewandBought` (these are automatically generated according to the activity of the store). | `similars` |
| `groupBy` | `enum` | Defines if you are ot nog going to group your recommendations by: `PRODUCT` (only display individual products and not SKUs, limited by 12 products) or `NONE` (if you want to display all registered SKUs, limited by 50 products). | `PRODUCT` |
| `hideOutOfStockItems` | `boolean` | Whether out of stock items should be hidden: (`true`) or (`false`). | `false` |
| `productList` | `ProductListSchema` | Product list schema. See `ProductListSchema`. | - |

`ProductListSchema`:

| Prop name | Type | Description | Default value |
| - | - | - | - |
| `maxItems` | `number` | Maximum number of items to be displayed on the related product shelf. | `10` |
| `scroll` | `enum` | Slide transition scroll type. Possible values: `BY_PAGE`, and `ONE_BY_ONE`. | `BY_PAGE` |
| `arrows` | `boolean` | Whether the arrows should be displayed on the shelf (`true`) or not (`false`). | `true` |
| `showTitle` | `boolean` | Whether a title should be displayed on the product-related shelf (`true`) or not (`false`). | `true` |
| `titleText` | `string`  | Related product shelf title. | `null` |
| `gap` | `enum` | Space between items being displayed. Possible values are: `ph0`, `ph3`,`ph5`, and `ph7`. | `ph3` |
| `minItemsPerPage` | `number` | Minimum number of items per shelf slides. This prop defines how many items will be displayed on the related product shelf, even in the smallest screen size. Its value can be a float, which means that you can choose a multiple of `0.5` to indicate that you want to show a *peek* of the next slide on the shelf. | `1` |
| `itemsPerPage` | `number` | Maximum number of items per shelf slides. This prop defines how many items will be displayed on the related product shelf, even in the largest screen size. Its value can be a float, which means that you can choose a multiple of `0.5` to indicate that you want to show a *peek* of the next slide on the shelf.  | `5` |
| `summary` | `object`  | Schema declaring the desired related product shelf items. This prop object must contain the [`product-summary.shelf` block props](https://developers.vtex.com/docs/guides/vtex-product-summary#configuration). | `undefined` |
' `infinite` | `boolean` | Determines whether the list should be infinite (`true`) or not (`false`). When this prop is set as `false`, the slider will have an explicit end for users. | `true` |

## Customization

To apply CSS customizations to this and other blocks, follow the instructions in [Using CSS Handles for store customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization).

| CSS Handles       |
| ----------------- |
| `relatedProducts` |

>⚠ The CSS Handles list above refers to the `shelf.relatedProducts` block. Since the `shelf` block is deprecated, your shelf customization must be done using the CSS Handles available for the [Product Summary List](https://developers.vtex.com/docs/guides/vtex-product-summary-productsummarylist), the [Product Summary Shelf](https://developers.vtex.com/docs/guides/vtex-product-summary), and the [Slider Layout](https://developers.vtex.com/docs/guides/vtex-slider-layout) blocks.

## Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tr>
    <td align="center"><a href="https://github.com/sahanljc"><img src="https://avatars2.githubusercontent.com/u/42151054?v=4" width="100px;" alt=""/><br /><sub><b>Sahan Jayawardana</b></sub></a><br /><a href="https://github.com/vtex-apps/shelf/commits?author=sahanljc" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/lucaspacheco-acct"><img src="https://avatars0.githubusercontent.com/u/59736416?v=4" width="100px;" alt=""/><br /><sub><b>Lucas Pacheco</b></sub></a><br /><a href="https://github.com/vtex-apps/shelf/commits?author=lucaspacheco-acct" title="Code">💻</a></td>
  </tr>
</table>

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

```


[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 shelf/react/Shelf.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import React, { useMemo } from 'react'
import { graphql } from 'react-apollo'
import { Loading, useTreePath } from 'vtex.render-runtime'
import { useDevice } from 'vtex.device-detector'
import { useCssHandles } from 'vtex.css-handles'
import { ProductListContext } from 'vtex.product-list-context'

import OrdenationTypes, { getOrdenationValues } from './utils/OrdenationTypes'
import ProductList from './components/ProductList'
import {
  productListSchemaPropTypes,
  shelfContentPropTypes,
} from './utils/propTypes'
import productsQuery from './queries/productsQuery.gql'
import { normalizeBuyable } from './utils/normalize'

const CSS_HANDLES = ['container']

const { ProductListProvider } = ProductListContext

/**
 * Shelf Component. Queries a list of products and shows them.
 */
const Shelf = props => {
  const {
    data,
    paginationDotsVisibility = 'visible',
    maxItems,
    productList = ProductList.defaultProps,
  } = props
  let { trackingId } = props
  const treePath = useTreePath()
  const handles = useCssHandles(CSS_HANDLES)
  const { isMobile } = useDevice()
  const { loading, error, products } = data || {}
  if (!trackingId) {
    // Taking the block name to pass to listName if no trackingId is passed
    const treePathList =
      (typeof treePath === 'string' && treePath.split()) || []
    trackingId = treePathList[treePathList.length - 1] || 'List of products'
  }

  const filteredProducts = useMemo(() => {
    return products && products.map(normalizeBuyable).filter(Boolean)
  }, [products])

  const productListProps = {
    ...productList,
    maxItems,
    isMobile,
    loading,
    paginationDotsVisibility,
    products: filteredProducts,
    trackingId,
  }

  if (loading) {
    return <Loading />
  }

  if (error) {
    return null
  }

  return (
    <div className={`${handles.container} pv4 pb9`}>
      <ProductListProvider listName={trackingId}>
        <ProductList {...productListProps} />
      </ProductListProvider>
    </div>
  )
}

Shelf.propTypes = {
  /** Graphql data response. */
  data: PropTypes.shape({
    products: shelfContentPropTypes.products,
  }),
  /** Category Id. */
  category: PropTypes.string,
  /** Collection Id. */
  collection: PropTypes.string,
  /** Ordenation Type. */
  orderBy: PropTypes.oneOf(getOrdenationValues()),
  /** Hide unavailable items */
  hideUnavailableItems: PropTypes.bool,
  /** Should display navigation dots below the Shelf */
  paginationDotsVisibility: PropTypes.oneOf([
    'visible',
    'hidden',
    'mobileOnly',
    'desktopOnly',
  ]),
  /** ProductList schema configuration */
  productList: PropTypes.shape(productListSchemaPropTypes),
  trackingId: PropTypes.string,
  maxItems: PropTypes.number,
}

const parseFilters = ({ id, value }) => `specificationFilter_${id}:${value}`

const toBoolean = x => (typeof x === 'boolean' ? x : x === 'true')

const options = {
  options: ({
    category,
    collection,
    hideUnavailableItems,
    orderBy = OrdenationTypes.ORDER_BY_TOP_SALE_DESC.value,
    specificationFilters = [],
    maxItems = ProductList.defaultProps.maxItems,
    skusFilter,
  }) => ({
    ssr: true,
    variables: {
      ...(category && { category: category.toString() }),
      ...(collection && { collection: collection.toString() }),
      specificationFilters: specificationFilters.map(parseFilters),
      orderBy,
      from: 0,
      to: maxItems - 1,
      hideUnavailableItems: toBoolean(hideUnavailableItems),
      skusFilter,
    },
  }),
}

const EnhancedShelf = graphql(productsQuery, options)(Shelf)

EnhancedShelf.schema = {
  title: 'admin/editor.shelf.title',
}

export default EnhancedShelf

```


[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 shelf/react/TabbedShelf.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import TabbedShelf from './components/TabbedShelf/index'

export default TabbedShelf

```


[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 shelf/react/RelatedProducts.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useMemo } from 'react'
import PropTypes from 'prop-types'
import path from 'ramda/es/path'
import last from 'ramda/es/last'
import { Query } from 'react-apollo'
import { useDevice } from 'vtex.device-detector'
import { ProductListContext } from 'vtex.product-list-context'
import { useProduct } from 'vtex.product-context'
import { useCssHandles } from 'vtex.css-handles'
import { useTreePath } from 'vtex.render-runtime'

import productRecommendationsQuery from './queries/productRecommendations.gql'
import ProductList from './components/ProductList'
import { productListSchemaPropTypes } from './utils/propTypes'
import { filterOutOfStock } from './utils/filterOutOfStock'

const CSS_HANDLES = ['relatedProducts']

const { ProductListProvider } = ProductListContext

// Previous values were in a wrong format with the message string in the enum value.
const fixRecommendation = recommendation => {
  if (recommendation.includes('editor.relatedProducts.')) {
    return last(recommendation.split('.'))
  }
  return recommendation
}

/**
 * Related Products Component. Queries and shows the related products
 */
const RelatedProducts = ({
  productQuery,
  productList,
  groupBy,
  recommendation: cmsRecommendation,
  trackingId: rawTrackingId,
  hideOutOfStockItems,
}) => {
  const handles = useCssHandles(CSS_HANDLES)
  const { isMobile } = useDevice()
  const treePath = useTreePath()

  const productContext = useProduct()

  let trackingId = rawTrackingId

  if (!trackingId) {
    // Taking the block name to pass to listName if no trackingId is passed
    const treePathList =
      (typeof treePath === 'string' && treePath.split()) || []
    trackingId = treePathList[treePathList.length - 1] || 'List of products'
  }

  const productId =
    path(['product', 'productId'], productQuery) ||
    path(['product', 'productId'], productContext)

  const recommendation = productId ? fixRecommendation(cmsRecommendation) : null
  const variables = useMemo(() => {
    if (!productId) {
      return null
    }

    return {
      identifier: { field: 'id', value: productId },
      type: recommendation,
      groupBy,
    }
  }, [productId, recommendation, groupBy])

  if (!productId) {
    return null
  }

  return (
    <Query
      query={productRecommendationsQuery}
      variables={variables}
      partialRefetch
      ssr={false}
    >
      {({ data, loading }) => {
        if (!data) {
          return null
        }
        const { productRecommendations = [] } = data

        const productListProps = {
          products: hideOutOfStockItems
            ? filterOutOfStock(productRecommendations)
            : productRecommendations,
          loading,
          ...productList,
          isMobile,
          trackingId,
        }
        return (
          <div className={handles.relatedProducts}>
            <ProductListProvider listName={trackingId}>
              <ProductList {...productListProps} />
            </ProductListProvider>
          </div>
        )
      }}
    </Query>
  )
}

RelatedProducts.propTypes = {
  /** Main product to have related products queried */
  slug: PropTypes.string,
  /** Graphql productQuery response. */
  productQuery: PropTypes.shape({
    /** Product to have related products queried */
    product: PropTypes.shape({
      productId: PropTypes.string,
    }),
    loading: PropTypes.bool,
  }),
  /** ProductList schema configuration */
  productList: PropTypes.shape(productListSchemaPropTypes),
  trackingId: PropTypes.string,
  hideOutOfStockItems: PropTypes.bool,
}

RelatedProducts.defaultProps = {
  recommendation: 'similars',
  productList: {
    ...ProductList.defaultProps,
    titleText: 'Related Products',
  },
  groupBy: 'PRODUCT',
  hideOutOfStockItems: false,
}

RelatedProducts.schema = {
  title: 'admin/editor.relatedProducts.title',
  description: 'admin/editor.relatedProducts.description',
  type: 'object',
  properties: {
    recommendation: {
      title: 'admin/editor.relatedProducts.recommendation',
      description: 'admin/editor.relatedProducts.recommendation.description',
      type: 'string',
      default: RelatedProducts.defaultProps.recommendation,
      enum: [
        'similars',
        'view',
        'buy',
        'accessories',
        'viewAndBought',
        'suggestions',
      ],
      enumNames: [
        'admin/editor.relatedProducts.similars',
        'admin/editor.relatedProducts.view',
        'admin/editor.relatedProducts.buy',
        'admin/editor.relatedProducts.accessories',
        'admin/editor.relatedProducts.viewAndBought',
        'admin/editor.relatedProducts.suggestions',
      ],
    },
    groupBy: {
      title: 'admin/editor.relatedProducts.groupBy.title',
      description: 'admin/editor.relatedProducts.groupBy.description',
      type: 'string',
      default: RelatedProducts.defaultProps.groupBy,
      enum: ['PRODUCT', 'NONE'],
      enumNames: [
        'admin/editor.relatedProducts.groupBy.product',
        'admin/editor.relatedProducts.groupBy.none',
      ],
    },
    productList: ProductList.schema,
    hideOutOfStockItems: {
      title: 'admin/editor.shelf.hideOutOfStockItems',
      type: 'boolean',
      default: false,
    },
  },
}

export default RelatedProducts

```


[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 shelf/react/package.json from the shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.shelf",
  "version": "1.49.0",
  "description": "A Shelf Component.",
  "license": "ISC",
  "author": "VTEX",
  "private": true,
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "classnames": "^2.2.6",
    "debounce": "^1.2.0",
    "ramda": "^0.25.0",
    "react-amphtml": "^4.0.2",
    "react-apollo": "^2.5.8",
    "react-intersection-observer": "^8.23.0",
    "react-intl": "^2.7.2",
    "react-resize-detector": "^3.4.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.4",
    "@types/graphql": "^14.5.0",
    "@types/react": "^16.9.3",
    "@vtex/test-tools": "^3.1.0",
    "@vtex/tsconfig": "^0.3.0",
    "babel-eslint": "^10.1.0"
  }
}

```


[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 shelf/react/ProductList.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import ProductList from './components/ProductList'

export default ProductList

```


[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 shelf/store/contentSchemas.json from the shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "Shelf": {
      "title": "admin/editor.shelf.title",
      "type": "object",
      "dependencies": {
        "advancedProperties": {
          "oneOf": [
            {
              "properties": {
                "advancedProperties": {
                  "enum": [true]
                },
                "trackingId": {
                  "title": "admin/editor.shelf.advanced-properties.tracking-id.title",
                  "description": "admin/editor.shelf.advanced-properties.tracking-id.description",
                  "type": "string"
                }
              }
            }
          ]
        }
      },
      "properties": {
        "category": {
          "title": "admin/editor.shelf.category.title",
          "description": "admin/editor.shelf.category.description",
          "type": "string",
          "isLayout": false
        },
        "specificationFilters": {
          "title": "admin/editor.shelf.specificationFilters.title",
          "type": "array",
          "items": {
            "title": "admin/editor.shelf.specificationFilters.item.title",
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "title": "admin/editor.shelf.specificationFilters.item.id.title"
              },
              "value": {
                "type": "string",
                "title": "admin/editor.shelf.specificationFilters.item.value.title"
              }
            }
          }
        },
        "collection": {
          "title": "admin/editor.shelf.collection.title",
          "type": "string",
          "isLayout": false
        },
        "orderBy": {
          "title": "admin/editor.shelf.orderBy.title",
          "type": "string",
          "enum": [
            "",
            "OrderByTopSaleDESC",
            "OrderByPriceDESC",
            "OrderByPriceASC",
            "OrderByNameASC",
            "OrderByNameDESC",
            "OrderByReleaseDateDESC",
            "OrderByBestDiscountDESC"
          ],
          "enumNames": [
            "admin/editor.shelf.orderType.relevance",
            "admin/editor.shelf.orderType.sales",
            "admin/editor.shelf.orderType.priceDesc",
            "admin/editor.shelf.orderType.priceAsc",
            "admin/editor.shelf.orderType.nameAsc",
            "admin/editor.shelf.orderType.nameDesc",
            "admin/editor.shelf.orderType.releaseDate",
            "admin/editor.shelf.orderType.discount"
          ],
          "default": "",
          "isLayout": false
        },
        "productList": { "$ref": "app:vtex.shelf#/definitions/ProductList" },
        "hideUnavailableItems": {
          "title": "admin/editor.shelf.hideUnavailableItems",
          "type": "boolean",
          "default": false,
          "isLayout": false
        },
        "skusFilter": {
          "title": "admin/editor.shelf.skusFilter",
          "description": "admin/editor.shelf.skusFilter.description",
          "type": "string",
          "default": "ALL_AVAILABLE",
          "enum": ["ALL_AVAILABLE", "ALL", "FIRST_AVAILABLE"],
          "enumNames": [
            "admin/editor.shelf.skusFilter.all-available",
            "admin/editor.shelf.skusFilter.none",
            "admin/editor.shelf.skusFilter.first-available"
          ]
        },
        "advancedProperties": {
          "title": "admin/editor.shelf.advanced-properties.title",
          "type": "boolean",
          "default": false
        }
      }
    },
    "ProductList": {
      "title": "admin/editor.shelf.title",
      "properties": {
        "maxItems": {
          "title": "admin/editor.shelf.maxItems.title",
          "type": "number",
          "default": 10,
          "isLayout": true
        },
        "arrows": {
          "title": "admin/editor.shelf-properties.arrows.title",
          "description": "admin/editor.shelf-properties.arrows.description",
          "type": "boolean",
          "isLayout": false,
          "default": true
        },
        "autoplay": {
          "title": "admin/editor.shelf-properties.autoplay.title",
          "description": "admin/editor.shelf-properties.autoplay.description",
          "type": "boolean",
          "isLayout": false,
          "default": false
        },
        "navigationStep": {
          "title": "admin/editor.shelf-properties.navigation-step.title",
          "description": "admin/editor.shelf-properties.navigation-step.description",
          "type": "string",
          "isLayout": false
        },
        "titleText": {
          "title": "admin/editor.shelf-properties.title.title",
          "description": "admin/editor.shelf-properties.title.description",
          "$ref": "app:vtex.native-types#/definitions/text",
          "isLayout": false,
          "default": "admin/editor.shelf.title"
        },
        "showTitle": {
          "title": "admin/editor.shelf-properties.show-title.title",
          "description": "admin/editor.shelf-properties.show-title.description",
          "type": "boolean",
          "default": true,
          "isLayout": false
        },
        "itemsPerPage": {
          "title": "admin/editor.shelf-properties.items-per-page.title",
          "description": "admin/editor.shelf-properties.items-per-page.description",
          "type": "number",
          "default": 5,
          "isLayout": false
        },
        "minItemsPerPage": {
          "title": "admin/editor.shelf-properties.min-items-per-page.title",
          "description": "admin/editor.shelf-properties.min-items-per-page.description",
          "type": "number",
          "isLayout": false,
          "default": 1
        },
        "gap": {
          "title": "admin/editor.shelf.gap.title",
          "type": "string",
          "enum": [
            "admin/editor.shelf.gapType.none",
            "admin/editor.shelf.gapType.small",
            "admin/editor.shelf.gapType.medium",
            "admin/editor.shelf.gapType.large"
          ],
          "enumNames": ["ph0", "ph3", "ph5", "ph7"],
          "default": "ph0",
          "isLayout": true
        },
        "scroll": {
          "title": "admin/editor.shelf.scrollType.title",
          "type": "string",
          "enum": [
            "admin/editor.shelf.scrollType.byPage",
            "admin/editor.shelf.scrollType.oneByOne"
          ],
          "enumNames": ["BY_PAGE", "ONE_BY_ONE"],
          "default": "BY_PAGE",
          "isLayout": 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 shelf/store/interfaces.json from the shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "shelf": {
    "required": ["product-summary"],
    "component": "Shelf",
    "track": ["click"],
    "preview": {
      "type": "grid",
      "height": 550
    },
    "content": {
      "$ref": "app:vtex.shelf#/definitions/Shelf"
    }
  },
  "shelf.relatedProducts": {
    "required": ["product-summary"],
    "component": "RelatedProducts",
    "preview": {
      "type": "grid",
      "height": 550
    }
  },
  "shelf.tabbed": {
    "required": ["product-summary"],
    "component": "TabbedShelf",
    "preview": {
      "type": "grid",
      "height": 550
    }
  }
}

```


[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 shelf/react/__test__/Shelf.test.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
/* eslint-env jest */
import React from 'react'
import { render } from '@vtex/test-tools/react'

import ProductList from '../components/ProductList'
// eslint-disable-next-line jest/no-mocks-import
import { productMock } from '../__mocks__/productMock'
import Shelf from '../Shelf'
import { resolvePaginationDotsVisibility } from '../utils/resolvePaginationDots'

describe('Shelf component', () => {
  const renderComponent = customProps => {
    const props = {
      maxItems: 1,
      itemsPerPage: 1,
      arrows: true,
      showTitle: true,
    }

    const titleText = 'store/shelf.title'
    const wrapper = render(
      <ProductList titleText={titleText} {...props} {...customProps} />
    )
    return wrapper
  }

  it('should be rendered', () => {
    const component = renderComponent()
    expect(component).toBeDefined()
  })

  it('should render nothing if there is no products', () => {
    const component = renderComponent({ products: [] })

    expect(component.container.querySelector('.title')).toBeFalsy()
  })

  it('should match the snapshot', () => {
    const component = renderComponent({ products: productMock })
    expect(component.asFragment()).toMatchSnapshot()
  })

  it('should show in Site Editor', () => {
    const { schema } = Shelf
    expect(schema).toBeDefined()
    expect(typeof schema.title).toBe('string')
  })
})

describe('Util functions', () => {
  it('should return the correct value for pagination dots visibility', () => {
    const MOBILE_ONLY = 'mobileOnly'
    const DESKTOP_ONLY = 'desktopOnly'
    const VISIBLE = 'visible'
    const HIDDEN = 'hidden'

    /** resolvePaginationDotsVisibility(visibility: string, isMobile: boolean) */
    expect(resolvePaginationDotsVisibility(MOBILE_ONLY, false)).toBeFalsy()
    expect(resolvePaginationDotsVisibility(MOBILE_ONLY, true)).toBeTruthy()

    expect(resolvePaginationDotsVisibility(DESKTOP_ONLY, false)).toBeTruthy()
    expect(resolvePaginationDotsVisibility(DESKTOP_ONLY, true)).toBeFalsy()

    expect(resolvePaginationDotsVisibility(VISIBLE, false)).toBeTruthy()
    expect(resolvePaginationDotsVisibility(VISIBLE, true)).toBeTruthy()

    expect(resolvePaginationDotsVisibility(HIDDEN, false)).toBeFalsy()
    expect(resolvePaginationDotsVisibility(HIDDEN, true)).toBeFalsy()
  })
})

```


[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 shelf/react/typings/vtex.native-types.d.ts from the shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.native-types' {
  import type { Component } from 'react'
  import type { InjectedIntl, InjectedIntlProps } from 'react-intl'

  interface FormatIOMessageParams {
    id: string
    intl: InjectedIntl
  }

  export const formatIOMessage: (params: FormatIOMessageParams) => string

  interface IOMessageProps extends InjectedIntlProps {
    id: string
  }

  export const IOMessage: Component<IOMessageProps>
}

```


[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 shelf/react/queries/productRecommendations.gql from the shelf VTEX app.

[Assistant]
Here's the implementation:

```graphql
query ProductRecommendations(
  $identifier: ProductUniqueIdentifier
  $type: CrossSelingInputEnum
  $groupBy: CrossSelingGroupByEnum
) {
  productRecommendations(identifier: $identifier, type: $type, groupBy: $groupBy)
    @context(provider: "vtex.search-graphql") {
    cacheId
    productId
    productName
    productReference
    description
    link
    linkText
    brand
    brandId
    categories
    priceRange {
      sellingPrice {
        highPrice
        lowPrice
      }
      listPrice {
        highPrice
        lowPrice
      }
    }
    specificationGroups {
      name
      originalName
      specifications {
        name
        originalName
        values
      }
    }
    skuSpecifications {
      field {
        name
        originalName
      }
      values {
        name
        originalName
      }
    }
    items {
      name
      itemId
      measurementUnit
      unitMultiplier
      referenceId {
        Value
      }
      images {
        imageId
        imageLabel
        imageTag
        imageUrl
        imageText
      }
      variations {
        name
        values
      }
      sellers {
        sellerId
        sellerName
        addToCartLink
        sellerDefault
        commertialOffer {
          Installments(criteria: MAX) {
            Value
            InterestRate
            TotalValuePlusInterestRate
            NumberOfInstallments
            Name
          }
          AvailableQuantity
          CacheVersionUsedToCallCheckout
          ListPrice
          Price
          PriceValidUntil
          PriceWithoutDiscount
          RewardValue
          spotPrice
          Tax
          taxPercentage
          teasers {
            name
          }
          discountHighlights {
            name
          }
        }
      }
    }
    clusterHighlights {
      id
      name
    }
    productClusters {
      id
      name
    }
    properties {
      name
      values
    }
  }
}

```


[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 shelf/react/queries/productsQuery.gql from the shelf VTEX app.

[Assistant]
Here's the implementation:

```graphql
query Products(
  $category: String
  $collection: String
  $specificationFilters: [String]
  $orderBy: String
  $from: Int
  $to: Int
  $hideUnavailableItems: Boolean = false
  $skusFilter: ItemsFilter = ALL_AVAILABLE
) {
  products(
    category: $category
    collection: $collection
    specificationFilters: $specificationFilters
    orderBy: $orderBy
    from: $from
    to: $to
    hideUnavailableItems: $hideUnavailableItems
  ) @context(provider: "vtex.search-graphql") {
    cacheId
    productId
    productName
    productReference
    description
    link
    linkText
    brand
    brandId
    categories
    priceRange {
      sellingPrice {
        highPrice
        lowPrice
      }
      listPrice {
        highPrice
        lowPrice
      }
    }
    specificationGroups {
      name
      originalName
      specifications {
        name
        originalName
        values
      }
    }
    skuSpecifications {
      field {
        name
        originalName
      }
      values {
        name
        originalName
      }
    }
    items(filter: $skusFilter) {
      name
      itemId
      measurementUnit
      unitMultiplier
      referenceId {
        Value
      }
      images {
        imageUrl
        imageTag
        imageLabel
      }
      variations {
        name
        values
      }
      sellers {
        sellerId
        sellerName
        commertialOffer {
          Installments(criteria: MAX) {
            Value
            InterestRate
            TotalValuePlusInterestRate
            NumberOfInstallments
            Name
          }
          AvailableQuantity
          Price
          PriceWithoutDiscount
          ListPrice
          spotPrice
          Tax
          taxPercentage
          teasers {
            name
          }
          discountHighlights {
            name
          }
        }
      }
    }
    productClusters {
      id
      name
    }
    properties {
      name
      values
    }
  }
}

```


[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 shelf/react/utils/resolveSlidesNumber.js from the shelf 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 shelf/react/utils/normalize.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
function getBuyableSellers(sellers) {
  return sellers && sellers.length > 0
    ? sellers.filter(seller => seller.sellerId)
    : sellers
}

export function normalizeBuyable(product) {
  if (!product || !product.items || product.items.length === 0) {
    return product
  }

  const buyableItems = product.items
    .map(item => ({
      ...item,
      sellers: getBuyableSellers(item.sellers),
    }))
    .filter(item => item && item.sellers && item.sellers.length > 0)

  return buyableItems ? { ...product, items: buyableItems } : null
}

```


[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 shelf/react/utils/paddingEnum.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
// eslint-disable-next-line no-restricted-imports
import { pluck, values } from 'ramda'

const gapPaddingTypes = {
  NONE: {
    name: 'admin/editor.shelf.gapType.none',
    value: 'ph0',
  },
  SMALL: {
    name: 'admin/editor.shelf.gapType.small',
    value: 'ph3',
  },
  MEDIUM: {
    name: 'admin/editor.shelf.gapType.medium',
    value: 'ph5',
  },
  LARGE: {
    name: 'admin/editor.shelf.gapType.large',
    value: 'ph7',
  },
}

export const getGapPaddingNames = () => values(pluck('name', gapPaddingTypes))

export const getGapPaddingValues = () => values(pluck('value', gapPaddingTypes))

export default gapPaddingTypes

```


[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 shelf/react/utils/filterOutOfStock.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
export function filterOutOfStock(products = []) {
  return products.filter(
    product => product.items[0]?.sellers[0]?.commertialOffer?.AvailableQuantity
  )
}

```


[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 shelf/react/utils/OrdenationTypes.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
const ordenationTypes = {
  ORDER_BY_RELEVANCE: {
    name: 'admin/editor.shelf.orderType.relevance',
    value: '',
  },
  ORDER_BY_TOP_SALE_DESC: {
    name: 'admin/editor.shelf.orderType.sales',
    value: 'OrderByTopSaleDESC',
  },
  ORDER_BY_PRICE_DESC: {
    name: 'admin/editor.shelf.orderType.priceDesc',
    value: 'OrderByPriceDESC',
  },
  ORDER_BY_PRICE_ASC: {
    name: 'admin/editor.shelf.orderType.priceAsc',
    value: 'OrderByPriceASC',
  },
  ORDER_BY_NAME_ASC: {
    name: 'admin/editor.shelf.orderType.nameAsc',
    value: 'OrderByNameASC',
  },
  ORDER_BY_NAME_DESC: {
    name: 'admin/editor.shelf.orderType.nameDesc',
    value: 'OrderByNameDESC',
  },
  ORDER_BY_RELEASE_DATE_DESC: {
    name: 'admin/editor.shelf.orderType.releaseDate',
    value: 'OrderByReleaseDateDESC',
  },
  ORDER_BY_BEST_DISCOUNT_DESC: {
    name: 'admin/editor.shelf.orderType.discount',
    value: 'OrderByBestDiscountDESC',
  },
}

export function getOrdenationNames() {
  const names = []
  for (const key in ordenationTypes) {
    names.push(ordenationTypes[key].name)
  }
  return names
}

export function getOrdenationValues() {
  const values = []
  for (const key in ordenationTypes) {
    values.push(ordenationTypes[key].value)
  }
  return values
}

export default ordenationTypes

```


[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 shelf/react/utils/propTypes.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

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

import { getScrollValues } from './ScrollTypes'
import { getGapPaddingValues } from './paddingEnum'

export const shelfItemPropTypes = {
  item: PropTypes.shape({
    productId: PropTypes.string.isRequired,
    productName: PropTypes.string.isRequired,
    description: PropTypes.string.isRequired,
    categories: PropTypes.array,
    link: PropTypes.string.isRequired,
    linkText: PropTypes.string.isRequired,
    brandId: PropTypes.number,
    brand: PropTypes.string.isRequired,
    items: PropTypes.arrayOf(
      PropTypes.shape({
        itemId: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
        referenceId: PropTypes.arrayOf(
          PropTypes.shape({
            Value: PropTypes.string.isRequired,
          })
        ),
        images: PropTypes.arrayOf(
          PropTypes.shape({
            imageUrl: PropTypes.string.isRequired,
            imageTag: PropTypes.string.isRequired,
          })
        ).isRequired,
        sellers: PropTypes.arrayOf(
          PropTypes.shape({
            commertialOffer: PropTypes.shape({
              /** SKU installments */
              Installments: PropTypes.arrayOf(
                PropTypes.shape({
                  /** Installment value */
                  Value: PropTypes.number.isRequired,
                  /** Interest rate (zero if interest-free) */
                  InterestRate: PropTypes.number.isRequired,
                  /** Calculated total value */
                  TotalValuePlusInterestRate: PropTypes.number,
                  /** Number of installments */
                  NumberOfInstallments: PropTypes.number.isRequired,
                  /** Installments offer name */
                  Name: PropTypes.string,
                })
              ),
              Price: PropTypes.number.isRequired,
              ListPrice: PropTypes.number.isRequired,
            }).isRequired,
          })
        ).isRequired,
      })
    ).isRequired,
  }),
  summary: PropTypes.any,
  position: PropTypes.number,
}

export const productListSchemaPropTypes = {
  /** Maximum number of items in the shelf. */
  maxItems: PropTypes.number.isRequired,
  /** Maximum number of items in a page. */
  itemsPerPage: PropTypes.number.isRequired,
  /** Minimum number of items in a page. */
  minItemsPerPage: PropTypes.number,
  /** Scroll options. */
  scroll: PropTypes.oneOf(getScrollValues()),
  /** If the arrows are showable or not. */
  arrows: PropTypes.bool.isRequired,
  /** Show value of the title. */
  showTitle: PropTypes.bool,
  /** Text value of the title. */
  titleText: PropTypes.string,
  /** Product Summary schema props */
  summary: PropTypes.any,
}

export const shelfContentPropTypes = {
  /** List of products */
  products: PropTypes.arrayOf(shelfItemPropTypes.item),
  /** Max Items per page */
  itemsPerPage: PropTypes.number,
  /** Minimum Items per page */
  minItemsPerPage: PropTypes.number,
  /** Max items in shelf */
  maxItems: PropTypes.number.isRequired,
  /** Show Arrows */
  arrows: PropTypes.bool.isRequired,
  /** Scroll type */
  scroll: PropTypes.string.isRequired,
  /** Should display navigation dots below the Shelf */
  paginationDotsVisibility: PropTypes.oneOf([
    'visible',
    'hidden',
    'desktopOnly',
    'mobileOnly',
  ]),
  /** Container width */
  width: PropTypes.number,
  /** Props to ProductsSummary */
  summary: PropTypes.any,
  /** Is mobile */
  isMobile: PropTypes.bool,
  /** Gap between Shelf Items */
  gap: PropTypes.oneOf(getGapPaddingValues()),
  /** Title of the shelf */
  listName: PropTypes.string.isRequired,
  /** Is infinite */
  infinite: 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 shelf/react/utils/ScrollTypes.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
const scrollTypes = {
  BY_PAGE: {
    name: 'admin/editor.shelf.scrollType.byPage',
    value: 'BY_PAGE',
  },
  ONE_BY_ONE: {
    name: 'admin/editor.shelf.scrollType.oneByOne',
    value: 'ONE_BY_ONE',
  },
}

export function getScrollNames() {
  const names = []
  for (const key in scrollTypes) {
    names.push(scrollTypes[key].name)
  }
  return names
}

export function getScrollValues() {
  const values = []
  for (const key in scrollTypes) {
    values.push(scrollTypes[key].value)
  }
  return values
}

export default scrollTypes

```


[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 shelf/react/utils/resolvePaginationDots.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
export function resolvePaginationDotsVisibility(visibility, isMobile) {
  return !!(
    visibility === 'visible' ||
    (visibility === 'mobileOnly' && isMobile) ||
    (visibility === 'desktopOnly' && !isMobile)
  )
}

```


[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 shelf/react/components/ShelfItem.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useMemo, useCallback } from 'react'
// eslint-disable-next-line no-restricted-imports
import { assocPath } from 'ramda'
import ProductSummary from 'vtex.product-summary/ProductSummaryCustom'
import { ExtensionPoint } from 'vtex.render-runtime'
import { usePixel } from 'vtex.pixel-manager/PixelContext'

/**
 * ShelfItem Component. Normalizes the item received in the props
 * to adapt to the extension point prop.
 */
const ShelfItem = ({ item, summary, position, listName }) => {
  const { push } = usePixel()
  const newSummary = useMemo(() => assocPath(['name', 'tag'], 'h2', summary), [
    summary,
  ])
  const product = useMemo(
    () => ProductSummary.mapCatalogProductToProductSummary(item),
    [item]
  )

  const pushPixelProductClick = useCallback(() => {
    push({
      event: 'productClick',
      product,
      list: listName,
      position,
    })
  }, [product, position, listName, push])

  return (
    <ExtensionPoint
      id="product-summary"
      product={product}
      listName={listName}
      actionOnClick={pushPixelProductClick}
      position={position}
      {...newSummary}
    />
  )
}

export default ShelfItem

```


[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 shelf/react/components/shelf.css from the shelf VTEX app.

[Assistant]
Here's the implementation:

```css
.arrow {
  top: 50%;
  transform: translate(0, -50%);
}

.dot {
  height: 0.625rem;
  width: 0.625rem;
}

```


[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 shelf/react/components/ProductList.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import React, { Fragment } from 'react'
import ReactResizeDetector from 'react-resize-detector'
import { IOMessage, formatIOMessage } from 'vtex.native-types'
import { useCssHandles } from 'vtex.css-handles'

import {
  productListSchemaPropTypes,
  shelfItemPropTypes,
} from '../utils/propTypes'
import ScrollTypes from '../utils/ScrollTypes'
import GapPaddingTypes from '../utils/paddingEnum'
import ShelfContent from './ShelfContent'
import ProductListEventCaller from './ProductListEventCaller'

const CSS_HANDLES = ['title']

const DEFAULT_MAX_ITEMS = 10
const DEFAULT_ITEMS_PER_PAGE = 5
const DEFAULT_MIN_ITEMS_PER_PAGE = 1

/**
 * Product List Component. Shows a collection of products.
 */
const ProductList = ({
  gap,
  arrows,
  scroll,
  summary,
  maxItems,
  products,
  isMobile,
  autoplay,
  showTitle,
  titleText,
  itemsPerPage,
  minItemsPerPage,
  paginationDotsVisibility,
  navigationStep: navigationStepProp,
  trackingId,
  infinite,
}) => {
  const handles = useCssHandles(CSS_HANDLES)
  const navigationStep = Number.isNaN(parseInt(navigationStepProp, 10))
    ? navigationStepProp
    : parseInt(navigationStepProp, 10)

  let listName = trackingId

  if (!listName) {
    listName =
      showTitle && titleText ? formatIOMessage(titleText) : 'List of products'
  }

  return products && !products.length ? null : (
    <Fragment>
      {showTitle && (
        <div
          className={`${handles.title} t-heading-2 fw3 w-100 flex justify-center pt7 pb6 c-muted-1`}
        >
          <IOMessage id={titleText} />
        </div>
      )}
      <ReactResizeDetector handleWidth>
        {width => (
          <ShelfContent
            gap={gap}
            width={width}
            arrows={arrows}
            scroll={scroll}
            summary={summary}
            products={products}
            maxItems={maxItems}
            isMobile={isMobile}
            autoplay={autoplay}
            itemsPerPage={itemsPerPage}
            navigationStep={navigationStep}
            minItemsPerPage={minItemsPerPage}
            paginationDotsVisibility={paginationDotsVisibility}
            listName={listName}
            infinite={infinite}
          />
        )}
      </ReactResizeDetector>
      <ProductListEventCaller />
    </Fragment>
  )
}

ProductList.defaultProps = {
  maxItems: DEFAULT_MAX_ITEMS,
  minItemsPerPage: DEFAULT_MIN_ITEMS_PER_PAGE,
  itemsPerPage: DEFAULT_ITEMS_PER_PAGE,
  scroll: ScrollTypes.BY_PAGE.value,
  gap: GapPaddingTypes.SMALL.value,
  arrows: true,
  showTitle: true,
  titleText: null,
  isMobile: false,
  infinite: true,
}

ProductList.propTypes = {
  /** Loading status */
  loading: PropTypes.bool,
  /** Graphql data response. */
  products: PropTypes.arrayOf(shelfItemPropTypes.item),
  /** Verifies if is a mobile device. */
  isMobile: PropTypes.bool,
  /** Should display navigation dots below the Shelf */
  paginationDotsVisibility: PropTypes.oneOf([
    'visible',
    'hidden',
    'desktopOnly',
    'mobileOnly',
  ]),
  trackingId: PropTypes.string,
  infinite: PropTypes.bool,
  ...productListSchemaPropTypes,
}

ProductList.schema = {
  title: 'admin/editor.shelf.title',
}

export default ProductList

```


[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 shelf/react/components/ProductListEventCaller.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { useProductImpression } from 'vtex.product-list-context'

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

export default ProductListEventCaller

```


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

[User] Show me the implementation of shelf/react/components/ShelfContent.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
// eslint-disable-next-line no-restricted-imports
import { path } from 'ramda'
import React, { Component } from 'react'
import { IconCaret } from 'vtex.store-icons'
import classNames from 'classnames'
import { NoSSR } from 'vtex.render-runtime'
import { Slider, Slide, Dots, SliderContainer } from 'vtex.slider'
import { withCssHandles } from 'vtex.css-handles'

import { resolvePaginationDotsVisibility } from '../utils/resolvePaginationDots'
import resolveSlidesNumber from '../utils/resolveSlidesNumber'
import ScrollTypes from '../utils/ScrollTypes'
import ShelfItem from './ShelfItem'
import { shelfContentPropTypes } from '../utils/propTypes'
import shelf from './shelf.css'

const CSS_HANDLES = [
  'arrow',
  'arrowLeft',
  'arrowRight',
  'shelfContentContainer',
  'sliderContainer',
  'slide',
  'dot--isActive',
]
const SLIDER_WIDTH_ONE_ELEMENT = 320
const SLIDER_WIDTH_TWO_ELEMENTS = 500
const SLIDER_WIDTH_THREE_ELEMENTS = 750
const SLIDER_WIDTH_FOUR_ELEMENTS = 1000
const SLIDER_WIDTH_FIVE_ELEMENTS = 1290
const DEFAULT_SHELF_ITEM_WIDTH = 260

/**
 * ShelfContent Component. Executes the interaction with react-slick
 * and render the properly content of the Shelf depending of edit mode state.
 */
class ShelfContent extends Component {
  constructor(props) {
    super(props)
    this.perPage = {
      [SLIDER_WIDTH_FIVE_ELEMENTS]: 5,
      [SLIDER_WIDTH_FOUR_ELEMENTS]: 4,
      [SLIDER_WIDTH_THREE_ELEMENTS]: 3,
      [SLIDER_WIDTH_TWO_ELEMENTS]: 2,
      [SLIDER_WIDTH_ONE_ELEMENT]: 1,
    }
    this.calcItemsPerPage()
    this.state = {
      currentSlide: 0,
      firstRender: true,
    }
  }

  calcItemsPerPage = () => {
    const { itemsPerPage } = this.props
    for (const key in this.perPage) {
      if (this.perPage[key] > itemsPerPage) delete this.perPage[key]
    }
  }

  handleChangeSlide = i => {
    this.setState({ currentSlide: i })
  }

  handleNextSlide = () => {
    const { currentSlide } = this.state
    const { itemsPerPage, maxItems, products, isMobile } = this.props
    const productList =
      !products || !products.length ? Array(maxItems).fill(null) : products
    const totalItems = productList.slice(0, maxItems).length
    let customPerPage = (!isMobile && itemsPerPage) || this.perPage

    /** Fix for a case where customPerPage would come from this.perPage,
     * which would be an object, and would cause nextSlide to be cast into
     * a string in the sum below. This was a quick fix, feel free to improve
     * this code later on if you judge it necessary.
     */
    if (typeof customPerPage !== 'number') {
      let minPerPage = this.props.minItemsPerPage
      if (typeof minPerPage !== 'number') {
        minPerPage = 1
      }
      customPerPage = resolveSlidesNumber(
        this.roundHalf(minPerPage),
        customPerPage,
        isMobile
      )
    }
    const nextSlide = (currentSlide % totalItems) + customPerPage

    this.handleChangeSlide(nextSlide)
  }

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

  arrowRender = ({ orientation, onClick }) => {
    const { gap, cssHandles } = this.props
    const containerClasses = classNames(
      shelf.arrow,
      'pointer z-1 flex absolute',
      {
        [`${cssHandles.arrowLeft} left-0 ${gap}`]: orientation === 'left',
        [`${cssHandles.arrowRight} right-0 ${gap}`]: orientation === 'right',
      }
    )
    return (
      <div
        className={containerClasses}
        onClick={e => {
          if (e) {
            e.stopPropagation()
            e.preventDefault()
          }
          onClick(e)
        }}
        role="button"
        tabIndex="0"
        onKeypress={e => e.key === 'Enter' || (e.key === ' ' && onClick(e))}
      >
        <IconCaret orientation={orientation} thin size={20} />
      </div>
    )
  }

  roundHalf = num => Math.round(num * 2) / 2

  render() {
    const {
      gap,
      scroll,
      arrows,
      summary,
      autoplay,
      isMobile,
      maxItems,
      products,
      cssHandles,
      itemsPerPage,
      navigationStep,
      minItemsPerPage,
      paginationDotsVisibility,
      listName,
      infinite,
    } = this.props

    const { currentSlide } = this.state
    const showPaginationDots = resolvePaginationDotsVisibility(
      paginationDotsVisibility,
      isMobile
    )

    const isScrollByPage = scroll === ScrollTypes.BY_PAGE.value

    const productList =
      !products || !products.length ? Array(maxItems).fill(null) : products

    const roundedMinItems = this.roundHalf(minItemsPerPage)
    const customPerPage = !isMobile && itemsPerPage

    return (
      <div
        className={`${cssHandles.shelfContentContainer} flex justify-center`}
      >
        <SliderContainer
          autoplay={autoplay}
          onNextSlide={this.handleNextSlide}
          className={`${cssHandles.sliderContainer} w-100 mw9`}
        >
          <Slider
            loop={infinite}
            easing="ease"
            duration={500}
            minPerPage={roundedMinItems}
            scrollByPage={isScrollByPage}
            navigationStep={navigationStep}
            currentSlide={Math.ceil(currentSlide)}
            onChangeSlide={this.handleChangeSlide}
            perPage={customPerPage || this.perPage}
            arrowRender={arrows && this.arrowRender}
          >
            {productList.slice(0, maxItems).map((item, index) => (
              <Slide
                sliderTransitionDuration={500}
                className={classNames(
                  'justify-center h-100',
                  gap,
                  cssHandles.slide
                )}
                key={path(['productId'], item) || index}
                defaultWidth={DEFAULT_SHELF_ITEM_WIDTH}
              >
                <ShelfItem
                  item={item}
                  position={index + 1}
                  summary={summary}
                  listName={listName}
                />
              </Slide>
            ))}
          </Slider>
          {showPaginationDots && (
            <NoSSR>
              <Dots
                loop
                showDotsPerPage={isScrollByPage}
                minPerPage={roundedMinItems}
                perPage={this.perPage}
                currentSlide={Math.ceil(currentSlide)}
                totalSlides={productList.slice(0, maxItems).length}
                onChangeSlide={this.handleChangeSlide}
                classes={{
                  root: 'pt4',
                  notActiveDot: 'bg-muted-3',
                  dot: classNames(shelf.dot, 'mh2 mv0 pointer br-100'),
                  activeDot: `${cssHandles['dot--isActive']} bg-emphasis`,
                }}
              />
            </NoSSR>
          )}
        </SliderContainer>
      </div>
    )
  }
}

ShelfContent.defaultProps = {
  itemsPerPage: 5,
  minItemsPerPage: 1,
  paginationDotsVisibility: 'visible',
}

ShelfContent.propTypes = {
  /** List of products */
  products: shelfContentPropTypes.products,
  /** Max Items per page */
  itemsPerPage: shelfContentPropTypes.itemsPerPage,
  /** Minimum Items per page */
  minItemsPerPage: shelfContentPropTypes.minItemsPerPage,
  /** Max items in shelf */
  maxItems: shelfContentPropTypes.maxItems,
  /** Show Arrows */
  arrows: shelfContentPropTypes.arrows,
  /** Scroll type */
  scroll: shelfContentPropTypes.scroll,
  /** Should display navigation dots below the Shelf */
  paginationDotsVisibility: shelfContentPropTypes.paginationDotsVisibility,
  /** Container width */
  width: shelfContentPropTypes.width,
  /** Props to ProductsSummary */
  summary: shelfContentPropTypes.summary,
  /** Is mobile */
  isMobile: shelfContentPropTypes.isMobile,
  /** Gap between Shelf Items */
  gap: shelfContentPropTypes.gap,
  /** Title of the shelf */
  listName: shelfContentPropTypes.listName,
  /** Is infinite */
  infinite: shelfContentPropTypes.infinite,
}

export default withCssHandles(CSS_HANDLES)(ShelfContent)

```


[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 shelf/react/components/TabbedShelf/Tabs.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import classNames from 'classnames'
import { withCssHandles } from 'vtex.css-handles'

const CSS_HANDLES = [
  'itemContainer',
  'itemContainerSelected',
  'itemContainerUnselected',
  'tabsContainer',
  'tabsNamesContainer',
  'shelfContainer',
  'tabButton',
]

class Tabs extends Component {
  state = {
    selectedIndex: 0,
  }

  handleClick = index => this.setState({ selectedIndex: index })

  render() {
    const { panes, cssHandles } = this.props
    const { selectedIndex } = this.state
    if (!panes || panes.length === 0) {
      return null
    }

    return (
      <div className="flex justify-center items-center">
        <div
          className={`${cssHandles.tabsContainer} flex-ns pa6-ns justify-between-ns w-100-s`}
        >
          <div
            className={`${cssHandles.tabsNamesContainer} flex flex-column mh6`}
          >
            {panes.map((pane, index) => {
              const isSelected = index === selectedIndex
              const isLast = index === panes.length - 1
              const itemContainer = classNames(
                `t-body pa4 tl bb b--muted-4 ${cssHandles.itemContainer}`,
                {
                  [`bg-base--inverted c-on-muted-1 ${cssHandles.itemContainerSelected}`]: isSelected,
                  [cssHandles.itemContainerUnselected]: !isSelected,
                  bw0: isLast,
                }
              )
              return (
                <button
                  key={index}
                  type="button"
                  onClick={() => this.handleClick(index)}
                  className={`${cssHandles.tabButton} bn outline-0 bg-transparent pa0`}
                >
                  <div className={itemContainer} key={pane.menuItem}>
                    {pane.menuItem}
                  </div>
                </button>
              )
            })}
          </div>
          <div
            className={`${cssHandles.shelfContainer} mh6-s mw-100 overflow-hidden`}
          >
            {panes[selectedIndex].render()}
          </div>
        </div>
      </div>
    )
  }
}

export default withCssHandles(CSS_HANDLES)(Tabs)

```


[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 shelf/react/components/TabbedShelf/index.js from the shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import { injectIntl } from 'react-intl'
import React, { Fragment, Component } from 'react'
import { Button } from 'vtex.styleguide'
import { withRuntimeContext } from 'vtex.render-runtime'
import { withCssHandles } from 'vtex.css-handles'

import Tabs from './Tabs'
import Shelf from '../../Shelf'
import tabbedShelf from './tabbedShelf.css'

const MAX_NUMBER_OF_MENUS = 6
const CSS_HANDLES = ['headline']

/**
 * Tabbed Shelf Module
 */
class TabbedShelf extends Component {
  /**
   * The prop types for this component
   * Used for type checking
   */
  static propTypes = {
    isEnabled: PropTypes.bool,
    headline: PropTypes.string,
    bottomText: PropTypes.string,
    tabs: PropTypes.PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.number,
        __editorItemTitle: PropTypes.string,
      })
    ),
    shelf: PropTypes.object,
  }

  /**
   * Default prop types for this component
   */
  static defaultProps = {
    isEnabled: false,
    headline: '',
    bottomText: '',
    tabs: [],
    shelf: {},
  }

  /**
   * Handle primary call to action button click
   */
  handleButtonClick(url) {
    if (url !== undefined && url !== '') {
      window.open(url.buttunUrl, '_self')
    }
  }

  /**
   * Return the component
   *
   * @returns {*}
   */
  render() {
    const {
      isEnabled,
      headline,
      bottomText,
      buttunUrl,
      buttonText,
      tabs,
      cssHandles,
    } = this.props

    const panes =
      tabs.length > 0
        ? tabs.map(tab => ({
            menuItem: tab.__editorItemTitle,
            render: () => (
              <Shelf {...{ ...this.props.shelf }} category={tab.id} />
            ),
          }))
        : ''

    return (
      <Fragment>
        {isEnabled ? (
          <div className={`${tabbedShelf.container}`}>
            <h3 className={`${cssHandles.headline}`}>{headline}</h3>
            <Tabs panes={panes} />
            <div className={`${tabbedShelf.blockContainer}`}>
              <p className={`${tabbedShelf.blockText}`}>{bottomText}</p>
              {buttonText ? (
                <div className={`${tabbedShelf.buttonContainer}`}>
                  <Button onClick={() => this.handleButtonClick({ buttunUrl })}>
                    {buttonText}
                  </Button>
                </div>
              ) : (
                ''
              )}
            </div>
          </div>
        ) : null}
      </Fragment>
    )
  }
}

/**
 * Schema for component to allow configuration of props from admin configuration
 */
TabbedShelf.getSchema = props => ({
  title: 'admin/editor.tabbed-shelf.title',
  description: 'admin/editor.tabbed-shelf.description',
  type: 'object',
  properties: {
    isEnabled: {
      title: 'admin/editor.tabbed-shelf.isEnabled.title',
      type: 'boolean',
      default: false,
    },
    headline: {
      title: 'admin/editor.tabbed-shelf.headline',
      type: 'string',
    },
    bottomText: {
      title: 'admin/editor.tabbed-shelf.bottomText',
      type: 'string',
      widget: {
        'ui:widget': 'textarea',
      },
    },
    buttonText: {
      title: 'admin/editor.tabbed-shelf.buttonText',
      type: 'string',
    },
    buttunUrl: {
      title: 'admin/editor.tabbed-shelf.buttonUrl',
      type: 'string',
    },
    tabs: {
      title: 'admin/editor.tabbed-shelf.tabs',
      type: 'array',
      minItems: 0,
      maxItems: MAX_NUMBER_OF_MENUS,
      items: {
        title: 'admin/editor.tabbed-shelf.tabs.items',
        type: 'object',
        properties: {
          id: {
            title: 'admin/editor.tabbed-shelf.tabs.items.id',
            type: 'number',
          },
        },
      },
    },
    shelf: {
      title: 'admin/editor.tabbed-shelf.shelf.title',
      type: 'object',
      properties: Shelf.getSchema(props).properties,
    },
  },
})

export default withRuntimeContext(
  injectIntl(withCssHandles(CSS_HANDLES)(TabbedShelf))
)

```


[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 shelf/react/components/TabbedShelf/tabbedShelf.css from the shelf VTEX app.

[Assistant]
Here's the implementation:

```css
.container {
  display:block;
}

.container .mh7-ns,
.container .pv4,
.container .pb7 {
  margin:0 0 0 25px;
  padding:0;
}

.blockContainer {
  font-size: .625em;
  width: 15%;
  position: absolute;
  margin-top: -320px;
  color: #45474a;
  line-height: 17px;
}

.blockContainer:after {
  clear:both;
}

.blockText {
  margin:0 0 19px;
}

.buttonContainer {
  margin: 0 !important;
  padding: 8px 20px !important;
  text-transform: inherit;
  font-size: 16px !important;
}

@media only screen and (max-width: 1047px) {
  .blockContainer {
      margin-top: -300px;
  }
}

@media only screen and (max-width: 854px) {
  .blockContainer {
      margin-top: -280px;
  }
}

@media only screen and (max-width: 821px) {
  .blockContainer {
      margin-top: -320px;
  }
}

@media only screen and (max-width: 639px) {
  .blockContainer {
      margin-top: -220px;
      width:25%;
  }
}

/* Switch to mobile tabs */
@media only screen and (max-width: 570px) {
  .blockContainer {
      margin-top: 45px;
      width: 100%;
      position: relative;
  }
}

```


[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 blueknow/docs/README.md from the blueknow VTEX app.

[Assistant]
Here's the implementation:

```markdown
📢 Use this project, [contribute](https://github.com/vtex-apps/CHANGEME) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).

# Blueknow app

<!-- DOCS-IGNORE:start -->
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<!-- DOCS-IGNORE:end -->

Blueknow first party app

## Configuration

It is possible to install in your store either by using App Store or the VTEX IO Toolbelt.

### Using VTEX App Store

1. Access the **Apps** section in your account's admin page and look for the Blueknow box;
2. Then, click on the **Install** button;
3. You'll see a warning message about needing to enter the necessary configurations. Scroll down and type in your **Blueknow ID** in the `Blueknow` field.
4. Click on **Save**.

### Using VTEX IO Toolbelt

1. [Install](https://vtex.io/docs/recipes/development/installing-an-app/) the `vtex.blueknow@1.x` app. You can confirm that the app has now been installed by running `vtex ls` again.
2. Access the **Apps** section in your account's admin page and look for the Blueknow box. Once you find it, click on the box.
3. Fill in the `Blueknow` field with your **Blueknow ID**.
4. Click on **Save**.

<!-- Remember to also **showcase any necessary disclaimer** related to the app in this section, such as the different behavior it may display during its configuration. -->

<!-- DOCS-IGNORE:start -->
## Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!
<!-- DOCS-IGNORE:end -->

```


[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 blueknow/public/metadata/messages/es-AR.json from the blueknow VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "",
  "headline": "",
  "overview": "",
  "features": [],
  "additionalInformation": "",
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://support.vtex.com/hc/requests"
  }
}

```


[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 blueknow/public/metadata/messages/pt-BR.json from the blueknow VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "",
  "headline": "",
  "overview": "",
  "features": [],
  "additionalInformation": "",
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://support.vtex.com/hc/requests"
  }
}

```


[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 blueknow/public/metadata/messages/en-US.json from the blueknow VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "",
  "headline": "",
  "overview": "",
  "features": [],
  "additionalInformation": "",
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://support.vtex.com/hc/requests"
  }
}

```


[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 assemblers-theme/sitemap/sitemap.json from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "urlset": {
    "url": [
      {
        "loc": "https://storetheme.vtex.com/about-us"
      }
    ]
  }
}
```


[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 assemblers-theme/docs/README.md from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Assemblers Appliance Theme
A simple example store implemented in Store Framework

## Preview
![](https://user-images.githubusercontent.com/484167/71480046-e9aa7080-27d5-11ea-9923-e5ad48891cec.png)

```


[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 assemblers-theme/store/blocks.jsonc from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```json
/* Blocks can be defined both on the store/blocks.json file, and in any number of json
 * files inside the store/blocks directory, with any arbitrary directory structure.
 *
 * Additionally, all blocks files can support comments, such as this one, if given the
 * .jsonc file extension.
 *
 * The store/blocks.json file is intended for backwards compatibility, for miscellaneous
 * blocks, or if the app is simple enough that it doesn't warrant splitting the file.
 */
{
  "store.orderplaced": {
    "blocks": ["order-placed"]
  },

  "store.account": {
    "blocks": ["my-account"],
    "parent": {
      "challenge": "challenge.profile"
    }
  },

  "store.login": {
    "blocks": ["login-content#default"]
  },

  "login-content#default": {
    "props": {
      "isInitialScreenOptionOnly": false,
      "defaultOption": 1,
      "showPasswordVerificationIntoTooltip": true
    }
  },

  "product-summary.shelf": {
    "children": [
      "product-summary-add-to-list-button",
      "stack-layout#prodsum",
      "product-summary-name",
      "product-rating-inline",
      "product-summary-space",
      "product-summary-price"
    ]
  },

  "stack-layout#prodsum": {
    "children": [
      "product-summary-image",
      "product-summary-specification-badges"
    ]
  },

  "product-summary-specification-badges": {
    "props": {
      "specificationGroupName": "Group",
      "specificationName": "On Sale",
      "visibleWhen": "True",
      "displayValue": "SPECIFICATION_NAME"
    }
  },

  "store.product-review-form": {
    "blocks": ["product-review-form"]
  }
}

```


[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 assemblers-theme/styles/css/vtex.rich-text.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container--xp {
  width: 80%;
}

.container--newsletter{
  max-height: 350px;
}

```


[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 assemblers-theme/styles/css/vtex.store-header.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.headerRow--menu-link :global(.vtex-menu-2-x-styledLink) {
  color: #ffffff;
  font-size: 14px;
}

.headerRow--main-header .headerRowBackground {
  background-color: #212222;
  padding: 1.5em 0;
}

.headerRow--main-header :global(a) {
  margin: 0 auto;
}

.headerRow--main-topbar :global(.vtex-menu-2-x-styledLink)  {
  color: #727273;
  font-size: 14px;
}

.headerRow--main-header-mobile .headerRowBackground {
  background-color: #212222;
  padding: 1.5em 0;
}

```


[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 assemblers-theme/styles/css/vtex.store-components.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
@import url('https://fonts.googleapis.com/css?family=Playfair+Display:700|Roboto&display=swap');

.notificationBarContainer {
  background-color: #E6F1E6;
  color: #03034E;
  font-weight: 700;
  font-size: 12px;
  text-decoration: underline;
}

.searchBarContainer {
  max-width: 265px;
}

.infoCardContainer--info-card-home {
  max-width: 1520px;
  margin: 0 auto;
  background-color: #E6F1E6;
  padding: 0px;
}

.newsletter {
  color: #727273;
  max-width: 1528px;
  padding-top: 1rem;
}

#newsletter-input {
  background-color: #ffffff;
}

.newsletter .container {
  padding: 0 0 20px 0;
}

.label {
  color: #727273;
  font-size: 18px;
}

.inputGroup {
  padding-bottom: 4px;
  display: flex;
  color: #fff;
}

.inputGroup input {
  background-color: #ffffff;
  color: #727273;
  border: 2px solid #E3E4E6;
  box-sizing: border-box;
  border-radius: 4px;
}

.inputGroup input::placeholder {
  color: #fff;
  font-size: 16px;
}

.imageElement--storePrint {
  max-height: 300px;
  margin-bottom: 20px;
}

.infoCardTextContainer--depbanner {
  min-height: 400px;
}

@media only screen and (min-width: 640px) {
  .label {
    font-size: 40px;
  }

  .infoCardContainer--info-card-home .infoCardTextContainer {
    width: 30%;
  }

  .infoCardContainer--info-card-home .infoCardImageContainer {
    width: 70%;
  }

  .imageElement--storePrint {
    margin-bottom: 0px;
    max-height: 600px;
  }
}

.imageElement {

}
/*
.shippingContainer {
  background: red;
}

.shippingContainer .items-start {
  width: 50%;
} */

```


[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 assemblers-theme/styles/css/vtex.flex-menu.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container {
    display: block;
}
.menuItem {
    width: 100%;
}
```


[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 assemblers-theme/styles/css/vtex.flex-layout.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.flexRow--deals {
  background-color: #a7afbd;
  padding: 14px 0px;
}

.flexRow--newsletter {
  background-color: #e8ccc9;
  padding-bottom: 2rem;
}

.flexRow--pinkRow {
  background-color: #e8ccc9;
  padding-bottom: 3rem;
  margin-top: 15px;
  margin-bottom: 35px;
}

.flexColChild--newsletter :global(p) {
  margin-bottom: 0;
}

.flexColChild--newsletter :global(.buttonContainer) {
  padding: 0;
  background: red;
}

.flexRow--deals .stretchChildrenWidth {
  align-items: center;
}

.flexRow--deals .flexCol {
  align-items: center;
}

.flexCol--filterCol {
  max-width: 500px;
  min-width: 230px;
}

.flexCol--productCountCol {
  align-items: flex-start;
}

.flexCol--orderByCol {
  align-items: flex-end;
}

.flexCol--orderByMobileCol {
  width: 42%;
}

.flexCol--filterMobileCol {
  width: 38%;
}

.flexCol--switcherMobileCol {
  width: 20%;
}

@media only screen and (min-width: 640px) {
  .flexColChild--pinkCol {
    width: 50%;
  }
}

/* Footer */
.flexRow--footer-row {
  padding-top: 10px;
  padding-bottom: 10px;
  background: #3255A6;
}

.flexRow--footer-row {
  text-align: right;
}

.flexRow--footer-row :global(a) {
  color: #E3E4E6;
  font-size: 14px;
}

@media only screen and (max-width: 640px) {
  .flexRow--footer-row :global(li) {
    display: block;
  }
}

.flexRow--footer-row :global(img) {
  filter: brightness(2);
}

/* Product */
.flexRow--product-main {
  color: #727273
}

```


[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 assemblers-theme/styles/css/vtex.breadcrumb.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container {
  /* background: red; */
  margin-top: 20px;
}

```


[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 assemblers-theme/styles/css/vtex.slider-layout.css from the assemblers-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.slide--styles {
  width: 80% !important
}

.slideChildrenContainer {
  text-align: center;
  margin-top: 25px;
}

```