Skip to content

Commit

Permalink
Merge 64303f6 into 6bd7ced
Browse files Browse the repository at this point in the history
  • Loading branch information
victorhmp committed Feb 6, 2020
2 parents 6bd7ced + 64303f6 commit e1cb4c7
Show file tree
Hide file tree
Showing 17 changed files with 388 additions and 104 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- `ProductSummaryList` component.

## [2.50.2] - 2020-02-05

Expand Down
37 changes: 37 additions & 0 deletions docs/ProductSummaryList.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ProductSummaryList

The `list-context.product-list` interface is a instance of the `list-context` interfaces, which means its part of a set of special interfaces that enables you to create lists of content that can be edited via Site Editor.

In order to create a list of products, you need to use the `list-context.product-list` block and a `product-summary.shelf`.

## product-list-block

This block is used to specify what variation of `product-summary` to be used to create the list of products, and the `list-context.product-list` you want as follows:

```json
"product-summary.shelf#demo1": {
"children": [
"stack-layout#prodsum",
"product-summary-name",
"product-rating-inline",
"product-summary-space",
"product-summary-price",
"product-summary-buy-button"
]
},
"list-context.product-list#demo1": {
"blocks": ["product-summary.shelf#demo1"],
"children": ["slider-layout#demo-products"]
},
```

`list-context.product-list` is also responsible for performing the GraphQL query that fetches the list of products, so it can receive the following props:

| Prop name | Type | Description | Default value |
| ---------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `category` | `String` | Category ID of the listed items. For sub-categories, use "/" (e.g. "1/2/3") | - |
| `specificationFilters` | `Array({ id: String, value: String })` | Specification Filters of the listed items. | [] |
| `collection` | `String` | Filter by collection. | - |
| `orderBy` | `Enum` | Ordination type of the items. Possible values: `OrderByTopSaleDESC`, `OrderByReleaseDateDESC`, `OrderByBestDiscountDESC`, `OrderByPriceDESC`, `OrderByPriceASC`, `OrderByNameASC`, `OrderByNameDESC` | `OrderByTopSaleDESC` |
| `hideUnavailableItems` | `Boolean` | Hides items that are unavailable. | `false` |
| `maxItems` | `Number` | Maximum items to be fetched. | `10` |
11 changes: 2 additions & 9 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,16 @@
"vtex.native-types": "0.x",
"vtex.store-components": "3.x",
"vtex.store-resources": "0.x",
"vtex.product-review-interfaces": "1.x",
"vtex.product-summary-context": "0.x",
"vtex.product-identifier": "0.x",
"vtex.styleguide": "9.x",
"vtex.pixel-manager": "1.x",
"vtex.product-teaser-interfaces": "1.x",
"vtex.device-detector": "0.x",
"vtex.product-quantity": "1.x",
"vtex.product-specification-badges": "0.x",
"vtex.stack-layout": "0.x",
"vtex.responsive-values": "0.x",
"vtex.css-handles": "0.x",
"vtex.product-context": "0.x",
"vtex.flex-layout": "0.x",
"vtex.rich-text": "0.x",
"vtex.add-to-cart-button": "0.x",
"vtex.product-bookmark-interfaces": "1.x"
"vtex.list-context": "0.x",
"vtex.product-list-context": "0.x"
},
"$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema"
}
22 changes: 21 additions & 1 deletion messages/context.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,25 @@
"admin/editor.productSummaryImage.hoverImageLabel.title": "admin/editor.productSummaryImage.hoverImageLabel.title",
"admin/editor.productSummaryBuyButton.title": "admin/editor.productSummaryBuyButton.title",
"admin/editor.productSummaryName.title": "admin/editor.productSummaryName.title",
"admin/editor.product-summary-specification-badges.title": "admin/editor.product-summary-specification-badges.title"
"admin/editor.product-summary-specification-badges.title": "admin/editor.product-summary-specification-badges.title",
"admin/editor.productSummaryList.title": "Product List",
"admin/editor.productSummaryList.description": "A product list featuring a collection",
"admin/editor.productSummaryList.category.title": "Category Id",
"admin/editor.productSummaryList.category.description": "For sub-categories, use \"/\" (e.g. 1/2/3)",
"admin/editor.productSummaryList.collection.title": "Collection",
"admin/editor.productSummaryList.orderBy.title": "List Ordenation",
"admin/editor.productSummaryList.hideUnavailableItems": "Hide unavailable items",
"admin/editor.productSummaryList.maxItems.title": "Max Items",
"admin/editor.productSummaryList.specificationFilters.title": "Specification Filters",
"admin/editor.productSummaryList.specificationFilters.item.title": "Specification Filter Item",
"admin/editor.productSummaryList.specificationFilters.item.id.title": "Specification Filter ID",
"admin/editor.productSummaryList.specificationFilters.item.value.title": "Specification Filter Value",
"admin/editor.productSummaryList.orderType.sales": "Sales",
"admin/editor.productSummaryList.orderType.priceDesc": "Price, descending",
"admin/editor.productSummaryList.orderType.priceAsc": "Price, ascending",
"admin/editor.productSummaryList.orderType.nameAsc": "Name, ascending",
"admin/editor.productSummaryList.orderType.nameDesc": "Name, descending",
"admin/editor.productSummaryList.orderType.releaseDate": "Release Date",
"admin/editor.productSummaryList.orderType.discount": "Discount",
"admin/editor.productSummaryList.orderType.relevance": "Relevance"
}
22 changes: 21 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,25 @@
"admin/editor.productSummaryImage.hoverImageLabel.title": "Hover Image Label",
"admin/editor.productSummaryBuyButton.title": "Product Summary Buy Button",
"admin/editor.productSummaryName.title": "Product Summary Name",
"admin/editor.product-summary-specification-badges.title": "Product Summary Specification Badges"
"admin/editor.product-summary-specification-badges.title": "Product Summary Specification Badges",
"admin/editor.productSummaryList.title": "Product List",
"admin/editor.productSummaryList.description": "A product list featuring a collection",
"admin/editor.productSummaryList.category.title": "Category Id",
"admin/editor.productSummaryList.category.description": "For sub-categories, use \"/\" (e.g. 1/2/3)",
"admin/editor.productSummaryList.collection.title": "Collection",
"admin/editor.productSummaryList.orderBy.title": "List Ordination",
"admin/editor.productSummaryList.hideUnavailableItems": "Hide unavailable items",
"admin/editor.productSummaryList.maxItems.title": "Max Items",
"admin/editor.productSummaryList.specificationFilters.title": "Specification Filters",
"admin/editor.productSummaryList.specificationFilters.item.title": "Specification Filter Item",
"admin/editor.productSummaryList.specificationFilters.item.id.title": "Specification Filter ID",
"admin/editor.productSummaryList.specificationFilters.item.value.title": "Specification Filter Value",
"admin/editor.productSummaryList.orderType.sales": "Sales",
"admin/editor.productSummaryList.orderType.priceDesc": "Price, descending",
"admin/editor.productSummaryList.orderType.priceAsc": "Price, ascending",
"admin/editor.productSummaryList.orderType.nameAsc": "Name, ascending",
"admin/editor.productSummaryList.orderType.nameDesc": "Name, descending",
"admin/editor.productSummaryList.orderType.releaseDate": "Release Date",
"admin/editor.productSummaryList.orderType.discount": "Discount",
"admin/editor.productSummaryList.orderType.relevance": "Relevance"
}
22 changes: 21 additions & 1 deletion messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,25 @@
"admin/editor.productSummaryImage.hoverImageLabel.title": "Etiqueta de imagen secundaria",
"admin/editor.productSummaryBuyButton.title": "Botón de compra",
"admin/editor.productSummaryName.title": "Nombre de Resumen del producto",
"admin/editor.product-summary-specification-badges.title": "Resumen del producto Especificaciones Medallas"
"admin/editor.product-summary-specification-badges.title": "Resumen del producto Especificaciones Medallas",
"admin/editor.productSummaryList.title": "Lista de productos",
"admin/editor.productSummaryList.description": "Una lista de productos con una colección de productos",
"admin/editor.productSummaryList.category.title": "Id de la Categoría",
"admin/editor.productSummaryList.category.description": "Para subcategorías, utilice \"/\" (por ejemplo: 1/2/3)",
"admin/editor.productSummaryList.collection.title": "Colección",
"admin/editor.productSummaryList.orderBy.title": "Ordenación de la Lista",
"admin/editor.productSummaryList.hideUnavailableItems": "Ocultar artículos no disponibles",
"admin/editor.productSummaryList.maxItems.title": "Cantidad máxima de Elementos",
"admin/editor.productSummaryList.specificationFilters.title": "Filtros de especificación",
"admin/editor.productSummaryList.specificationFilters.item.title": "Elemento de filtro de especificación",
"admin/editor.productSummaryList.specificationFilters.item.id.title": "ID del filtro de especificación",
"admin/editor.productSummaryList.specificationFilters.item.value.title": "Valor del filtro de especificación",
"admin/editor.productSummaryList.orderType.sales": "Ventas",
"admin/editor.productSummaryList.orderType.priceDesc": "Precio, descendiendo",
"admin/editor.productSummaryList.orderType.priceAsc": "Precio, ascendente",
"admin/editor.productSummaryList.orderType.nameAsc": "Nombre, ascendente",
"admin/editor.productSummaryList.orderType.nameDesc": "Nombre, descendiendo",
"admin/editor.productSummaryList.orderType.releaseDate": "Fecha de lanzamiento",
"admin/editor.productSummaryList.orderType.discount": "Descuento",
"admin/editor.productSummaryList.orderType.relevance": "Relevancia"
}
22 changes: 21 additions & 1 deletion messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,25 @@
"admin/editor.productSummaryImage.hoverImageLabel.title": "Rótulo da imagem secundária",
"admin/editor.productSummaryBuyButton.title": "Botão de compra",
"admin/editor.productSummaryName.title": "Nome do resumo do produto",
"admin/editor.product-summary-specification-badges.title": "Medalhas de Especificação do resumo do produto"
"admin/editor.product-summary-specification-badges.title": "Medalhas de Especificação do resumo do produto",
"admin/editor.productSummaryList.title": "Lista de produtos",
"admin/editor.productSummaryList.description": "Uma lista de produtos de uma coleção",
"admin/editor.productSummaryList.category.title": "Id da Categoria",
"admin/editor.productSummaryList.category.description": "Para sub-categorias, use \"/\" (por exemplo: 1/2/3)",
"admin/editor.productSummaryList.collection.title": "Coleção",
"admin/editor.productSummaryList.orderBy.title": "Ordenação da Lista",
"admin/editor.productSummaryList.hideUnavailableItems": "Esconder itens não disponíveis",
"admin/editor.productSummaryList.maxItems.title": "Quantidade máxima de itens",
"admin/editor.productSummaryList.specificationFilters.title": "Filtros de Especificação",
"admin/editor.productSummaryList.specificationFilters.item.title": "Item de Filtro de Especificação",
"admin/editor.productSummaryList.specificationFilters.item.id.title": "ID do Filtro de Especificação",
"admin/editor.productSummaryList.specificationFilters.item.value.title": "Valor do Filtro de Especificação",
"admin/editor.productSummaryList.orderType.sales": "Vendas",
"admin/editor.productSummaryList.orderType.priceDesc": "Preço, descrescente",
"admin/editor.productSummaryList.orderType.priceAsc": "Preço, crescente",
"admin/editor.productSummaryList.orderType.nameAsc": "Nome, crescente",
"admin/editor.productSummaryList.orderType.nameDesc": "Nome, decrescente",
"admin/editor.productSummaryList.orderType.releaseDate": "Data de lançamento",
"admin/editor.productSummaryList.orderType.discount": "Desconto",
"admin/editor.productSummaryList.orderType.relevance": "Relevância"
}
181 changes: 181 additions & 0 deletions react/ProductSummaryList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import React from 'react'
import { useQuery } from 'react-apollo'
import { ProductListContext } from 'vtex.product-list-context'
import { ExtensionPoint, useTreePath } from 'vtex.render-runtime'
import { useListContext, ListContextProvider } from 'vtex.list-context'

import { mapCatalogProductToProductSummary } from './utils/normalize'
import ProductListEventCaller from './components/ProductListEventCaller'

import { productSearchV2 } from 'vtex.store-resources/Queries'

const ORDER_BY_OPTIONS = {
RELEVANCE: {
name: 'admin/editor.productSummaryList.orderType.relevance',
value: 'OrderByScoreDESC',
},
TOP_SALE_DESC: {
name: 'admin/editor.productSummaryList.orderType.sales',
value: 'OrderByTopSaleDESC',
},
PRICE_DESC: {
name: 'admin/editor.productSummaryList.orderType.priceDesc',
value: 'OrderByPriceDESC',
},
PRICE_ASC: {
name: 'admin/editor.productSummaryList.orderType.priceAsc',
value: 'OrderByPriceASC',
},
NAME_ASC: {
name: 'admin/editor.productSummaryList.orderType.nameAsc',
value: 'OrderByNameASC',
},
NAME_DESC: {
name: 'admin/editor.productSummaryList.orderType.nameDesc',
value: 'OrderByNameDESC',
},
RELEASE_DATE_DESC: {
name: 'admin/editor.productSummaryList.orderType.releaseDate',
value: 'OrderByReleaseDateDESC',
},
BEST_DISCOUNT_DESC: {
name: 'admin/editor.productSummaryList.orderType.discount',
value: 'OrderByBestDiscountDESC',
},
}
const parseFilters = ({ id, value }) => `specificationFilter_${id}:${value}`

function getOrdinationProp(attribute) {
return Object.keys(ORDER_BY_OPTIONS).map(
key => ORDER_BY_OPTIONS[key][attribute]
)
}

const ProductSummaryList = ({
children,
category = '',
collection,
hideUnavailableItems = false,
orderBy = ORDER_BY_OPTIONS.TOP_SALE_DESC.value,
specificationFilters = [],
maxItems = 10,
withFacets = false,
}) => {
const { data } = useQuery(productSearchV2, {
ssr: true,
name: 'productList',
variables: {
category,
...(collection != null
? {
collection,
}
: {}),
specificationFilters: specificationFilters.map(parseFilters),
orderBy,
from: 0,
to: maxItems - 1,
hideUnavailableItems,
withFacets,
},
})

const { list } = useListContext()
const { treePath } = useTreePath()

const componentList =
data.productSearch &&
data.productSearch.products.map(product => {
const normalizedProduct = mapCatalogProductToProductSummary(product)

return (
<ExtensionPoint
id="product-summary"
key={product.id}
treePath={treePath}
product={normalizedProduct}
/>
)
})

const newListContextValue = list.concat(componentList)

return (
<ListContextProvider list={newListContextValue}>
{children}
</ListContextProvider>
)
}

const EnhancedProductList = ({ children }) => {
const { ProductListProvider } = ProductListContext

return (
<ProductListProvider>
<ProductSummaryList>{children}</ProductSummaryList>
<ProductListEventCaller />
</ProductListProvider>
)
}

EnhancedProductList.getSchema = () => ({
title: 'admin/editor.productSummaryList.title',
description: 'admin/editor.productSummaryList.description',
type: 'object',
properties: {
category: {
title: 'admin/editor.productSummaryList.category.title',
description: 'admin/editor.productSummaryList.category.description',
type: 'string',
isLayout: false,
},
specificationFilters: {
title: 'admin/editor.productSummaryList.specificationFilters.title',
type: 'array',
items: {
title:
'admin/editor.productSummaryList.specificationFilters.item.title',
type: 'object',
properties: {
id: {
type: 'string',
title:
'admin/editor.productSummaryList.specificationFilters.item.id.title',
},
value: {
type: 'string',
title:
'admin/editor.productSummaryList.specificationFilters.item.value.title',
},
},
},
},
collection: {
title: 'admin/editor.productSummaryList.collection.title',
type: 'number',
isLayout: false,
},
orderBy: {
title: 'admin/editor.productSummaryList.orderBy.title',
type: 'string',
enum: getOrdinationProp('value'),
enumNames: getOrdinationProp('name'),
default: ORDER_BY_OPTIONS.TOP_SALE_DESC.value,
isLayout: false,
},
hideUnavailableItems: {
title: 'admin/editor.productSummaryList.hideUnavailableItems',
type: 'boolean',
default: false,
isLayout: false,
},
maxItems: {
title: 'admin/editor.productSummaryList.maxItems.title',
type: 'number',
isLayout: false,
default: 10,
},
},
})

export default EnhancedProductList
8 changes: 8 additions & 0 deletions react/__mocks__/vtex.product-list-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React, { Fragment } from 'react'

export const useProductImpression = () => null
export const ProductListContext = {
useProductListDispatch: () => null,
// eslint-disable-next-line react/display-name
ProductListProvider: ({ children }) => <Fragment>{children}</Fragment>,
}
8 changes: 8 additions & 0 deletions react/components/ProductListEventCaller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useProductImpression } from 'vtex.product-list-context'

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

export default ProductListEventCaller

0 comments on commit e1cb4c7

Please sign in to comment.