diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f8985b..8abedbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `product-installments.list` block. ## [1.3.2] - 2020-06-03 ### Fixed diff --git a/messages/en.json b/messages/en.json index dafb9aa..c07d9c7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -8,7 +8,6 @@ "store/list-price-range-no-range-message.default": "{listPriceValue}", "store/selling-price-range-message.default": "{minPriceValue} - {maxPriceValue}", "store/selling-price-range-no-range-message.default": "{sellingPriceValue}", - "admin/list-price.description": "Values available for interpolation: '{listPriceValue}, {listPriceWithTax}, {taxPercentage}'", "admin/list-price.title": "List Price", "admin/selling-price.description": "Values available for interpolation: '{sellingPriceValue}, {sellingPriceWithTax}, {taxPercentage}'", @@ -19,6 +18,7 @@ "admin/savings.title": "Savings", "admin/installments.description": "Values available for interpolation: '{installmentsNumber}, {installmentValue}, {installmentsTotalValue}, {interestRate} {hasInterest}'", "admin/installments.title": "Installments", + "admin/installments-list.title": "Installments List", "admin/list-price-range.title": "List Price Range", "admin/list-price-range-message.description": "Message to be shown when there is a difference in price between the SKUs.\nValues available for interpolation: '{minPriceValue}, {maxPriceValue}, {minPriceWithTax}, {maxPriceWithTax}'", "admin/list-price-range-message.title": "List Price (Range)", diff --git a/messages/es.json b/messages/es.json index 62f8705..f398dfc 100644 --- a/messages/es.json +++ b/messages/es.json @@ -8,7 +8,6 @@ "store/list-price-range-no-range-message.default": "{listPriceValue}", "store/selling-price-range-message.default": "{minPriceValue} - {maxPriceValue}", "store/selling-price-range-no-range-message.default": "{sellingPriceValue}", - "admin/list-price.description": "Valores disponibles para interpolación: '{listPriceValue}, {listPriceWithTax}, {taxPercentage}'", "admin/list-price.title": "Precio de Lista", "admin/selling-price.description": "Valores disponibles para interpolación: '{sellingPriceValue}, {sellingPriceWithTax}, {taxPercentage}'", @@ -19,6 +18,7 @@ "admin/savings.title": "Ahorros", "admin/installments.description": "Valores disponibles para interpolación: '{installmentsNumber}, {installmentValue}, {installmentsTotalValue}, {interestRate}, {hasInterest}'", "admin/installments.title": "Cuotas", + "admin/installments-list.title": "Lista de Cuotas", "admin/list-price-range.title": "Rango de Precio de Lista", "admin/list-price-range-message.description": "Mensaje que se mostrará cuando haya una diferencia de precio entre los SKU.\nValores disponibles para interpolación: '{minPriceValue}, {maxPriceValue}, {minPriceWithTax}, {maxPriceWithTax}'", "admin/list-price-range-message.title": "Precio de Lista (Rango)", @@ -29,4 +29,4 @@ "admin/selling-price-range-message.title": "Precio de Venta (Rango)", "admin/selling-price-range-no-range-message.description": "ensaje que se mostrará cuando no haya una diferencia de precio entre los SKU.\nValores disponibles para interpolación: '{sellingPriceValue}, {sellingPriceWithTax}'", "admin/selling-price-range-no-range-message.title": "Precio de Venta (Sin rango)" -} +} \ No newline at end of file diff --git a/messages/pt.json b/messages/pt.json index 579deba..1767fa2 100644 --- a/messages/pt.json +++ b/messages/pt.json @@ -8,7 +8,6 @@ "store/list-price-range-no-range-message.default": "{listPriceValue}", "store/selling-price-range-message.default": "{minPriceValue} - {maxPriceValue}", "store/selling-price-range-no-range-message.default": "{sellingPriceValue}", - "admin/list-price.description": "Valores disponiveis para interpolação: '{listPriceValue}, {listPriceWithTax}, {taxPercentage}'", "admin/list-price.title": "Preço de Tabela", "admin/selling-price.description": "Valores disponiveis para interpolação: '{sellingPriceValue}, {sellingPriceWithTax}, {taxPercentage}'", @@ -19,6 +18,7 @@ "admin/savings.title": "Economias", "admin/installments.description": "Valores disponiveis para interpolação: '{installmentsNumber}, {installmentValue}, {installmentsTotalValue}, {interestRate}, {hasInterest}'", "admin/installments.title": "Parcelamento", + "admin/installments-list.title": "Lista de Parcelamentos", "admin/list-price-range.title": "Faixa de Preço de Tabela", "admin/list-price-range-message.description": "Mensagem a ser mostrada quando houver diferença de preço entre SKUs.\nValores disponiveis para interpolação: '{minPriceValue}, {maxPriceValue}, {minPriceWithTax}, {maxPriceWithTax}'", "admin/list-price-range-message.title": "Preço de Tabela (Faixa)", @@ -29,4 +29,4 @@ "admin/selling-price-range-message.title": "Preço de Venda (Faixa)", "admin/selling-price-range-no-range-message.description": "Mensagem a ser mostrada quando não houver diferença de preço entre SKUs.\nValores disponiveis para interpolação: '{sellingPriceValue}, {sellingPriceWithTax}'", "admin/selling-price-range-no-range-message.title": "Preço de Venda (Sem faixa)" -} +} \ No newline at end of file diff --git a/react/InstallmentsList.tsx b/react/InstallmentsList.tsx new file mode 100644 index 0000000..7a6f1e9 --- /dev/null +++ b/react/InstallmentsList.tsx @@ -0,0 +1,69 @@ +import React, { useContext } from 'react' +import { defineMessages } from 'react-intl' +import { useCssHandles } from 'vtex.css-handles' +import { ProductContext } from 'vtex.product-context' + +import { BasicPriceProps } from './types' +import InstallmentsRenderer, { + Installments, +} from './components/InstallmentsRenderer' + +const CSS_HANDLES = ['installmentsListContainer'] as const + +function InstallmentsList(props: BasicPriceProps) { + const { message, markers } = props + const { selectedItem } = useContext(ProductContext) + const handles = useCssHandles(CSS_HANDLES) + + const commertialOffer = selectedItem?.sellers[0]?.commertialOffer + + if ( + !commertialOffer?.Installments || + commertialOffer.Installments?.length === 0 + ) { + return null + } + + const sortedInstallments = commertialOffer.Installments.sort( + (a: Installments, b: Installments) => + a.NumberOfInstallments - b.NumberOfInstallments + ) + + return ( +
+ {sortedInstallments.map((inst: Installments, i: number) => { + return ( + + ) + })} +
+ ) +} + +defineMessages({ + title: { + id: 'admin/installments-list.title', + }, + titleMessage: { + id: 'admin/installments.title', + }, + description: { + id: 'admin/installments.description', + }, + default: { + id: 'store/installments.default', + }, +}) + +InstallmentsList.schema = { + title: 'admin/installments-list.title', +} + +export default InstallmentsList diff --git a/react/components/InstallmentsRenderer.tsx b/react/components/InstallmentsRenderer.tsx new file mode 100644 index 0000000..515580f --- /dev/null +++ b/react/components/InstallmentsRenderer.tsx @@ -0,0 +1,80 @@ +import React from 'react' +import { FormattedNumber } from 'react-intl' +import { useCssHandles } from 'vtex.css-handles' +import { FormattedCurrency } from 'vtex.format-currency' +import { IOMessageWithMarkers } from 'vtex.native-types' + +import { BasicPriceProps } from '../types' + +export interface Installments { + Value: number + InterestRate: number + TotalValuePlusInterestRate: number + NumberOfInstallments: number +} + +const CSS_HANDLES = [ + 'installments', + 'installmentsNumber', + 'installmentValue', + 'installmentsTotalValue', + 'interestRate', +] as const + +interface Props extends BasicPriceProps { + installments: Installments +} + +function InstallmentsRenderer(props: Props) { + const { message, markers, installments } = props + const handles = useCssHandles(CSS_HANDLES) + + const { + Value, + NumberOfInstallments, + InterestRate, + TotalValuePlusInterestRate, + } = installments + const hasInterest = InterestRate !== 0 + + return ( + + + + + ), + installmentValue: ( + + + + ), + installmentsTotalValue: ( + + + + ), + interestRate: ( + + + + ), + hasInterest, + }} + /> + + ) +} + +export default InstallmentsRenderer diff --git a/store/contentSchemas.json b/store/contentSchemas.json index c0fafde..55413cb 100644 --- a/store/contentSchemas.json +++ b/store/contentSchemas.json @@ -55,6 +55,13 @@ } } }, + "InstallmentsList": { + "title": "admin/installments-list.title", + "type": "object", + "properties": { + "$ref": "app:vtex.product-price#/definitions/Installments/properties" + } + }, "ListPriceRange": { "type": "object", "properties": { diff --git a/store/interfaces.json b/store/interfaces.json index 78c60b4..2d12bcd 100644 --- a/store/interfaces.json +++ b/store/interfaces.json @@ -34,6 +34,14 @@ "$ref": "app:vtex.product-price#/definitions/Installments" } }, + "product-installments.list": { + "component": "InstallmentsList", + "composition": "children", + "overrideContentRule": "self", + "content": { + "$ref": "app:vtex.product-price#/definitions/InstallmentsList" + } + }, "product-list-price-range": { "component": "ListPriceRange", "composition": "children",