├── README.md ├── 9 - Chamando as APIs de Commerce ├── README.md ├── 1 - Introdução ao curso │ └── README.md ├── 3 - Importando Clients do pacote VTEX │ └── README.md ├── 2 - Encontrando as APIs do VTEX Commerce │ └── README.md └── 4 - Usando o Client Catalog para fazer requisições │ └── README.md ├── 7 - Serviços ├── README.md ├── 8 - GraphQL - Utilizando GraphiQL │ └── README.md ├── 5 - Utilizando eventos como gatilhos │ └── README.md ├── 1 - Serviços no VTEX IO │ └── README.md ├── 2 - Visão geral - Entendendo o Boilerplate │ └── README.md ├── 7 - GraphQL - Consultando dados do Master Data │ └── README.md ├── 3 - Eventos - recebendo e lidando com eventos │ └── README.md └── 4 - Conhecendo um pouco mais sobre clientes │ └── README.md ├── 2 - Layouts Complexos ├── README.md ├── 1 - Apresentando blocos de layout │ └── README.md ├── 7 - Quick view │ └── README.md ├── 6 - Layout modal │ └── README.md ├── 2 - Flex layout │ └── README.md ├── 8 - Stack layout │ └── README.md ├── 3 - Carrossel de blocos │ └── README.md ├── 4 - Tornando seu conteúdo responsivo │ └── README.md ├── 5 - Layout de abas │ └── README.md └── 9 - Conditional layout │ └── README.md ├── 6 - Blocos customizados ├── README.md ├── 1 - Introdução │ └── README.md ├── 2 - Conhecendo uma app VTEX IO │ └── README.md ├── 4 - Tornando o bloco countdown customizável │ └── README.md ├── 6 - Modificando o bloco countdown para ter um estilo configurável │ └── README.md ├── 3 - Linkando uma app e utilizando-a no tema da loja │ └── README.md ├── 5 - Criando a funcionalidade do bloco countdown │ └── README.md ├── 7 - Práticas de internacionalização no VTEX IO │ └── README.md ├── 9 - Conectando backend e frontend │ └── README.md └── 8 - Componentizando o bloco countdown │ └── README.md ├── 4 - Site Editor e Conteúdo ├── README.md ├── 1 - Conhecendo mais sobre workspaces │ └── README.md ├── 4 - Apresentando o Site Editor e alterando um banner de uma loja │ └── README.md ├── 2 - Publicando uma aplicação no VTEX IO │ └── README.md └── 3 - Instalando uma app em uma conta VTEX │ └── README.md ├── 3 - Tornando sua loja única ├── README.md ├── 1 - Introdução │ └── README.md ├── 5 - Explorando o poder do rich text │ └── README.md ├── 3 - Estilos globais │ └── README.md ├── 4 - Criando templates customizados │ └── README.md └── 6 - Construindo uma landing customizada de busca │ └── README.md ├── 8 - Aplicações Administrativas ├── README.md ├── 5 - Homogeneidade visual │ └── README.md ├── 3 - Melhorando a navegação │ └── README.md ├── 2 - Navigation & Routes │ └── README.md ├── 6 - Conectando a um serviço │ └── README.md ├── 4 - Sub seções │ └── README.md └── 1 - Admin framework │ └── README.md ├── 5 - Melhorando performance ├── README.md ├── 5 - Melhorias na busca │ └── README.md ├── 1 - Melhorando load inicial │ └── README.md ├── 2 - Otimizando menus │ └── README.md ├── 3 - Otimização de submenus │ └── README.md ├── 6 - Refatorando blocos │ └── README.md └── 4 - Imagens │ └── README.md └── 1 - Blocos Básicos ├── 1 - Introdução e Boilerplate └── README.md ├── README.md ├── 5 - Evoluindo sua página de produto └── README.md ├── 6 - Página de busca └── README.md ├── 2 - Começando com Rich Text └── README.md ├── 4 - Pagina de produto └── README.md └── 3 - Info Card o call to action do store Framework └── README.md /README.md: -------------------------------------------------------------------------------- 1 | # vtexio -------------------------------------------------------------------------------- /9 - Chamando as APIs de Commerce/README.md: -------------------------------------------------------------------------------- 1 | ## Chamando as APIs de Core Commerce no VTEX IO 2 | 3 | Neste curso você aprenderá como encontrar e usar as APIs de Commerce da VTEX dentro de sua aplicação no VTEX IO, aprendendo sobre autorização e também como reusar Clients já feitos pela comunidade. 4 | -------------------------------------------------------------------------------- /7 - Serviços/README.md: -------------------------------------------------------------------------------- 1 | ## Desenvolvendo serviços no VTEX IO 2 | 3 | Neste curso, aprenda as inúmeras possibilidades de aplicações backend no VTEX IO. Exporte rotas, lide com eventos e conecte-se com aplicações internas e externas, de modo a tornar sua aplicação ainda melhor e aproveitar ao máximo a infraestrutura da VTEX. 4 | -------------------------------------------------------------------------------- /2 - Layouts Complexos/README.md: -------------------------------------------------------------------------------- 1 | ## Construindo _layouts_ complexos 2 | 3 | Este curso mostrará como utilizar os diversos blocos do Store Framework a fim de desenvolver _layouts_ mais complexos. Descubra como utilizar blocos de composição, junto com os blocos já aprendidos no curso de Blocos Básicos para obter _layouts_ diversos e complexos. -------------------------------------------------------------------------------- /6 - Blocos customizados/README.md: -------------------------------------------------------------------------------- 1 | ## Desenvolvendo blocos customizados no VTEX IO 2 | 3 | De forma a introduzir os desenvolvedores a como construir blocos customizados no VTEX IO, este curso foi lançado. Ele complempla os conceitos necessários, passo a passo, para ter um bloco customizado em um tema, que utilize React, Typescript e GraphQL. 4 | -------------------------------------------------------------------------------- /4 - Site Editor e Conteúdo/README.md: -------------------------------------------------------------------------------- 1 | ## Utilizando o Site Editor e o VTEX Toolbelt para gerenciar e customizar sua loja 2 | 3 | Este curso tem como objetivo introduzir os desenvolvedores em como utilizar o Site Editor e o VTEX Toolbelt, de forma a aprender como gerenciar os diferentes tipos de workspace, publicar e instalar aplicações e, por fim, como customizar sua frente de loja. -------------------------------------------------------------------------------- /3 - Tornando sua loja única/README.md: -------------------------------------------------------------------------------- 1 | ## Customizando sua loja para criar uma experiência única para o usuário final 2 | 3 | Os blocos do Store Framework provêm uma ampla oportunidade de customização através de propriedades do CSS e estilização. Neste curso, você aprenderá como customizar blocos do Store Framework, de forma a criar frentes de loja que sejam alinhadas com a sua identidade visual. -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/README.md: -------------------------------------------------------------------------------- 1 | ## Aprenda a construir apps administrativas usando o Admin Framework 2 | 3 | Neste curso vamos aprender como construir aplicações para extender o admin nativo da VTEX para enriquecer a operação de uma loja. Com ele você verá como construir criar a extensão, enriquecer a navegação, manter a identidade visual e, por fim, conectar a aplicação a um serviço. 4 | 5 | -------------------------------------------------------------------------------- /5 - Melhorando performance/README.md: -------------------------------------------------------------------------------- 1 | # A importância da performance em uma loja 2 | 3 | Em 2012, o Walmart fez uma pesquisa relacionando performance _web_ com de negócios, descobrindo que para cada `100ms` de melhoria de carregamento haveria `1%` de melhoria incremental em revendas. Tendo em vista todo o impacto e relevância que a performance de loja tem para um negócio, neste curso aprenderemos como seguir as melhores práticas de implementação com o Store Framework, evoluindo um tema já existente e garantindo sua otimização. 4 | -------------------------------------------------------------------------------- /1 - Blocos Básicos/1 - Introdução e Boilerplate/README.md: -------------------------------------------------------------------------------- 1 | # Introdução e Boilerplate 2 | 3 | ## Introdução 4 | Durante este curso, você aprenderá como usar os blocos principais do Store Framework para iniciar rapidamente o desenvolvimento da sua frente de loja. 5 | 6 | Boilerplate: Iniciando o Curso 7 | 8 | Para começar a tirar o melhor proveito deste curso, começaremos com um repositório de tema de loja básico, que você pode clonar [neste link](https://github.com/vtex-apps/minimum-boilerplate-theme). Neste tema, existem alguns arquivos iniciais necessários e você pode seguir as instruções em seu README.md para cloná-lo corretamente. -------------------------------------------------------------------------------- /3 - Tornando sua loja única/1 - Introdução/README.md: -------------------------------------------------------------------------------- 1 | # Tornando sua loja única 2 | 3 | ## Introdução 4 | De forma a torna a experiência de compra da loja única, é possível aplicar camadas de customização aos componentes já existentes, criar páginas customizadas, entre outras coisas. 5 | 6 | ## Sobre este curso 7 | Neste curso, serão abordados tópicos que envolvem a customização da loja a fim de torná-la única e que contemple a identidade visual da marca. 8 | 9 | É importante frisar que este é um de vários cursos elaborados com o intuito de apresentar todos os conceitos necessários para o desenvolvimento de uma loja totalmente funcional. Dessa forma, caso você já tenha feito os cursos anteriores, é provável que já tenha utilizado o repositório de um tema básico, chamado [Minimum Boilerplate Theme](https://github.com/vtex-apps/minimum-boilerplate-theme). 10 | 11 | Ao longo dos cursos anteriores, você deve ter utilizado blocos básicos e conceitos de _layout_ dentro do tema mencionado anteriormente para entender melhor como estes funcionam. Agora, neste curso, você irá aprender, dentre outras coisas, a customizá-los. Vamos lá? -------------------------------------------------------------------------------- /9 - Chamando as APIs de Commerce/1 - Introdução ao curso/README.md: -------------------------------------------------------------------------------- 1 | # Chamando APIs do VTEX Commerce pelo VTEX IO 2 | 3 | ## Introdução 4 | 5 | Neste curso você aprenderá alguns conceitos básicos sobre as **APIs de Commerce da VTEX** e também como usá-las em sua aplicação rodando no VTEX IO. 6 | 7 | ## Requerimentos 8 | 9 | - É importante que você tenha finalizado o **VTEX IO Service Course**, que explica como funcionam os serviços de _backend_ dentro do VTEX IO. 10 | - Esperamos também que você tenha aprendido o conceito de _Client_ nos serviços. 11 | 12 | ## O que você aprenderá? 13 | 14 | - Como encontrar as referências sobre as APIs de Commerce da VTEX. 15 | - Como se autenticar para realizar as chamadas às APIs. 16 | - Como reusar _Clients_ disponíveis na comunidade. 17 | - Como utilizar estes _Clients_ para fazer requisições em uma aplicação do VTEX IO. 18 | 19 | ## Atividade 20 | Para exercitarmos os conceitos aprendidos neste curso, é necessário que você tenha disponível localmente a app `vtex.service-example`, também utilizada no curso de Serviços. 21 | 22 | Portanto, caso você já não tenha essa aplicação no seu computador: 23 | 24 | 1. Clone o repositório `vtex-apps/service.example` com o comando: `git clone https://github.com/vtex-apps/service-example`. 25 | 2. Dentro da pasta da app, rode `vtex link` para verificar se a app builda normalmente. Você deve receber um link de uma rota pública que o código expõe. -------------------------------------------------------------------------------- /6 - Blocos customizados/1 - Introdução/README.md: -------------------------------------------------------------------------------- 1 | # Criando blocos customizados 2 | 3 | ## Introdução 4 | De forma a torna a experiência de compra da loja única, é possível aplicar camadas de customização aos componentes já existentes, criar páginas customizadas, entre outras coisas. 5 | 6 | ## Sobre esse curso 7 | Este curso irá guiá-lo no aprendizado de desenvolvimento de aplicações customizadas no VTEX IO. No fim, você terá uma _app_ completamente funcional, que é um bloco contador para sua loja. 8 | 9 | Há alguns pré-requisitos para que você tenha uma experiência gratificante ao fazer esse tutorial, que são: 10 | - Conhecimento em React e como utilizar _hooks_ 11 | - Conceitos básicos de GraphQL 12 | - Entender como desenvolver utilizando Typescript 13 | 14 | Se você não está familiarizado com alguma destas ferramentas, nós o encorajamos a dar uma olhada nas seguintes documentações: 15 | - [**React.js**](https://reactjs.org/) 16 | - [**React Hook API**](https:/**/reactjs.org/docs/hooks-intro.html) 17 | - [**Documentação de Typescript**](https://www.typescriptlang.org/) 18 | 19 | Para começar o curso, você deve utilizar o repositório _template_ que disponibilizamos com todos os arquivos iniciais que você precisa ter para começar. Você encontrará este repositório neste [link](https://github.com/vtex-trainings/store-block-template). 20 | 21 | > Se você ainda tem dúvidas em como utilizar um repositório _template_, você pode checar este [artigo](https://developers.vtex.com/page/como-utilizar-um-reposit%C3%B3rio-template). -------------------------------------------------------------------------------- /7 - Serviços/8 - GraphQL - Utilizando GraphiQL/README.md: -------------------------------------------------------------------------------- 1 | # GraphQL: Usando o GraphiQL 2 | 3 | ## Introdução 4 | 5 | Agora, como a _query_ e o _resolver_ implementados, precisamos utilizá-los para pegar as informações dos N produtos mais vistos. Utilizando a **IDE de GraphQL**, podemos testar a _query_ que implementamos anteriormente. 6 | 7 | ## GraphiQL 8 | 9 | [GraphiQL](https://github.com/graphql/graphiql) é uma ID interativa acessada através de um navegador. Antes de utilizar a _query_ na sua _app_, é interessante testar sua funcionalidade. Para fazer isso, vamos reproduzir o uso da _query_ na IDE do GraphQL. 10 | 11 | Explorando um pouco a interface da IDE, há três áreas principais: área de código, área das variáveis da _query_ e a área de _debug_. É possível checar onde cada área está na interfacr através da imagem abaixo: 12 | 13 | ![image](https://user-images.githubusercontent.com/43679629/83764107-e900ea80-a64f-11ea-969f-116ea896fe2d.png) 14 | 15 | ## Testando sua _query_ 16 | 17 | 1. Abra a rota do GraphiQL e digite o código abaixo na devida área na interface: 18 | 19 | ``` 20 | query ($topN: Int) { 21 | productList(topN: $topN){ 22 | slug 23 | count 24 | } 25 | } 26 | ``` 27 | 28 | 2. A _query_ que acabamos de declarar utiliza uma variável (_topN_). Agora, precisamos declará-la na área de variáveis: 29 | 30 | ``` 31 | { 32 | "topN": 2 33 | } 34 | ``` 35 | 36 | > :exclamation: A área de variáveis de _query_ se encontra abaixo da área de código. Para aumentar o seu tamanho, basta clicar no título e arrastar. 37 | 38 | 3. Por fim, basta clicar no botão de _play_ e checar a saída na área de _debug_. Os resultados da _query_ devem ser similares ao da imagem abaixo: 39 | 40 | ![image](https://user-images.githubusercontent.com/43679629/83763622-4c3e4d00-a64f-11ea-9615-435811d411c6.png) -------------------------------------------------------------------------------- /5 - Melhorando performance/5 - Melhorias na busca/README.md: -------------------------------------------------------------------------------- 1 | # Melhorias na busca 2 | 3 | Uma das operações mais pesadas e pouco performáticas na navegação de uma loja é a sua busca. Para melhorar a experiência, também podemos otimizar a busca por dados e torná-la mais eficiente, neste sentido dois pontos devem ser observados: os SKUs e o preço 4 | 5 | ## Atividade 6 | 7 | 1. Para otimizar o contexto da busca, adicione a propriedade `context` ao _template_ de busca no arquivo `store/blocks/search.jsonc`: 8 | 9 | ```diff 10 | // store/blocks/search.jsonc 11 | { 12 | "store.search": { 13 | + "props": { 14 | + "context": {} 15 | + }, 16 | "blocks": ["search-result-layout#search"] 17 | }, 18 | ... 19 | } 20 | ``` 21 | 22 | 2. Para garantir redução de resultados carregados e, portanto, tornar o volume de resultados menor. É possível controlar para que apenas o primeiro SKU disponível seja retornado, para isso, adicione no `context` o `skusFilter` como sendo `FIRST_AVAILABLE`: 23 | 24 | ```diff 25 | { 26 | "store.search": { 27 | "props": { 28 | "context": { 29 | + "skusFilter": "FIRST_AVAILABLE" 30 | } 31 | }, 32 | "blocks": ["search-result-layout#search"] 33 | }, 34 | } 35 | ``` 36 | 37 | 3. Para tornar os preços mais _cacheáveis_ e evitar simulá-los para cada resultado de busca obtido, podemos também escolher `skip` como `simulationBehavior`: 38 | 39 | ```diff 40 | { 41 | "store.search": { 42 | "props": { 43 | "context": { 44 | "skusFilter": "FIRST_AVAILABLE" 45 | + "simulationBehavior": "skip" 46 | } 47 | }, 48 | "blocks": ["search-result-layout#search"] 49 | }, 50 | } 51 | ``` 52 | 53 | 54 | ### Está com dúvidas? 55 | 56 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-performance-step05searching-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /4 - Site Editor e Conteúdo/1 - Conhecendo mais sobre workspaces/README.md: -------------------------------------------------------------------------------- 1 | # Conhecendo mais sobre _workspaces_ 2 | 3 | ## Introdução 4 | 5 | Workspaces são geralmente definidos como ambientes que são diferentes versões da mesma conta, de forma que quaisquer mudanças feitas em um _workspace_ não intereferem no trabalho de outros desenvolvedores. 6 | 7 | > _Workspaces_ são isolados uns dos outros. 8 | 9 | 10 | Há três diferentes tipos de _workspaces_: 11 | 12 | - Workspace de desenvolvimento: um ambiente onde é possível linkar, desenvolver, instalar e publicar aplicações. É um _workspace_ onde você tem mais liberdade nas configurações que irá fazer. Não lida com o tráfego de clientes de produção, não pode ser promovido a _master_ e nem pode ser utilizado para testes A/B; 13 | 14 | - _Workspace_ de produção: lida com tráfego de lojas em produção, pode ser utilizado para testes A/B e pode ser promovido ao _workspace master_. Não é permitido linkar aplicações; 15 | 16 | - _Workspace Master_: um _workspace_ de produção **único** em que o conteúdo dele reflete no que é apresentado ao usuário final da loja. 17 | 18 | ## Criando um _workspace_ de produção 19 | 20 | Neste passo, vamos criar um _workspace_ de produção e é tão simples quanto rodar o seguinte comando da nossa CLI: 21 | 22 | ``` 23 | vtex use {WorkspaceName} --production 24 | ``` 25 | 26 | > `WorkspaceName` é o nome que você quer utilizar para identificar seu _workspace_. 27 | 28 | Uma vez que você executa o comando, se o nome escolhido não existe, haverá uma pergunta se você deseja criar o _workspace_, como você pode ver na seguinte imagem: 29 | 30 | ![image](https://user-images.githubusercontent.com/19495917/88816710-0efbc480-d193-11ea-8918-1d595c7595f5.png) 31 | 32 | Neste caso, você precisa apenas digitar `y`: 33 | 34 | ![image](https://user-images.githubusercontent.com/19495917/88816914-4cf8e880-d193-11ea-9676-3647626a3236.png) 35 | 36 | Pronto! Seu _workspace_ de produção foi criado! De forma a verificar em que _workspace_ e conta você está, use o seguinte comando: 37 | 38 | ``` 39 | vtex whoami 40 | ``` -------------------------------------------------------------------------------- /4 - Site Editor e Conteúdo/4 - Apresentando o Site Editor e alterando um banner de uma loja/README.md: -------------------------------------------------------------------------------- 1 | # Apresentando o Site Editor 2 | 3 | ## Introdução 4 | 5 | O Site Editor é um painel que se encontra dentro da página de _admin_ de uma loja que permite você alterar propriedades dos blocos referentes à frente de loja. A página de _admin_ de sua loja pode ser acessada adicionando `/admin` na url. As mudanças que são feitas aqui são automaticamente refletidas na loja e todos os blocos que estão na frente de loja podem ser alterados através deste painel. Por exemplo, é possível alterar o conteúdo de um _rich text_, propriedades de uma prateleira, como as coleções sendo mostradas, entre outras coisas. 6 | 7 | ![site-editor](https://user-images.githubusercontent.com/19495917/90414123-c181c180-e085-11ea-91f0-cd5a70a3b803.png) 8 | 9 | ## Adicionando um _banner_ a um carrossel 10 | 11 | É possível adicionar um novo _banner_, como a promoção de uma data em especial, ou uma oferta que precisa ser promovida na página inicial. Dentro do Site Editor, utilizando uma loja de demonstração, vamos selecionar o carrossel que está na página inicial, como visto abaixo: 12 | 13 | ![banner](https://user-images.githubusercontent.com/19495917/90414209-deb69000-e085-11ea-8d7b-39a1b411f9af.png) 14 | 15 | Com o carrossel selecionado, há uma aba no lado direito da tela, que contém as propriedades do carrossel, como os _banners_. De forma a adicionar um novo, você precisa clicar em **Add**, ou **Adicionar**, escolher a imagem e fazer o _upload_ (você pode encontrar uma imagem para utilizar de exemplo neste [link](https://drive.google.com/file/d/12J1CkfRrr_ogHp3GJlwfOQZH2EVheVIp/view?usp=sharing)). Feito isso, será possível ver uma prévia de como o carrossel ficará! 16 | 17 | Você gostou? Se sim, apenas desça com o _scroll_ até o fim da aba na direita e clique em **Apply**, ou **Salvar**. Uma fez que isso é feito, a mudança será feita imediatamente na loja. 18 | 19 | ![banner-changed](https://user-images.githubusercontent.com/19495917/90414222-e24a1700-e085-11ea-9927-2534b4741af5.png) 20 | 21 | Vá até sua _home page_ e veja seu novo _banner_! -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/5 - Homogeneidade visual/README.md: -------------------------------------------------------------------------------- 1 | # Homogeneidade visual 2 | 3 | ## Introdução 4 | 5 | O Admin Framework existe para unificar canais e facilitar a vida do operador de loja. É importante, no entanto, que a experiência visual seja homogênea para evitar inconsistência de usabilidade. 6 | 7 | A fim de facilitar a integração visual para o desenvolvedor, o [Styleguide](https://styleguide.vtex.com), encontra-se disponível e com vários componentes que podem ser utilizados para criar rapidamente telas administrativas. 8 | 9 | ## Atividade 10 | 11 | 1. No passo 1, adicionamos o `vtex.styleguide` como dependência, importe o `Layout` e `PageBlock` do styleguide para que possamos usá-los: 12 | 13 | ``` 14 | import { Layout, PageBlock } from 'vtex.styleguide' 15 | ``` 16 | 17 | 2. Ambos estes componentes são responsáveis por criar o layout de admin que é utilizado pelas apps VTEX, você pode compô-los da seguinte forma: 18 | 19 | ``` 20 | import React, { FC } from 'react' 21 | import { Layout, PageBlock } from 'vtex.styleguide' 22 | 23 | const AdminExample: FC = () => { 24 | return ( 25 | 26 | 27 |

Hello, World!

28 |
29 |
30 | ) 31 | } 32 | 33 | export default AdminExample 34 | ``` 35 | 36 | 3. Vendo a documentação do [PageBlock](https://styleguide.vtex.com/#/Components/Admin%20structure/PageBlock), nós podemos enriquecê-lo para adicionar um título e uma descrição: 37 | 38 | ```diff 39 | import React, { FC } from "react"; 40 | import { Layout, PageBlock } from "vtex.styleguide"; 41 | 42 | const AdminExample: FC = () => { 43 | return ( 44 | 45 | 50 |

Hello, World!

51 |
52 |
53 | ); 54 | }; 55 | 56 | export default AdminExample; 57 | ``` 58 | 59 | O resultado esperado deve ser: 60 | 61 | ![image](https://user-images.githubusercontent.com/18701182/92802313-cc7df800-f38c-11ea-95a1-035948dbbc85.png) -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/3 - Melhorando a navegação/README.md: -------------------------------------------------------------------------------- 1 | # Melhorando a navegação 2 | 3 | ## Introdução 4 | 5 | O `navigation.json` tem uma série de funcionalidades que podem melhorar a relevância e navegação da sua aplicação, neste passo aprenderemos como definir uma mensagem de título e criar _keywords_. 6 | 7 | ## Atividade 8 | 9 | 1. No passo anterior usamos o `titleId`: `admin-example.navigation.label`, para atribuir um valor textual a essa chave, precisamos na pasta messages, nos três arquivos de idioma, escrever o valor correspondente: 10 | 11 | /messages/pt.json 12 | ``` 13 | { 14 | "admin-example.navigation.label": "Treinamento de IO" 15 | } 16 | ``` 17 | 18 | /messages/en.json 19 | ``` 20 | { 21 | "admin-example.navigation.label": "IO Training" 22 | } 23 | ``` 24 | 25 | /messages/es.json 26 | ``` 27 | { 28 | "admin-example.navigation.label": "Entrenamiento de IO" 29 | } 30 | ``` 31 | 32 | Feito isso, conseguimos agora ver uma mensagem traduzível para o menu que criamos: 33 | 34 | ![image](https://user-images.githubusercontent.com/18701182/92776306-85d0d380-f375-11ea-84b1-da5321b89538.png) 35 | 36 | 2. Adicione keywords para tornar mais simples a busca pela sua aplicação: 37 | 38 | /admin/navigation.json 39 | ```diff 40 | { 41 | ... 42 | + "searchKeyWordsHelpers": "admin-example.navigation.search.kws" 43 | } 44 | ``` 45 | 46 | 3. Analogamente, crie as mensagens para as _keywords_, separadas por vírgulas: 47 | 48 | /messages/pt.json 49 | ```diff 50 | { 51 | "admin-example.navigation.label": "Treinamento de IO", 52 | + "admin-example.navigation.search.kws": "mock, test, treinamento, io" 53 | } 54 | ``` 55 | 56 | /messages/en.json 57 | ```diff 58 | { 59 | "admin-example.navigation.label": "IO Training", 60 | + "admin-example.navigation.search.kws": "mock, test, training, io" 61 | } 62 | ``` 63 | 64 | /messages/es.json 65 | ```diff 66 | { 67 | "admin-example.navigation.label": "Entrenamiento de IO", 68 | + "admin-example.navigation.search.kws": "mock, test, entrenamiento, io" 69 | } 70 | ``` 71 | 72 | ![image](https://user-images.githubusercontent.com/18701182/92777236-65eddf80-f376-11ea-9c07-fac14f5d5172.png) -------------------------------------------------------------------------------- /2 - Layouts Complexos/1 - Apresentando blocos de layout/README.md: -------------------------------------------------------------------------------- 1 | # Apresentando blocos de layout 2 | 3 | ## Introdução 4 | 5 | Em cursos anteriores vimos como usar blocos básicos do Store Framework que trazem funcionalidade, mas que em geral são muito simples para serem usados em um layout real de loja. 6 | 7 | O mínimo que precisamos quando construímos um _template_ é definir um _grid_, ou seja, conseguir dispor blocos um ao lado do outro, mas há ainda muitas outros _layouts_ mais complexos que em geral precisam ser atingidos: abas, modais, empilhados, etc. 8 | 9 | Neste curso aprenderemos como é possível usar alguns dos blocos de _layout_ e entender melhor cada uma das peculiaridades. 10 | 11 | ## Padrão entre _layouts_ 12 | 13 | Apesar de cada bloco de _layout_ ter sua funcionalidade, a ideia por trás de todos é muito parecida. Todos eles dependem fortemente do conceito de `children`, ou seja, de receberem blocos filhos e definirem a regra de renderização. É também comum aos blocos de _layout_ apresentar algumas regras de formatação mas que sempre culminam em usar qualquer bloco filho, garantindo assim a flexibilidade em atingir o template desejado. 14 | 15 | ```json 16 | { 17 | "layout-block": { 18 | "children": [ 19 | "qualquer-coisa" 20 | ] 21 | } 22 | } 23 | ``` 24 | *Exemplo da ideia de todos os blocos de layout* 25 | 26 | ## Atividade 27 | 28 | Para que o curso funcione bem, é preciso adicionar as dependências de _apps_ de _layout_ que vamos precisar. 29 | 30 | 1. Vá ao `manifest.json` do seu tema e adicione as seguintes dependências: 31 | 32 | ```diff 33 | { 34 | ... 35 | "dependencies": { 36 | ... 37 | + "vtex.condition-layout": "1.x", 38 | + "vtex.store-link": "0.x", 39 | + "vtex.modal-layout": "0.x", 40 | + "vtex.product-price": "1.x", 41 | + "vtex.stack-layout": "0.x", 42 | + "vtex.tab-layout": "0.x", 43 | + "vtex.responsive-layout": "0.x", 44 | + "vtex.slider-layout": "0.x", 45 | } 46 | } 47 | ``` 48 | 49 | 50 | ### Está com dúvidas? 51 | 52 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step01introducing-layout-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/7 - Quick view/README.md: -------------------------------------------------------------------------------- 1 | # Quick View 2 | 3 | ## Introdução 4 | 5 | Seguiremos os conceitos aprendidos no passo anterior e vamos aprofundar um pouco mais para aprender como construir o comportamento de _Quick View_ em uma prateleira de produtos. 6 | 7 | ## Atividade 8 | 9 | 1. Adicione uma prateleira na sua página inicial: 10 | 11 | ```diff 12 | { 13 | "store.home": { 14 | "blocks": [ 15 | ... 16 | + "list-context.product-list" 17 | ] 18 | }, 19 | + "list-context.product-list": { 20 | + "blocks": ["product-summary.shelf"], 21 | + "children": ["slider-layout"] 22 | + }, 23 | + "product-summary.shelf": { 24 | + "children": [ 25 | + "product-summary-name", 26 | + "product-selling-price" 27 | + ] 28 | + } 29 | } 30 | ``` 31 | 32 | 2. No `product-summary` adicione um _trigger_ para o modal: 33 | 34 | ```diff 35 | { 36 | ... 37 | "product-summary.shelf": { 38 | "children": [ 39 | + "modal-trigger#quickview", 40 | "product-summary-name", 41 | "product-selling-price" 42 | ] 43 | } 44 | } 45 | ``` 46 | 47 | 3. Vamos, então, fazer com que o _trigger_ para o modal seja a imagem do produto e definir que usaremos um _layout_: 48 | 49 | ```diff 50 | { 51 | ... 52 | "product-summary.shelf": { 53 | "children": [ 54 | "modal-trigger#quickview", 55 | "product-summary-name", 56 | "product-selling-price" 57 | ] 58 | }, 59 | + "modal-trigger#quickview": { 60 | + "children": ["product-summary-image", "modal-layout#quickview"] 61 | + } 62 | } 63 | ``` 64 | 65 | 4. Para fechar vamos definir um simples modal com algumas opções de produto: 66 | 67 | ```diff 68 | { 69 | ... 70 | + "modal-layout#quickview": { 71 | + "children": [ 72 | + "product-summary-name", 73 | + "product-images", 74 | + "product-summary-sku-selector", 75 | + "product-summary-quantity", 76 | + "add-to-cart-button" 77 | + ] 78 | + } 79 | } 80 | ``` 81 | 82 | O resultado, então, deve ser: 83 | 84 | ![modallayout](https://user-images.githubusercontent.com/18701182/90278764-585c3d00-de3e-11ea-8fa9-491a1cfd6001.gif) 85 | 86 | 87 | 88 | ### Está com dúvidas? 89 | 90 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step07quick-view-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /4 - Site Editor e Conteúdo/2 - Publicando uma aplicação no VTEX IO/README.md: -------------------------------------------------------------------------------- 1 | # Publicando uma _app_ no VTEX IO 2 | 3 | ## Introdução 4 | Após ser apresentado ao conceitos dos diferentes tipos de _workspaces_, vamos então ensinar como publicar uma aplicação no VTEX IO. Para realizar operações como esta, são utilizados comandos no [VTEX Toolbelt](https://developers.vtex.com/docs/vtex-io-documentation-toolbelt), nossa CLI que dá acesso aos recursos da plataforma. 5 | 6 | ## Usando o VTEX Toolbelt para publicar uma _app_ 7 | 8 | Para publicar uma _app_ no VTEX IO, é necessário utilizar o seguinte comando do VTEX Toolbelt, dentro da pasta da aplicação: 9 | 10 | ``` 11 | vtex publish 12 | ``` 13 | 14 | > Qual aplicação vamos publicar? 15 | 16 | Ao fim do curso de Store Framework, você desenvolveu uma loja completamente funcional e é justamente essa _app_ que você irá publicar. 17 | 18 | > E se eu não fiz o curso de Store Framework? 19 | 20 | Não se preocupe, para este passo, você pode pegar qualquer tema que você já tenha e publicá-lo. Caso você ainda não tenha, pode voltar nos nossos cursos para criar um! 21 | 22 | Com uma aplicação de um tema qualquer, vá ao arquivo `manifest.json` e mude o nome da _app_ para o seguinte formato: 23 | ``` 24 | trainingweek-{{devname}} 25 | ``` 26 | onde `devname` é um nome de sua escolha, que te identifique. Além disso, é necessário mudar o _vendor_ da aplicação, que **precisará** ser `appliancetheme`. 27 | 28 | Abaixo, você pode encontrar um exemplo de parte do `manifest.json` feitas as mudanças citadas acima: 29 | ```json 30 | { 31 | "vendor": "appliancetheme", 32 | "name": "trainingweek-fabiana", 33 | ... 34 | } 35 | ``` 36 | Ao fim desses passos, vamos efetivamente publicar a _app_! Dentro do diretório da sua _app_, rode o comando mencionado no início deste passo. Dentro da pasta da aplicação, rode o comando que foi citado anteriormente, no início deste passo. Ao rodar o comando, você precisará confirmar a ação, como você pode ver na imagem abaixo: 37 | 38 | ![image](https://user-images.githubusercontent.com/19495917/88819289-2d16f400-d196-11ea-8cb6-f86a902c4887.png) 39 | 40 | Após a confirmação, o _build_ da _app_ começará e, após ser finalizado, você deverá ver uma mensagem informando que a publicação foi bem sucedida: 41 | 42 | ![image](https://user-images.githubusercontent.com/19495917/88824809-3061ae00-d19d-11ea-86c1-4118bf609ec3.png) 43 | 44 | Pronto! Você acabou de fazer sua primeira publicação! -------------------------------------------------------------------------------- /3 - Tornando sua loja única/5 - Explorando o poder do rich text/README.md: -------------------------------------------------------------------------------- 1 | # Explorando o poder do rich text 2 | 3 | ## Introdução 4 | 5 | [Markdown](https://www.markdownguide.org/) é uma linguagem de marcação amigável que pode ser convertida de maneira simples para HTML. Nesta lição, veremos como é possível utilizar esta linguagem em nosso bloco [**Rich Text**](https://developers.vtex.com/docs/vtex-rich-text) para customizá-los e criar textos interessantes. 6 | 7 | ## Rich Text com Markdown 8 | 9 | Para incluir textos no bloco de `rich-text`, é necessário utilizar a prop `text`: 10 | 11 | ```json 12 | "rich-text#home1": { 13 | "props": { 14 | "text": "Meu texto", 15 | "textPosition": "LEFT", 16 | "textAlignment": "LEFT" 17 | } 18 | } 19 | ``` 20 | 21 | A prop `text` aceita o formato de markdown. Portanto, se você deseja escrever seu texto utilizando essa linguagem, seu código deve ficar semelhante a este: 22 | 23 | ```json 24 | "rich-text#home1": { 25 | "props": { 26 | "text": "# Meu título h1 \n Escreva aqui um parágrafo \n ## Meu título h2 \n Escreva aqui seu segundo parágrafo \n Inclua aqui uma lista \n - Item 1 \n - Item 2 \n - Item3", 27 | "textPosition": "LEFT", 28 | "textAlignment": "LEFT" 29 | } 30 | } 31 | ``` 32 | 33 | >**Dica**: Sempre utilize o comando `\n` para pular linhas ao utilizar markdown na prop `text`. 34 | 35 | Outras propriedades do componente `rich-text` podem ser encontrados na [documentação oficial do Store Framework](https://developers.vtex.com/docs/vtex-rich-text). 36 | 37 | ## Alterando o estilo e o conteúdo do _rich text_ através de Markdown 38 | 39 | 1. Dentro do arquivo `about-us.jsonc`, troque o texto da `rich-text#about-content` para que `This is VTEX Minimum Theme` se torne um _header_ pequeno (`h3`). Assegure-se que você quebre uma linha depois desse trecho com `\n`; 40 | 41 | 2. Coloque o trecho `VTEX Minimum Theme` em itálico. 42 | 43 | Este é o resultado esperado: 44 | 45 | ![image](https://user-images.githubusercontent.com/19495917/90180384-410d4900-dd85-11ea-88b9-3af68e8f3a08.png) 46 | 47 | Note: Lembre-se de acessar a [documentação](https://developers.vtex.com/docs/vtex-rich-text) do Rich Text caso tenha alguma dúvida durante a atividade. 48 | 49 | 50 | ### Está com dúvidas? 51 | 52 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-styles-course-step04richtextmarkdown-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/6 - Layout modal/README.md: -------------------------------------------------------------------------------- 1 | # Layout modal 2 | 3 | ## Introdução 4 | 5 | Também é possível, com o Store Framework, criar uma experiência de modais na loja. Seja para se inscrever em uma _newsletter_ ou criar um _quick view_, o Modal Layout funciona como todos os outros blocos de _layout_, em que qualquer bloco pode ser usado como seu conteúdo. 6 | 7 | Neste passo, vamos, então, construir um modal mais simples, para, em seguida, construirmos um _Quick View_ funcional. 8 | 9 | ### Um pouco mais sobre como o Modal Layout funciona 10 | 11 | O bloco de Modal Layout divide a sua lógica em dois sub-blocos: `modal-trigger` e `modal-layout`. 12 | 13 | O `modal-trigger` é usado para que seja escolhido qual bloco deve ser o responsável por disparar o comportamento de modal, você poderia usar uma imagem, um texto, _link_ ou o bloco que preferir. 14 | 15 | O `modal-layout` define quais blocos filhos serão usados dentro do modal. É, portanto, nesse bloco, que o conteúdo do modal em si, deve ser colocado. 16 | 17 | ## Atividade 18 | 19 | 1. Na sua home, adicione um `modal-trigger#first` aos blocos: 20 | 21 | ``` 22 | { 23 | "store.home": { 24 | "blocks": [ 25 | ... 26 | "modal-trigger#first" 27 | ] 28 | } 29 | } 30 | ``` 31 | 32 | 2. Defina, então, o `modal-trigger#first` com um texto de _Click Me_: 33 | 34 | ``` 35 | { 36 | ... 37 | "modal-trigger#first": { 38 | "children": [ 39 | "rich-text#trigger" 40 | ] 41 | }, 42 | "rich-text#trigger": { 43 | "props": { 44 | "text": "CLICK ME" 45 | } 46 | } 47 | } 48 | ``` 49 | 50 | 3. Coloque nos filhos do `modal-trigger#first` o `modal-layout#first`: 51 | 52 | ```diff 53 | { 54 | ... 55 | "modal-trigger#first": { 56 | "children": [ 57 | "rich-text#trigger", 58 | + "modal-layout#first" 59 | ] 60 | }, 61 | ... 62 | + "modal-layout#first": { 63 | + "children": [ 64 | + "rich-text#hello" 65 | + ] 66 | + }, 67 | + "rich-text#hello": { 68 | + "props": { 69 | + "text": "Hello" 70 | + } 71 | + } 72 | ... 73 | } 74 | ``` 75 | 76 | O resultado, então, deve ser: 77 | 78 | ![modal gif](https://user-images.githubusercontent.com/18701182/90183287-9f3c2b00-dd89-11ea-924d-6195465ffd25.gif) 79 | 80 | 81 | ### Está com dúvidas? 82 | 83 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step06modal-layout-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /7 - Serviços/5 - Utilizando eventos como gatilhos/README.md: -------------------------------------------------------------------------------- 1 | # Utilizando eventos como gatilhos 2 | 3 | ## Introdução 4 | 5 | Com o cliente de _analytics_ implementado, nós queremos utilizar os eventos como gatilhos para os _requests_. Isso significa que, para cada evento escutado, queremos fazer um _request_ para a _app_ de _analytics_, de forma que, a cada X segundos, tenhamos novos dados em **Live Products**. 6 | 7 | ## Eventos 8 | 9 | No VTEX IO, eventos são usualmente utilizados como gatilhos para outras ações, como enviar emails para o cliente final. Para implementar isto, é necessário configurar nossa a _app_ do cliente e o _handler_ de eventos. 10 | 11 | ## Usando eventos como gatilhos para fazer um _request_ 12 | 13 | 1. Com o cliente de _analytics_ implementado, precisamos apenas utilizá-lo no _handler_ de eventos. Primeiro, no arquivo `node/event/liveusersUpdate.ts`, importe o cliente que implementados no passo anterior: 14 | 15 | ```ts 16 | import { Clients } from '../clients/index' 17 | ``` 18 | 19 | 2. Agora, precisamos utilizar o `EventContext` que foi configurado previamente. Importe-o atualizando o método. É possível fazer como abaixo: 20 | 21 | ```diff 22 | //node/event/liveUsersUpdate.ts 23 | import { Clients } from './../clients/index' 24 | +import { EventContext } from '@vtex/api' 25 | 26 | +export async function updateLiveUsers(ctx: EventContext) { 27 | ... 28 | } 29 | ``` 30 | 31 | > Nota: você também pode declarar globalmente seu contexto de evento, através do arquivo `/node/index.ts`. Se você fizer desta forma, não é necessário importá-lo em cada arquivo que você precise utilizá-lo. 32 | 33 | 3. Agora, para utilizar o cliente de _analytics_, faça o seguinte: 34 | 35 | ```diff 36 | //node/event/liveUsersUpdate.ts 37 | export async function updateLiveUsers(ctx: EventContext) { 38 | + const liveUsersProducts = await ctx.clients.analytics.getLiveUsers() 39 | + console.log('LIVE USERS: ', liveUsersProducts) 40 | + return true 41 | } 42 | ``` 43 | 44 | 4. Finalmente, rode o comando `vtex link` e, para cada evento disparado, você deve ver os dados pegos do _analytics_. O resultado é similar ao da imagem abaixo: 45 | ![image](https://user-images.githubusercontent.com/43679629/85150833-69ffda80-b229-11ea-9260-b9255adf7d9c.png) 46 | 47 | 48 | ### Está com dúvidas? 49 | 50 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-service-course-step05events-triggers-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /7 - Serviços/1 - Serviços no VTEX IO/README.md: -------------------------------------------------------------------------------- 1 | # Serviços no VTEX IO 2 | 3 | ## Introdução 4 | 5 | A plataforma do VTEX IO permite que desenvolveores criem experiências de comércio únicas, utilizando tecnologias _Web_. É possível criar blocos de _frontend_ para o Store Framework, serviços de _backend_ que expõem APIS REST ou de GraphQL e combina uma série de módulos da VTEX numa solução completa, juntando-as em uma _app_. 6 | 7 | Dado que o VTEX IO alavanca grandes operações de _e-commerce_, é necessário ter seus códigos rodando em um servidor. Serviços são a maneira de rodar códigos em Node.js ou .NET na infrastrutura do VTEX IO, apoiado por abstrações de APIs de forma a melhorar a experiência do desenvolvedor. 8 | 9 | ## Serviços 10 | 11 | Um **Serviço** precisa ser exportado de uma _app_ no VTEX IO, assim como temas ou blocos de loja, utilizando _builders_ `node` ou `dotnet`. Com estes, você está apto a desenvolver uma API REST sem a obrigação de configurar um servidor, APIs de GraphQL e rotas. 12 | 13 | Os serviços no VTEX IO suportam _rollbacks_ feitos através de apenas um comando e integração contínua. Podem exportar rotas internas ou externas e rodam em Kubertnets. 14 | 15 | Dentro da pasta `/node` de um serviço, há um arquivo chamado `service.json`, onde é possível **declarar rotas que o serviço precisa responder** e outras configurações, como _timeout_ e _memory_. 16 | 17 | Durante este curso, você irá implementar alguns serviços no VTEX IO e aprenderá um pouco mais sobre as possibilidades que eles oferecem para desenvolvimento. 18 | 19 | ## Sobre este curso 20 | Este curso irá guiá-lo no aprendizado de desenvolvimento de aplicações de serviço no VTEX IO. Há alguns pré-requisitos para que você tenha uma experiência gratificante ao fazer esse curso, que são: 21 | - Conceitos básicos de GraphQL 22 | - Entender como desenvolver utilizando Typescript 23 | 24 | Se você não está familiarizado com alguma destas ferramentas, nós o encorajamos a dar uma olhada nas seguintes documentações: 25 | - [**Documentação de Typescript**](https://www.typescriptlang.org/) 26 | - [**GraphQL documentation**](https://graphql.org/learn/) 27 | 28 | Para começar o curso, você deve utilizar o repositório _template_ que disponibilizamos com todos os arquivos iniciais que você precisa ter para começar. Você encontrará este repositório neste [link](https://github.com/vtex-trainings/service-course-template). 29 | 30 | > Se você ainda tem dúvidas em como utilizar um repositório _template_, você pode checar este [artigo](https://developers.vtex.com/page/como-utilizar-um-reposit%C3%B3rio-template). -------------------------------------------------------------------------------- /1 - Blocos Básicos/README.md: -------------------------------------------------------------------------------- 1 | # Configurações 2 | 3 | ## Introdução 4 | 5 | Antes de colocar as mãos na massa e aprender mais sobre o Store Framework no VTEX IO, você precisará definir algumas configurações básicas, como: 6 | 7 | * Instalação do Git; 8 | * Instalação do Toolbelt; 9 | * Login em uma conta VTEX; 10 | * Criação de um workspace de desenvolvimento; 11 | * Vinculando seus arquivos locais à plataforma. 12 | 13 | Dê uma olhada no passo a passo abaixo para cada uma dessas configurações: 14 | 15 | ## Instalando o Git 16 | 17 | Instale o Git em seu computador clicando no link abaixo e selecionando seu sistema operacional (Windows, MAC ou Linux): 18 | 19 | 20 | 21 | ## Instalando o Toolbelt 22 | Toolbelt é uma ferramenta VTEX de linha de comando. Ele permite que você execute qualquer atividade na plataforma, como criar um novo workspace de desenvolvimento, fazer login em uma conta VTEX, desenvolver novas aplicações ou gerenciar os já existentes, etc. 23 | 24 | Uma vez que é o Toolbelt que estabelece a comunicação entre o desenvolvedor e a plataforma, você precisará dele para realizar todas as atividades propostas durante esse e os outros cursos. 25 | 26 | ## Instale o Node.js. 27 | 28 | Se você estiver usando um MAC, instale também Yarn; 29 | Execute `npm i -g vtex` em seu terminal se estiver usando Windows ou `yarn global add vtex` se estiver usando MAC; 30 | Você pode executar `vtex-v` (Windows) ou `vtex` (MAC) para confirmar se a instalação do Toolbelt foi conforme o esperado. 31 | 32 | Depois de instalado com sucesso, a próxima etapa é fazer login em uma conta VTEX. 33 | 34 | ## Fazendo login 35 | Execute `vtex login appliancetheme` em seu terminal, durante esse treinamento, usaremos essa conta para o desenvolvimento. 36 | 37 | Depois de fazer login, execute `vtex whoami` para confirmar a conta e a área de trabalho em que você se encontra. 38 | 39 | Os workspaces nada mais são do que o que o homônimo sugere. No VTEX IO, as contas têm três tipos principais de workspace, a saber master, produção e desenvolvimento. 40 | 41 | O próximo passo é criar um workspace de desenvolvimento, que permitirá que você brinque com as configurações ao longo do curso sem alterar a versão pública final da loja. 42 | 43 | ## Criação de um workspace de desenvolvimento 44 | Execute `vtex use workspace-name`, substituindo workspace-name pelo nome desejado. Use um nome único para seu workspace. 45 | 46 | ## Acessando seu workspace 47 | Depois de criar o workspace, você poderá acessá-lo neste link: https://{workspace}-{conta}.myvtex.com, substituindo{workspace}e{conta}com o nome do workspace e conta criados anteriormente. Por exemplo, -------------------------------------------------------------------------------- /4 - Site Editor e Conteúdo/3 - Instalando uma app em uma conta VTEX/README.md: -------------------------------------------------------------------------------- 1 | # Instalando uma _app_ no VTEX IO 2 | 3 | ## Introdução 4 | 5 | Uma vez que você publica uma _app_, é possível instalá-la em uma conta VTEX. Em geral, depois de instalar, há um robô chamado _House Keeper_, que se assegura de que todas as contas VTEX se mantenham com as _apps_ atualizadas com a versão mais recente. Versões _minors_ e _patches_ que são lançadas, são automaticamente atualizadas nas contas. 6 | 7 | Porém, para instalar uma _app_ pela primeira vez ou uma nova versão _major_, é necessário que seja feito manualmente. Neste passo, você aprenderá como fazer isso. 8 | 9 | ## Instalando a app 10 | 11 | Como no passo anterior, é necessário apenas um único comando para instalar uma _app_ em uma conta específica. Há duas possíveis situações para isso: 12 | 13 | - Você não tem o repositório raiz do projeto da _app_, mas você sabe o _vendor_, o nome da _app_ e também a versão que você gostaria de instalar; 14 | - Você não tem o projeto da aplicação no seu computador. 15 | 16 | No primeiro caso, você pode instalá-la rodando o seguinte comando: 17 | ``` 18 | vtex install {vendor}.{appName}@{version} 19 | ``` 20 | 21 | Já no caso de ter projeto da _app_, você precisar ir na pasta do projeto e rodar o seguinte comando: 22 | ``` 23 | vtex install 24 | ``` 25 | 26 | > Em ambos os casos, você precisa ter certeza que está na conta correta, na qual você quer instalar a aplicação. 27 | 28 | Considerando o caso que temos neste passo - tendo o projeto da _app_ - é tão simples como rodar o segundo comando que foi mencionado anteriormente. 29 | 30 | Em primeiro lugar, tenha certeza de que está na conta correta, utilizando o comando `vtex whoami`; você irá instalar a _app_ na conta `appliancetheme`. Ao rodar o comando, o resultado deve ser similar a imagem abaixo: 31 | 32 | ![image](https://user-images.githubusercontent.com/19495917/88828271-62750f00-d1a1-11ea-89d0-068340f8b522.png) 33 | 34 | Agora, vá até a pasta correta, que é a do projeto da _app_, e rode o seguinte comando: 35 | 36 | ``` 37 | vtex install 38 | ``` 39 | 40 | Após executá-lo, é esperado que você veja uma mensagem que constata que a _app_ foi instalada com sucesso, como a imagem abaixo: 41 | 42 | ![image](https://user-images.githubusercontent.com/19495917/88828538-c0095b80-d1a1-11ea-86cf-bac9cfdf554e.png) 43 | 44 | Dica: se você quer listar as _apps_ que estão atualmente instaladas em uma conta, você pode utilizar o comando `vtex ls`, você verá uma lista semelhante a seguinte imagem: 45 | 46 | ![image](https://user-images.githubusercontent.com/19495917/88828816-1e363e80-d1a2-11ea-88bb-b3f082b90877.png) 47 | 48 | > **Atenção**: Há mais informação ao rodar o comando mencionado acima, mas foi omitida da imagem devido a sua extensão. -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/2 - Navigation & Routes/README.md: -------------------------------------------------------------------------------- 1 | # Navigation & Routes 2 | 3 | ## Introdução 4 | 5 | Um dos pontos altos de uma boa aplicação de admin é garantir que está bem posicionada e que sua navegação é simples. Para controlar a navegação no menu lateral do admin VTEX existem dois arquivos que serão úteis: o `navigation.json` e o `routes.json`. 6 | 7 | ## navigation.json 8 | 9 | O navigation é o arquivo que define as regras de navegação na barra lateral do admin VTEX. Com ele você pode construir desde um link mais simples, em que um clique leva para sua app, como construir menus mais complexos com submenus associados. 10 | 11 | ![image](https://user-images.githubusercontent.com/18701182/92757455-21f1df00-f364-11ea-8798-87f8f73863c8.png) 12 | 13 | 14 | ## routes.json 15 | 16 | O routes é quem define as rotas e componentes react associados, da sua aplicação, qualquer componente que esteja mapeado para uma rota, deve ser declarado no routes, ainda que não esteja diretamente associado a um item de navegação no `navigation.json`. 17 | 18 | ## Atividade 19 | 20 | 1. Dentro da pasta `admin/` criada no passo anterior, crie mais dois arquivos, o `navigation.json` e o `routes.json` 21 | 22 | ```diff 23 | |_ admin/ 24 | + |_ navigation.json 25 | + |_ routes.json 26 | ``` 27 | 28 | 2. No `navigation.json` crie um _json_ com as propriedades `section`, `titleId` e `path`: 29 | 30 | ``` 31 | { 32 | "section": "orders", 33 | "titleId": "admin-example.navigation.label", 34 | "path": "/admin/iotraining" 35 | } 36 | ``` 37 | 38 | 3. No `routes.json` atribua um `component` e um `path` para a navegação criada: 39 | 40 | ``` 41 | { 42 | "admin.app.example": { 43 | "component": "adminExample", 44 | "path": "/admin/app/iotraining" 45 | } 46 | } 47 | ``` 48 | 49 | **NOTA:** O mapeamento de um *navigation* para uma *route* é feito através do path. O path deve divergir apenas por um `/app/` no routes.json 50 | 51 | ``` 52 | //navigation.json 53 | 54 | /admin/{{seupath}} 55 | 56 | //routes.json 57 | 58 | /admin/app/{{seupath}} 59 | ``` 60 | 61 | 4. Para finalizar, crie um componente simples de hello world com o mesmo nome que você deu para o `component` no `routes.json` 62 | 63 | ```tsx 64 | //react/adminExample.tsx 65 | import React, { FC } from 'react' 66 | 67 | const AdminExample: FC = () => { 68 | return

Hello, World!

69 | } 70 | 71 | export default AdminExample 72 | ``` 73 | 74 | Link a aplicação (`vtex link`). O resultado deve ser o seguinte: 75 | 76 | ![image](https://user-images.githubusercontent.com/18701182/92773790-486b4680-f373-11ea-8d1b-c4b84dad4375.png) 77 | 78 | Repare que o menu criado está sem nenhuma mensagem ainda, nós o evoluiremos posteriormente, clique no espaço em branco mostrado acima para ver a mensagem de `Hello, World!`. -------------------------------------------------------------------------------- /5 - Melhorando performance/1 - Melhorando load inicial/README.md: -------------------------------------------------------------------------------- 1 | # Melhorando load inicial 2 | 3 | ## Introdução 4 | 5 | A performance é um ponto cada vez mais crítico na criação de uma loja e, para garantir que seu tema está dentro das nossas melhores práticas de otimização, criamos este curso totalmente voltado para pontos de melhoria em um tema. 6 | 7 | Para este curso, podemos usar um tema já completo para focarmos apenas em pontos de melhoria. 8 | 9 | Clone o repositório: 10 | [https://github.com/vtex-apps/demostore-theme](https://github.com/vtex-apps/demostore-theme) 11 | 12 | ``` 13 | git clone https://github.com/vtex-apps/demostore-theme 14 | ``` 15 | 16 | ## Bloco de fold 17 | 18 | Nem todo conteúdo de uma página precisa ser carregado de primeira. Inicialmente quando um usuário entra na loja existe um limite do quanto este consegue ver. É por isso que com o bloco de `__fold__` você consegue controlar o que inicialmente será visto, diminuindo assim a necessidade de carregamento de dados no *load* inicial. Automaticamente, o que fica abaixo do `__fold__` é então carregado depois que o essencial já estiver disponível e o usuário começar a *scroll*ar para baixo. 19 | 20 | 21 | 22 | ## Atividade 23 | 24 | 1. Rode um `vtex workspace reset` garantindo que nenhum outro tema está linkado na loja 25 | 26 | 2. Vá até o diretório do repositório clonado e *link*e, então, o tema oferecido: 27 | 28 | ``` 29 | vtex link 30 | ``` 31 | 32 | Você deve ver a seguinte loja: 33 | 34 | ![screencapture-savioperformance-appliancetheme-myvtex-2020-09-21-19_42_00](https://user-images.githubusercontent.com/18701182/93828834-91a87980-fc42-11ea-9f84-dd3053822621.png) 35 | 36 | 37 | 3. O conteúdo abaixo da prateleira de *Clearance* não pode ser visto pelo usuário, vamos então otimizar o primeiro carregamento, postergando o *fetching* deste. Para isso, no arquivo `home.jsonc` no diretório `/store/blocks/home/` adicione o bloco `__fold__` logo abaixo do `"shelf#clearance"`: 38 | 39 | ```diff 40 | "store.home": { 41 | "blocks": [ 42 | "flex-layout.row#slider", 43 | "shelf#new-arrivals", 44 | "shelf#clearance", 45 | + "__fold__", 46 | "flex-layout.row#newsletter", 47 | "rich-text#brands", 48 | "flex-layout.row#brands", 49 | "rich-text#instagram", 50 | "flex-layout.row#instagram" 51 | ] 52 | } 53 | ``` 54 | 55 | No seu navegador, então, rode um CTRL(Cmd) + `-` (dando um zoom out para conseguir enxergar toda a página) e perceba que tudo que está abaixo da `Clearance` é carregado posteriormente (assim que o *scroll* é executado) ao que está acima: 56 | 57 | ![image](https://user-images.githubusercontent.com/18701182/93830718-5fe5e180-fc47-11ea-9caf-f7b8a10b0a23.png) 58 | 59 | 60 | 61 | 62 | ### Está com dúvidas? 63 | 64 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-performance-step01fold-block-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /9 - Chamando as APIs de Commerce/3 - Importando Clients do pacote VTEX/README.md: -------------------------------------------------------------------------------- 1 | # Importando um Client em sua aplicação 2 | 3 | ## Introdução 4 | 5 | Neste passo você aprenderá como buscar _Clients_ já prontos que abstraem as APIs de Core Commerce, além de como importá-los para sua app no VTEX IO. Importaremos o _Client_ `Catalog` que permitirá que busquemos detalhes sobre um SKU dentro da plataforma VTEX. 6 | 7 | ## Clients 8 | 9 | *Clients*, no VTEX IO, são abstrações para serviços externos e são usados nativamente para fazermos requisições externas em serviços de _backend_. Você pode ler um pouco sobre eles [aqui](https://www.notion.so/How-to-use-and-create-Clients-on-VTEX-IO-1dbd20c928c642d0ba059d5efbe7874b). 10 | 11 | ## VTEX IO Commerce Clients 12 | 13 | O pacote [Commerce Clients](https://github.com/vtex/commerce-io-clients/blob/master/src/clients/catalog.ts) é uma biblioteca Typescript que oferece vários **clients já configurados** para acessar as APIs de Core Commerce da VTEX. Para usá-lo em sua app, basta instalá-lo na pasta `node/` rodando: 14 | 15 | `yarn add @vtex/clients` 16 | 17 | ## Custom Clients 18 | 19 | Caso você não encontre o _Client_ que você deseja para um serviço de Core Commerce da VTEX, recomendamos que você **envie um Pull Request** para o repositório `commerce-clients`. Ficaremos felizes em revisar e, eventualmente, mergear sua contribuição. 20 | 21 | Mas, caso o serviço que você esteja tentando acessar seja um provedor externo (ex: API do Here Maps), recomendamos que você crie o _Client_ na sua própria app seguindo [estes passos](https://www.notion.so/How-to-use-and-create-Clients-on-VTEX-IO-1dbd20c928c642d0ba059d5efbe7874b). 22 | 23 | # Atividade 24 | 25 | 1. Vamos agora importar um _Client_ do módulo **Catalog** em nossa app. Após ter clonado a app de boilerplate, abra no seu editor o código da app que foi baixado na pasta `service-example`. 26 | 27 | 2. Como o _Client_ que usaremos é oferecido no pacote de Commerce Clients, vamos realizar a instalação. **Dentro da pasta `node`, rode o seguinte comando:** 28 | 29 | `yarn add @vtex/clients` 30 | 31 | 3. Agora que o pacote foi instalado, precisamos configurar o _Client_ para utilizá-lo nos _resolvers_ e _middlewares_ de nossa app. Para isso, precisamos que você abra no seu editor o arquivo `node/clients/index.ts`. 32 | 33 | 4. Importe o _Client_ `Catalog` a partir da biblioteca `@vtex/clients`. 34 | 5. Adicione o _getter_ `catalog`, similar ao método acima na classe `Clients`. 35 | 36 | ```diff 37 | + import { Catalog } from '@vtex/clients' 38 | ... 39 | + public get catalog() { 40 | + return this.getOrSet('catalog', Catalog) 41 | + } 42 | ``` 43 | 44 | Pronto! Agora, qualquer uma das funções de _resolver_ GraphQL ou _middlewares_ de serviço pode utilizar este Client através de `ctx.clients.catalog`. Por conta do Typescript, é possível ter _autocomplete_ dos métodos e ver detalhes dos tipos necessários nos parâmetros. 45 | 46 | 47 | ### Está com dúvidas? 48 | 49 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-calling-commerce-apis-step03importing-client-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /1 - Blocos Básicos/5 - Evoluindo sua página de produto/README.md: -------------------------------------------------------------------------------- 1 | # Evoluindo sua página de produto 2 | 3 | ## Introdução 4 | 5 | Durante a última etapa, aprendemos como criar uma página de produto simples com uma quantidade mínima de conteúdo sobre produtos, mas sabemos que o resultado está longe de ser uma página de produto ideal, por isso adicionaremos outros elementos que aparecem com frequência nas páginas de produtos de várias lojas. 6 | 7 | ![image](https://user-images.githubusercontent.com/18701182/69391258-002e4b00-0cb1-11ea-901f-f69d9c0b3062.png) 8 | 9 | ## Mais de 30 blocos de produtos 10 | 11 | Nossa [documentação](https://vtex.io/docs/components/product-related) contém mais de 30 blocos relacionados ao produto. Exploraremos mais 4 nesta etapa: 12 | 13 | - [Breadcrumb](https://developers.vtex.com/docs/vtex-breadcrumb) 14 | - [Product Identifier](https://developers.vtex.com/docs/vtex-product-identifier) 15 | - [Product Quantity](https://developers.vtex.com/docs/vtex-product-quantity) 16 | - [SKU Selector](https://developers.vtex.com/docs/vtex-store-components-skuselector) 17 | 18 | É importante que ao final do curso você reserve um tempo para explorar totalmente nossos componentes, além das possibilidades de customização que acompanham cada um. 19 | 20 | ## Activity 21 | 22 | Desenvolva a página do produto adicionando os 4 blocos listados acima ao`product.jsonc` da seguinte forma: 23 | 24 | 1. Defina a `breadcrumb` logo antes da **row**; 25 | 26 | ```json 27 | "store.product": { 28 | "children": [ 29 | "breadcrumb", 30 | "flex-layout.row#main" 31 | ] 32 | } 33 | ``` 34 | 35 | 2. Defina o `product-identifier.product` logo depois de `product-name`; 36 | 37 | ```diff 38 | }, 39 | "children": [ 40 | "product-name", 41 | + "product-identifier.product", 42 | ... 43 | ] 44 | }, 45 | ``` 46 | 47 | 3. Crie uma **row** logo abaixo do preço, contendo o `sku-selector` e `product-quantity` como filhos; 48 | 49 | ```json 50 | { 51 | ... 52 | "children": [ 53 | "product-price", 54 | "flex-layout.row#qty-sku" 55 | ] 56 | }, 57 | "flex-layout.row#qty-sku": { 58 | "children": [ 59 | "sku-selector", 60 | "product-quantity" 61 | ] 62 | }, 63 | ... 64 | } 65 | ``` 66 | 67 | 4. Defina o `shipping-simulator` logo abaixo da linha definindo o `SKU Selector` e o `Product Quantity`: 68 | 69 | ```diff 70 | "children": [ 71 | ... 72 | + "shipping-simulator", 73 | "buy-button" 74 | ] 75 | ``` 76 | 77 | 78 | Note: Lembre-se de acessar a documentação do [Breadcrumb](https://developers.vtex.com/docs/vtex-breadcrumb), [Product Identifier](https://developers.vtex.com/docs/vtex-product-identifier), [Product Quantity](https://developers.vtex.com/docs/vtex-product-quantity) e [SKU Selector](https://developers.vtex.com/docs/vtex-store-components-skuselector) se tiver qualquer dúvida durante a atividade. 79 | 80 | 81 | ### Está com dúvidas? 82 | 83 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-basic-blocks-step05pdp2-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /6 - Blocos customizados/2 - Conhecendo uma app VTEX IO/README.md: -------------------------------------------------------------------------------- 1 | # Conhecendo uma app no VTEX IO 2 | De forma a implementar uma aplicação totalmente customizada no VTEX IO, é necessário entender alguns conceitos que serão apresentados e tudo começa com um arquivo muito importante de uma _app_: o `manifest.json`. 3 | 4 | 5 | # O arquivo `manifest.json` 6 | Este arquivo define algumas configurações básicas e abstrações que são necessárias para que o _build_ da sua aplicação funcione. Nesta etapa, alguns campos deste arquivo serão explicados, que são: 7 | - vendor 8 | - name 9 | - version 10 | - dependencies 11 | 12 | Vamos começar! 13 | 14 | ### _vendor_ 15 | 16 | Define o nome da conta VTEX que está desenvolvendo a _app_. Esta conta é responsável por sua manutenção e distribuição (a aplicação pode ser instalada em outras contas ou apenas na própria). 17 | 18 | >O vendor `vtex` é utilizado para _apps_ nativas. 19 | 20 | ### _name_ 21 | 22 | Identifica o nome da aplicação. Não deve conter nenhum caractere especial (exceto por `-`, que é permitido) ou caracteres maiúsculos. 23 | 24 | ### _version_ 25 | Identifica a versão atual da _app_. Utilizamos a especificação de [Versionamento Semântico 2.0.0](https://semver.org/). O formato é bem definido, dividido em _releases_ de _patch_, _minor_ ou _major_. 26 | 27 | Você pode encontrar abaixo um resumo da especificação: 28 | - *Patches*: É utilizado para _bug fixes_ que são retrocompatíveis; 29 | - *Minors*: Deve ser utilizado para _features_ retrocompatíveis; 30 | - *Majors*: Utilizado quando mudanças imcompatíveis de API são feitas (_breaking changes_). 31 | 32 | Por exemplo: se uma API está na versão `2.3.2` e uma _feature_ que não é _breaking change_ é adicionada, então a versão pode ser atualizada para `2.4.0`. 33 | 34 | No momento em que o _deployment_ é feito, há um _worker_ que chamamos de _housekeeper_, cuja responsabilidade é atualizar automaticamente as aplicações para a nova versão em cada conta VTEX. Dessa forma, irá sempre instalar todas as atualizações que são _minor_ ou _patch_, dada a retrocompatibilidade. Porém, não irá atualizar automaticamente versões _major_, dado que podem vir também com mudanças de dependências. 35 | 36 | ### _dependencies_ 37 | 38 | Uma _app_ pode depender de outras aplicações. Este campo listas todas as dependências necessárias para o correto funcionamento da aplicação. 39 | 40 | ## Exemplo 41 | Neste exemplo de um arquivo `manifest.json`, é possível observar algumas das características mencionadas anteriormente. Em particular, a versão da _app_ é `0.0.1` e estes números correspondem, respectivamente, a _major_, _minor_ e _patch_. 42 | 43 | ```json 44 | { 45 | "vendor": "vtex", 46 | "name": "countdown", 47 | "version": "0.0.1", 48 | "title": "Countdown", 49 | "description": "Countdown component", 50 | "defaultLocale": "pt-BR", 51 | "builders": { 52 | "messages": "1.x", 53 | "store": "0.x", 54 | "react": "3.x" 55 | }, 56 | "mustUpdateAt": "2019-04-02", 57 | "scripts": { 58 | "postreleasy": "vtex publish --verbose" 59 | }, 60 | "dependencies": { 61 | "vtex.styleguide": "9.x", 62 | "vtex.css-handles": "0.x" 63 | }, 64 | "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-a pi/master/gen/manifest.schema" 65 | } 66 | ``` -------------------------------------------------------------------------------- /6 - Blocos customizados/4 - Tornando o bloco countdown customizável/README.md: -------------------------------------------------------------------------------- 1 | # Tornando o bloco countdown customizável 2 | 3 | ## Introdução 4 | Agora que temos um elemento `h1` renderizado, é possível utilizá-lo para mostrar informações que dependam de uma *prop* do componente. Para isso, alguns conceitos serão apresentados, já que são necessários para desenvolver uma aplicação. 5 | 6 | ## Alterando o conteúdo renderizado do componente 7 | 8 | 1. Na interface definida no `Countdown.tsx`, adicione uma *prop* chamada `targetDate`, ela é do tipo *string*. Com isso, estamos definindo uma *prop* do componente que será utilizada para inicializar o contador. 9 | 10 | ```diff 11 | // react/Countdown.tsx 12 | interface CountdownProps { 13 | + targetDate: string 14 | } 15 | ``` 16 | 17 | 2. Feito isso, é preciso utilizá-la no componente, substituindo o texto de antes, "Teste Countdown" por um outro texto, através do *Site Editor*. 18 | 19 | >No futuro, esse targetDate será utilizado para definir a data de término para o contador. Porém, por enquanto, esse campo pode ser genérico. 20 | 21 | Primeiramente, é preciso alterar o componente para utilizar a *prop* `targetDate` definida anteriormente. Para isso, é preciso adicionar dentro do componente React a variável a ser utilizada no `h1`. Você lembra do bloco de código do componente na etapa anterior? Vamos utilizá-lo novamente para fazer as alterações. 22 | 23 | ```tsx 24 | // react/Countdown.tsx 25 | const Countdown: StorefrontFunctionComponent = ({ targetDate }) => { 26 | return ( 27 |
28 |

{ targetDate }

29 |
30 | ) 31 | } 32 | ``` 33 | 34 | 3. Além disso, para alterar essa propriedade através do *Site Editor*, é necessário adicionar essa mesma *prop* ao *schema*. Isso é feito através da adição de um objeto com chave `targetDate` dentro do objeto `properties` no *schema*. Ou seja: 35 | 36 | ```diff 37 | // react/Countdown.tsx 38 | Countdown.schema = { 39 | title: 'editor.countdown.title', 40 | description: 'editor.countdown.description', 41 | type: 'object', 42 | properties: { 43 | + targetDate: { 44 | + title: 'Data final', 45 | + description: 'Data final utilizada no contador', 46 | + type: 'string', 47 | + default: null, 48 | + }, 49 | }, 50 | } 51 | ``` 52 | 53 | Pronto! Agora você pode alterar o conteúdo do texto através do *Site Editor*. Vamos ver como ficou? 54 | 55 | > Você pode acessar o _Site Editor_ através do seguinte _link_: `{yourWorkspace}--appliancetheme.myvtex.com/admin/cms/site-editor`. 56 | 57 | Vá até o *Site Editor* e clique em `Countdown` no menu lateral, isso abrirá o menu de edição da *app*, que será como a imagem abaixo. 58 | 59 | ![image](https://user-images.githubusercontent.com/19495917/80977387-0cd7d300-8dfb-11ea-87e4-35218eab524b.png) 60 | 61 | Agora, no campo abaixo do título, digite uma data no formato `AAAA-MM-DD` e veja a alteração, que passará a exibir o texto que você digitou. 62 | 63 | ![image](https://user-images.githubusercontent.com/19495917/80977331-f6ca1280-8dfa-11ea-81f6-b7b551a8c41f.png) 64 | 65 | 66 | 67 | 68 | ### Está com dúvidas? 69 | 70 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-block-step03props-implementation-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/6 - Conectando a um serviço/README.md: -------------------------------------------------------------------------------- 1 | # Conectando a um serviço 2 | 3 | ## Introdução 4 | 5 | Uma app de admin acaba perdendo o seu sentido se não puder consumir dados. Sendo assim, no último passo do curso, vamos aprender como conectar sua app de admin a um serviço e, em seguida, usá-lo no *front-end* da aplicação. 6 | 7 | ## Atividade 8 | 9 | 1. Comece adicionando os *builders* para serviço necessários: 10 | 11 | /manifest.json 12 | ```diff 13 | { 14 | ... 15 | "builders": { 16 | "react": "3.x", 17 | "messages": "1.x", 18 | "docs": "0.x", 19 | "admin": "0.x", 20 | + "node": "6.x", 21 | + "graphql": "1.x" 22 | } 23 | } 24 | 25 | ``` 26 | 27 | 2. Crie uma pasta `graphql/` e adicione um arquivo simples `schema.graphql` com uma única query: 28 | 29 | /graphql/schema.graphql 30 | ``` 31 | type Query { 32 | helloworld: String 33 | } 34 | ``` 35 | 36 | 3. Crie uma pasta `node/` e nela adicione um `index.ts` que vai instanciar nosso serviço: 37 | 38 | /node/index.ts 39 | ``` 40 | import { Service } from '@vtex/api' 41 | 42 | export default new Service({ 43 | graphql: { 44 | resolvers: { 45 | Query: { 46 | helloworld: () => `Service number: ${Math.random()}`, 47 | }, 48 | }, 49 | }, 50 | }) 51 | ``` 52 | 53 | Nosso serviço vai então, na query `helloworld` retornar um número aleatório. 54 | 55 | 4. Na pasta `/node` para que você consiga desenvolver bem localmente, será necessário um `package.json`, voce pode adicionar um simples: 56 | 57 | /node/package.json 58 | ``` 59 | { 60 | "dependencies": { 61 | "co-body": "^6.0.0", 62 | "ramda": "^0.25.0" 63 | }, 64 | "devDependencies": { 65 | "@types/co-body": "^0.0.3", 66 | "@types/jest": "^24.0.18", 67 | "@types/node": "^12.0.0", 68 | "@types/ramda": "types/npm-ramda#dist", 69 | "@vtex/api": "6.36.2", 70 | "@vtex/test-tools": "^1.0.0", 71 | "tslint": "^5.14.0", 72 | "tslint-config-vtex": "^2.1.0", 73 | "typescript": "3.8.3" 74 | }, 75 | "scripts": { 76 | "lint": "tsc --noEmit --pretty && tslint -c tslint.json --fix './**/*.ts'" 77 | }, 78 | "version": "0.0.7" 79 | } 80 | 81 | ``` 82 | 83 | 5. Na pasta `react/` nós vamos precisar definir uma *query* para conseguir usar o resolver que definimos no serviço, para fazer isso, crie uma pasta `graphql/` dentro da pasta `react/` e nesta pasta, crie um `helloworld.gql` com: 84 | 85 | /react/graphql/helloworld.gql: 86 | ``` 87 | query hello { 88 | helloworld 89 | } 90 | ``` 91 | 92 | 6. Para finalizar, precisamos adicionar essa *query* ao nosso componente no `adminExample.ts` 93 | 94 | ```diff 95 | import React, { FC } from 'react' 96 | import { Layout, PageBlock } from 'vtex.styleguide' 97 | +import { useQuery } from 'react-apollo' 98 | 99 | +import helloworld from './graphql/helloworld.gql' 100 | 101 | const AdminExample: FC = () => { 102 | + const { data } = useQuery(helloworld) 103 | 104 | return ( 105 | 106 | 107 |

Hello, World!

108 | +

{data?.helloworld}

109 |
110 |
111 | ) 112 | } 113 | 114 | export default AdminExample 115 | ``` 116 | 117 | O resultado deve ser: 118 | 119 | ![image](https://user-images.githubusercontent.com/18701182/92937440-b79f7400-f421-11ea-9e92-a24ef710e83e.png) 120 | 121 | Com isto você tem um serviço conectado à sua aplicação de admin e pode, agora, conectar a serviços externos (aprenda mais sobre no nosso curso de serviços 🚀). -------------------------------------------------------------------------------- /2 - Layouts Complexos/2 - Flex layout/README.md: -------------------------------------------------------------------------------- 1 | # Flex Layout: crie _layouts_ utilizando o poder do Flexbox 2 | 3 | ## Introdução 4 | 5 | O [Flex Layout](https://developers.vtex.com/docs/vtex-flex-layout#flex-layout) é um paradigma de estruturação de _layout_ criado no Store Framework para permitir a construção de _layouts_ complexos. Esse paradigma usa o conceito de **linhas** e **colunas** para definir a estrutura e o posicionamento desejados dos blocos em uma determinada página. 6 | 7 | Existem dois blocos de construção básicos de cada Flex Layout: 8 | 9 | - `flex-layout.row` 10 | - `flex-layout.col` 11 | 12 | Se você já está familiarizado com o Flexbox utilizado no CSS, o Flex Layout deve ser simples de entender, já que o Flexbox está sendo utilizado "por debaixo dos panos" pelo `flex-layout.row` e `flex-layout.col`. 13 | 14 | ## Flex Layout 15 | 16 | Com o Flex Layout é possível criar _layouts_ personalizados, utilizando a estrutura de linhas e colunas do Flexbox. 17 | 18 | Analisando a documentação do bloco, vemos que você pode utilizar qualquer *array* de blocos como `children` do Flex Layout. Além disso, você deve sempre usar `flex-layout.row` e `flex-layout.col`, **NUNCA** `flex-layout` de forma isolada. 19 | 20 | Abaixo, temos um exemplo de flex layout composto de um `flex-layout.row` com dois *children*: um `info-card` e um `rich-text`: 21 | 22 | ```json 23 | "flex-layout.row":{ 24 | "children": [ 25 | "info-card#rethink", 26 | "rich-text#deletar" 27 | ] 28 | }, 29 | 30 | "info-card#rethink": { 31 | "props": { 32 | "imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/utensilios-cozinha-min.png", 33 | "isFullModeStyle": true, 34 | "headline": "Time to rethink your kitchen", 35 | "callToActionText": "Discover", 36 | "textPosition": "center" 37 | } 38 | }, 39 | 40 | "rich-text#deletar": { 41 | "props": { 42 | "text": "I'll be deleted soon" 43 | } 44 | } 45 | ``` 46 | 47 | ## Atividade 48 | 49 | 1. Declare o `flex-layout.row` dentro dos `blocks` do template de `store.home` e declare os blocos propostos acima no seu arquivo `home.jsonc` 50 | 2. Altere as *children* do `flex-layout.row`, substituindo o bloco `rich-text` por uma coluna `flex-layout.col`. 51 | 3. Delete do seu tema o bloco de `rich-text` proposto acima. 52 | 4. Declare o bloco `flex-layout.col` no seu arquivo `home.jsonc` com dois componentes de imagem como children: `image#electronics` e `image#major-appliance`, *nesta ordem*. 53 | 5. Defina os blocos `image` com as seguintes props: 54 | 55 | ```json 56 | ... 57 | "image#electronics": { 58 | "props": { 59 | "src": "https://appliancetheme.vteximg.com.br/assets/vtex.file-manager-graphql/images/electronics_banner___25d69b49f8224b369375e68513b4d593.png", 60 | "maxWidth": "100%" 61 | } 62 | }, 63 | "image#major-appliance": { 64 | "props": { 65 | "src": "https://appliancetheme.vteximg.com.br/assets/vtex.file-manager-graphql/images/major_appliance_banner___bb10093866a127345ddfbcca3efa5022.png", 66 | "maxWidth": "100%" 67 | } 68 | } 69 | ``` 70 | 71 | O resultado obtido deve ser semelhante a este: 72 | 73 | ![image](https://user-images.githubusercontent.com/12139385/70185681-0c5ed300-16c9-11ea-9260-b88179b508f2.png) 74 | 75 | Note: Lembre-se de acessar a [documentação](https://developers.vtex.com/docs/vtex-flex-layout#flex-layout) do Flex Layout caso tenha alguma dúvida durante a atividade. 76 | 77 | 78 | ### Está com dúvidas? 79 | 80 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step02flexlayout-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/8 - Stack layout/README.md: -------------------------------------------------------------------------------- 1 | # Stack Layout 2 | 3 | ## Introdução 4 | 5 | O Stack Layout é mais um tipo possível de construir _layouts_ complexos se alavancando dos blocos nativos, com ele é possível facilmente empilhar bloco. Para este passo, vamos criar um _call-to-action_ (CTA) na página principal com um _banner_ e um botão de redirecionamento. 6 | 7 | ## Atividade 8 | 9 | Pensando melhor no problema que queremos resolver, conseguimos dividi-lo em duas partes: 10 | 11 | - Uma imagem (bloco `image`) de fundo: 12 | 13 | ![image](https://appliancetheme.vtexassets.com/assets/app/src/appliancecat___1b7592b49667c6a89203a0997e06bc87.jpg) 14 | 15 | - Um botão de CTA: 16 | 17 | ![image](https://user-images.githubusercontent.com/18701182/90291114-8a2cce00-de55-11ea-982c-3fef741535fb.png) 18 | 19 | Vamos então construir o _info card_ usando ambos elementos: 20 | 21 | 1. Declare o `stack-layout` na sua página: 22 | 23 | ```diff 24 | { 25 | "store.home": { 26 | "blocks": [ 27 | + "stack-layout#cta" 28 | ] 29 | } 30 | } 31 | ``` 32 | 33 | 2. Adicione uma imagem e um _link_ para o `stack-layout`: 34 | 35 | ```diff 36 | { 37 | "store.home": { 38 | "blocks": [ 39 | "stack-layout#cta" 40 | ] 41 | }, 42 | + "stack-layout#cta": { 43 | + "children": [ 44 | + "image#cta", 45 | + "link#cta" 46 | + ] 47 | + } 48 | } 49 | ``` 50 | 51 | 3. Declare a imagem e o _link_ que usaremos: 52 | 53 | ```diff 54 | { 55 | ... 56 | + "image#cta": { 57 | + "props": { 58 | + "blockClass": "cover", 59 | + "width": "100%", 60 | + "height": 400, 61 | + "src": "https://appliancetheme.vtexassets.com/assets/app/src/appliancecat___1b7592b49667c6a89203a0997e06bc87.jpg" 62 | + } 63 | + }, 64 | + "link#cta": { 65 | + "props": { 66 | + "displayMode": "button", 67 | + "buttonProps": { 68 | + "variant": "primary", 69 | + "size": "large" 70 | + }, 71 | + "href": "/washer", 72 | + "label": "Check these awesome discounts" 73 | + } 74 | + } 75 | } 76 | ``` 77 | 78 | 4. O resultado deve ser então: 79 | 80 | ![infocard](https://appliancetheme.vtexassets.com/assets/app/src/appliancecat___0a2e8bde5418359bdaf0a06d9a4d09f5.jpg) 81 | 82 | **OPCIONAL:** Se você quiser melhorar um pouco o visual do _info card_ criado, siga os passos seguintes: 83 | 84 | 5. Crie um arquivo `vtex.stack-layout.css` na pasta `/styles/css` e adicione os seguintes estilos: 85 | 86 | ``` 87 | .stackItem { 88 | width: 100%; 89 | height: 100%; 90 | display: flex; 91 | align-items: center; 92 | justify-content: center; 93 | } 94 | ``` 95 | 96 | 6. No arquivo `vtex.store-components.css` da pasta `/styles/css` adicione: 97 | 98 | ``` 99 | .imageElement--cover { 100 | object-fit: cover; 101 | } 102 | ``` 103 | 104 | O resultado deve ser então: 105 | 106 | ![image](https://user-images.githubusercontent.com/18701182/90292857-22788200-de59-11ea-9a9c-8668b01ffb1c.png) 107 | 108 | ## Notas 109 | 110 | - Não se preocupe se não entender bem como funcionou a estilização feita nos passos opcionais, temos um curso exclusivo para estilização que será visto mais a frente. 111 | 112 | - Se você clicar no botão e não estiver vendo uma página de resultado de busca, garanta que você tem um layout de busca definido (vimos isso no curso de blocos básicos) seguindo a documentação de [Search Result](https://developers.vtex.com/docs/vtex-search-result#search-result) 113 | 114 | 115 | ### Está com dúvidas? 116 | 117 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step08stack-layout-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/4 - Sub seções/README.md: -------------------------------------------------------------------------------- 1 | # Subseções 2 | 3 | ## Introdução 4 | 5 | Em alguns casos a sua aplicação é mais complexa e precisa de vários seções navegáveis (e.g. uma tela para insights e outra para gestão). O Admin Framework oferece a possibilidade de criar itens de navegação de seção que funcionam de forma análoga. 6 | 7 | ## Atividade 8 | 9 | 1. Remova o `path` do navigation que tínhamos usado antes e adicione um novo campo `subSectionItems` com um _array_ vazio: 10 | 11 | ```diff 12 | { 13 | "section": "orders", 14 | "titleId": "admin-example.navigation.label", 15 | - "path": "/admin/iotraining", 16 | "searchKeyWordsHelpers": "admin-example.navigation.search.kws", 17 | + "subSectionItems": [] 18 | } 19 | ``` 20 | 21 | 2. Adicione um elemento para o _array_ de `subSectionItems` com uma `labelId` e um `path` (que pode ser o mesmo do anterior): 22 | 23 | ```diff 24 | { 25 | "section": "orders", 26 | "titleId": "admin-example.navigation.label", 27 | "searchKeyWordsHelpers": "admin-example.navigation.search.kws", 28 | "subSectionItems": [ 29 | + { 30 | + "labelId": "admin-example.navigation.insight", 31 | + "path": "/admin/iotraining", 32 | + } 33 | ] 34 | } 35 | ``` 36 | 37 | 3. Adicione mais outro elemento com um `labelId` diferente e outro `path`: 38 | 39 | ```diff 40 | { 41 | "section": "orders", 42 | "titleId": "admin-example.navigation.label", 43 | "searchKeyWordsHelpers": "admin-example.navigation.search.kws", 44 | "subSectionItems": [ 45 | + { 46 | + "labelId": "admin-example.navigation.insight", 47 | + "path": "/admin/iotraining", 48 | + }, 49 | + { 50 | + "labelId": "admin-example.navigation.management", 51 | + "path": "/admin/otheriotraining", 52 | + } 53 | ] 54 | } 55 | ``` 56 | 57 | 4. Com os _paths_ novos, faça as alterações necessárias no `routes.json`: 58 | 59 | ```diff 60 | { 61 | "admin.app.example": { 62 | "component": "adminExample", 63 | "path": "/admin/app/iotraining" 64 | }, 65 | + "admin.app.otherexample": { 66 | + "component": "adminOtherExample", 67 | + "path": "/admin/app/otheriotraining" 68 | + } 69 | } 70 | ``` 71 | 72 | 5. Crie o novo componente `adminOtherExample.tsx` na raiz da pasta `react/`: 73 | 74 | /react/adminOtherExample.tsx 75 | ``` 76 | import React, { FC } from 'react' 77 | 78 | const AdminOtherExample: FC = () => { 79 | return

Other Example!

80 | } 81 | 82 | export default AdminOtherExample 83 | ``` 84 | 85 | 6. Finalize criando as mensagens para cada um dos `labelId` definidos no passo 3: 86 | 87 | 88 | /messages/pt.json 89 | ```diff 90 | { 91 | "admin-example.navigation.label": "Treinamento de IO", 92 | "admin-example.navigation.search.kws": "mock, test, treinamento, io", 93 | + "admin-example.navigation.insight": "Informações", 94 | + "admin-example.navigation.management": "Gerenciamento" 95 | } 96 | ``` 97 | 98 | /messages/en.json 99 | ```diff 100 | { 101 | "admin-example.navigation.label": "IO Training", 102 | "admin-example.navigation.search.kws": "mock, test, training, io", 103 | + "admin-example.navigation.insight": "Insights", 104 | + "admin-example.navigation.management": "Management" 105 | } 106 | ``` 107 | 108 | /messages/es.json 109 | ```diff 110 | { 111 | "admin-example.navigation.label": "Entrenamiento de IO", 112 | "admin-example.navigation.search.kws": "mock, test, entrenamiento, io", 113 | + "admin-example.navigation.insight": "Información", 114 | + "admin-example.navigation.management": "Administración" 115 | } 116 | ``` 117 | 118 | O resultado esperado é então: 119 | 120 | ![admin](https://user-images.githubusercontent.com/18701182/92791871-6fca0f80-f383-11ea-98f8-382c743a6657.gif) -------------------------------------------------------------------------------- /8 - Aplicações Administrativas/1 - Admin framework/README.md: -------------------------------------------------------------------------------- 1 | # Admin framework 2 | 3 | # Introdução 4 | 5 | Nos cursos anteriores conhecemos o Store Framework, um motor de construção de frente de loja construído usando o VTEX IO. Assim como o Store Framework, o Admin Framework se propõe a resolver um caso de uso específico: extensões para o painel administrativo. 6 | 7 | Operações de comércio complexas quase nunca conseguem funcionar com uma única solução SaaS integrada, são necessários integrações de ERP, personalização, tracking, marketing digital, entre outros. A VTEX entende, no entanto, que ter um único ponto de contato facilitaria muito o trabalho dos operadores, tornando o admin uma ferramenta universal. É com essa premissa que o Admin Framework foi criado, trazendo a possibilidade de extensão de *backoffice* não apenas para criar dashboards que são característicos de um cliente e seu segmento, como para trazer insights e operação de provedores externos. 8 | 9 | # Atividade 10 | 11 | Uma app de admin, funciona de forma muito parecida com a app de bloco de loja. Vamos iniciar o curso clonando um repositório template de react e evoluiremos para torná-lo uma app de admin: 12 | 13 | 1. Clone o react app template: 14 | 15 | ``` 16 | git clone https://github.com/vtex-apps/react-app-template admin-course 17 | ``` 18 | 19 | 2. Abra o `admin-course` no seu editor de texto e adicione o builder de admin no `manifest.json`: 20 | 21 | ```diff 22 | //manifest.json 23 | { 24 | "vendor": "CHANGE_ME", 25 | "name": "CHANGE_ME", 26 | "version": "0.0.0", 27 | "title": "CHANGE_ME", 28 | "description": "CHANGE_ME", 29 | "builders": { 30 | "react": "3.x", 31 | "messages": "1.x", 32 | "docs": "0.x", 33 | + "admin": "0.x" 34 | }, 35 | "dependencies": {}, 36 | "registries": [ 37 | "smartcheckout" 38 | ], 39 | "policies": [], 40 | "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema" 41 | } 42 | ``` 43 | 44 | 3. Edite o `vendor`, `name`, `title` e `description` da aplicação: 45 | 46 | ```diff 47 | //manifest.json 48 | { 49 | + "vendor": "appliancetheme", 50 | + "name": "admin-sandbox", 51 | "version": "0.0.0", 52 | "title": "Admin Sandbox", 53 | "description": "Admin Sandbox", 54 | "builders": { 55 | "react": "3.x", 56 | "messages": "1.x", 57 | "docs": "0.x", 58 | "admin": "0.x" 59 | }, 60 | "dependencies": {}, 61 | "registries": [ 62 | "smartcheckout" 63 | ], 64 | "policies": [], 65 | "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema" 66 | } 67 | ``` 68 | **NOTA:** Se estiver fazendo o curso na sua própria loja e desenvolvendo sua própria app, lembre-se de que terá que passar pelo [form de whitelist](https://forms.gle/ovi4h7mnwgUKS2hu5). 69 | 70 | 5. Adicione o `vtex.styleguide` como dependência, nós vamos utilizá-lo mais a frente no curso: 71 | ```diff 72 | //manifest.json 73 | { 74 | "vendor": "appliancetheme", 75 | "name": "admin-sandbox", 76 | "version": "0.0.0", 77 | "title": "Admin Sandbox", 78 | "description": "Admin Sandbox", 79 | "builders": { 80 | "react": "3.x", 81 | "messages": "1.x", 82 | "docs": "0.x", 83 | "admin": "0.x" 84 | }, 85 | "dependencies": { 86 | + "vtex.styleguide": "9.x" 87 | }, 88 | "registries": [ 89 | "smartcheckout" 90 | ], 91 | "policies": [], 92 | "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema" 93 | } 94 | ``` 95 | 96 | 6. Na raiz do projeto, crie um diretório `/admin`, a sua estrutura deve ficar: 97 | 98 | ```diff 99 | | 100 | |_ CHANGELOG.md 101 | |_ docs/ 102 | |_ messages/ 103 | |_ react/ 104 | +|_ admin/ 105 | |_ package.json 106 | |_ manifest.json 107 | |_ yarn.lock 108 | ``` -------------------------------------------------------------------------------- /3 - Tornando sua loja única/3 - Estilos globais/README.md: -------------------------------------------------------------------------------- 1 | # Estilos globais 2 | 3 | ## Introdução 4 | 5 | Além do CSS, que já foi aprendido anteriormente, o Store Framework oferece um outro tipo de customização de design, provida a partir do `style.json`. 6 | 7 | ## Estilização semântica 8 | 9 | Todos os blocos do Store Framework se alavancam das mesmas definições semânticas de estilo, definidas usando o [Tachyons](https://tachyons.io/). Na prática, isso significa que, ao invés de precisar mudar todos os fundos de botões para usar a cor que se interessa, é necessário apenas redefinir a cor que um `background` de uma `action-primary` tem. 10 | 11 | Customizações através do `style.json` tendem a ter um impacto muito maior que através de CSS, pois, em geral, mantém a identidade visual da loja ao longo de todas as páginas sendo necessárias poucas mudanças. Por esse motivo, sempre que possível, essa ferramenta deve ser usada, evitando assim _overhead_ de CSS desnecessário. 12 | 13 | ## Investigando o `style.json` 14 | 15 | ### Cores 16 | 17 | ![](https://user-images.githubusercontent.com/18701182/69848546-24fa6380-1259-11ea-9978-9020222ed77e.png) 18 | 19 | O `styles/configs/style.json` pode ser confuso em primeiro momento, por conter todas as definições de estilo que todos os blocos visuais do Store Framework usam. No entanto, um bom fluxo para identificar que estilos mudar, é através da inspeção de elementos no navegador. 20 | 21 | Por exemplo, **clique com o botão direito em cima de qualquer botão da loja aperte em inspecionar**. 22 | 23 | ![image](https://user-images.githubusercontent.com/19495917/90169302-cb997c80-dd74-11ea-983e-6af755b1aa5d.png) 24 | 25 | Observando a barra lateral no Chrome que abriu é possível ver uma série de definições, uma delas é a de cor do _background_ do botão (#3f3f40): 26 | 27 | ![image](https://user-images.githubusercontent.com/19495917/90169845-875aac00-dd75-11ea-968b-db03f14435e7.png) 28 | 29 | Se fizermos uma busca pelas ocorrências de ambas as cores no `style.json`, as cores que descobrimos são, respectivamente, as usadas para `action-primary` em `hover-background` e `background`, por exemplo. Isso nos dá uma ideia melhor de onde poderemos achar outras ocorrências dessa mesma definição. 30 | 31 | ### Tipografia 32 | 33 | Para descobrir definições semânticas de texto e quais campos são editáveis, o processo é o mesmo do anterior, podemos buscar atributos como tamanho da fonte, peso, família. 34 | 35 | Em um cabeçalho nível 1, por exemplo, ao inspecionar descobrimos que seu tamanho foi definido como `3 rem`. 36 | 37 | ![image](https://user-images.githubusercontent.com/19495917/90170621-b0c80780-dd76-11ea-9d41-c96639944e58.png) 38 | 39 | ![image](https://user-images.githubusercontent.com/19495917/90170541-9b52dd80-dd76-11ea-8390-f243e267e145.png) 40 | 41 | ## Alterando globalmente a cor e a tipografia 42 | 43 | 1. No arquivo `style.json`, substitua todas as ocorrências das cores que encontramos, trocando: 44 | - **#3f3f40** with **#e68e94** 45 | 46 | 2. Mude o tamanho da fonte do cabeçalho de nível 1 (`heading level 1`) para que agora tenha `2.5 rem` de altura: 47 | 48 | ```diff 49 | "heading-1": { 50 | "fontFamily": "Fabriga, -apple-system, BlinkMacSystemFont, avenir next, avenir, helvetica neue, helvetica, ubuntu, roboto, noto, segoe ui, arial, sans-serif", 51 | "fontWeight": "700", 52 | + "fontSize": "2.5rem", 53 | "textTransform": "initial", 54 | "letterSpacing": "0" 55 | }, 56 | ``` 57 | 58 | O resultado esperado pode ser visto abaixo: 59 | 60 | ![image](https://user-images.githubusercontent.com/19495917/90172958-17025980-dd7a-11ea-80d1-31b6e3f3ac1f.png) 61 | 62 | 63 | ### Está com dúvidas? 64 | 65 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-styles-course-step02styles-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/3 - Carrossel de blocos/README.md: -------------------------------------------------------------------------------- 1 | # Carrossel de blocos 2 | 3 | ## Introdução 4 | 5 | O Slider Layout, como o Flex Layout, é uma forma flexível de criar um novo bloco a partir de outros blocos usando `children`. Ele permite que sejam criados _sliders_ de outros blocos, como `info-card`s e até mesmo `flex-layout`s por exemplo. 6 | 7 | Com o Slider Layout é possível criar um carrossel não só de imagens, como de qualquer conteúdo que se queira. Para este exemplo, vamos utilizar o Slider Layout para tornar um conjunto de info-cards em um slider. 8 | 9 | ## Slider Layout 10 | 11 | Analisando a [documentação](https://developers.vtex.com/docs/vtex-slider-layout), vemos que você pode utilizar qualquer _array_ de blocos como `children`, assim como no Flex Layout. 12 | 13 | Abaixo, segue um exemplo de implementação de um slider-layout com dois `info-card`: 14 | 15 | ```json 16 | 17 | "slider-layout#home": { 18 | "children": ["info-card#1", "info-card#2"], 19 | "props": { 20 | "autoplay": { 21 | "timeout": 5000, 22 | "stopOnHover": false 23 | } 24 | } 25 | }, 26 | 27 | "info-card#1": { 28 | "props": { 29 | "imageUrl": "https://images.unsplash.com/photo-1524185962737-ea7c028a12cd?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80", 30 | "isFullModeStyle": true, 31 | "headline": "Black Friday", 32 | "callToActionText": "Subscribe", 33 | "textPosition": "center" 34 | } 35 | }, 36 | 37 | "info-card#2": { 38 | "props": { 39 | "imageUrl": "https://images.unsplash.com/photo-1524185962737-ea7c028a12cd?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80", 40 | "isFullModeStyle": true, 41 | "headline": "Black Friday", 42 | "callToActionText": "Subscribe", 43 | "textPosition": "center" 44 | } 45 | } 46 | 47 | ``` 48 | 49 | ## Atividade 50 | 51 | Nesta atividade, vamos criar um _slider_ de marcas para o nosso site: 52 | 53 | ![](https://appliancetheme.vteximg.com.br/arquivos/brand-slider.png) 54 | 55 | 1. No arquivo `home.jsonc`, declare o bloco `slider-layout#home` ao template `store.home`. 56 | 57 | 2. Crie um arquivo chamado `slider-layout.jsonc` dentro da pasta `/store/blocks`; 58 | 59 | 3. Neste arquivo, baseando-se no código acima, substitua os `info-card` declarados como children de `slider-layout#home` e adicione 6 [componentes de imagem](https://vtex.io/docs/components/general/vtex.store-components/image) `image` como children. Utilize o formato `image#brand1`, `image#brand2` (...) `image#brand6` para declarar os componentes; 60 | 61 | 4. Declare uma prop `src` específica para cada `image#brand` definido. Utilize as URLs abaixo para cada uma delas: 62 | 1. `https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square1.png` 63 | 2. `https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square2.png` 64 | 3. `https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square3.png` 65 | 4. `https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square4.png` 66 | 5. `https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square5.png` 67 | 6. `https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square6.png` 68 | 69 | 5. Por fim, você deve utilizar a propriedade de `autoplay` no bloco `slider-layout#home`. Faça com que o _slide_ aconteça automaticamente a cada **7 segundos e que ele pare quando o usuário passar o mouse em cima do _slide_**. 70 | 71 | Note: Lembre-se de acessar a documentação do [Slider Layout](https://developers.vtex.com/docs/vtex-slider-layout) e [Image](https://developers.vtex.com/docs/vtex-store-components-image) caso tenha alguma dúvida durante a atividade. 72 | 73 | ### Está com dúvidas? 74 | 75 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step03slider-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /1 - Blocos Básicos/6 - Página de busca/README.md: -------------------------------------------------------------------------------- 1 | # Página de pesquisa 2 | 3 | ## Introdução 4 | 5 | ![image](https://user-images.githubusercontent.com/18701182/69843114-d6db6500-1244-11ea-82a7-b10880e2ed55.png) 6 | 7 | Acabamos de implementar nossa página de produto e estamos avançando para a página de pesquisa. Ambos são semelhantes no sentido de que ambos têm blocos que são únicos neste contexto. Vamos explorar os blocos de forma desordenada, sem pensar no design da página, por enquanto, apenas para ter uma ideia de seu comportamento. 8 | 9 | ## Começando com o Search Layout 10 | 11 | Da mesma forma que outros modelos, `store.search` também pode ser flexível. Para construir um layout único, você precisará usar um bloco chamado `search-result-layout`. 12 | 13 | ```json 14 | { 15 | "store.search": { 16 | "blocks": ["search-result-layout"] 17 | } 18 | } 19 | ``` 20 | 21 | O `search-result-layout`, por sua vez, deve conter outros 3 blocos: 22 | 23 | - `search-result-layout.desktop` 24 | - `search-result-layout.mobile` 25 | - `search-not-found-layout` 26 | 27 | Como você já percebeu, os dois primeiros definem qual layout será exibido no **desktop e celular** respectivamente, enquanto o terceiro define o layout da **página de pesquisa sem resultados**. 28 | 29 | ```json 30 | { 31 | "store.search": { 32 | "blocks": ["search-result-layout"] 33 | }, 34 | "search-result-layout": { 35 | "blocks": [ 36 | "search-result-layout.desktop", 37 | "search-result-layout.mobile", 38 | "search-not-found-layout" 39 | ] 40 | } 41 | } 42 | ``` 43 | 44 | Nesse curso, vamos **focar** na implementação do **layout para desktop**. 45 | 46 | ## Blocos de Busca 47 | 48 | A [documentação dos resultados da pesquisa](https://developers.vtex.com/docs/vtex-search-result) oferece uma boa referência para blocos que podem ser usados ​​em um **contexto de pesquisa**. Esta etapa se concentrará em destacar os principais: 49 | 50 | - Breadcrumb de pesquisa (`breadcrumb.search`); 51 | - Título de pesquisa (`search-title.v2`); 52 | - Total de produtos encontrados (`total-products.v2`); 53 | - Ordenação de produtos (`order-by.v2`); 54 | - Botão Mostrar mais resultados (`search-fetch-more`); 55 | - Mostrar botão de resultados anteriores (`search-fetch-previous`); 56 | - Filtro de navegação (`filter-navigator.v3`); 57 | - Resultados da pesquisa (`search-content`) 58 | 59 | Embora serem muitos, todos esses blocos são relativamente simples e funcionam muito bem sem a necessidade expressa de configurar suas `props`. 60 | 61 | ## Atividade 62 | 63 | ![image](https://user-images.githubusercontent.com/18701182/69843046-7f3cf980-1244-11ea-8309-8a26071cd6f0.png) 64 | 65 | Copie os códigos acima no arquivo `search.jsonc` e defina a `search-result-layout.desktop` contendo o seguinte, na ordem abaixo: 66 | 67 | - `breadcrumb.search`; 68 | - `search-title.v2`; 69 | - `total-products.v2`; 70 | - `order-by.v2`; 71 | - `search-fetch-previous`; 72 | - `search-content`; 73 | - `filter-navigator.v3`; 74 | - `search-fetch-more`. 75 | 76 | Para isso, escreva um código similar a este: 77 | 78 | ```json 79 | ... 80 | }, 81 | "search-result-layout.desktop": { 82 | "children": [ 83 | "breadcrumb.search", 84 | "search-title.v2", 85 | "total-products.v2", 86 | "order-by.v2", 87 | "search-fetch-previous", 88 | "search-content", 89 | "filter-navigator.v3", 90 | "search-fetch-more" 91 | ] 92 | } 93 | ... 94 | ``` 95 | 96 | Note: Lembre-se de olhar a [documentação](https://developers.vtex.com/docs/vtex-search-result) caso tenha dúvidas ao longo da atividade. 97 | 98 | 99 | ### Está com dúvidas? 100 | 101 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-basic-blocks-step06search-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /5 - Melhorando performance/2 - Otimizando menus/README.md: -------------------------------------------------------------------------------- 1 | # Otimizando menus 2 | 3 | O menu é um dos pontos críticos de performance em uma loja. Por estar presente em (quase) todas as páginas, quando mal otimizado, pode fazer com que qualquer página tenha problemas de performance independente do quão bem implementada ela esteja. Neste passo, vamos aprender como otimizar a sua implementação para, não só viabilizar a edição deste no Site Editor, como reduzir o overhead de blocos necessários em sua definição 4 | 5 | ## Props vs children 6 | 7 | Em geral uma implementação de menu em uma loja segue o seguinte padrão: 8 | 9 | ```json 10 | { 11 | "vtex.menu@2.x:menu#category-menu": { 12 | "children": [ 13 | "menu-item#category-electronics", 14 | "menu-item#category-major-appliances", 15 | "menu-item#category-small-appliances" 16 | ] 17 | }, 18 | "menu-item#category-electronics": { 19 | "props": { 20 | "id": "menu-item-category-electronics", 21 | "type": "custom", 22 | "iconId": null, 23 | "highlight": false, 24 | "itemProps": { 25 | "categoryId": 153, 26 | "type": "internal", 27 | "href": "/electronics/", 28 | "noFollow": true, 29 | "tagTitle": "Electronics", 30 | "text": "Electronics" 31 | } 32 | } 33 | }, 34 | ... 35 | } 36 | ``` 37 | 38 | Existem dois problemas em implementar um menu desta forma: 39 | 40 | 1. Por se usar o `children`, o menu passa a ter implementação parecida com a de um _layout_, o que faz com que todo o conteúdo dentro dele não seja facilmente editável no Site Editor 41 | 42 | 2. Para cada novo menu que for criado, é necessária a definição de um novo bloco, o que aumenta o _overhead_ dos blocos que são necessários para compor uma página 43 | 44 | ## Atividade 45 | 46 | 1. Para melhorar, então, a performance do menu da nossa *Appliance Store*, vá até o arquivo `/store/blocks/header/category-menu.jsonc` e remova sua seção de `children`: 47 | 48 | ```diff 49 | { 50 | "vtex.menu@2.x:menu#category-menu": { 51 | - "children": [ 52 | - "menu-item#category-electronics", 53 | - "menu-item#category-major-appliances", 54 | - "menu-item#category-small-appliances" 55 | - ] 56 | } 57 | ... 58 | } 59 | ``` 60 | 61 | **NOTA:** Não apague as definições destes blocos, eles estão sendo utilizados em outros lugares 62 | 63 | 2. Adicione agora uma nova seção de `props` e um _array_ de `items`: 64 | 65 | ```diff 66 | { 67 | "vtex.menu@2.x:menu#category-menu": { 68 | + "props": { 69 | + "items": [] 70 | + } 71 | } 72 | ... 73 | } 74 | ``` 75 | 76 | 3. Para fechar, para cada um dos `menu-items` que tínhamos ( `"menu-item#category-electronics"`; `"menu-item#category-major-appliances"`; `"menu-item#category-small-appliances"`), adicione suas `props` como itens do _array_ que criamos: 77 | 78 | ```diff 79 | { 80 | "vtex.menu@2.x:menu#category-menu": { 81 | "props": { 82 | "items": [ 83 | + { 84 | + "id": "menu-item-category-electronics", 85 | + "type": "custom", 86 | + "iconId": null, 87 | + "highlight": false, 88 | + "itemProps": { 89 | + "categoryId": 153, 90 | + "type": "internal", 91 | + "href": "/electronics/", 92 | + "noFollow": true, 93 | + "tagTitle": "Electronics", 94 | + "text": "Electronics" 95 | + } 96 | + } 97 | + ... 98 | ] 99 | } 100 | ``` 101 | 102 | O resultado esperado é um menu exatamente igual ao que tínhamos, mas que agora conseguimos controlar pelo Site Editor e adicionar novos itens. 103 | 104 | ![image](https://user-images.githubusercontent.com/18701182/93832191-53638800-fc4b-11ea-9b51-b2ba59ebdb47.png) 105 | 106 | 107 | ### Está com dúvidas? 108 | 109 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-performance-step02menu-items-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /5 - Melhorando performance/3 - Otimização de submenus/README.md: -------------------------------------------------------------------------------- 1 | # Otimização de submenus 2 | 3 | No passo anterior aprendemos como otimizar itens de menu, tornando-os propriedades do menu ao invés de blocos filhos. Alguns menus, no entanto, possuem outros submenus, como o da [Store Theme](storetheme.vtex.com): 4 | 5 | ![image](https://user-images.githubusercontent.com/18701182/93831521-5d848700-fc49-11ea-9773-c2d727013f95.png) 6 | 7 | Estes se comportam como um _layout_, então não há otimizações que possam ser feitas além de usar o comportamento de `children`. Para esses casos, o ideal é ir para uma solução híbrida, em que os menus pais são usados com `children` e os menus *folha* (últimos na árvore de menus) podem ser usados como `props`. 8 | 9 | Todavia, como o usuário não vai ver o conteúdo dos submenus quando a página é carregada, podemos postergar o carregamento do seu conteúdo. 10 | 11 | ## Atividade 12 | 13 | 1. Para entender como podemos otimizar submenus, vamos modificar um pouco nosso exemplo para ficar mais parecido com o que temos na Store Theme, comece editando o nome do bloco que trabalhamos no passo anterior (`"vtex.menu@2.x:menu#category-menu"`) para `"vtex.menu@2.x:menu#categories"`: 14 | 15 | ```diff 16 | // store/blocks/header/category-menu.jsonc 17 | { 18 | ... 19 | - "vtex.menu@2.x:menu#category-menu": { 20 | + "vtex.menu@2.x:menu#categories": { 21 | ... 22 | } 23 | ``` 24 | 25 | 2. Defina um `menu` e um `sub-menu` agora no lugar do antigo `#category-menu`, nele colocaremos todo o menu que já tínhamos construído: 26 | 27 | ```diff 28 | { 29 | + "vtex.menu@2.x:menu#category-menu": { 30 | + "children": [ 31 | + "menu-item#categories" 32 | + ] 33 | + }, 34 | + "menu-item#categories": { 35 | + "props": { 36 | + "id": "menu-item-custom-categories", 37 | + "type": "custom", 38 | + "iconId": null, 39 | + "highlight": false, 40 | + "itemProps": { 41 | + "type": "internal", 42 | + "href": "#", 43 | + "noFollow": true, 44 | + "tagTitle": "Categories", 45 | + "text": "Categories" 46 | + } 47 | + }, 48 | + "blocks": [ "vtex.menu@2.x:submenu#categories" ] 49 | + }, 50 | + "vtex.menu@2.x:submenu#categories": { 51 | + "children": ["vtex.menu@2.x:menu#categories"] 52 | + }, 53 | "vtex.menu@2.x:menu#categories": { 54 | ... 55 | } 56 | ``` 57 | 58 | O que estamos fazendo aqui é criar um nível acima do menu que já tínhamos definido para então modificar a navegação para um formato de submenu, o resultado deve ser: 59 | 60 | ![image](https://user-images.githubusercontent.com/18701182/93835843-fa015600-fc56-11ea-9b0e-b30a281b2d2b.png) 61 | 62 | 3. No navegador, antes da URL do seu _workspace_ adicione um `view-source:` e procure por `title="Major Appliances"`, você verá duas referências no código, uma para o _header_ e outra para o _footer_. Isto significa que quando carregamos o HTML estamos trazendo juntos esses menus, ainda que não estejam sendo consumidos no primeiro momento: 63 | 64 | ![image](https://user-images.githubusercontent.com/18701182/93836918-a7299d80-fc5a-11ea-8804-0b2722742e17.png) 65 | 66 | 4. Com o menu em níveis agora definido, podemos adicionar uma nova `prop` ao menu pai, a fim de prevenir que os submenus sejam carregados até que o usuário interaja com as categorias: 67 | 68 | ```diff 69 | { 70 | "vtex.menu@2.x:menu#category-menu": { 71 | + "props": { 72 | + "experimentalOptimizeRendering": true 73 | + }, 74 | "children": [ 75 | "menu-item#categories" 76 | ] 77 | }, 78 | ... 79 | } 80 | ``` 81 | 82 | Volte para o código fonte, atualize a página e procure novamente por `title="Major Appliances"` 83 | 84 | ![image](https://user-images.githubusercontent.com/18701182/93837006-f5d73780-fc5a-11ea-84c8-18542756e5a7.png) 85 | 86 | Veja que nenhuma referência é encontrada, mas que se você navegar, o comportamento continua o mesmo. Isso porque os submenus são carregados somente depois do *load* inicial. 87 | 88 | 89 | ### Está com dúvidas? 90 | 91 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-performance-step03submenu-optimization-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /5 - Melhorando performance/6 - Refatorando blocos/README.md: -------------------------------------------------------------------------------- 1 | # Refatorando blocos 2 | 3 | Alguns blocos ao longo do tempo são substituídos por outros não só para aumentar a flexibilidade e facilidade de operação, mas também para otimizar o seu comportamento e performance. 4 | 5 | O Slider Layout (conhecido no curso de Layouts Complexos) foi aprimorado para que usasse _lazy load_ no conteúdo carregado. Isto quer dizer que produtos e imagens só são carregados quando o usuário, de fato, as solicita. Este tipo de comportamento não está disponível na Shelf e Carrossel, e para otimizar ainda mais a performance, vamos ver como podemos substituí-los. 6 | 7 | ## Atividade 8 | 9 | 1. No arquivo `home.jsonc` declare dois blocos de texto para substituir os títulos: 10 | 11 | 12 | ```diff 13 | // store/blocks/home/home.jsonc 14 | { 15 | ... 16 | + "rich-text#new-arrivals": { 17 | + "props": { 18 | + "text": "New arrivals", 19 | + "font": "t-heading-2", 20 | + "textPosition": "CENTER", 21 | + "textAlign": "CENTER" 22 | + } 23 | + }, 24 | + "rich-text#clearance": { 25 | + "props": { 26 | + "text": "Clearance", 27 | + "font": "t-heading-2", 28 | + "textPosition": "CENTER", 29 | + "textAlign": "CENTER" 30 | + } 31 | + }, 32 | } 33 | ``` 34 | 35 | 2. Mude o nome das `shelf`'s para que use `list-context.product-list`: 36 | 37 | ```diff 38 | { 39 | ... 40 | - "shelf#new-arrivals": { 41 | + "list-context.product-list#new-arrivals": { 42 | ... 43 | - "shelf#clearance": { 44 | + "list-context.product-list#clearance": { 45 | ... 46 | } 47 | ``` 48 | 49 | 3. Remova as propriedades da shelf que não são mais necessárias em **ambas as shelfs**: 50 | 51 | ```diff 52 | { 53 | "list-context.product-list#new-arrivals": { 54 | "blocks": ["product-summary.shelf"], 55 | "props": { 56 | "orderBy": "OrderByTopSaleDESC", 57 | - "paginationDotsVisibility": "never", 58 | "collection": "139", 59 | - "productList": { 60 | - "maxItems": 9, 61 | - "itemsPerPage": 3, 62 | - "minItemsPerPage": 1.5, 63 | - "scroll": "BY_PAGE", 64 | - "arrows": true, 65 | - "titleText": "New arrivals" 66 | - } 67 | } 68 | }, 69 | ... 70 | } 71 | ``` 72 | 73 | 4. Adicione um `slider-layout#shelf` a ambos `product-list`'s: 74 | 75 | ```diff 76 | { 77 | "list-context.product-list#new-arrivals": { 78 | "blocks": ["product-summary.shelf"], 79 | + "children": ["slider-layout#shelf"], 80 | ... 81 | }, 82 | "list-context.product-list#clearance": { 83 | "blocks": ["product-summary.shelf"], 84 | + "children": ["slider-layout#shelf"], 85 | ... 86 | }, 87 | } 88 | ``` 89 | 90 | 5. Por fim, defina o `slider-layout#shelf` para que tenha o mesmo comportamento da prateleira que tiramos: 91 | 92 | ```diff 93 | { 94 | ... 95 | + "slider-layout#shelf": { 96 | + "props": { 97 | + "itemsPerPage": { 98 | + "desktop": 3 99 | + } 100 | + } 101 | + } 102 | } 103 | ``` 104 | 105 | 6. Edite os blocos que estão sendo usados no _template_: 106 | 107 | ```diff 108 | { 109 | "store.home": { 110 | "blocks": [ 111 | - "shelf#new-arrivals", 112 | - "shelf#clearance", 113 | + "rich-text#new-arrivals", 114 | + "list-context.product-list#new-arrivals", 115 | + "rich-text#clearance", 116 | + "list-context.product-list#clearance", 117 | ] 118 | } 119 | } 120 | 121 | ``` 122 | 123 | O resultado deve ser: 124 | 125 | ![image](https://user-images.githubusercontent.com/18701182/93842015-c977e700-fc6b-11ea-8cf5-0678a5f890fa.png) 126 | 127 | > **DICA:** Experimente fazer a mesma investigação do `view-source` do passo 3 e ver que os produtos da segunda página de cada prateleira não são carregados no HTML depois do refatoramento. 128 | 129 | 130 | ### Está com dúvidas? 131 | 132 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-performance-step06blocks-refact-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /6 - Blocos customizados/6 - Modificando o bloco countdown para ter um estilo configurável/README.md: -------------------------------------------------------------------------------- 1 | # Modificando o bloco countdown para ter estilos configuráveis 2 | 3 | ## Introdução 4 | Agora que já implementamos o `countdown`, que tal adicionar um pouco de customização? Nessa etapa, você irá aprender conceitos básicos a respeito de CSS *handles* e Tachyons para, em seguida, customizar o estilo da sua *app*. 5 | 6 | ### CSS Handles 7 | 8 | Os *handles* de CSS são utilizados para customizar os componentes da sua loja através de classes de CSS no código do tema. Todas essas configurações são definidas através da *app* `vtex.css-handles`, responsável por declarar todos os pontos de customização do seu bloco. 9 | 10 | Definindo os nomes dos seus *handles* e adicionando aos seus respectivos elementos HTML, é possível entregar ao usuário do tema pontos de customização que que permitam criar *layouts* flexíveis. 11 | 12 | ### Tachyons 13 | O Tachyons é um *framework* para CSS funcional. Diferentemente de outros *frameworks* conhecidos, como o Bootstrap, ele não apresenta componentes UI "pré-buildados". Na verdade, seu objetivo é justamente separar as regras de CSS em partes pequenas e reutilizáveis. Esse tipo de estratégia é comumente conhecida como *Subatomic Design System* e, caso você tenha interesse, pode encontrar uma referência [neste link](https://daneden.me/2018/01/05/subatomic-design-systems/). Essa estratégia torna *frameworks* como o Tachyons muito flexíveis, escaláveis e rápidos. 14 | 15 | Grande parte das definições de Tachyons podem ser alteradas, de forma que sua loja passe a ter um estilo mais customizado. Para isso, basta definir um arquivo JSON na pasta `styles/configs`; essas informações podem ser encontradas de forma mais detalhada em: [Customizing styles on VTEX IO](https://developers.vtex.com/docs/vtex-io-documentation-5-customizingstyles). 16 | 17 | ## Customizando seu bloco 18 | 19 | 1. Primeiro, importe o *hook* `useCssHandles`. Para isso, volte ao `Countdown.tsx` e faça o *import*: 20 | 21 | ```tsx 22 | // react/Countdown.tsx 23 | import { useCssHandles } from 'vtex.css-handles' 24 | ``` 25 | 26 | 2. Feito isso, defina em um *Array* todos os *handles* que serão necessários (neste caso, será utilizado apenas `'countdown'`): 27 | 28 | ```tsx 29 | // react/Countdown.tsx 30 | const CSS_HANDLES = ['countdown'] 31 | ``` 32 | 33 | 3. Após a definição do _array_, utilize o `useCssHandles` no componente `Countdown` para definir o *handle* do `countdown`: 34 | 35 | ```diff 36 | // react/Countdown.tsx 37 | const Countdown: StorefrontFunctionComponent = ({ targetDate = DEFAULT_TARGET_DATE }) => { 38 | const [timeRemaining, setTime] = useState({ 39 | hours: '00', 40 | minutes: '00', 41 | seconds: '00' 42 | }) 43 | 44 | + const handles = useCssHandles(CSS_HANDLES) 45 | 46 | tick(targetDate, setTime) 47 | 48 | return ( 49 |
50 |

51 | { `${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}` } 52 |

53 |
54 | ) 55 | } 56 | ``` 57 | 58 | 4. Por fim, é preciso utilizar o *handle* no componente a fim de ver a customização. Para isso, é necessário utilizar a prop `className` com as classes a serem utilizadas e as classes de Tachyons, para os estilos globais. 59 | 60 | ```diff 61 | // react/Countdown.tsx 62 | import React from 'react' 63 | ... 64 | 65 | const Countdown: StorefrontFunctionComponent = ({ targetDate = DEFAULT_TARGET_DATE }) => { 66 | const [timeRemaining, setTime] = useState({ 67 | hours: '00', 68 | minutes: '00', 69 | seconds: '00' 70 | }) 71 | 72 | const handles = useCssHandles(CSS_HANDLES) 73 | 74 | tick(targetDate, setTime) 75 | 76 | return ( 77 | +
78 | {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`} 79 |
80 | ) 81 | } 82 | ``` 83 | 84 | Vamos ver o resultado? 85 | 86 | ![image](https://user-images.githubusercontent.com/19495917/75475280-457cab80-5977-11ea-938e-d3c2b532e891.png) 87 | 88 | 89 | 90 | 91 | ### Está com dúvidas? 92 | 93 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-block-step05css-handles-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /5 - Melhorando performance/4 - Imagens/README.md: -------------------------------------------------------------------------------- 1 | # Imagens 2 | 3 | As imagens são parte essencial de uma loja. É imprescindível ter fotos de muito boa qualidade e que estejam com excelente resolução, para garantir que a experiência do produto esteja sendo passada da melhor maneira possível. 4 | 5 | Buscar qualidade ótima, no entanto, não deve ser sinônimo de desperdiçar banda. Não é necessário, por exemplo, carregar uma imagem de `8000px` de largura, sendo que na loja ela vai ser renderizada em uma tela de `600px` de largura. O que acontece, nesses casos, é que a imagem, depois de baixada, é redimensionada pelo navegador e a resolução extra é, então, perdida. 6 | 7 | ## Pontos de otimização 8 | 9 | No Store Framework, existem basicamente dois pontos em que as imagens podem ser otimizadas: 10 | 11 | - `product-image`: é a imagem de produto que é mostrada em sua página (pdp); 12 | - `product-summary-image` é a imagem de produto que é exibida em prateleiras e resultados de busca; 13 | - `image`: são imagens comuns, usadas para banners, carrosséis e _infocards_ 14 | 15 | Se estiver responsável por cuidar do cadastramento de imagens de uma loja, tenha certeza de comprimi-las antes. Isto pode garantir uma redução de até 85% do seu peso, sem que seja necessário também perder qualidade. Uma boa alternativa de ferramenta para facilitar este trabalho é usar o [Squoosh](https://squoosh.app/). 16 | 17 | ## Atividade 18 | 19 | 1. Na página principal, inspecione algum dos produtos da prateleira de _New arrivals_ clicando com o botão direito em cima e em seguida em `Inspecionar`. É possível observar no código que aparece, que existe um desperdício de resolução, está sendo solicitado `500px` como valor padrão, sendo que apenas `281px` estão sendo utilizados: 20 | 21 | ![image](https://user-images.githubusercontent.com/18701182/93837727-ad6d4900-fc5d-11ea-818c-1f4942f091cf.png) 22 | 23 | 2. No arquivo `/store/blocks.jsonc`, defina então o `product-image`, especificando o seu `width`: 24 | 25 | ```diff 26 | // /store/blocks.jsonc 27 | { 28 | ... 29 | "stack-layout#prodsum": { 30 | "children": [ 31 | "product-summary-image", 32 | "product-summary-specification-badges" 33 | ] 34 | }, 35 | + "product-summary-image": { 36 | + "props": { 37 | + "width": 281 38 | + } 39 | + }, 40 | ... 41 | } 42 | ``` 43 | 44 | Inspecionando novamente, vemos que todas as imagens de prateleira e resultado de busca estão com o tamanho correto: 45 | 46 | 47 | 48 | 3) Para melhorar o _caching_ de CDN e garantir que nenhuma imagem externa está sendo carregada, no arquivo `store/blocks/search.jsonc`, edite o `info-card` existente para atualizar sua implementação e fazê-lo usando um `image`: 49 | 50 | ```diff 51 | // /store/blocks/search.jsonc 52 | { 53 | "flex-layout.row#depBanner": { 54 | "children": [ 55 | - "info-card#depbanner" 56 | + "image#depbanner" 57 | ] 58 | }, 59 | } 60 | ``` 61 | 62 | > Para saber um pouco mais sobre a definicação de _Content Delivery Network_ (CDN), veja [esse artigo](https://www.cloudflare.com/learning/cdn/what-is-a-cdn/) da Cloudflare. 63 | 64 | 4) Defina, por último, o `image#depbanner`: 65 | 66 | ```diff 67 | { 68 | ... 69 | + "image#depbanner": { 70 | + "props": { 71 | + "src": "assets/electronics.png" 72 | + } 73 | + }, 74 | } 75 | ``` 76 | 77 | ![image](https://user-images.githubusercontent.com/18701182/93905955-f52db800-fcd1-11ea-9129-065bea80145b.png) 78 | 79 | 5. Usamos o exemplo `electronics.png` que já estava disponível no repositório, mas qualquer imagem pode ser adicionada se inserida dentro da pasta `/assets`. Experimente acessar algum portal de stock photo gratuito (como o [Pexels](https://www.pexels.com/)), baixar uma imagem e comprimí-la no [Squoosh](https://squoosh.app/). Baixe a imagem, adicione-a a pasta de `/assets` e depois referencie com o nome que voce adicionou: 80 | 81 | ```diff 82 | { 83 | ... 84 | "image#depbanner": { 85 | "props": { 86 | - "src": "assets/electronics.png" 87 | + "src": "assets/{{sua_imagem}}" 88 | } 89 | }, 90 | } 91 | ``` 92 | 93 | ![image](https://user-images.githubusercontent.com/18701182/93907719-168fa380-fcd4-11ea-8b03-6d864d4aeadd.png) 94 | >Exemplo de redução de 60% na compressão com Squoosh 95 | 96 | 97 | ### Está com dúvidas? 98 | 99 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-performance-step04images-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /1 - Blocos Básicos/2 - Começando com Rich Text/README.md: -------------------------------------------------------------------------------- 1 | # Introduzindo o Rich Text 2 | 3 | ## Rich Text 4 | 5 | Começaremos personalizando a *página inicial*. Na pasta `/store/blocks` do seu tema, você encontrará um arquivo chamado` home.jsonc`. Este arquivo determina como os blocos que você pretende usar são organizados. A linguagem usada na composição do layout é simples e baseada em [JSON](http://www.json.org/json-en.html). 6 | 7 | Em `home.jsonc`, você notará um bloco que é padrão em todos os temas, ou seja,` store.home`. Este bloco determina quais blocos filhos serão exibidos na página inicial. 8 | 9 | ```json 10 | { 11 | "store.home": { 12 | "blocks": [] 13 | } 14 | ... 15 | } 16 | ``` 17 | 18 | Vamos usar Rich Text em seu corpo: 19 | 20 | ```json 21 | { 22 | "store.home": { 23 | "blocks": [ 24 | "rich-text" 25 | ] 26 | } 27 | ... 28 | } 29 | ``` 30 | 31 | Portanto, `store.home` agora sabe que precisa renderizar um Rich Text. No entanto, ainda não especificamos qual visual esse Rich Text deve adotar. Para isso, precisaremos **definir o bloco**. 32 | 33 | ## Definindo blocos 34 | 35 | A definição de um bloco deve sempre ser executada separadamente de qualquer outro bloco, no nível de origem do arquivo JSON. 36 | 37 | ```json 38 | { 39 | "store.home": { 40 | "blocks": [ 41 | "rich-text" <----- Aqui o bloco é usado dentro de outro 42 | ] 43 | }, 44 | "rich-text": { <----- Aqui está no nível da fonte 45 | } 46 | } 47 | ``` 48 | 49 | Na definição do bloco, você pode definir seu comportamento e visual. **Pontos de personalização** devem ser usados ​​para conseguir isso, então vamos começar usando os `props` de Rich Text: 50 | 51 | ```json 52 | { 53 | "store.home": { 54 | "blocks": [ 55 | "rich-text" 56 | ] 57 | }, 58 | "rich-text": { 59 | "props": { 60 | 61 | } 62 | } 63 | } 64 | ``` 65 | 66 | Leia o Rich Text [documentação](https://developers.vtex.com/docs/vtex-rich-text#rich-text) mais uma vez e vamos definir os adereços que usaremos para personalizar o bloco. 67 | 68 | Queremos obter um simples "Olá, Mundo!", E olhando para as props, notamos um chamado: `text` [(Texto escrito em linguagem de marcação a ser exibido)](https://developers.vtex.com/docs/vtex-rich-text#rich-text). Esta é a prop que determina qual texto será exibido. 69 | 70 | Incluindo esta prop, agora temos o seguinte: 71 | 72 | ```json 73 | { 74 | "store.home": { 75 | "blocks": [ 76 | "rich-text" 77 | ] 78 | }, 79 | "rich-text": { 80 | "props": { 81 | "text": "Hello, World!" 82 | } 83 | } 84 | } 85 | ``` 86 | 87 | Lendo a [documentação do Markdown](https://www.markdownguide.org/cheat-sheet/), aprendemos que, para que um texto apareça em *itálico*, precisamos apenas colocar esse texto entre `*` 88 | 89 | ```json 90 | { 91 | "store.home": { 92 | "blocks": [ 93 | "rich-text" 94 | ] 95 | }, 96 | "rich-text": { 97 | "props": { 98 | "text": "*Hello, World!*" 99 | } 100 | } 101 | } 102 | ``` 103 | 104 | Para centralizar o alinhamento do texto, podemos adicionar a prop `textPosition` e atribuir a ela o valor `CENTER`: 105 | 106 | ```json 107 | { 108 | "store.home": { 109 | "blocks": [ 110 | "rich-text" 111 | ] 112 | }, 113 | "rich-text": { 114 | "props": { 115 | "text": "*Hello, World!*", 116 | "textPosition": "CENTER" 117 | } 118 | } 119 | } 120 | ``` 121 | 122 | ## Atividade 123 | 124 | Defina um [Rich Text](https://developers.vtex.com/docs/vtex-rich-text#rich-text) em sua página inicial e crie um **negrito** "Hello, World!" que está **alinhado à direita**. Faça isso trocando o código já presente no arquivo `store/blocks/home.jsonc` por este: 125 | 126 | ```diff 127 | { 128 | "store.home": { 129 | "blocks": [ 130 | + "rich-text" 131 | ] 132 | }, 133 | + "rich-text": { 134 | + "props": { 135 | + "text": "**Hello, World!**", 136 | + "textPosition": "RIGHT" 137 | + } 138 | + } 139 | } 140 | ``` 141 | 142 | Depois de executar o `vtex link`, seu` rich-text` deve ficar assim: 143 | 144 | 145 | 146 | Note: Lembre-se de acessar a [documentação](https://vtex.io/docs/components/all/vtex.rich-text/) do Rich Text se você tiver alguma dúvida durante a atividade. 147 | 148 | 149 | ### Está com dúvidas? 150 | 151 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-basic-blocks-step02richtext-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /7 - Serviços/2 - Visão geral - Entendendo o Boilerplate/README.md: -------------------------------------------------------------------------------- 1 | # Visão geral: Entendendo o _Boilerplate_ 2 | 3 | ## Introdução 4 | 5 | Fazendo uma breve apresentação do _boilerplate_, há duas pastas (`/node` e `/graphql`) e o arquivo `manifest.json`, que é um arquivo importante para a sua aplicação no VTEX IO, dado que será o primeiro ponto de comunicação da sua _app_ com o VTEX IO. 6 | 7 | ## Visão geral do `manifest.json` 8 | 9 | No arquivo `manifest.json`, você encontrará o nome da _app_, _vendor_, versão e outras informações que você deve prestar atenção: _builders_, _policies_ e _dependencies_. Neste passo inicial, temos as seguintes configurações: 10 | 11 | - builders: quais _builders_ sua _app_ precisará. Neste caso, temos até o momento os builders `docs` e `node`, com suas respectivas versões; 12 | - policies: se a _app_ que está sendo implementada necessita acessar serviços externos ou pegar dados de um local específico, é necessário declará-las. Até o momento, não há nenhuma _policy_ declarada. 13 | - dependencies: outras _apps_ do VTEX IO que a sua _app_ depende. Como mostrado abaixo, será necessário também linkar a _app_ `events-example`, e esta é uma depenência que está declarada na aplicação deste curso. 14 | 15 | ## Visão geral do diretório `/node` 16 | 17 | Todas as pastas utilizadas durante este curso já estão no projeto inicial. A maioria dos diretórios está vazio e serão preenchidos com outros arquivos ao longo do curso. 18 | 19 | - `/node/clients`: ambos os arquivos estão praticamente em branco e são apenas _placeholders_ para os próximos passos; 20 | 21 | - `/node/handlers`: contém um _handler_ que será utilizado nos próximos passos; 22 | 23 | - `/node/utils`: você encontrará um aquivo que contém declarações de constantes globais (`/node/constants.ts`); 24 | 25 | - `/node/index.ts`: contém as declarações iniciais para as funcionalidades da _app_, como as declarações de serviços e de cache, que serão incrementadas durante o curso. Neste arquivo, também é possível exportar implementações de funções que são _resolvers_; 26 | 27 | - `/node/service.json`: Descreve a sua API REST e algumas características que impactam diretamente nos atributos de infrastrutura da sua _app_. Seu 28 | 29 | Seu arquivo `service.json` pode ser encontrado dentro da pasta `/node` e será similar a: 30 | 31 | ``` 32 | { 33 | "memory": 256, 34 | "timeout": 2, 35 | "minReplicas": 2, 36 | "maxReplicas": 4, 37 | "routes": { 38 | "status": { 39 | "path": "/_v/status/:code", 40 | "public": true 41 | } 42 | } 43 | ``` 44 | 45 | | Field | Type | Description | 46 | | ----------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | 47 | | memory | MegaBytes. | O quanto de memória sua _app_ terá alocada. Este valor será sobrescrito se o IO detectar que sua _app_ está abusando no uso de memória 48 | | timeout | Seconds | A infrastrutura do VTEX IO irá abortar a conexão se o _request_ demora mais do que o valor do _timeout 49 | | minReplicas | Integer | Quando sua _app_ estiver rodando, este valor é a quantidade réplicas mínimas estarão disponíveis | 50 | | maxReplicas | Integer | A máxima quantidade de réplicas a estarem disponíveis | 51 | | routes | - | Descreve as rotas REST da sua _app_, dentro deste objeto, você informará o nome, o caminho e se é pública ou privada | 52 | 53 | ## Visão geral do diretório `/graphql` 54 | 55 | Neste diretório, você encontrará apenas pastas vazias e o arquivo vazio `/graphql/schema.graphql`. Este também será preenchido ao longo do curso. 56 | 57 | ## Dependências 58 | 59 | A _app_ tem uma dependência, que é a _app_ `events-example`. Esta aplicação, quando linkada em uma conta e _workspace_ específicos, é responsável por prover exemplos de eventos. Durante o curso, conforme nos aproximarmos do assunto de eventos, haverá uma visão mais completa a respeito da _app_ `events-example`. 60 | 61 | ## Dando início ao curso 62 | 63 | Por enquanto, clone (`git clone`) a _app_ `events-example` [deste repositório](https://github.com/vtex-apps/events-example) e rode `vtex link` na pasta onde o repositório foi clonado. 64 | 65 | > Sem a aplicação `events-example`, este curso não será linkado com sucesso, dado que a _app_ `events-example` está listada como uma dependência. 66 | 67 | Após rodar `vtex link` na _app_ `events-example`, o terminal deve exibir uma rota de _healthcheck_, que será utilizada mais tarde. Ela é similar a imagem abaixo: 68 | 69 | ![image](https://user-images.githubusercontent.com/43679629/83797811-91777480-a679-11ea-9bc9-9d32ace321d7.png) -------------------------------------------------------------------------------- /6 - Blocos customizados/3 - Linkando uma app e utilizando-a no tema da loja/README.md: -------------------------------------------------------------------------------- 1 | # Linkando uma _app_ e a utilizando em um tema de loja 2 | 3 | ## Introdução 4 | 5 | Dado que você já está familiarizado com o Store Framework, você deve saber que utilizamos blocos, como a `shelf` e o `sku-selector`, para criar uma loja no VTEX IO. Neste passo, você irá criar um bloco a ser utilizado na _home_ do tema da sua loja. 6 | 7 | ## Adicionando um texto fixo ao nosso componente 8 | 9 | 1. No _template_ local que foi clonado, abra o arquivo `Countdown.tsx`. Você verá que contém uma implementação base de um componente React, que é uma `div` vazia, como mostrado abaixo: 10 | 11 | ```tsx 12 | //react/Countdown.tsx 13 | import React from 'react' 14 | 15 | interface CountdownProps {} 16 | 17 | const Countdown: StorefrontFunctionComponent = ({}) => { 18 | return
19 | } 20 | 21 | Countdown.schema = { 22 | title: 'editor.countdown.title', 23 | description: 'editor.countdown.description', 24 | type: 'object', 25 | properties: {}, 26 | } 27 | 28 | export default Countdown 29 | ``` 30 | 31 | Algumas coisas para prestar atenção: 32 | 33 | - Os tipos para as _props_ do componente são definidos aqui: 34 | 35 | ```ts 36 | interface CountdownProps {} 37 | ``` 38 | 39 | - Este _schema_ se refere ao conteúdo que é mostrado no _Site Editor_: 40 | 41 | ```tsx 42 | Countdown.schema = { 43 | title: 'editor.countdown.title', 44 | description: 'editor.countdown.description', 45 | type: 'object', 46 | properties: {}, 47 | } 48 | ``` 49 | 50 | > Para que o seu bloco possa **aceitar configurações do usuário**, é preciso exportar um `schema` no componente React responsável por aquele bloco utilizando [JSON *schema*](https://json-schema.org/). Isso irá, automaticamente, gerar um formulário para o Site Editor relativo ao bloco que você está desenvolvendo. 51 | 52 | 2. Agora, vamos adicionar uma _tag_ `h1` dentro do componente: 53 | 54 | ```diff 55 | const Countdown: StorefrontFunctionComponent = ({}) => { 56 | - return
57 | + return ( 58 | +
59 | +

Countdown Test

60 | +
61 | + ) 62 | } 63 | ``` 64 | 65 | 3. De forma a ver o bloco que você acabou de criar, é necessário declará-lo em um tema. 66 | 67 | > Qual tema eu posso utilizar? 68 | 69 | No caso de já ter um tema dos cursos feitos anteriormente, você pode utilizá-lo. Porém, se você ainda não tiver um, pode utilizar o `vtex.store-theme`, que pode ser clonado ao rodar o seguinte comando no seu terminal: 70 | 71 | ``` 72 | git clone https://github.com/vtex-apps/store-theme.git 73 | ``` 74 | 75 | >Observação: Pode ser clonado em uma pasta de sua preferência, mas não dentro do diretório da aplicação que você está desenvolvendo. 76 | 77 | Agora, para evitar conflitos, vá ao terminal e unlinke qualquer tema ou aplicação que você tenha linkado no seu _workspace_: 78 | 79 | ``` 80 | vtex unlink --all 81 | ``` 82 | 83 | Com os dois repositórios prontos, você precisa linkar ambos, em dois terminais diferentes, utilizando o seguinte comando: 84 | ``` 85 | vtex link 86 | ``` 87 | > Lembre-se de utilizar seu próprio _workspace_! 88 | 89 | 4. Com ambos os _links_ ativos (tema e bloco customizado), vamos adicionar o bloco ao tema. Para fazer isso, é necessário adicioná-lo nas dependências do tema: 90 | 91 | ```diff 92 | { 93 | ... 94 | "dependencies": { 95 | ... 96 | + "vtex.countdown": "0.x", 97 | ... 98 | }, 99 | ... 100 | } 101 | ``` 102 | 103 | 5. Por fim, nós queremos adicionar o bloco na loja, para que este possa ser visto. Dentro do arquivo `store-theme/store/blocks/home/home.jsonc`, declare um bloco `countdown`: 104 | 105 | ```diff 106 | { 107 | "store.home": { 108 | "blocks": [ 109 | + "countdown", 110 | ... 111 | ] 112 | ... 113 | } 114 | ... 115 | } 116 | ``` 117 | 118 | O resultado esperado é encontrar um _header_ no topo da _home_ da sua loja, como visto abaixo: 119 | 120 | ![image](https://user-images.githubusercontent.com/19495917/80492927-0e0c8a00-893b-11ea-8a1d-aaad2874a014.png) 121 | 122 | > No caso de adicionar o bloco como o último em `store.home`, você o verá no final da página. 123 | 124 | ### Está com dúvidas? 125 | 126 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-block-step02component-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /7 - Serviços/7 - GraphQL - Consultando dados do Master Data/README.md: -------------------------------------------------------------------------------- 1 | # GraphQL 2 | 3 | ## Introdução 4 | 5 | Agora que a contagem dos produtos está atualizada, precisamos consultar os dados dos N produtos mais vistos. Para tal, é possível utilizar o Master Data para consultar os dados de visitas às páginas de produto e ordená-los pelo campo _count_. Também podemos limitar a quantidade de produtos que são consultados, de forma a criar um _rank_ customizado de produtos mais visitados. 6 | 7 | ## GraphQL 8 | 9 | Para pegar os dados de visitas por produto, vamos utilizar [GraphQL](https://graphql.org/), a tecnologia utilizada pelo VTEX IO para consulta de dados, para implementar uma _query_ para o Master Data. GraphQL permite que implementemos _queries_ de maneira simples e rápida, especificando os dados que você deseja consultar. Isto faz com que a API seja confiável, dado que o GraphQL controla os dados que são consultados, ao invés do servidor em si. 10 | 11 | **Também é a única maneira de criar uma interface entre os serviços e as aplicações de frontend.** 12 | 13 | Portanto, o GraphQL utiliza tipos e um _schema_ para as _queries_ para especificar os dados consultados, e _resolvers_ para pegar apenas os dados necessários. 14 | 15 | Vamos lá? 16 | 17 | ## Recuperando dados do Master Data 18 | 19 | 1. Dentro do diretório `/graphql`, crie uma pasta chamada `/types`. Nesta pasta, crie o arquivo `productView.graphql` e declare o tipo de lista de produto que você quer consultar: 20 | 21 | ``` 22 | # /graphql/types/productView.graphql 23 | type ProductView { 24 | slug: String 25 | count: Int 26 | } 27 | ``` 28 | 29 | 2. Ainda na pasta `/graphql`, defina o _schema_ no arquivo `schema.graphql`: 30 | 31 | ``` 32 | type Query { 33 | productList(topN: Int): [ProductView] 34 | } 35 | ``` 36 | 37 | > Tenha em mente que o _schema_ irá definir a estrutura da _query_ e os dados que serão recuperados. 38 | 39 | Além disso, na declaração do _schema_, você pode incluir diretivas. Em alguns casos, é necessário, como casos em que precisamos pegar _tokens_ de usuário ou usar _cookies_ (exemplo: `OrderForm`). Para ler um pouco mais sobre isso, veja [este _link_](https://github.com/vtex-apps/graphql-example). 40 | 41 | 3. Com o _schena_, os tipos e a _query_ definida, precisamos criar o _resolver_ da _query_. O _resolver_ é o código a ser executado quando uma _query_ acontece. No nosso caso, queremos executar um _scroll_ no **Master Data**, ordenando pela contagem (já que queremos pegar os N produtos mais vistos) e limitando o tamanho da página (_top N_). Para definir este _resolver_, crie a pasta `/node/resolvers` e nela, crie o arquivo `products.ts` e faça o seguinte: 42 | 43 | ```ts 44 | // node/resolvers/products.ts 45 | import { COURSE_ENTITY } from '../utils/constants' 46 | 47 | export const productList = async ( 48 | _: any, 49 | { topN }: { topN: number }, 50 | { clients: { masterdata } }: Context 51 | ) => 52 | masterdata.scrollDocuments( 53 | { 54 | dataEntity: COURSE_ENTITY, 55 | fields: ['count', 'slug'], 56 | schema: 'v1', 57 | size: topN, 58 | sort: `count DESC` 59 | } 60 | ).then((({data}) => data)) 61 | ``` 62 | 63 | > Nota: você pode checar a documentação a respeito do uso de _scroll_ no Master Data neste [link](https://help.vtex.com/tutorial/querying-the-master-data-via-scroll-path--tutorials_4631) 64 | 65 | 4. Importe o _resolver_ no arquivo `index.ts`: 66 | 67 | ```ts 68 | import { productList } from './resolvers/products' 69 | ``` 70 | 71 | 5. Por fim, precisamos atualizar o arquivo `index.ts` para definir o _resolver_ e a _query_. Complete a declaração de `Service` como abaixo: 72 | 73 | ```ts 74 | }, 75 | graphql: { 76 | resolvers: { 77 | Query: { 78 | productList, 79 | }, 80 | }, 81 | }, 82 | }) 83 | ``` 84 | 85 | Também é necessário lembrar de adicionar o builder de `graphql` ao arquivo `manifest.json`: 86 | 87 | ```diff 88 | //manifest.json 89 | "builders": { 90 | + "graphql": "1.x", 91 | "docs": "0.x", 92 | "node": "6.x" 93 | }, 94 | ``` 95 | 96 | Finalmente, linke a _app_ e você poderá ver no terminal uma rota GraphQL. O resultado deve ser semelhante ao da imagem abaixo: 97 | 98 | ![image](https://user-images.githubusercontent.com/43679629/82947940-3c4faa80-9f77-11ea-8bfa-138d11cdec1f.png) 99 | 100 | 101 | ### Está com dúvidas? 102 | 103 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-service-course-step07graphql-implementation-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /6 - Blocos customizados/5 - Criando a funcionalidade do bloco countdown/README.md: -------------------------------------------------------------------------------- 1 | # Criando a funcionalidade do bloco countdown 2 | 3 | ## Introdução 4 | Agora que o básico do nosso componente está funcional, é hora de implementar efetivamente o contador. Para isso, é preciso utilizar um *hook* do React, chamado `useState`; 5 | 6 | 7 | ## O *hook* `useState` 8 | 9 | É chamado dentro de um componente funcional para atualizar e consumir o *state* de um componente. O *state* simboliza o estado atual de um componente. 10 | 11 | > O `useState` retorna um par: o valor do estado atual e uma função para atualizá-lo. 12 | 13 | Voltando ao exemplo apresentado na etapa anterior, podemos mostrar na prática os conceitos abordados anteriormente. Para lembrar do exemplo, veja o código abaixo: 14 | 15 | ```tsx 16 | const [count, setCount] = useState(0) 17 | ``` 18 | 19 | No trecho acima é importante observar três coisas: 20 | * Na variável `count`, é possível consumir o estado atual; 21 | * `setCount` é uma função para atualizá-lo; 22 | * `0` é o valor do estado inicial 23 | 24 | 25 | ```tsx 26 | const [timeRemaining, setTime] = useState({ 27 | hours: '00', 28 | minutes: '00', 29 | seconds: '00' 30 | }) 31 | ``` 32 | 33 | ## Fazendo seu contador funcionar! 34 | 1. Precisamos importar algumas funções e tipos para continuar: 35 | 36 | ```tsx 37 | //react/Countdown.tsx 38 | import React, { useState } from 'react' 39 | import { TimeSplit } from './typings/global' 40 | import { tick, getTwoDaysFromNow } from './utils/time' 41 | ``` 42 | 43 | > A função `getTwoDaysFromNow` será utilizada para tratar condições de borda. Será explicado mais tarde neste passo. 44 | 45 | 2. Adicione o *hook* de atualização de estado (`useState`) 46 | 47 | ```diff 48 | //react/Countdown.tsx 49 | const Countdown: StorefrontFunctionComponent = ({ targetDate }) => { 50 | + const [timeRemaining, setTime] = useState({ 51 | + hours: '00', 52 | + minutes: '00', 53 | + seconds: '00' 54 | + }) 55 | 56 | return ( 57 |
58 | { targetDate } 59 |
60 | ) 61 | } 62 | ``` 63 | >Observe os detalhes: `timeRemaining` é o estado atual, `setTime` é a função de atualização do estado, `TimeSplit` é o tipo e, por fim, o objeto `{hours: '00', minutes: '00', seconds: '00'}` é o estado inicial do componente. 64 | 65 | 3. Adicione uma `targetDate` padrão para o caso de não haver um valor inicial definido. Vamos utilizar para isto uma data que é definida como dois dias a partir da data atual e ela será calculada em uma função utilitária que foi previamente importada da pasta `/utils`: 66 | 67 | ```typescript 68 | //react/Countdown.tsx 69 | const DEFAULT_TARGET_DATE = getTwoDaysFromNow() 70 | ``` 71 | 72 | 4. Utilize a função `tick` e a constante `DEFAULT_TARGET_DATE` para fazer o contador: 73 | ```diff 74 | //react/Countdown.tsx 75 | const Countdown: StorefrontFunctionComponent = ({ targetDate = DEFAULT_TARGET_DATE }) => { 76 | const [timeRemaining, setTime] = useState({ 77 | hours: '00', 78 | minutes: '00', 79 | seconds: '00' 80 | }) 81 | 82 | + tick(targetDate, setTime) 83 | 84 | return ( 85 |
86 | { targetDate } 87 |
88 | ) 89 | } 90 | ``` 91 | 92 | 5. Altere o `h1` para que ele exiba o contador que criamos. Para isso, precisamos utilizar o estado atual `timeRemaining`: 93 | ```diff 94 | //react/Countdown.tsx 95 | const Countdown: StorefrontFunctionComponent = ({ targetDate = DEFAULT_TARGET_DATE }) => { 96 | const [timeRemaining, setTime] = useState({ 97 | hours: '00', 98 | minutes: '00', 99 | seconds: '00' 100 | }) 101 | 102 | tick(targetDate, setTime) 103 | 104 | return ( 105 |
106 | -

{ targetDate }

107 | +

{ `${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}` }

108 |
109 | ) 110 | } 111 | ``` 112 | > A formatação da *string* do contador está no formato `HH:MM:SS`, feita através do *split* em `hours`, `minutes` e `seconds`. 113 | 114 | Assim, com essas alterações, veremos a atualização em tempo real do contador! O resultado na *home* é esse: 115 | 116 | ![image](https://user-images.githubusercontent.com/19495917/75474406-b3c06e80-5975-11ea-82ec-89ab27504873.png) 117 | 118 | 119 | 120 | 121 | ### Está com dúvidas? 122 | 123 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-block-step04countdown-implementation-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /9 - Chamando as APIs de Commerce/2 - Encontrando as APIs do VTEX Commerce/README.md: -------------------------------------------------------------------------------- 1 | # Encontrando as APIs do VTEX Commerce 2 | 3 | ## Introdução 4 | 5 | Neste passo, você aprenderá como encontrar a documentação das APIs da VTEX, além de entender as diferenças para chamá-las através do VTEX IO. 6 | 7 | ## Portal do Desenvolvedor 8 | 9 | Antes de começar a desenvolver sua integração com as APIs de Commerce da VTEX, é fundamental que você possa **descobrí-las** e entender seu funcionamento. O [Portal de Desenvolvedor](https://developers.vtex.com/reference/get-to-know-vtex-apis) da VTEX lista todas as APIs disponíveis, além de conter explicações sobre como usar cada um dos _endpoints_ oferecidos. 10 | 11 | ![Portal de Desenvolvedor da VTEX](https://user-images.githubusercontent.com/18706156/92934603-0f3be080-f41e-11ea-95f7-34f0238a8d96.png) 12 | 13 | A maioria das APIs seguem a especificação [REST](https://en.wikipedia.org/wiki/Representational_state_transfer). Também é importante ressaltar que todas as chamadas **operam sobre uma conta** na VTEX. 14 | 15 | ## Diferenças no VTEX IO 16 | 17 | O VTEX IO é um *first-class citizen* para as APIs da VTEX e, por isso, existem algumas diferenças usando-as na sua aplicação. O Portal do Desenvolvedor recebe alguns parâmetros de identificação e autorização que não são necessários quando chamando os *endpoints* pelo VTEX IO. 18 | 19 | ## Autenticação 20 | 21 | Tradicionalmente, a VTEX autentica chamadas para rotas privadas (`/pvt`) utilizando um par **AppKey** e **AppToken**, obtidos no painel de administração de uma conta. No VTEX IO **não é recomendado que se use esse par de chave e token para se autenticar**, já que a plataforma oferece outra maneira mais escalável e elegante. 22 | 23 | Todas as apps que são desenvolvidas no VTEX IO representam um **recurso** na plataforma, o que possibilita uma aplicação interagir com outros sistemas **em nome de si mesma**, devidamente autorizada pelo administrador da conta. Fica a cargo do desenvolvedor da app **declarar as permissões necessárias**. 24 | 25 | Na prática, isso significa duas coisas: 26 | 1. Tanto o endpoint como o *role* necessários para acessar alguma API devem ser **declarados no `manifest.json` da app**. 27 | 2. As chamadas devem ser realizadas com **um token do VTEX ID** ao invés do par **AppKey** e **AppToken**. 28 | 29 | Você aprenderá como realizar essas configurações logo mais! 30 | 31 | > O *role*, falando sobre autorização dentro da VTEX, representa um "papel" no *License Manager*, gerenciador de usuários e autorizações na plataforma. Alguns módulos da VTEX não requerem nenhum *role* específico, mas outros podem requerer e são necessários ao "caller" para conseguir acessar aquele recuros. 32 | 33 | ## Token da app e Token do usuário 34 | - Cada app no VTEX IO, automaticamente, recebe um `authToken` que pode ser utilizado para chamar APIs externas. Esse token, que pode ser obtido no objeto de contexto em qualquer requisição, tem todas as permissões que foram declaradas no campo `policies` do manifesto da aplicação. 35 | - É necessário verificar se faz sentido usar este token nas requisições, especialmente ao acessar **sistemas críticos** das contas. Caso você identifique uma situação assim, também é possível utilizar o **token do usuário que está usando a app**. 36 | 37 | 38 | ## `accountName` 39 | 40 | Como dito, todas as chamadas para módulos do Commerce da VTEX são relativas à alguma `account` na VTEX, e tradicionalmente essa informação é passada através da *query string* `?an`. Porém, ao longo do curso, iremos apresentar abstrações criadas no VTEX IO que **dispensam essa configuração manual**. 41 | 42 | Vale ressaltar que as apps que são desenvolvidas no VTEX IO **devem funcionar independente da conta onde estão instaladas**, por isso é importante que nenhuma destas informações críticas seja *"hard-coded"*. 43 | 44 | ## Atividade 45 | 46 | 1. Para verificar o token que cada aplicação recebe da plataforma, no _middleware_ de validação da app `service-example`, adicione o seguinte _log_: 47 | 48 | `node/middlewares/validate.ts` 49 | ```diff 50 | + console.log(ctx.vtex.authToken) 51 | console.log('Received params:', params) 52 | 53 | const { code } = params 54 | ... 55 | ``` 56 | 2. Agora, **linke sua app** e acesse a URL pública fornecida no processo. A URL será algo como `https://{workspace}--{account}.myvtex.com/_v/status/:code`. Substitua `code` por `200` e, após acessar a URL, verifique o conteúdo que foi loggado no `console.log` através do processo do `vtex link`. 57 | ![Exemplo do console.log do Token](https://user-images.githubusercontent.com/18706156/93616134-b4206580-f9aa-11ea-8331-0fbecc7cf586.png) 58 | 59 | > Você pode verificar o conteúdo desse token no site https://jwt.io/. Ele é um token parecido com o seu token pessoal (rode o comando `vtex local token`), porém representa a aplicação que você está desenvolvendo e conterá as permissões que foram solicitadas por esta app no `manifest.json`. 60 | 61 | 62 | ### Está com dúvidas? 63 | 64 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-calling-commerce-apis-step02references-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /3 - Tornando sua loja única/4 - Criando templates customizados/README.md: -------------------------------------------------------------------------------- 1 | # Criando templates customizados 2 | 3 | ## Introdução 4 | 5 | Até agora, você aprendeu como utilizar CSS, _Tachyons_ e _Markdown_ para customizar seus blocos no Store Framework. Porém, também é importante aprende como criar _templates_ customizados, de forma que a sua loja possa ter _landing pages_ customizadas, com uma URL bem definida e conteúdos específicos. 6 | 7 | Lojas são compostas por várias páginas diferentes, cada uma com _layout_ e conteúdo específicos. Ao criar uma loja do zero no VTEX IO, algumas páginas padrão com URLs predefinidas já são disponibilizadas para você. Abaixo, vemos uma lista com algumas dessas páginas padrão: 8 | 9 | - `store.home` (Home page) 10 | - `store.product` (Product page) 11 | - `store.search` (Search Results page) 12 | - `store.account` (Client Account page) 13 | - `store.login` (Login page) 14 | - `store.orderplaced` (Order Placed page) 15 | 16 | Neste passo, você aprenderá como criar _templates_ customizados do zero. 17 | 18 | ## Criando uma Landing Page 19 | 20 | São necessários poucos passos para se criar uma _landing page_ customizada: 21 | 22 | 1. Criar um novo _template_ no tema sua loja 23 | 2. Criar o novo caminho (_path_) para acessar este _template_ 24 | 25 | ### Template 26 | 27 | Um _template_ define o _layout_ da página. Portanto, se você deseja criar uma página personalizada, também precisará criar um novo _template_ no seu tema. 28 | 29 | Vamos supor que você queira criar uma página simples com informações sobre a sua loja. Dentro da pasta `blocks`, você pode criar um arquivo que contenha o seguinte código, declarando um novo _template_ para uma página customizada, 30 | 31 | ```json 32 | { 33 | "store.custom#{templatename}": { 34 | "blocks": [ 35 | ] 36 | } 37 | } 38 | ``` 39 | 40 | onde `{templateName}` deve ser substituído pelo nome identificador do _template_. 41 | 42 | A seguir, você deve preencher o código com os componentes necessários para montar o _layout_, que será mostrado em mais detalhes na atividade. 43 | 44 | ### Path 45 | 46 | Agora que um novo _template_ com o _layout_ da página foi definido no código do tema da loja, a próxima etapa é definir o caminho (path) da página que acessará este _layout_. 47 | 48 | Devemos criar um arquivo `routes.json` dentro da pasta `store` do seu tema. Após isto, insira o código abaixo, 49 | 50 | ```json 51 | { 52 | "store.custom#about-us": { 53 | "path": "/{URL}" 54 | } 55 | } 56 | ``` 57 | 58 | onde `{URL}` é o nome do caminho desejado 59 | 60 | ## Criando um _template_ customizado 61 | 62 | Vamos criar uma página com informações sobre a sua loja conforme o exemplo abaixo: 63 | 64 | ![image](https://user-images.githubusercontent.com/19495917/90177742-5aac9180-dd81-11ea-9566-be74d563664f.png) 65 | 66 | 1. Na pasta `blocks`, crie um arquivo `about-us.jsonc`; 67 | 2. Declare um template `store.custom#about-us` neste arquivo; 68 | 3. Inclua um block "flex-layout.row#about-us" neste _template_: 69 | 70 | ```json 71 | { 72 | "store.custom#about-us": { 73 | "blocks": [ 74 | "flex-layout.row#about-us" 75 | ] 76 | } 77 | } 78 | ``` 79 | 4. No mesmo arquivo, adicione o código abaixo, logo depois da declaração de `store.custom#about-us`. Ele é responsável por definir `flex-layout.row#about-us`. 80 | 81 | ```json 82 | "flex-layout.row#about-us": { 83 | "children": [ 84 | "image#about-us", 85 | "flex-layout.col#text-about-us" 86 | ] 87 | }, 88 | ``` 89 | 90 | 91 | 92 | 5. Agora, vamos definir seus blocos filhos para montar o _layout_: 93 | 94 | ```json 95 | "flex-layout.col#text-about-us": { 96 | "children": [ 97 | "rich-text#about-title", 98 | "rich-text#about-content" 99 | ], 100 | "props": { 101 | "preventVerticalStretch": true 102 | } 103 | }, 104 | "rich-text#about-title": { 105 | "props": { 106 | "text": "# About Minimum Theme" 107 | } 108 | }, 109 | "rich-text#about-content": { 110 | "props": { 111 | "text": 112 | " This is the VTEX Minimum Theme, you can use it to test blocks usage and build your first store from scratch." 113 | } 114 | }, 115 | "image#about-us": { 116 | "props": { 117 | "src": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-about-us.png", 118 | "maxHeight": "600px" 119 | } 120 | } 121 | ``` 122 | 123 | 6. Na pasta `store`, crie um arquivo chamado `routes.json`; 124 | 125 | 6. Neste arquivo, declare um _path_ `/about-us`: 126 | 127 | ```json 128 | { 129 | "store.custom#about-us": { 130 | "path": "/about-us" 131 | } 132 | } 133 | ``` 134 | 135 | 7. Com o código linkado, acesse `{workspace}--appliancetheme.myvtex.com/about-us` para ver sua nova _landing page_. 136 | 137 | 138 | ### Está com dúvidas? 139 | 140 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-styles-course-step03custom-template-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/4 - Tornando seu conteúdo responsivo/README.md: -------------------------------------------------------------------------------- 1 | # Tornando seu conteúdo responsivo 2 | 3 | ## Introdução 4 | 5 | A página inicial de um e-commerce é sempre o primeiro contato do cliente com a marca. Por isso, é comum que o lojista queira estabelecer uma **comunicação direta** com os seus usuários nesse momento estratégico da navegação. 6 | 7 | No Store Framework, existem alguns componentes que atendem a esse cenário, como o [Info Card](https://developers.vtex.com/docs/vtex-store-components-infocard) e o [Rich Text](https://developers.vtex.com/docs/vtex-rich-text#rich-text). 8 | 9 | ## Configurando o Rich Text 10 | 11 | Assim como a sua funcionalidade, a configuração do Rich Text também é simples, podemos montar um exemplo de implementação do bloco usando texto escrito em markdown. Por exemplo: 12 | 13 | ```json 14 | "rich-text": { 15 | "props": { 16 | "text": "# Your Coffee, Your Way \n ### New Coffee Makers Collection", 17 | "textPosition": "CENTER", 18 | "textAlignment": "CENTER" 19 | } 20 | }, 21 | ``` 22 | 23 | Como falado anteriormente, o uso de Markdown permite flexibilidade ao componente. Mas, por outro lado, também pode fazer com que a sua renderização sofra alterações de acordo com o dispositivo usado pelo usuário. 24 | 25 | Por exemplo: a frase acima ( `# Your Coffee, Your Way \n ### New Coffee Makers Collection` ) pode usar um _markdown_ adequado para _desktop_, mas não necessariamente para _mobile_ (cujo tamanho de tela é menor). 26 | 27 | Para resolver esse cenário e tornar o componente mais adaptável a outros dispositivos, devemos usar o [**Responsive Layout**](https://developers.vtex.com/docs/vtex-responsive-layout). 28 | 29 | 30 | Primeiramente devemos declarar os blocos dentro do template `store.home`: 31 | 32 | `"responsive-layout.desktop#desktop", 33 | "responsive-layout.mobile#mobile"` 34 | 35 | 36 | Em seguida devemos declarar esses blocos da seguinte forma: 37 | 38 | ```json 39 | 40 | ... 41 | 42 | "responsive-layout.desktop#desktop": { 43 | "children": ["rich-text#desktop"] 44 | }, 45 | 46 | "responsive-layout.mobile#mobile": { 47 | "children": ["rich-text#mobile"] 48 | }, 49 | 50 | "rich-text#desktop": { 51 | "props": { 52 | "text": "# Your Coffee, Your Way \n ### New Coffee Makers Collection (I'm on desktop)", 53 | "textPosition": "CENTER", 54 | "textAlignment": "CENTER" 55 | } 56 | }, 57 | 58 | "rich-text#mobile": { 59 | "props": { 60 | "text": "# Your Coffee, Your Way \n ### New Coffee Makers Collection (I'm on mobile)", 61 | "textPosition": "CENTER", 62 | "textAlignment": "CENTER" 63 | } 64 | } 65 | ``` 66 | 67 | Ao interpretar o código acima, perceba como duas configurações de Rich Text são construídas a partir do uso de `responsive-layout.desktop#desktop` e `responsive-layout.mobile#mobile`. 68 | 69 | ## Atividade 70 | 71 | Nessa atividade, vamos brincar um pouco com o markdown do [Rich Text](https://developers.vtex.com/docs/vtex-rich-text#rich-text) e aprender a usá-lo com o componente [Image](https://developers.vtex.com/docs/vtex-store-components-image). Tudo isso usando o Responsive Layout, é claro! 72 | 73 | ### Desktop: 74 | 75 | ![image](https://user-images.githubusercontent.com/12139385/70152049-414c3500-168b-11ea-8da3-4f4ce0f5fee6.png) 76 | 77 | ### Mobile: 78 | 79 | ![image](https://user-images.githubusercontent.com/12139385/70152883-bf5d0b80-168c-11ea-81e0-25be5ed3d5ce.png) 80 | 81 | 1. Adicione o código proposto acima no arquivo `home.jsonc` e declare os blocos de `responsive-layout` no template `store.home`; 82 | 2. No `rich-text#mobile`, altere o markdown da primeira frase para `h3` e da segunda para `h4`; 83 | > Se você não se lembra da sintaxe de Markdown, é possível consultá-la em [**Markdown Documentation**](https://www.markdownguide.org/). 84 | 3. Adicione `image#desktop` como children de `responsive-layout.desktop#desktop`. Faça o mesmo com `image#mobile` em `responsive-layout.mobile#mobile`; 85 | 4. Declare os seguintes blocos de Image: 86 | 87 | ```json 88 | "image#desktop": { 89 | "props": { 90 | "src": "https://appliancetheme.vteximg.com.br/arquivos/Responsive-Image-Desktop.jpg?q=1", 91 | "link": { 92 | "url": "/small-appliances/coffee-makers" 93 | } , 94 | "alt": "Coffee Makers Collection" 95 | } 96 | }, 97 | 98 | "image#mobile": { 99 | "props": { 100 | "src": "https://appliancetheme.vteximg.com.br/arquivos/Responsive-Image-Mobile.jpg?q=1", 101 | "link": { 102 | "url": "/small-appliances/coffee-makers" 103 | } , 104 | "alt": "Coffee Makers Collection" 105 | } 106 | }, 107 | ``` 108 | 109 | 5. Analisando as props do [componente Image](https://developers.vtex.com/docs/vtex-store-components-image#configuration), defina a largura máxima das duas imagens como `100%`. 110 | 111 | Note: Lembre-se de acessar a [documentação](https://developers.vtex.com/docs/vtex-responsive-layout) do Responsive Layout caso tenha alguma dúvida durante a atividade. 112 | 113 | 114 | ### Está com dúvidas? 115 | 116 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step04responsive-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /9 - Chamando as APIs de Commerce/4 - Usando o Client Catalog para fazer requisições/README.md: -------------------------------------------------------------------------------- 1 | # Usando o Client Catalog para fazer requisições 2 | 3 | ## Introdução 4 | 5 | Neste passo você aprenderá como usar o _Client_ que você acabou de configurar em um _middleware_ da app `service-example`. Iremos usar o método `getSkuById` para retornar informações de um SKU (Stock Keeping Unit) no Catálogo da VTEX. 6 | 7 | > O termo Stock Keeping Unit (SKU), em português Unidade de Manutenção de Estoque, está ligado à logística de armazém e designa os diferentes itens do estoque, estando normalmente associado a um código identificador. _(Wikipedia)_ 8 | 9 | ## Rota de Testes 10 | 11 | Já que o app `service-example` já exporta uma rota pública para testes (`https://{workspace}--{account}.myvtex.com/_v/status/:code`), iremos utilizá-la para testar a realização de uma chamada utilizando o _Client_ de _Catalog_. Iremos usar o parâmetro `code` como o nosso "ID do Sku" para rapidamente testarmos o nosso _Client_. 12 | 13 | Se você já rodou o comando `vtex link`, basta mantê-lo rodando já que a CLI da VTEX **atualiza automaticamente sua aplicação com mudanças no código.** Caso não, rode o comando agora. 14 | 15 | ## Atividade 16 | 17 | Como vimos no passo anterior, agora já temos disponível os métodos do nosso _Client_ em `ctx.clients.catalog`. Para utilizá-lo, precisaremos chamar os métodos em algum _middleware_ de nossa app. 18 | 19 | 1. No arquivo `node/middlewares/status.ts` para usar o `ctx.clients.catalog`. Cole lá o seguinte código: 20 | 21 | ```typescript 22 | export async function status(ctx: Context, next: () => Promise) { 23 | const { 24 | state: { code }, 25 | clients: { catalog }, 26 | } = ctx 27 | 28 | const data = await catalog.getSkuById(code.toString()) 29 | ctx.body = data 30 | 31 | await next() 32 | } 33 | ``` 34 | 35 | **O que estamos fazendo?** 36 | - Extraindo `catalog` do contexto que é recebido nas funções de middleware. Isso é um atalho para não precisarmos chamar `ctx.clients.catalog`. Saiba mais sobre Destructuring [aqui](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). 37 | - Extraindo a variável `code`, que virá como parâmetro da URL da nossa rota (`/_v/status/:code`). Usaremos este dado para representar o ID do SKU que iremos testar na chamada ao Catálogo. 38 | - Chamando o método `getSkuById` do _Client_ Catalog. Este método irá, internamente, chamar o endpoint relativo no módulo do catálogo, repassando o parâmetro que estamos passando (`code`) como o ID do SKU a ser buscado. Lembrando que esta é uma chamado assíncrona, então precisamos adicionar o `await` logo antes para esperá-la. 39 | 40 | Porém, ainda precisamos configurar um último passo para testar! 41 | 42 | 2. Geralmente, os _Clients_ do `commerce-clients` já são configurados automaticamente para fazerem chamadas autenticadas, por padrão **usando o token da app**. Mesmo assim, ainda precisamos **declarar que nossa aplicação estará fazendo requisições para algum serviço**, e isso é feito no arquivo `manifest.json`. 43 | 44 | Para o nosso caso especificamente, precisamos adicionar a seguinte sessão no campo `policies` deste arquivo: 45 | 46 | ```json 47 | { 48 | "name": "outbound-access", 49 | "attrs": { 50 | "host": "portal.vtexcommercestable.com.br", 51 | "path": "/api/catalog/*" 52 | } 53 | }, 54 | ``` 55 | 56 | Isso permitirá que sua app faça chamadas para essa URL, especificamente. Por mais que você não tenha precisado colocá-la em seu código, é ela que é usada internamente pelo Catalog _Client._ 57 | 58 | > Essa declaração é necessária e importante para apps distribuídas na [App Store da VTEX](https://apps.vtex.com). No processo de instalação, o responsável pela conta deve ler e aceitar todas as permissões que a app está solicitando. 59 | 60 | > Caso o recurso que você esteja tentando acessar precise de algum _role_ de autorização, você também precisará adicioná-lo nesta sessão. Por exemplo, a app `store-graphql` precisa [declarar que precisa da _policy_](https://github.com/vtex-apps/store-graphql/blob/91454631bffad6ad661cb87391f42f8886d9edd5/manifest.json#L117) `LogisticsAdmin` para que possa ser autorizadas a acessar alguns recursos do módulo de Logística. 61 | 62 | 63 | 3. Agora, vamos testar o que fizemos! O processo do `vtex link` já deve ter atualizado, e poderemos copiar a URL pública que nosso serviço está expondo: 64 | ![Exemplo](https://user-images.githubusercontent.com/18706156/93384506-4d306e80-f83b-11ea-9cec-0e1b23f23a48.png) 65 | 66 | Neste caso, a app está sendo desenvolvida na conta `marinbrasil` e no workspace `trainingweek`, mas no seu Terminal você deverá copiar o link fornecido para seu ambiente. 67 | 68 | Como o nosso _middleware_ é ativado por uma requisição GET, podemos testar a funcionalidade no nosso próprio navegador. Cole na barra de endereços `https://{workspace}--{account}.myvtex.com/_v/status/1` para buscarmos informações sobre o SKU de ID 1. 69 | 70 | O resultado abaixo deve ser esperado: 71 | 72 | ![image](https://user-images.githubusercontent.com/18706156/93388848-b87d3f00-f841-11ea-8d2e-bed1c14d355d.png) 73 | 74 | > Lembrando que esta informação dependerá **do catálogo da conta sendo utilizada**. 75 | 76 | 77 | ### Está com dúvidas? 78 | 79 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-calling-commerce-apis-step04using-client-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /1 - Blocos Básicos/4 - Pagina de produto/README.md: -------------------------------------------------------------------------------- 1 | # Página do produto 2 | 3 | ## Introdução 4 | 5 | Assim que a página inicial da loja estiver pronta, podemos começar a trabalhar em um novo modelo de loja: a página do produto. As páginas de produtos são provavelmente os modelos com mais blocos, o que as torna extremamente flexíveis e personalizáveis. 6 | 7 | ## Página do produto 8 | 9 | Vamos construir uma página de produto mínima, com apenas o essencial: 10 | 11 | - **imagens;** 12 | - **preços;** 13 | - **nomes;** 14 | - **botão de compra** 15 | 16 | ![image](https://user-images.githubusercontent.com/18701182/69375575-6b632780-0c87-11ea-85d2-41e1e858a33e.png) 17 | 18 | ## Blocos de produto 19 | 20 | A maioria dos blocos de produto, ao contrário dos blocos de conteúdo, são inseridos em um determinado contexto, tornando-os um pouco "plug-n-play": colocar `product-images` na página do produto levará automaticamente a imagens sendo renderizadas nessa página, o mesmo sendo válido para preço e nome. 21 | 22 | Isso não significa que esses blocos sejam menos personalizáveis, muito pelo contrário, como veremos em breve. 23 | 24 | ## Atividade 25 | 26 | Construa uma página de produto usando os seguintes blocos em `product.jsonc` e declare-a na pasta `store/blocks`: [`product-images`](https://developers.vtex.com/docs/vtex-store-components-productimages), [`product-price`](https://developers.vtex.com/docs/vtex-product-price#product-price), [`product-name`](https://developers.vtex.com/docs/vtex-store-components-productname) and [`buy-button`](https://developers.vtex.com/docs/vtex-store-components-buybutton). Esperamos que a estrutura contenha o seguinte: 27 | 28 | 1. Uma **row** em `store.product`; 29 | 30 | ```json 31 | { 32 | "store.product": { 33 | "children": [ 34 | "flex-layout.row#main" 35 | ] 36 | } 37 | } 38 | ``` 39 | 40 | 2. Essa **row** deve conter **duas *columns***; 41 | 42 | ```json 43 | "flex-layout.row#main": { 44 | "props": { 45 | "marginTop": 6 46 | }, 47 | "children": [ 48 | "flex-layout.col#left", 49 | "flex-layout.col#right" 50 | ] 51 | } 52 | ``` 53 | 54 | 3. A coluna da esquerda deve conter [`product-images`](https://developers.vtex.com/docs/vtex-store-components-productimages); 55 | 56 | ```json 57 | "flex-layout.col#left": { 58 | "children": [ 59 | "product-images" 60 | ] 61 | } 62 | ``` 63 | 64 | 4. A coluna da direita deve conter [`product-name`](https://developers.vtex.com/docs/vtex-store-components-productname), [`product-price`](https://developers.vtex.com/docs/vtex-product-price#product-price) e [`buy-button`](https://developers.vtex.com/docs/vtex-store-components-buybutton): 65 | 66 | ```json 67 | "flex-layout.col#right": { 68 | "children": [ 69 | "product-name", 70 | "product-price", 71 | "buy-button" 72 | ] 73 | }, 74 | ``` 75 | 76 | Ainda queremos: 77 | 78 | 1. A coluna da direita alinhada ao centro (veja as props `verticalAlign` e `preventVerticalStretch` na [documentação do Flex Layout Column](https://developers.vtex.com/docs/vtex-flex-layout#flex-layoutcol)): 79 | 80 | ```json 81 | "flex-layout.col#right": { 82 | "props": { 83 | "preventVerticalStretch": true, 84 | "verticalAlign": "middle" 85 | }, 86 | "children": [ 87 | ... 88 | ] 89 | }, 90 | ``` 91 | 92 | 2. O [`product-price`](https://developers.vtex.com/docs/vtex-product-price#configuration) mostrar economias totais e lista de preçoes (`showSavings` e `showListPrice`): 93 | 94 | ```json 95 | "product-price": { 96 | "props": { 97 | "showSavings": true, 98 | "showListPrice": true 99 | } 100 | } 101 | ``` 102 | 103 | Após terminados os passos anteriores, você pode procurar por um produto na barra de busca, no canto superior direito da página. 104 | 105 | ![image](https://user-images.githubusercontent.com/19495917/90903507-682ad280-e3a4-11ea-9781-77a9b111218b.png) 106 | 107 | Se você estiver na conta `appliancetheme`, tente buscar por uma máquina de café, por exemplo: 108 | 109 | 110 | 111 | Ao clicar na segunda, a `Red Retro Coffee Machine`, você i'ra para a sua página de produto, ou `pdp`, e verá os blocos que a compõe. 112 | 113 | ![image](https://user-images.githubusercontent.com/19495917/90905481-9f9a7e80-e3a6-11ea-99c4-6a546e0000a3.png) 114 | 115 | > Nota: Alguns dos produtos não terão _savings_, dado que não há descontos baseados no preço de catálogo, ou _list price_. 116 | 117 | Note: Lembre de acessar as documentações de [`product-images`](https://developers.vtex.com/docs/vtex-store-components-productimages), [`product-price`](https://developers.vtex.com/docs/vtex-product-price#product-price), [`product-name`](https://developers.vtex.com/docs/vtex-store-components-productname) e [`buy-button`](https://developers.vtex.com/docs/vtex-store-components-buybutton) em caso de dúvidas durante a atividade. 118 | 119 | 120 | ### Está com dúvidas? 121 | 122 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-basic-blocks-step04pdp-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /1 - Blocos Básicos/3 - Info Card o call to action do store Framework/README.md: -------------------------------------------------------------------------------- 1 | # Info Card: *call to action* do Store Framework 2 | 3 | ## Introdução 4 | 5 | Uma loja precisa de uma boa *página inicial* para envolver os usuários, aumentando o tempo da sessão e, portanto, as chances de conversão. Para tal, é necessário utilizar vários elementos, como banners promocionais, estantes com destaques, material sobre nós, etc. 6 | 7 | Criamos o próximo bloco na *página inicial* usando uma *call to action*. No Store Framework, temos um bloco desenhado para esse fim, denominado [**Info Card**](https://developers.vtex.com/docs/vtex-store-components-infocard). 8 | 9 | ## Começando com o Info Card 10 | 11 | ![image](https://user-images.githubusercontent.com/18701182/68480411-7b085800-0213-11ea-9426-31dcb0d0aa7d.png) 12 | 13 | Usando o Info Card, você pode criar imagens que possuem links e botões (parte superior ou lateral do bloco) que direcionam o fluxo do usuário (*Call to action*). 14 | 15 | Olhando a [documentação](https://developers.vtex.com/docs/vtex-store-components-infocard#configuration), podemos ver que: 16 | 17 | - `isFullModeStyle` define se o *Call to Action (CTA)* é definido acima do banner; 18 | - `textPosition` define a posição do texto; 19 | - `textAlignment` define o alinhamento do texto; 20 | - `imageUrl` define qual imagem será usada como banner; 21 | - `headline` determina qual texto será usado como título; 22 | - `callToActionMode` permite escolher o modo *CTA* como um link ou um botão; 23 | - `callToActionText` define o texto *CTA*; 24 | - `callToActionUrl` determina a URL para a qual ele redireciona; 25 | 26 | Portanto, temos as seguintes _props_: 27 | 28 | ```json 29 | { 30 | "store.home": { 31 | "blocks": [ 32 | "rich-text", 33 | "info-card" 34 | ] 35 | }, 36 | "rich-text": { 37 | "props": { 38 | "text": "*Hello, World!*", 39 | "textPosition": "RIGHT" 40 | } 41 | }, 42 | "info-card": { 43 | "props": { 44 | "isFullModeStyle": false, 45 | "textPosition": "right", 46 | "imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-rosa-min.png", 47 | "headline": "Vintage Pink", 48 | "subhead": "Give your kitchen a boho style adding vintage apparels.
Available until January 2020.", 49 | "callToActionMode": "button", 50 | "callToActionText": "Explore", 51 | "callToActionUrl": "/sale/d", 52 | "textAlignment": "center" 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | ## Instâncias de Blocos 59 | 60 | Você pode ter se perguntado: 61 | > "E se eu quisesse ter dois _info cards_ diferentes?" 62 | 63 | É possível por meio de **instâncias de blocos**. 64 | 65 | Todos os blocos têm nomes pré-estabelecidos, mas você pode criar instâncias de bloco e definir diferentes formas de exibição dos tipos de bloco. Após cada bloco ter sido definido, simplesmente coloque um '#' com um nome **arbitrário**, por exemplo: 66 | 67 | ```json 68 | { 69 | "store.home": { 70 | "blocks": [ 71 | "rich-text", 72 | "info-card#button-right" 73 | ] 74 | }, 75 | ... 76 | "info-card#button-right": { 77 | "props": { 78 | "isFullModeStyle": false, 79 | "textPosition": "right", 80 | "imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-rosa-min.png", 81 | "headline": "Vintage Pink", 82 | "subhead": "Give your kitchen a boho style adding vintage apparels.
Available until January 2020.", 83 | "callToActionMode": "button", 84 | "callToActionText": "Explore", 85 | "callToActionUrl": "/sale/d", 86 | "textAlignment": "center" 87 | } 88 | } 89 | } 90 | ``` 91 | 92 | > **ATENÇÃO:** Ao longo do curso, você notará vários `...`, que você não deve copiar, pois representa o progresso alcançado durante as etapas anteriores. 93 | 94 | ## Atividade 95 | 96 | 1. No arquivo `home.jsonc`, com base no código acima, crie o `info-card#button-left` logo abaixo do infocard: `info-card#button-right`. Este novo info card deve implementar os seguintes adereços: 97 | 98 | - O título deve ser `Shining chrome` 99 | - Uma frase de *call to action* do tipo link com o seguinte texto em vez de um botão: `Go to Collection` 100 | - A seguinte imagem `https://appliancetheme.vteximg.com.br/arquivos/cozinha-cinza-min.png` 101 | - O seguinte subtítulo `Give your kitchen a cool style adding warm metallic finishes.
Available until December 2020.` 102 | - Texto à esquerda da imagem (`textPosition`). 103 | 104 | ```json 105 | ... 106 | "info-card#button-left": { 107 | "props": { 108 | "isFullModeStyle": false, 109 | "textPosition": "left", 110 | "imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-cinza-min.png", 111 | "headline": "Shining chrome", 112 | "subhead": "Give your kitchen a cool style adding warm metallic finishes.
Available until January 2020.", 113 | "callToActionMode": "link", 114 | "callToActionText": "Go to collection", 115 | "textAlignment": "center" 116 | } 117 | } 118 | ... 119 | ``` 120 | 121 | O resultado esperado será semelhante a este: 122 | 123 | ![imagem](https://appliancetheme.vteximg.com.br/arquivos/info-card-activity.png) 124 | 125 | Note: Lembre-se de acessar a documentação do [Info Card](https://developers.vtex.com/docs/vtex-store-components-infocard) se você tiver alguma dúvida sobre a atividade. 126 | 127 | 128 | ### Está com dúvidas? 129 | 130 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-basic-blocks-step03infocard-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/5 - Layout de abas/README.md: -------------------------------------------------------------------------------- 1 | # Layout de abas 2 | 3 | ## Introdução 4 | 5 | O [Tab Layout](https://developers.vtex.com/docs/vtex-tab-layout#tab-layout) é um paradigma de estruturação de _layouts_ criado no Store Framework para permitir a construção de _layouts_ com abas ou guias. 6 | 7 | Neste paradigma, temos dois containers: o `tab-list` e o `tab-content`. Em cada um destes containers, temos os itens que os compõem. Dentro do `tab-list`, temos os `tab-list.item`. Já no `tab-content`, temos os `tab-content.item`. 8 | 9 | Abaixo, veremos um exemplo de implementação de um _tab layout_. 10 | 11 | Primeiro, é necessário declarar o block `tab-layout` no _template_ desejado: 12 | 13 | ```json 14 | { 15 | "store.home": { 16 | "blocks": [ 17 | ... 18 | "tab-layout" 19 | ] 20 | } 21 | } 22 | 23 | ``` 24 | 25 | Depois, é necessário declarar um `tab-list` e um `tab-content` como children do `tab-layout`: 26 | 27 | ```json 28 | ... 29 | "tab-layout": { 30 | "children": [ 31 | "tab-list", 32 | "tab-content" 33 | ] 34 | } 35 | ``` 36 | 37 | 38 | Com isso, temos esses dois containers como componentes do nosso `tab-layout`. O próximo passo é declarar os `tab-list.item` e `tab-content.item` como children do `tab-list` e do `tab-content`, respectivamente: 39 | 40 | ```json 41 | ... 42 | "tab-list": { 43 | "children": [ 44 | "tab-list.item#1", 45 | "tab-list.item#2" 46 | ] 47 | } 48 | ``` 49 | 50 | ```json 51 | ... 52 | "tab-content": { 53 | "children": [ 54 | "tab-content.item#1", 55 | "tab-content.item#2" 56 | ] 57 | } 58 | ``` 59 | 60 | Na próxima etapa, temos que declarar as propriedades dos `tab-list.item`. O código abaixo gera uma interface de tabs como a desta imagem: 61 | 62 | ![image](https://user-images.githubusercontent.com/18701182/90059099-076f0c00-dcb9-11ea-918d-664761c34f3a.png) 63 | 64 | 65 | A propriedade `tabId` é muito importante, pois ela é a chave que conecta o botão de um `tab-list.item` com um `tab-content.item`. 66 | 67 | ```json 68 | ... 69 | "tab-list.item#1": { 70 | "props": { 71 | "tabId": "majorAppliances", 72 | "label": "Major Appliances", 73 | "defaultActiveTab": true 74 | } 75 | }, 76 | "tab-list.item#2": { 77 | "props": { 78 | "tabId": "electronics", 79 | "label": "Electronics" 80 | } 81 | } 82 | ``` 83 | 84 | A seguir, vamos declarar as _children_ e as _props_ dos `tab-content.item`. 85 | 86 | No _array_ de _children_, é possível incluir diversos blocos como `rich-text`, `info-card`, `image`, `flex-layout` e etc. 87 | 88 | Na prop `tabId`, é necessário incluir os mesmos identificadores (_ids_) declarados nos `tab-list.item` para que o _link_ entre a aba e o conteúdo funcione. 89 | 90 | ```json 91 | ... 92 | "tab-content.item#1": { 93 | "children": [ 94 | "rich-text#1" 95 | ], 96 | "props": { 97 | "tabId": "majorAppliances" 98 | } 99 | }, 100 | "tab-content.item#2": { 101 | "children": [ 102 | "rich-text#2" 103 | ], 104 | "props": { 105 | "tabId": "electronics" 106 | } 107 | } 108 | ``` 109 | 110 | Por fim, você deve declarar as propriedades do seu conteúdo. No nosso exemplo, colocamos apenas um `rich-text` em cada `tab-content.item`: 111 | 112 | ```json 113 | "rich-text#1": { 114 | "props": { 115 | "text": "Texto para Major Appliances", 116 | "textPosition": "CENTER", 117 | "font": "t-heading-3" 118 | } 119 | }, 120 | "rich-text#2": { 121 | "props": { 122 | "text": "Texto para Electronics", 123 | "textPosition": "CENTER", 124 | "font": "t-heading-3" 125 | } 126 | } 127 | ``` 128 | 129 | ## Atividade 130 | 131 | Nesta atividade, vamos criar a estrutura simples de um _tab layout_, conforme imagem abaixo. Mais tarde, vamos incluir algum conteúdo para estilizar nossa página customizada. 132 | 133 | ![](https://appliancetheme.vteximg.com.br/arquivos/tarefa-tab-layout.png) 134 | 135 | 1. No arquivo `home.jsonc` criado anteriormente, adicione um `tab-layout#home`; 136 | 2. Declare o bloco `tab-layout#home` e adicione como seus filhos um `tab-list#home` e um `tab-content#home`; 137 | 3. Declare um `tab-list#home` e adicione como seus filhos um `tab-list.item#home1` e um `tab-list.item#home2`; 138 | 4. Declare as props do `tab-list.item#home1` de maneira que a interface exiba o texto "Major Appliances". (Dica: não se esqueça que incluir nas props um `tabId` = `"majorAppliances"` e a propriedade `defaultActiveTab` = `true`); 139 | 5. Declare as _props_ do `tab-list.item#home2` de maneira que a interface exiba o texto "Electronics". (Dica: não se esqueça que incluir nas props um `tabId` = `"electronics"`); 140 | 6. Agora, vamos para a parte o conteúdo. Declare um `tab-content#home` no seu tema e adicione os filhos `tab-content.item#home1` e `tab-content.item#home2`; 141 | 7. Em cada `tab-content.item`, declare apenas um `rich-text` como filho (por exemplo, `rich-text#home1` e `rich-text#home2`); 142 | 8. Depois, inclua uma _prop_ `tabId` em cada `tab-content.item` de maneira que aconteça o _link_ entre o `tab-list` criado anteriormente e `tab-content`; 143 | 9. Por fim, adicione os `rich-text` e declare suas _props_ conforme o código abaixo: 144 | 145 | ```json 146 | "rich-text#home1": { 147 | "props": { 148 | "text": "Área do conteúdo da tab-list.item com tabId = majorAppliances", 149 | "textPosition": "CENTER", 150 | "font": "t-heading-3" 151 | } 152 | }, 153 | "rich-text#home2": { 154 | "props": { 155 | "text": "Área do conteúdo da tab-list.item com tabId = electronics", 156 | "textPosition": "CENTER", 157 | "font": "t-heading-3" 158 | } 159 | } 160 | ``` 161 | 162 | Note: Lembre-se de acessar a documentação [Tab Layout](https://vtex.io/docs/components/layout/vtex.tab-layout) e do [Rich Text](https://vtex.io/docs/components/all/vtex.rich-text/) caso tenha alguma dúvida durante a atividade. 163 | 164 | 165 | ### Está com dúvidas? 166 | 167 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step05tab-layout-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /3 - Tornando sua loja única/6 - Construindo uma landing customizada de busca/README.md: -------------------------------------------------------------------------------- 1 | # Construindo uma landing customizada de busca 2 | 3 | ## Introdução 4 | 5 | No passo anterior, você pôde aprender um pouco mais sobre como criar um _template_ customizado. É muito comum que, em cenários de promoção e datas comemorativas, seja necessário criar *landing pages* especiais. 6 | 7 | ## Buscas customizadas 8 | 9 | Vimos que a busca infere o que precisa pelo contexto que está inclusa. Numa página customizada, no entanto, o contexto não existe e é preciso que se defina qual a *query* deve ser realizada para inferir os resultados. Tudo isso é possível através do `search-result-layout.customQuery`. 10 | 11 | ## Query schema 12 | 13 | A _query schema_ é uma das [props do _search result custom query_](https://developers.vtex.com/docs/vtex-search-result) com ela é possível controlar a busca que a nossa *landing page* deverá fazer. Para saber todas as possibilidades da _query schema_, veja sua [documentação aqui](https://developers.vtex.com/docs/vtex-search-result#step-3---defining-how-the-search-query-data-should-be-fetched). 14 | 15 | ## Criando uma nova _landing page_ 16 | 17 | 1. Defina uma rota nova (`store.custom#landing`) no arquivo `routes.json`; 18 | 19 | ```json 20 | // store/routes.json 21 | "store.custom#landing": { 22 | "path": "/landing" 23 | } 24 | ``` 25 | 26 | 2. Crie um novo arquivo na pasta de blocos chamado `search-landing.jsonc`; 27 | 3. Crie um novo _template custom_ `store.custom#landing`; 28 | 4. Defina o bloco [`image`](https://developers.vtex.com/docs/vtex-store-components-image) como um dos blocos desse template. Este bloco deve possuir _props_ `minWidth` de 100% e uma imagem a sua escolha. 29 | 5. Adicione o bloco `search-result-layout.customQuery`: 30 | 31 | ```diff 32 | // store/blocks/search-landing.jsonc 33 | { 34 | "store.custom#landing": { 35 | "blocks": [ 36 | "image#landingbanner", 37 | + "search-result-layout.customQuery" 38 | ] 39 | } 40 | } 41 | ``` 42 | 43 | 6. Defina o bloco `search-result-layout.customQuery` com [prop de *querySchema*](https://developers.vtex.com/docs/vtex-search-result#step-3---defining-how-the-search-query-data-should-be-fetched) que: 44 | - Ordena por data de lançamento de forma descrescente; 45 | - Esconda itens indisponíveis; 46 | - Mostre um máximo de 8 itens por página; 47 | - Use como *query* "Camera". 48 | 49 | 7. Neste ponto, é provável que você não esteja vendo o bloco na nova página. Isso se deve ao fato de que ainda não adicionamos nenhum bloco ao `search-result-layout.customQuery`. Aqui há duas possibilidades: 50 | 51 | - Caso você já tenha passado pelos cursos anteriores, é provável que você já tenha alterado o seu arquivo `search.jsonc`neste _template_ que estamos usando para que seja utilizado o conceito de _flex layout_. Sendo assim, basta adicionar as seguintes linhas de código ao arquivo `search-landing.jsonc`: 52 | ```diff 53 | // store/blocks/search-landing.jsonc 54 | { 55 | ... 56 | "search-result-layout.customQuery": { 57 | "props": { 58 | "querySchema": { 59 | "orderByField": "OrderByReleaseDateDESC", 60 | "hideUnavailableItems": true, 61 | "maxItemsPerPage": 8, 62 | "queryField": "Camera", 63 | "mapField": "ft", 64 | "skusFilter": "ALL_AVAILABLE" 65 | } 66 | }, 67 | + "blocks": [ 68 | + "search-result-layout.desktop" 69 | + ] 70 | } 71 | } 72 | ``` 73 | 74 | 75 | - Caso você ainda não fez os cursos anteriores e seu arquivo `search.jsonc` encontra-se vazio, é preciso adicionar blocos a ele. Para isso, utilize o bloco de código abaixo. Depois de fazer isso, você precisará apenas adicionar o bloco `search-result-layout.desktop` ao _array_ de blocos do `search-result-layout.customQuery`, como mencionado anteriormente. 76 | 77 | ```json 78 | // store/blocks/search.jsonc 79 | { 80 | "store.search": { 81 | "blocks": [ 82 | "search-result-layout" 83 | ] 84 | }, 85 | "search-result-layout": { 86 | "blocks": [ 87 | "search-result-layout.desktop", 88 | "search-result-layout.mobile", 89 | "search-not-found-layout" 90 | ] 91 | }, 92 | "search-result-layout.desktop": { 93 | "children": [ 94 | "breadcrumb.search", 95 | "search-title.v2", 96 | "flex-layout.row#top", 97 | "search-fetch-previous", 98 | "flex-layout.row#results", 99 | "search-fetch-more" 100 | ], 101 | "props":{ 102 | "pagination": "showMore" 103 | } 104 | }, 105 | "flex-layout.row#top": { 106 | "children": [ 107 | "total-products.v2", 108 | "order-by.v2" 109 | ] 110 | }, 111 | "flex-layout.row#results": { 112 | "children": [ 113 | "flex-layout.col#filter", 114 | "flex-layout.col#search" 115 | ] 116 | }, 117 | "flex-layout.col#filter": { 118 | "props": { 119 | "width": "20%" 120 | }, 121 | "children": [ 122 | "filter-navigator.v3" 123 | ] 124 | }, 125 | "flex-layout.col#search": { 126 | "children": [ 127 | "search-content" 128 | ] 129 | } 130 | } 131 | ``` 132 | > Neste caso, aproveite para observar com calma o código adicionado, de forma que você se assegure de que entendeu as relações entre os blocos e a função de cada um. 133 | 134 | O resultado final esperado é: 135 | 136 | ![image](https://user-images.githubusercontent.com/19495917/90278827-7033c100-de3e-11ea-9083-4d7279312d7f.png) 137 | 138 | 139 | ### Está com dúvidas? 140 | 141 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-styles-course-step05landing-answersheet) ou peça ajuda a um de nossos monitores 142 | -------------------------------------------------------------------------------- /6 - Blocos customizados/7 - Práticas de internacionalização no VTEX IO/README.md: -------------------------------------------------------------------------------- 1 | # Práticas de internacionalização no VTEX IO 2 | 3 | ## Introdução 4 | 5 | Com o bloco customizado na loja, devemos aprender a **internacionalizar** o conteúdo apresentado. 6 | 7 | É importante lembrar que os blocos devem sempre seguir boas práticas de localização, e **não devem mostrar strings _hardcoded_**, mas sim sensíveis a linguagem que a loja opera. 8 | 9 | Não se preocupe, você não precisará adicionar traduções de todos os textos para as variadas linguagens nas quais o Store Framework é usado. Portanto, nessa etapa, serão apresentados conceitos acerca da internacionalização de _apps_ e como fazê-la. 10 | 11 | ### As _Messages_ 12 | 13 | O conceito de _messages_ facilita a adição de novos idiomas ao tema. As _messages_ centralizam todos os serviços de tradução na plataforma. Dada um texto a ser traduzido, _Messages_ irá primeiramente checar o contexto definido pelo usuário para, em seguida, checar as traduções das _apps_ e, por fim, passa pelo sistema de tradução automática. 14 | 15 | Na estrutura do diretório, é possível observar que há uma pasta chamada `messages`, que apresenta três arquivos principais: `pt.json`, `en.json` e `es.json`, cada um responsável pelas traduções: português, inglês e espanhol, respectivamente. Além disso, a fim de fornecer traduções automáticas melhores, é utilizado o arquivo `context.json`, responsável por evitar ambiguidades. 16 | 17 | Para utilizar tais definições, os arquivos de tradução mencionados anteriormente são JSON, cujas chaves são as mensagens e os valores são as traduções. 18 | 19 | > O arquivo `context.json` é necessário e precisa conter todas as mensagens, além de oferecer as traduções automáticas em casos excepcionais. 20 | 21 | ## Internacionalizando seu bloco 22 | 23 | Você já deve ter aprendido a usar o nosso **builder _messages_**, e será através dele que serão adicionadas _strings_ internacionalizadas nos componentes. 24 | 25 | 1. Para isso, **na pasta `/messages`**, adicione agora uma mensagem de **título para o componente**: 26 | 27 | `messages/pt.json` 28 | 29 | ```diff 30 | { 31 | ..., 32 | + "countdown.title": "Contagem Regressiva" 33 | } 34 | ``` 35 | 36 | `messages/en.json` 37 | 38 | ```diff 39 | { 40 | ..., 41 | + "countdown.title": "Countdown" 42 | } 43 | ``` 44 | 45 | `messages/es.json` 46 | 47 | ```diff 48 | { 49 | ..., 50 | + "countdown.title": "Cuenta Regresiva" 51 | } 52 | ``` 53 | 54 | `messages/context.json` 55 | 56 | ```diff 57 | { 58 | ..., 59 | + "countdown.title": "Countdown" 60 | } 61 | ``` 62 | 63 | 2. Feito isso, para **renderizar o título** deve-se usar o componente `FormattedMessage` da biblioteca [react-intl](https://github.com/formatjs/react-intl). 64 | 65 | > A biblioteca _react-intl_ dá suporte a várias maneiras de configuração e internacionalização, vale a pena verificá-las. 66 | 67 | 3. Agora, adicione a biblioteca usando `yarn add react-intl` na pasta _react_. Feito isso, no código do seu componente `Countdown.tsx`,**importe o FormattedMessage** 68 | 69 | ```diff 70 | //react/Countdown.tsx 71 | + import { FormattedMessage } from 'react-intl' 72 | ``` 73 | 74 | 4. Também é necessário adicionar uma nova _prop_ ao `CountdownProps`: 75 | 76 | ```diff 77 | interface CountdownProps { 78 | + title: string 79 | targetDate: string 80 | } 81 | ``` 82 | 83 | 5. Além disso, adicione uma constante que será o seu título: 84 | 85 | ```tsx 86 | //react/Countdown.tsx 87 | const titleText = title || 88 | ``` 89 | 90 | 6. Agora, junte o título e o contador para renderizá-los. Para isso, defina um container por fora. Além disso, o texto do título será passado através da _prop_ `title`: 91 | 92 | ```tsx 93 | //react/Countdown.tsx 94 | const Countdown: StorefrontFunctionComponent = ({ 95 | title, 96 | targetDate, 97 | }) => { 98 | const [timeRemaining, setTime] = useState({ 99 | hours: '00', 100 | minutes: '00', 101 | seconds: '00', 102 | }) 103 | 104 | const titleText = title || 105 | const handles = useCssHandles(CSS_HANDLES) 106 | 107 | tick(targetDate, setTime) 108 | 109 | return ( 110 |
111 |
{titleText}
112 |
113 | {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`} 114 |
115 |
116 | ) 117 | } 118 | ``` 119 | 120 | 7. Note que são utilizados três _handles_ **novos**: _container_, _countdown_ e _title_. Dessa forma, lembre-se de declará-los na constante `CSS_HANDLES`, vista na etapa anterior: 121 | 122 | ```tsx 123 | //react/Countdown.tsx 124 | const CSS_HANDLES = ["container", "countdown", "title"] 125 | ``` 126 | 127 | 8. Por fim, é preciso adicionar a _prop_ de `title` no _schema_: 128 | 129 | ```diff 130 | //react/Countdown.tsx 131 | Countdown.schema = { 132 | title: 'editor.countdown.title', 133 | description: 'editor.countdown.description', 134 | type: 'object', 135 | properties: { 136 | + title: { 137 | + title: 'Sou um título', 138 | + type: 'string', 139 | + default: null, 140 | + }, 141 | targetDate: { 142 | title: 'Data final', 143 | description: 'Data final usada no contador', 144 | type: 'string', 145 | default: null, 146 | }, 147 | }, 148 | } 149 | ``` 150 | 151 | Pronto! Agora, para testar sua loja em outros idiomas basta adicionar a _query string_ `/?cultureInfo=pt-br` ou `/?cultureInfo=en-ar` na URL, por exemplo. Ao utilizar tal URL, o resultado esperado é esse aqui: 152 | 153 | ![image](https://user-images.githubusercontent.com/19495917/75484759-23d7f000-5988-11ea-8b0a-63a5fce4ea7e.png) 154 | 155 | 156 | ### Está com dúvidas? 157 | 158 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-block-step06messages-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /7 - Serviços/3 - Eventos - recebendo e lidando com eventos/README.md: -------------------------------------------------------------------------------- 1 | # Eventos: recebendo e lidando com eventos 2 | 3 | ## Introdução 4 | 5 | Algumas interações no VTEX IO podem gerar eventos e estes podem ser utilizados como gatilhos para ações, como a atividade presente neste passo. Por enquanto, utilizaremos os eventos disparados pela _app_ `events-example`. 6 | 7 | ## Eventos no VTEX IO 8 | 9 | Em _apps_ do VTEX IO, eventos podem ser disparados e utilizados como gatilhos para ações. Por exemplo, uma _app_ que escuta por pedidos e ativa um gatilho de email de confirmação. É importante ressaltar que eventos são dependentes da conta e do _workspace_, o que significa que são apenas visíveis pela conta e pelo _workspace_ de onde foram disparados. Ou seja, eventos disparados no seu _workspace_ pessoal de desenvolvimento serão apenas escutados por _apps_ que estão linkadas no mesmo _workspace_. 10 | 11 | Vamos começar? 12 | 13 | ## Ouvindo eventos na aplicação 14 | 15 | 1. Em primeiro lugar, vamos começar com o disparo de eventos sendo feito através da _app_ `events-example`. Esta _app_ irá disparar um evento a cada X segundos. Após rodar o comando `vtex link` no diretório de `events-example`, clique na rota de _healthcheck_ disponível e uma mensagem "ok" deve aparecer no navegador: 16 | 17 | ![image](https://user-images.githubusercontent.com/43679629/83802091-8c69f380-a680-11ea-82af-a438fb73f40b.png) 18 | 19 | > Este acesso a rota de _healthcheck_ cria um contexto de cache que é necessário para que o VTEX IO dispare eventos. Sem isso, a _app_ `events-example` não será capaz de disparar eventos que sua _app_ irá ouvir. 20 | 21 | 2. Agora, precisamos adicionar o _handler_ de eventos na declaração de `Service`, que é responsável por definir o que a _app_ vai fazer enquanto estiver ouvindo os eventos que podem chegar. Para fazer isso, no arquivo `/node/index.ts`, incremente a declaração de `Service`: 22 | ```diff 23 | //node/index/ts 24 | 25 | + const TREE_SECONDS_MS = 3 * 1000 26 | + const CONCURRENCY = 10 27 | 28 | export default new Service({ 29 | clients: { 30 | implementation: Clients, 31 | options: { 32 | default: { 33 | retries: 2, 34 | timeout: 10000, 35 | }, 36 | + events: { 37 | + exponentialTimeoutCoefficient: 2, 38 | + exponentialBackoffCoefficient: 2, 39 | + initialBackoffDelay: 50, 40 | + retries: 1, 41 | + timeout: TREE_SECONDS_MS, 42 | + concurrency: CONCURRENCY, 43 | + }, 44 | + }, 45 | + }, 46 | }) 47 | ``` 48 | 49 | Passando por cada uma das configurações, temos o seguinte: 50 | 51 | | Campo | Tipo | Descrição | 52 | | ------------------------------- | ------- | ------------------------------------------------------------------------------- | 53 | | `exponentialTimeoutCoefficient` | seconds | fator exponencial em que `timeout` é incrementado a cada tentativa | 54 | | `exponentialBackoffCoefficient` | seconds | fator exponencial em que o `backoff delay` será incrementado a cada tentativa | 55 | | `initialBackoffDelay` | seconds | tempo que a _app_ irá esperar até a próxima tentativa | 56 | | `retries` | - | quantidade máxima de tentativas da _app_ | 57 | | `timeout` | seconds | _timeout_ até ser considerado como uma tentativa mal sucedida | 58 | | `concurrency` | - | quantidade de processos simultâneos que o evento é capaz de ter | 59 | 60 | > Ao adicionar esse código ao `Service`, estamos adicionando ao `Client` de `Service` a capacidade de lidar com eventos. Neste ponto, não estamos utilizando ainda os clientes em si ao lidar com eventos. 61 | 62 | Por enquanto, vamos apenas criar um _log_ de recebimento de eventos. Para criar este _handler_, vá ao arquivo `liveUsersUpdate.ts`, que se encontra na pasta `/node/event` e faça as seguintes alterações: 63 | 64 | ```ts 65 | //node/event/liveUsersUpdate.ts 66 | export async function updateLiveUsers() { 67 | console.log('EVENT HANDLER: received event') 68 | } 69 | ``` 70 | 71 | 3. Após adicionar o bloco de código mencionado anteriormente, precisamos declarar em `Service`, a referência para esta função. No arquivo `/node/index.ts`, adicione o seguinte código: 72 | 73 | ```diff 74 | ... 75 | + import { updateLiveUsers } from './event/liveUsersUpdate' 76 | ... 77 | 78 | export default new Service({ 79 | ... 80 | + events: { 81 | + liveUsersUpdate: updateLiveUsers, 82 | + }, 83 | }) 84 | 85 | ``` 86 | 87 | 4. Também é necessário modificar o arquivo `service.json`. De forma a ouvir os eventos que são enviados, precisamos declarar isto para darmos a _app_ de serviço que estamos desenvolvendo esta capacidade. É possível fazer isso através das seguintes alterações no arquivo `service.json`: 88 | 89 | ```diff 90 | //node/service.json 91 | { 92 | "memory": 128, 93 | "ttl": 10, 94 | "timeout": 10, 95 | "minReplicas": 2, 96 | "maxReplicas": 10, 97 | "workers": 4, 98 | + "events": { 99 | + "liveUsersUpdate": { 100 | + "sender": "vtex.events-example", 101 | + "keys": ["send-event"] 102 | + } 103 | }, 104 | ... 105 | } 106 | ``` 107 | 108 | > Note que fazemos esta declaração ao utilizar o _resolver_ de eventos, definir a referência para a _app_ que efetivamente dispara os eventos (declarada como `sender`) e, por fim, adicionar a referência a _key_ do evento (declarada como `keys`). 109 | 110 | 5. Por fim, rode o comando `vtex link` e espere que os eventos sejam disparados através da _app_ `events-example`. Quando escutados, o _log_ deve aparece no terminal, como na imagem abaixo: 111 | 112 | ![image](https://user-images.githubusercontent.com/43679629/83823425-5f323b00-a6aa-11ea-816a-68525e5800d7.png) 113 | 114 | 115 | ### Está com dúvidas? 116 | 117 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-service-course-step03events-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /2 - Layouts Complexos/9 - Conditional layout/README.md: -------------------------------------------------------------------------------- 1 | # Conditional Layout 2 | 3 | ## Introdução 4 | 5 | Em alguns momentos, quando desenvolvendo uma loja, precisamos criar _layouts_ condicionais que seriam aplicados somente a um contexto específico. Já vimos que na utilização de dispositivos diferentes, é possível condicionar o _layout_ através do Responsive Layout, mas e se quiséssemos, por exemplo, ter uma página de produto diferente para produtos específicos? Para isso serve o Conditional Layout. 6 | 7 | ## Setup opcional 8 | 9 | Para criar um _layout_ condicional de página de produto é necessário, inicialmente, ter uma página de produto. Se você já não tiver definido um _template_ de produto para sua loja, copie o disponível abaixo: 10 | 11 | ```json 12 | //product.jsonc 13 | { 14 | "store.product": { 15 | "children": [ 16 | "flex-layout.row#product-breadcrumb", 17 | "flex-layout.row#product-main" 18 | ] 19 | }, 20 | "flex-layout.row#product-breadcrumb": { 21 | "props": { 22 | "marginTop": 20 23 | }, 24 | "children": ["breadcrumb"] 25 | }, 26 | "flex-layout.row#product-main": { 27 | "props": { 28 | "colGap": 9, 29 | "rowGap": 7, 30 | "marginTop": 4, 31 | "marginBottom": 7, 32 | "paddingTop": 7, 33 | "paddingBottom": 7, 34 | "blockClass": "product-main" 35 | }, 36 | "children": [ 37 | "product-images", 38 | "flex-layout.col#right-col" 39 | ] 40 | }, 41 | "product-images": { 42 | "props": { 43 | "displayThumbnailsArrows": true, 44 | "thumbnailsOrientation": "vertical" 45 | } 46 | }, 47 | "flex-layout.col#right-col": { 48 | "props": { 49 | "preventVerticalStretch": true, 50 | "rowGap": 0 51 | }, 52 | "children": [ 53 | "product-name", 54 | "product-price#product-details", 55 | "sku-selector", 56 | "flex-layout.row#buy-button", 57 | "shipping-simulator", 58 | "share#default" 59 | ] 60 | }, 61 | "product-price#product-details": { 62 | "props": { 63 | "showInstallments": true, 64 | "showSavings": true 65 | } 66 | }, 67 | "flex-layout.row#buy-button": { 68 | "props": { 69 | "marginTop": 4, 70 | "marginBottom": 7 71 | }, 72 | "children": ["buy-button"] 73 | }, 74 | "share#default": { 75 | "props": { 76 | "social": { 77 | "Facebook": true, 78 | "WhatsApp": true, 79 | "Twitter": false, 80 | "Pinterest": true 81 | } 82 | } 83 | } 84 | } 85 | ``` 86 | 87 | Fazendo isso, teremos uma página de produto como a mostrada abaixo: 88 | 89 | ![image](https://user-images.githubusercontent.com/18701182/90407144-84650180-e07c-11ea-9036-838d4d662ba1.png) 90 | 91 | ## Atividade 92 | 93 | 1. Vamos criar um _banner_ exclusivo para a geladeira Geladeira Retrô, para isso, use como primeiro filho da `store.product` um `condition-layout.product`: 94 | 95 | ```diff 96 | //product.jsonc 97 | { 98 | "store.product": { 99 | "children": [ 100 | + "condition-layout.product" 101 | ... 102 | ] 103 | } 104 | ... 105 | } 106 | ``` 107 | 108 | 2. Defina, então, o `condition-layout.product`, com uma condição específica para a Batedeira Retrô: 109 | 110 | ```diff 111 | //product.jsonc 112 | { 113 | ... 114 | + "condition-layout.product": { 115 | + "children": [ 116 | + "condition.product#retro-mixer" 117 | + ] 118 | + } 119 | } 120 | 121 | ``` 122 | 123 | 3. Agora, precisamos definir a condição para a batedeira. 124 | 125 | O `condition.product` requer a *prop* `conditions` para definir em quais condições deve ser aplicada (veja a [documentação](https://developers.vtex.com/docs/vtex-condition-layout)), uma condição é dividida em três partes: 126 | 127 | - **subject:** é o dado que vai ser usado para fins de comparação, no nosso caso usaremos `productId`, na documentação é possível ver todas as opções disponíveis; 128 | - **verb:** é o método comparativo, usaremos o `is` para validar se o `productId` é de um produto específico, mas poderíamos usar: `is`, `is-not`, `contains` ou `does-not-contain`; 129 | - **object:** é o valor com que queremos comparar, no nosso caso, usaremos o *productId* `20`. 130 | 131 | Sendo assim, o objeto formado é: 132 | 133 | ```diff 134 | //product.jsonc 135 | { 136 | ... 137 | + "condition.product#retro-mixer": { 138 | + "props": { 139 | + "conditions": [ 140 | + { 141 | + "subject": "productId", 142 | + "verb": "is", 143 | + "object": "20" 144 | + } 145 | + ] 146 | + }, 147 | + "children": ["image#retro-mixer-banner"] 148 | + } 149 | } 150 | ``` 151 | 152 | **NOTA:** Se você estiver fazendo o curso na sua própria loja, identifique o `productId` do produto que deseja customizar e coloque o valor no campo `object`. Você descobrir o valor atualizando a página, abrindo o _console_ do seu navegador e digitando `__RUNTIME__.route.params.id`: 153 | 154 | ![image](https://user-images.githubusercontent.com/18701182/90410392-aeb8be00-e080-11ea-8880-f5470c4e5d00.png) 155 | 156 | 4. Para finalizar, vamos definir o _banner_ retrô: 157 | 158 | ```diff 159 | //product.jsonc 160 | { 161 | ... 162 | + "image#retro-mixer-banner": { 163 | + "props": { 164 | + "src": "https://appliancetheme.vtexassets.com/assets/app/src/retroimage___92a8271aac7c51d2059193bdbe019016.jpg", 165 | + "width": "100%", 166 | + "height": "200px", 167 | + "blockClass": "cover" 168 | + } 169 | + } 170 | } 171 | ``` 172 | 173 | Visite a página do produto testado para ver o layout funcionando, se tiver usando a `appliancetheme` e o produto for a batedeira retro, a url será: 174 | 175 | `https://{{seuworkspace}}--appliancetheme.myvtex.com/3-colors-retro-stand-mixer/p`: 176 | 177 | ![image](https://user-images.githubusercontent.com/43679629/93816475-f6a5a480-fc2d-11ea-80e9-45f4b7907007.png) 178 | 179 | Para garantir que o layout condicional de fato funciona, visite qualquer outra página de produto, e verifique que o _banner_ não é aplicado: 180 | 181 | ![image](https://user-images.githubusercontent.com/18701182/90412377-68b12980-e083-11ea-86a8-99495acfd997.png) 182 | 183 | ## Fim 184 | 185 | Chegamos ao último passo do curso e nele aprendemos como criar layouts complexos se alavancando de blocos mais simples, não exploramos todos os layouts possíveis, mas a ideia de todos eles é muito parecida, para conhecer mais visite a seção de [`VTEX STORE FRAMEWORK - LAYOUT APPS`](https://developers.vtex.com/docs/vtex-condition-layout) no Developer Portal. 186 | 187 | 188 | ### Está com dúvidas? 189 | 190 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-layout-blocks-step09conditional-layout-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /7 - Serviços/4 - Conhecendo um pouco mais sobre clientes/README.md: -------------------------------------------------------------------------------- 1 | # Conhecendo um pouco mais sobre clientes 2 | 3 | ## Introdução 4 | 5 | Neste passo, alguns conceitos referentes a clientes serão brevemente explicados e é apresentado quais são os clientes necessários para este curso: **cliente de analytics** e **cliente do Master Data**. O primeiro será implementado neste passo e você também aprenderá como utilizar um cliente que já está implementado na nossa API. 6 | 7 | ## Sobre os clientes 8 | 9 | Clientes, no VTEX IO, são abstrações para outros serviços. Nós transpassamos a complexidade ao implementar um cliente HTTP, por exemplo, de forma que você consiga focar nos verdadeiros objetivos da sua aplicação. Sempre que vcoê precisar configurar uma conexão com uma API externa ou outro serviço da VTEX, você deve criar um cliente! Alguns clientes padrões já estão implementados no VTEX IO, você pode consultá-los [aqui](https://github.com/vtex/node-vtex-api/blob/ccf4d8f8d3208007c4bfd558baf979df8d825af8/src/clients/IOClients.ts). 10 | 11 | Caso você já saiba um pouco mais sobre serviços no IO, você provavelmente já sabe que sua implementação exporta funções que recebem um objeto de contexto. Estas funções podem ser um _resolver_ para um campo de GraphQL, um _middleware_ para um servidor HTTP ou um _handler_ de eventos. Em todos os casos, você recebe um `ctx` (ou como você preferir chamá-lo), que é um objeto do tipo `Context` e dentro de `ctx.clients`, você encontrará diversos clientes, dentre os quais estão os que você implementou. 12 | 13 | É possível ler mais sobre os conceitos que envolvem a definição de clientes [neste documento](https://www.notion.so/How-to-use-and-create-Clients-on-VTEX-IO-3598e97a761645e0befdac84a32f339d). 14 | 15 | ## O cliente de _analytics_ 16 | 17 | Neste curso, será necessário criar um cliente que será utilizado para consultar informações em relação ao número de visualizações de um determinado produto. O cliente que será criado fará um _request_ REST en qye irá receber e consumir estas informações de número de visualizações de produtos. Para fazer isso, esse cliente precisa ter uma função que será utilizada no _handler_ para uma rota específica e é assim que iremos testá-lo. 18 | 19 | ## Implementando o cliente _analytics_ e fazendo testes 20 | 21 | Neste passo, vamos implementar o cliente de _Analytics_. 22 | 23 | 1. Em primeiro lugar, no diretório `/node/clients`, você encontrará um arquivo chamado `analyticsClient.ts`, que já contém uma simples declaração de classe, como o código mostrado abaixo. É aqui que você implementará seu cliente. 24 | 25 | ```ts 26 | import { AppClient } from '@vtex/api' 27 | 28 | export default class Analytics extends AppClient {} 29 | ``` 30 | 31 | > É possível notar neste bloco de código que `Analytics` é um cliente que estende de `AppClient`, pois esta classe oferece configurações já pré-esbeleciadas que asseguram que seu cliente tem uma comunicação segura com outras partes da sua _app_. 32 | 33 | 2. O cliente precisa ter um construtor e apenas um método, que chamaremos de `getLiveUsers`. Este método retorna uma promessa de um _array_ em que seus elementos são do tipo `LiveUsersProduct`. Utilizando o código abaixo, adicione as linhas de código necessárias ao seu cliente: 34 | 35 | ```diff 36 | //node/clients/analyticsClient.ts 37 | import { AppClient, InstanceOptions, IOContext } from '@vtex/api' 38 | 39 | export default class Analytics extends AppClient { 40 | + constructor(context: IOContext, options?: InstanceOptions) { 41 | + super('vtex.mocked-analytics@0.x', context, options) 42 | + } 43 | 44 | + public getLiveUsers(): Promise {} 45 | } 46 | 47 | +interface LiveUsersProduct { 48 | + slug: string 49 | + liveUsers: number 50 | +} 51 | ``` 52 | 53 | > A interface que é definda será utilizada como tipagem para o método que vamos implementar. 54 | 55 | 3. Agora, vamos implementar o método em si, `getLiveUsers`. Ele retorna um _request_ HTTP GET para um _endpoint_ bem definido, que é responsável por pegar os dados que são necessários para esta aplicação. Dessa forma, adicione a seguinte linha ao método `getLiveUsers`: 56 | 57 | ```ts 58 | return this.http.get('_v/live-products') 59 | ``` 60 | 61 | > O método que você acabou de criar irá pegar os dados necessários para esta aplicação: um _array_ de objetos que contêm dois campos: `slug`, uma _string_ que representa o ID do produto e `liveUsers`, um número que é a quantidade de usuários visualizando o produto - que são os campos que estão na interface. 62 | 63 | 4. O _endpoint_ `_v/live-products` que chamamos precisa da _app_ `mocked-analytics` para funcionar, ou seu método `getLiveUsers` não verá nenhum dado. **No caso de não estar rodando essa aplicação na conta `appliancetheme`**, você precisará instalar a aplicação `mocked-analytics` no seu _workspace_. Para fazer isso, você pode rodar o seguinte comando: `vtex install vtex.mocked-analytics`. 64 | 65 | 5. Com o seu cliente de _analytics_ já implementado, é necessário declará-lo como um dos clientes na classe `Clientes`, de forma que ele ficará disponível e acessível através do uso de `Context`, do qual falamos anteriormente. 66 | 67 | Dessa forma, na pasta `/node/clients`, vá ao arquivo chamado `index.ts` e adicione um método referentes ao cliente de _analytics_. Também é necessário importar o cliente que você implementou anteriormente. 68 | 69 | ```diff 70 | // node/clients/index.ts 71 | + import Analytics from '../clients/analytics' 72 | 73 | export class Clients extends IOClients { 74 | + public get analytics() { 75 | + return this.getOrSet('analytics', Analytics) 76 | } 77 | } 78 | ``` 79 | 80 | 6. De forma que você possa ver suas mudanças funcionando, é possível utilizar o método `getLiveUsers` dentro de um _handler_. Utilizando uma rota que já está definida no projeto, você pode enviar um _request_ para ela e o _handler_ responsável por essa rota irá chamar o método que criamos. 81 | 82 | Para fazer isso, há uma pasta dentro do diretório `/node`, chamada `handlers`. Há um arquivo chamado `analytics.ts`, no qual é necessário fazer duas coisas para que seu teste funcione: pegar o cliente de _analytics_ de `ctx` e substituir o conteúdo de `ctx.body` pelo método mencionado anteriormente, como você pode ver no bloco de código abaixo: 83 | 84 | ```diff 85 | export async function analytics(ctx: Context, next: () => Promise) { 86 | + const { 87 | + clients: { analytics }, 88 | + } = ctx 89 | + ctx.status = 200 90 | - ctx.body = 'OK' 91 | + ctx.body = await analytics.getLiveUsers() 92 | + ctx.set('cache-control', 'no-cache') 93 | await next() 94 | } 95 | ``` 96 | 97 | Agora, vamos testá-lo! É possível utilizar o Postman para enviar um _request_ GET para a seguinte rota: 98 | 99 | `{your workspace}--{your account}.myvtex.com/_v/app/analytics/realTime` 100 | 101 | e é esperado que esta responsa com os dados e com status `200`. 102 | 103 | > Atenção! Geralmente, a conta utilizada para rodar aplicações em cursos é a `appliancetheme` 104 | 105 | ![image](https://user-images.githubusercontent.com/19495917/84827089-53c00780-affa-11ea-857f-fdcba0fef7c2.png) 106 | 107 | 108 | ### Está com dúvidas? 109 | 110 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-service-course-step04clients-analytics-answersheet) ou peça ajuda a um de nossos monitores -------------------------------------------------------------------------------- /6 - Blocos customizados/9 - Conectando backend e frontend/README.md: -------------------------------------------------------------------------------- 1 | # Conectando _backend_ e _frontend_ 2 | 3 | ## Introdução 4 | 5 | Agora aprenderemos como recuperar dados do _backend_ e exibí-los na interface. O VTEX IO utiliza [GraphQL](https://graphql.org/) como linguagem/tecnologia para transferência de dados, o que torna a programação dos nossos componentes bastante simples. Iremos modificar o nosso componente Countdown para buscar o _targetDate_ do **campo `releaseDate` de um produto da VTEX**. Para realizar queries GraphQL em React, é utilizado o **Apollo Client**, uma biblioteca de gerenciamento de estado que facilita a integração de uma API GraphQL com a aplicação _front-end_. 6 | 7 | A biblioteca **Apollo Client** disponibiliza uma integração nativa com React, por meio de _hooks_. Dessa forma, realizar uma _query_ significa usar um _hook_ que não só realizará as _queries_ e fará o _fetch_ dos dados, mas também proverá cache e atualização do estado da UI. Essa integração, chamada `react-apollo` já está declarada no `package.json`. 8 | 9 | ## Preparação 10 | 11 | - Para implementar esta funcionalidade, precisamos **adicionar o nosso bloco `countdown` na página de produto**, e também faremos nossos testes nessa página também. Para isso, faça o seguinte: 12 | 13 | 1. Primeiramente, em seu tema clonado (`store-theme`) acesse o arquivo `store/blocks/product.jsonc` e, no bloco `flex-layout.col#right-col` adicione o bloco `countdown`, logo antes do `buy-button`: 14 | 15 | ```diff 16 | "product-gifts", 17 | + "countdown", 18 | "flex-layout.row#buy-button", 19 | "availability-subscriber", 20 | ``` 21 | 22 | 2. Rode `vtex link` em seu tema novamente (caso o processo já não esteja sendo executado). Pronto, agora o nosso bloco está na página de produto. Acesse alguma destas páginas e veja o componente `Countdown` renderizado. 23 | 24 | ## Query de Release Date 25 | 26 | 1. Crie uma pasta `react/queries` e nela adicione um arquivo `productReleaseDate.graphql` que irá conter a _query_ a ser feita. Em particular, essa _query_ irá receber um termo, que será **o slug do produto a ser recuperado a data de lançamento**. Ela chamará o _resolver_ `product`, já disponível pela app `vtex.search-graphql`, e recuperaremos apenas o campo que precisamos. 27 | 28 | ```graphql 29 | query productReleaseDate($slug: String){ 30 | product(slug: $slug) { 31 | releaseDate 32 | } 33 | } 34 | ``` 35 | > Perceba que a query precisará do _slug_ do produto que buscamos. Para isso, **recuperaremos esta informação do contexto de Produto da VTEX**. 36 | 37 | 2. Para utilizar essa query, é necessário **adicionar a app `vtex.search-graphql` como dependência em sua app.** Também precisaremos utilizar o hook `useProduct`, exportado pela app `vtex.product-context`, para recuperar o slug do produto que está carregado na página. Para isso, no `manifest.json` de sua app, adicione em `dependencies`: 38 | 39 | ``` 40 | "vtex.search-graphql": "0.x", 41 | "vtex.product-context": "0.x" 42 | ``` 43 | 44 | 3. Agora, é necessário importar os hook `useQuery`, para fazer a _query_ que retornará o dado que descrevemos, e `useProduct`, para nos dar a informação sobre o slug do produto atual. Além disso, também é preciso importar a _query_, definida anteriormente, que se encontra no arquivo `productReleaseDate.graphql`. 45 | 46 | ```diff 47 | // react/Countdown.tsx 48 | import React from 'react' 49 | ... 50 | +import { useQuery } from 'react-apollo' 51 | 52 | +import useProduct from 'vtex.product-context/useProduct' 53 | 54 | +import productReleaseDate from './queries/productReleaseDate.graphql' 55 | ``` 56 | 57 | > É importante notar que há a possibilidade da sua IDE mostrar um erro ao fazer o *import* do `product-context`. 58 | 59 | > Vale ressaltar também que tanto a *prop* `targetDate` como a constante `DEFAULT_TARGET_DATE` não serão mais necessárias, então pode pode removê-las e ajustar os _imports_, no caso de não utilizar mais algumas funções. 60 | 61 | 4. Feito isso, defina a query usando o `productReleaseDate` importado e o `useQuery`. Os dados de produto podem ser encontrados em `useProduct`. Ambos são [hooks](https://reactjs.org/docs/hooks-intro.html), e portanto, devem ser adicionados dentro de um componente funcional React. 62 | 63 | ```diff 64 | + const { product } = useProduct() 65 | + const { data, loading, error } = useQuery(productReleaseDate, { 66 | + variables: { 67 | + slug: product?.linkText 68 | + }, 69 | + ssr: false 70 | + }) 71 | ``` 72 | 73 | > `linkText` será igual a `'red-analogic-coffee-and-tea-machine'`, por exemplo, quando o seu componente for renderizado na página deste produto. 74 | 75 | 5. Agora que estamos utilizando nosso bloco em páginas que têm contexto de produto, é importante testar se este context existe. Para fazer isso, vamos adicionar o bloco de código abaixo: 76 | 77 | ```tsx 78 | if (!product) { 79 | return ( 80 |
81 | There is no product context. 82 |
83 | ) 84 | } 85 | ``` 86 | 87 | 6. Além disso, é preciso tratar os casos de *loading* e *error* antes de retornar o componente principal do contador ao utilizar o *hook* `useQuery`. Para isso, é possível retornar um `span` em cada um dos casos, como no exemplo abaixo, dentro do componente `Countdown`: 88 | 89 | ```tsx 90 | if (loading) { 91 | return ( 92 |
93 | Loading... 94 |
95 | ) 96 | } 97 | if (error) { 98 | return ( 99 |
100 | Erro! 101 |
102 | ) 103 | } 104 | ``` 105 | 106 | 7. Após enviar as modificações, acesse uma página de produto e verifique se a _query_ está funcionando através de um `console.log({data})` após a chamada do `useQuery`, que deve mostrar algo como isso: 107 | 108 | ```ts 109 | { 110 | data: { 111 | product: { 112 | releaseDate: '2019-01-01T00:00:00"', 113 | __typename: "Product" 114 | } 115 | } 116 | } 117 | ``` 118 | 119 | 8. Por fim, para fazer com que o Countdown marque as horas para o `releaseDate` do produto, mude o parâmetro da função `tick`. Você também pode remover as `props` recebidas no componente, já que não serão mais usadas. 120 | ```diff 121 | -tick(targetDate, setTime) 122 | +tick(data?.product?.releaseDate || DEFAULT_TARGET_DATE, setTime) 123 | ``` 124 | 125 | Resultado no produto _Red Front-Loading Washer_: 126 | > No caso de você se deparar com casos em que o contador está contando para cima ou até mesmo com valores negativos, não se preocupe! Isso está relacionado ao fato de que o `releaseDate`pode estar no passado. 127 | 128 | ![image](https://user-images.githubusercontent.com/18706156/79596495-0fc28c00-80b7-11ea-8361-35075dba3bd5.png) 129 | 130 | --- 131 | ## Muito bem! 132 | Esse é o último passo do curso de Store Block, você avançou muito bem e esperamos que tenha aprendido bastante até esse momento. **Parabéns!** 133 | 134 | Se você deseja continuar aprendendo mais em como desenvolver utilizando o VTEX IO, nós o encorajamos a começar nosso próximo curso, que foca em ensinar como desenvolver serviços no VTEX IO. 135 | 136 | ### Está com dúvidas? 137 | 138 | Confira [aqui o gabarito para esta etapa](https://vtex-enterprise-group.readme.io/learning/docs/course-store-block-step08react-apollo-answersheet) ou peça ajuda a um de nossos monitores 139 | -------------------------------------------------------------------------------- /6 - Blocos customizados/8 - Componentizando o bloco countdown/README.md: -------------------------------------------------------------------------------- 1 | # Componentizando o bloco countdown 2 | 3 | ## Introdução 4 | Nessa etapa, a *app* tem dois elementos principais: o título e o contador. Porém, para obter uma maior flexibilidade de posicionamento e customização, é interessante que sejam separadas em dois blocos distintos. Para isso, é preciso apresentar brevemente o conceito de interfaces para, em seguida, ser desenvolvido um novo componente `Title`. Um exemplo de customização em termos de posicionamento, que será abordada nessa etapa, é: 5 | 6 | > E se eu quisesse que o título estivesse embaixo ou ao lado do contador? 7 | 8 | ## Interface 9 | Uma interface funciona como um contrato, com restrições bem definidas de como os blocos funcionarão juntos. Define, então, um mapeamento que cria um bloco do Store Framework, a partir de um componente React. É importante destacar que o uso de interfaces, de forma a separar uma *app* em diversas interfaces torna o poder de customização muito maior. 10 | 11 | Ao definir a *app* na interface, a propriedade `component` é responsável por definir o componente React que será usado. É importante ressaltar que o nome do `component` tem que ser igual ao nome do arquivo do componente dentro da pasta `react/`. 12 | 13 | Exemplo de `interfaces.json`: 14 | ```json 15 | { 16 | "countdown": { 17 | "component": "Countdown" 18 | } 19 | } 20 | ``` 21 | 22 | Agora, você irá separar o título do bloco do contador e adicioná-lo à nossa loja embaixo do contador. 23 | 24 | ### Alterando o componente `Countdown` 25 | 26 | 1. Em primeiro lugar, remova os *imports*, o `title` da interface e altere a constante do CSS *handles*: 27 | 28 | ```diff 29 | //react/Countdown.tsx 30 | import React, { useState } from 'react' 31 | import { TimeSplit } from './typings/global' 32 | import { tick, getTwoDaysFromNow } from './utils/time' 33 | import { useCssHandles } from 'vtex.css-handles' 34 | -import { FormattedMessage } from 'react-intl' 35 | 36 | interface CountdownProps { 37 | targetDate: string, 38 | - title: string 39 | } 40 | 41 | const DEFAULT_TARGET_DATE = getTwoDaysFromNow() 42 | -const CSS_HANDLES = ['container', 'countdown', 'title'] 43 | +const CSS_HANDLES = ['countdown'] 44 | ``` 45 | 46 | 2. Agora, no componente React em si, é preciso retirar o `title` como *prop* recebida e a constante do texto do título, além de alterar o que é renderizado: 47 | 48 | ```diff 49 | //react/Countdown.tsx 50 | const Countdown: StorefrontFunctionComponent = ({ 51 | - title, 52 | targetDate = DEFAULT_TARGET_DATE, 53 | }) => { 54 | const [ 55 | timeRemaining, 56 | setTime 57 | ] = useState({ 58 | hours: '00', 59 | minutes: '00', 60 | seconds: '00' 61 | }) 62 | 63 | - const titleText = title || 64 | const handles = useCssHandles(CSS_HANDLES) 65 | 66 | tick(targetDate, setTime) 67 | 68 | return ( 69 | -
70 | -
71 | - { titleText } 72 | -
73 |
74 | {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`} 75 |
76 | -
77 | ) 78 | } 79 | ``` 80 | 81 | 3. Por fim, retire o título do *schema*: 82 | 83 | ```diff 84 | //react/Countdown.tsx 85 | Countdown.schema = { 86 | title: 'editor.countdown.title', 87 | description: 'editor.countdown.description', 88 | type: 'object', 89 | properties: { 90 | - title: { 91 | - title: 'editor.countdown.title.title', 92 | - type: 'string', 93 | - default: null, 94 | - }, 95 | targetDate: { 96 | title: 'editor.countdown.targetDate.title', 97 | description: 'editor.countdown.targetDate.description', 98 | type: 'string', 99 | default: null, 100 | }, 101 | }, 102 | } 103 | ``` 104 | 105 | ### Criando um novo componente 106 | 107 | 1. Crie um novo arquivo dentro da pasta `/react`, chamado `Title.tsx`, ele será o novo componente do título. Nele, alguns *imports* precisam ser feitos. A estrutura básica do código é muito similar a do componente `Countdown`. Feito isso, adicione os *imports* necessários e a constante do CSS *handles*: 108 | 109 | ```tsx 110 | //react/Title.tsx 111 | import React from 'react' 112 | import { FormattedMessage } from 'react-intl' 113 | import { useCssHandles } from 'vtex.css-handles' 114 | 115 | const CSS_HANDLES = ['title'] as const 116 | ``` 117 | 2. Agora, é necessário alterar a função do componente: 118 | 119 | ```tsx 120 | //react/Title.tsx 121 | const Title: StorefrontFunctionComponent = ({title}) => { 122 | const handles = useCssHandles(CSS_HANDLES) 123 | const titleText = title || 124 | 125 | return ( 126 |
127 | { titleText } 128 |
129 | ) 130 | } 131 | ``` 132 | 133 | 3. Por fim, adicione a interface, o *schema* e o *export*: 134 | 135 | ```tsx 136 | //react/Title.tsx 137 | interface TitleProps { 138 | title: string 139 | } 140 | 141 | Title.schema = { 142 | title: 'editor.countdown-title.title', 143 | description: 'editor.countdown-title.description', 144 | type: 'object', 145 | properties: { 146 | title: { 147 | title: 'editor.countdown.title.title', 148 | type: 'string', 149 | default: null, 150 | } 151 | } 152 | } 153 | 154 | export default Title 155 | ``` 156 | 157 | ### Alterando o arquivo `interfaces.json` 158 | Nesta altura, há dois componentes na *app*: o título e o contador. Porém, é preciso alterar o arquivo `interfaces.json`, que se encontra na pasta `store`. É preciso declarar os componentes separadamente. No início, nossa interface tinha apenas o `Countdown`. É necessário adicionar o outro componente: 159 | ```diff 160 | { 161 | "countdown": { 162 | "component": "Countdown" 163 | }, 164 | + "countdown.title": { 165 | + "component": "Title" 166 | + } 167 | } 168 | ``` 169 | 170 | ### Adicionando internacionalização 171 | 172 | Também é preciso adicionar ao *Messages* as traduções cujas chaves são as *strings* do *schema* que incluímos no arquivo `Title.tsx` logo acima. Como visto na etapa de *Messages*, vá à pasta `/messages` e adicione em cada um dos arquivos as traduções necessárias (`pt.json`, `es.json` e `en.json`). Abaixo há um exemplo para o caso do arquivo `en.json`: 173 | ```diff 174 | { 175 | + "countdown.title": "Countdown", 176 | "editor.countdown.title": "Countdown", 177 | "editor.countdown.description": "Countdown component" 178 | } 179 | ``` 180 | 181 | ### Adicionando o novo bloco na home da loja 182 | Por fim, para ver as mudanças, volte ao tema para alterá-lo a fim de incluir o novo bloco. Para isso, basta adicionar à *home* o título! Assim como feito para o contador, é necessário adicionar o `countdown.title` como um bloco no tema da loja, ou seja, no arquivo `home.jsonc` do store-theme. 183 | ```diff 184 | //home.jsonc 185 | { 186 | "store.home": { 187 | "blocks": [ 188 | "countdown", 189 | + "countdown.title", 190 | ... 191 | ] 192 | }, 193 | ... 194 | } 195 | ``` 196 | 197 | Pronto! Agora vamos ver como deve ser o resultado: 198 | ![image](https://user-images.githubusercontent.com/19495917/75560163-6d294d80-5a23-11ea-859d-35a8239ddfad.png) --------------------------------------------------------------------------------