Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new list-context.product-list interface #229

Merged
merged 28 commits into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1a37914
Add products query
victorhmp Oct 17, 2019
5b6f3c2
Delete unnecessary tsconfig :(
victorhmp Oct 17, 2019
e75ee6d
First implementation for ProductSummaryList component
victorhmp Oct 17, 2019
e6bd97c
Add schema to enable edition via Site Editor
victorhmp Oct 17, 2019
f684563
Add messages for ProductList
victorhmp Oct 17, 2019
45f74f5
Update CHANGELOG
victorhmp Oct 17, 2019
30485d4
Fix typos
victorhmp Oct 17, 2019
8c3bc9f
Add `BuyButtonText` prop to `ProductSummaryList`
victorhmp Oct 18, 2019
1ee7e1c
Create new "list-context.product-list" based on the new implementatio…
victorhmp Oct 21, 2019
8e0bd0e
Fix typo
victorhmp Oct 22, 2019
90d22a0
Cleanup ProductSummaryList
victorhmp Oct 22, 2019
d0b646c
Use productSearchV2 query from vtex.store-resources
victorhmp Oct 22, 2019
1969c92
Add new `product-list-block` interface
victorhmp Oct 22, 2019
68c5eb2
Remove search-graphql dependency
victorhmp Oct 22, 2019
b22b549
Add ProductSummaryList documentation
victorhmp Oct 23, 2019
d347ff1
Remove unnecessary dependencies
victorhmp Jan 31, 2020
f079883
Update implementation of ProductSummaryList
victorhmp Jan 31, 2020
01a389c
Add react-intersection-observer dependency
victorhmp Feb 3, 2020
be66886
Add vtex.product-list-context dependency
victorhmp Feb 3, 2020
81cf293
Add support for productImpression events
victorhmp Feb 3, 2020
a0adf2c
Fix proptypes
victorhmp Feb 3, 2020
f1af937
Add mock definition for vtex.product-list-context
victorhmp Feb 3, 2020
bb05ec4
Update documentation
victorhmp Feb 3, 2020
b4cd95f
Update react/ProductSummaryList.js
victorhmp Feb 4, 2020
bebd793
Update variable naming
victorhmp Feb 4, 2020
eb21903
Add informative comment to ProductSummary
victorhmp Feb 4, 2020
6cd7f6e
Update docs/ProductSummaryList.md
victorhmp Feb 5, 2020
64303f6
trigger ci run
victorhmp Feb 6, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.1] - 2020-01-23

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
Loading