GithubHelp home page GithubHelp logo

store-block's People

Contributors

vtexgithubbot avatar

store-block's Issues

Componentizing the countdown block

Componentizando o bloco countdown

Introdução

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, é:

E se eu quisesse que o título estivesse embaixo ou ao lado do contador?

Interface

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.

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/.

Exemplo de interfaces.json:

{
  "countdown": {
    "component": "Countdown"
  }
}

Atividade

Nessa atividade, será separado o título e adicionado à nossa loja embaixo do contador.

Alterando o componente Countdown

  1. Remova os imports, o title da interface e altere a constante do CSS handles:
    //react/Countdown.tsx
    import React, { useState } from 'react'
    import { TimeSplit } from './typings/global'
    import { tick } from './utils/time'
    import { useCssHandles } from 'vtex.css-handles'
    -import { FormattedMessage } from 'react-intl'
    
    interface CountdownProps {
      targetDate: string,
    -  title: string
    }
    
    const DEFAULT_TARGET_DATE = (new Date('2020-03-02')).toISOString()
    -const CSS_HANDLES = ['container', 'countdown', 'title']
    +const CSS_HANDLES = ['countdown']
  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:
    //react/Countdown.tsx
    - const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ title, targetDate = DEFAULT_TARGET_DATE }) => {
    + const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [
        timeRemaining,
        setTime
      ] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
    - const titleText = title || <FormattedMessage id="countdown.title" />
      const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
          <div className={`${handles.container} t-heading-2 fw3 w-100 pt7 pb6 c-muted-1 db tc`}>
    -        <div className={`${handles.title} db tc`}>
    -          { titleText }
    -        </div>
            <div className={`db tc`}>
              {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}
            </div>
          </div>
      )
    }
  3. Por fim, retire o título do schema:
    //react/Countdown.tsx
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {
    -   title: {
    -     title: 'editor.countdown.title.title',
    -     type: 'string',
    -     default: null,
    -   },
        targetDate: {
          title: 'editor.countdown.targetDate.title',
          description: 'editor.countdown.targetDate.description',
          type: 'string',
          default: null,
        },
      },
    }

Criando um novo componente

  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.

  2. Adicione os imports necessários e a constante do CSS handles:

    //react/Title.tsx
    import React from 'react'
    import { FormattedMessage } from 'react-intl'
    import { useCssHandles } from 'vtex.css-handles'
    
    const CSS_HANDLES = ['title'] as const
  3. Altere a função do componente:

    //react/Title.tsx
    const Title: StorefrontFunctionComponent<TitleProps> = ({title}) => {
      const handles = useCssHandles(CSS_HANDLES)
      const titleText = title || <FormattedMessage id="countdown.title" />
    
      return (
        <div className={`${handles.title} t-heading-2 fw3 w-100 c-muted-1 db tc`}>
          { titleText }
        </div>
      )
    }
  4. Adicione a interface, o schema e o export:

    //react/Title.tsx
    interface TitleProps {
      title: string
    }
    
    Title.schema = {
      title: 'editor.countdown-title.title',
      description: 'editor.countdown-title.description',
      type: 'object',
      properties: {
        title: {
          title: 'editor.countdown.title.title',
          type: 'string',
          default: null,
        }
      }
    }
    
    export default Title

Alterando o arquivo interfaces.json

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:

{
  "countdown": {
    "component": "Countdown"
  },
+   "countdown.title": {
+     "component": "Title"
+   }
}

Adicionando internacionalização

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:

 {
+  "countdown.title": "Countdown",
   "editor.countdown.title": "Countdown",
   "editor.countdown.description": "Countdown component"
 }

Adicionando o novo bloco na home da loja

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.

//home.jsonc
 {
   "store.home": {
     "blocks": [
       "countdown",
+      "countdown.title",
       ...
     ]
   },
   ...
 }

Pronto! Agora vamos ver como deve ser o resultado:
image

Connecting _backend_ and _frontend_

Conectando backend e frontend

Introdução

Agora aprenderemos como recuperar dados do backend e exibí-los na interface. O VTEX IO utiliza GraphQL 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.

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.

Preparação

  • 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:
  1. 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:
        "product-gifts",
    +	"countdown",
        "flex-layout.row#buy-button",
        "availability-subscriber",
  2. Rode vtex link em seu tema novamente (caso o processo já não esteja sendo executado).
  3. Pronto, agora o nosso bloco está na página de produto. Acesse alguma destas páginas e veja o componente Countdown renderizado.

Query de Release Date

  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.

    query productReleaseDate($slug: String){
    	  product(slug: $slug) {
    		    releaseDate
    	  }
    }
    

    Perceba que a query precisará do slug do produto que buscamos. Para isso, recuperaremos esta informação do contexto de Produto da VTEX.

  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:

    "vtex.search-graphql": "0.x",
    "vtex.product-context": "0.x"
    
  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. Vale ressaltar também que a prop targetDate não será mais necessária.

    // react/Countdown.tsx
    import React from 'react'
    +import { useQuery } from 'react-apollo'
    +import useProduct from 'vtex.product-context/useProduct'
    
    import { useCssHandles } from 'vtex.css-handles'
    
    +import productReleaseDateQuery from './queries/productReleaseDate.graphql'

    É importante notar que há a possibilidade da sua IDE mostrar um erro ao fazer o import do product-context.

  4. Defina a query usando o productReleaseDateQuery importado e o useQuery, usando os dados do useProduct(). Como mencionado anteriormente, ambos são hooks, o que significa que devem ser adicionados dentro de um componente funcional React, no caso, o Countdown.

    + const { product: { linkText } } = useProduct()
    + const { data, loading, error } = useQuery(productReleaseDateQuery, {
    +   variables: {
    +     slug: linkText
    +   },
    +   ssr: false
    + })

    linkText será igual a 'red-analogic-coffee-and-tea-machine', por exemplo, quando o seu componente for renderizado na página deste produto.

    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:

    if (loading) {
      return (
        <div>
          <span>Loading...</span>
        </div>
      )
    }
    if (error) {
      return (
        <div>
          <span>Erro!</span>
        </div>
      )
    }
    if (!product) {
      return (
        <div>
          <span>Não há contexto de produto</span>
        </div>
      )
    }
  5. 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:

    {
      data: {
        product: {
         releaseDate: '2019-01-01T00:00:00"',
         __typename:  "Product"
        }
      }
    }
  6. 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.

    -tick(targetDate, setTime)
    +tick(data?.product?.releaseDate || DEFAULT_TARGET_DATE, setTime)

Resultado no produto Red Front-Loading Washer:

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 releaseDatepode estar no passado.

image

Getting to know an app on VTEX IO

Conhecendo uma app VTEX IO

Introdução

Antes de começar, é necessário relembrar alguns conceitos importantes para uma maior compreensão do fluxo lógico ao desenvolver uma app.

manifest.json

vendor

Define o nome da conta VTEX que está desenvolvendo a app. Essa conta é responsável pela manutenção e distribuição da app (pode ser instalada em outras contas ou somente na própria)

O vendor vtex é utilizado em casos de apps nativas.

name

Identifica o nome da aplicação. Não deve ter caracteres especiais - exceto - - ou caracteres maiúsculos.

version

Identifica a versão atual da app. Para versionamento, utilizamos a especificação Semantic Versioning 2.0.0. O formato do versionamento é bem definido, com o uso de patches, minors e majors.

Abaixo um resumo da especificação:

  • Patches: você deve criar um patch quando está consertando um bug de forma retrocompatível
  • Minors: você deve criar uma versão minor quando adicionar funcionalidade de forma retrocompatível.
  • Majors: você deve criar uma versão major quando você realiza mudanças incompatíveis de API (o que costumamos chamar de breaking changes)

Exemplo: Se uma API que está na versão 2.3.2 e uma nova funcionalidade não tiver breaking changes, você pode atualizar a versão para 2.4.0.

No momento que o deploy é feito, há um worker chamado housekeeper responsável por atualizar a versão automaticamente para todas as contas. No caso de minors e patches, o housekeeper atualiza a app automaticamente em todas as contas, já que as mudanças são retrocompatíveis. Atualizações de majors, no entanto, possuem breaking changes, por isso o housekeeper não atualiza a app em todas as contas; sendo assim, a atualização deve ser feita manualmente.

builders

O desenvolvimento de apps no VTEX IO utiliza o conceito de Code as Configuration (CaC). Este paradigma é abstraído através do campo de builders que facilita o desenvolvimento, abstraindo a configuração de serviços.

Exemplo: para criar uma extensão no painel administrativo criam-se apps que utilizam o builder de admin.

image

Ao linkar a app, portanto, uma pasta de nome correspondente é enviada ao seu builder, que, por sua vez, transforma cada arquivo em configuração para o serviço competente.

dependencies

Uma app pode depender de outras aplicações. Esse campo lista todas as dependências necessárias para o correto funcionamento da app.

Exemplo

No exemplo da estrutura do manifest.json abaixo, é possível observar características mencionadas acima. Em particular, a versão é 0.0.1, onde os números são, respectivamente, major, minor e patch.

{
  "vendor": "vtex",
  "name": "countdown",
  "version": "0.0.1",
  "title": "Countdown",
  "description": "Countdown component",
  "defaultLocale": "pt-BR",
  "builders": {
    "messages": "1.x",
    "store": "0.x",
    "react": "3.x"
  },
  "mustUpdateAt": "2019-04-02",
  "scripts": {
    "postreleasy": "vtex publish --verbose"
  },
  "dependencies": {
    "vtex.styleguide": "9.x",
    "vtex.css-handles": "0.x"
  },
  "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-a pi/master/gen/manifest.schema"
}

Creating the countdown block feature

Criando a funcionalidade do bloco countdown

Introdução

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;

O hook useState

É chamado dentro de um componente funcional para atualizar e consumir o state de um componente. O state simboliza o estado atual de um componente.

O useState retorna um par: o valor do estado atual e uma função para atualizá-lo.

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:

const [count, setCount] = useState(0)

No trecho acima é importante observar três coisas:

  • Na variável count, é possível consumir o estado atual;
  • setCount é uma função para atualizá-lo;
  • 0 é o valor do estado inicial
const [timeRemaining, setTime] = useState<TimeSplit>({
  hours: '00', 
  minutes: '00', 
  seconds: '00'
})

Atividades

  1. Precisamos importar algumas funções e tipos para continuar:

    //react/Countdown.tsx
    import React, { useState } from 'react'
    import { TimeSplit } from './typings/global'
    import { tick } from './utils/time'
  2. Adicione o hook de atualização de estado (useState)

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate }) => {
    +   const [timeRemaining, setTime] = useState<TimeSplit>({
    +     hours: '00',
    +     minutes: '00',
    +     seconds: '00'
    +   })
    
        return (
          <div>
            { targetDate }
          </div>
        ) 
    }

    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.

  3. Adicione uma targetDate padrão para o caso de não haver um valor inicial definido. Para isso, declare uma constante que será utilizada como padrão:

    //react/Countdown.tsx
    const DEFAULT_TARGET_DATE = (new Date('2020-06-25')).toISOString()
  4. Utilize a função tick e a constante DEFAULT_TARGET_DATE para fazer o contador:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
    })
    
    + tick(targetDate, setTime)
    
      return (
        <div>
          { targetDate }
        </div>
      ) 
    }
  5. Altere o h1 para que ele exiba o contador que criamos. Para isso, precisamos utilizar o estado atual timeRemaining:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
      tick(targetDate, setTime)
    
      return (
        <div>   
    -     <h1>{ targetDate }</h1>
    +     <h1>{ `${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}` }</h1>
        </div>
      ) 
    }

    A formatação da string do contador está no formato HH:MM:SS, feita através do split em hours, minutes e seconds.

Assim, com essas alterações, veremos a atualização em tempo real do contador! O resultado na home é esse:

image

Modifying the countdown block to have configurable styles

Modificando o bloco countdown para ter estilos configuráveis

Introdução

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.

CSS Handles

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.

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.

Tachyons

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. Essa estratégia torna frameworks como o Tachyons muito flexíveis, escaláveis e rápidos.

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: Build a store using VTEX IO - Customizing styles.

Atividade

  1. Importe o hook useCssHandles. Para isso, volte ao Countdown.tsx e faça o import:

    // react/Countdown.tsx
    import { useCssHandles } from 'vtex.css-handles'
  2. Além disso, defina em um Array todos os handles que serão necessários (neste caso, será utilizado apenas 'countdown'):

    // react/Countdown.tsx
    const CSS_HANDLES = ['countdown']
  3. Utilize o useCssHandles no componente Countdown para definir o handle do countdown:

    // react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
    + const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
        <div>
          <h1>
            { `${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}` }
          </h1>
        </div>
      )
    }
  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.

    // react/Countdown.tsx
    import React from 'react'
    ...
    
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
      const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
    +   <div className={`${handles.countdown} t-heading-2 fw3 w-100 c-muted-1 db tc`}>
          {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}
        </div>
      )
    }

Vamos ver o resultado?

image

Internationalization practices in VTEX IO

Práticas de internacionalização no VTEX IO

Introdução

Com o bloco customizado na loja, devemos aprender a internacionalizar o conteúdo apresentado.

É 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.

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.

As Messages

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.

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.

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.

O arquivo context.json é necessário e precisa conter todas as mensagens, além de oferecer as traduções automáticas em casos excepcionais.

Atividade

Você já deve ter aprendido a usar o nosso builder messages, e será através dele que serão adicionadas strings internacionalizadas nos componentes.

  1. Para isso, na pasta /messages, adicione agora uma mensagem de título para o componente:

    messages/pt.json

    {
      ...,
    +  "countdown.title": "Contagem Regressiva"
    }

    messages/en.json

    {
      ...,
    +  "countdown.title": "Countdown"
    }

    messages/es.json

    {
      ...,
    +  "countdown.title": "Cuenta Regresiva"
    }

    messages/context.json

    {
      ...,
    +  "countdown.title": "Countdown"
    }
  2. Feito isso, para renderizar o título deve-se usar o componente FormattedMessage da biblioteca react-intl.

    A biblioteca react-intl dá suporte a várias maneiras de configuração e internacionalização, vale a pena verificá-las.

  3. Adicione a biblioteca usando yarn add react-intl na pasta react

  4. No código do seu componente Countdown.tsx importe o FormattedMessage

    //react/Countdown.tsx
    +  import { FormattedMessage } from 'react-intl'
  5. Adicione uma constante que será o seu título:

    //react/Countdown.tsx
    const titleText = title || <FormattedMessage id="countdown.title" />
  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:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({
      title,
      targetDate,
    }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00',
      })
    
      const titleText = title || <FormattedMessage id="countdown.title" />
      const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
        <div className={`${handles.container} t-heading-2 fw3 w-100 c-muted-1`}>
          <div className={`${handles.title} db tc`}>{titleText}</div>
          <div className={`${handles.countdown} db tc`}>
            {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}
          </div>
        </div>
      )
    }

    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:

    //react/Countdown.tsx
    const CSS_HANDLES = ["container", "countdown", "title"]
  7. Por fim, é preciso adicionar a prop de title no schema:

    //react/Countdown.tsx
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {
    +   title: {
    +     title: 'Sou um título',
    +     type: 'string',
    +     default: null,
    +   },
        targetDate: {
          title: 'Data final',
          description: 'Data final usada no contador',
          type: 'string',
          default: null,
        },
      },
    }

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:

image

Linking an app and using it on a store's theme

Linkando uma app e utilizando-a no tema da loja

Introdução

Para desenvolver um bloco de frente de loja, similar aos que oferecemos nativamente no Store Framework, utilizamos a biblioteca de desenvolvimento de UIs React.js.

Um pouco sobre a tecnologia

A unidade básica de desenvolvimento em React é o componente, onde pode ser implementada a interface visual do componente, como também sua lógica de estado, ou recuperação de dados. Seguindo as recomendações mais modernas de desenvolvimento, iremos focar no uso da API de Hooks do React, não utilizando de classes para a construção dos componentes.

No VTEX IO, adotamos Typescript como linguagem padrão para programação frontend. Apesar de ser necessário aprender sintaxes novas, o esforço é rapidamente recompensado! Utilizando Typescript, ganha-se alta previsibilidade de bugs, por oferecer tipagem estática. Além disso, com as IDEs certas, é possível aumentar a velocidade de implementação através de um code completion mais esperto, com a tipagem de objetos no código.

Neste curso, será utilizado exclusivamente Typescript. Caso você não tenha familiaridade com a linguagem, será uma excelente oportunidade de experimentá-la!

Objetivo dessa Etapa

Como você já tem familiaridade com o Store Framework, já sabe que utilizamos blocos, como shelf e sku-selector, para a montagem de uma VTEX IO Store. Nesta etapa você irá criar um bloco que será utilizado no tema da home page de sua loja.

Atividade

  1. No template clonado localmente, abra o arquivo Countdown.tsx:

    //react/Countdown.tsx
    import React from 'react'
    
    interface CountdownProps {}
    
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({}) => {
      return <div></div>
    }
    
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {},
    }
    
    export default Countdown
  2. Para ver o seu componente na home page, linke o tema em um terminal e a app em outro terminal. Adicione uma tag h1 dentro do nosso componente e declarar o bloco no tema.

    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({}) => {
    -    return <div></div>
    +    return (
    +      <div>
    +        <h1>Teste Countdown</h1>
    +      </div>
    +    )
    }

    Para que o componente seja visto funcionando na loja, é preciso declarar o bloco que a app define no tema. Em primeiro lugar, será necessário ter um tema para adicionar a app, para isso, será necessário cloná-lo do Github. Nesse curso, o store-theme será utilizado. Para clonar o repositório, basta executar o seguinte comando:

    git clone https://github.com/vtex-apps/store-theme.git
    
  3. Com o repositório clonado, vá ao terminal para deslinkar quaisquer temas ou apps que estejam linkados. Para isso, basta digitar o seguinte comando:

    vtex unlink --all
    
  4. Com o repositório já clonado, vá até a pasta com cd store-theme; linke o tema no seu workspace.

    vtex link
    
  5. Agora, com o tema linkado, é preciso também linkar a app. Para isso, vá até a pasta da app, store-block, repositório do Github que foi criado quando você iniciou o curso, e faça o link.

    vtex link
    
  6. Para que a app seja utilizada no tema, é preciso adicioná-la às suas dependências, que como visto anteriormente, ficam no manifest.json. Dessa forma, adicione ao manifesto do tema, que se encontra na pasta store-theme, "vtex.countdown" como dependência. A versão dela está definida no manifesto da app (0.0.1). Feito isso, o JSON terá mais uma linha, como mostrado abaixo:

    {
        ...
        "dependencies": {
            ...
    +        "vtex.countdown": "0.x",
            ...
        },
        ...
    }
  7. Por fim, é preciso adicionar o bloco na loja. Dentro do arquivo store-theme/store/blocks/home/home.jsonc, declare um bloco chamado "countdown".

    {
        "store.home": {
            "blocks": [
                "countdown",
                ...
            ]
            ...
        }
        ...
    }
    

O resultado esperado é encontrar um header na home da sua loja, como a imagem abaixo:

image

Making the countdown block customizable

Tornando o bloco countdown customizável

Introdução

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.

Conceitos

  • Hook

    Hooks são APIs que permitem utilizar funcionalidades do React dentro de componentes funcionais. Sem os hooks, um componente funcional em React só consegue renderizar elementos de UI. Hooks permitem, entre outras coisas, armazenar estado entre diferentes renderizações e executar efeitos colaterais no ciclo de vida de um componente. Obs.: eles não funcionam dentro de classes.

    Exemplo:

    const [count, setCount] = useState(0)
  • Interface para props

    Define os tipos Typescript das props que o componente poderá receber, permitindo o Intelissense da IDE sobre o componente que você criou.

    interface CountdownProps {
      exampleProp: string
    }
  • Schema do bloco

    No VTEX IO, oferecemos uma ferramenta de gestão de conteúdo da loja chamada Site Editor. Com essa ferramenta, acessada através do Admin VTEX, podemos alterar imagens e texto dos blocos sem precisar modificar o código da loja.

    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. Isso irá, automaticamente, gerar um formulário para o Site Editor relativo ao bloco que você está desenvolvendo. Abaixo é possível ver um exemplo de schema:

    // react/Countdown.tsx
    Countdown.schema = {
        title: 'editor.countdown.title',
        description: 'editor.countdown.description',
        type: 'object',
        properties: {},
    }

    O schema também é responsável por definir os textos que serão vistos pelo usuário do admin no formulário.

Atividade

  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.

    A definição da prop em si é feita através da declaração dela na interface CountdownProps no arquivo Countdown.tsx, mostrada anteriormente. Assim, adicione uma linha que defina uma prop chamada targetDate, do tipo string.

    // react/Countdown.tsx
    interface CountdownProps {
    +   targetDate: string    
    }
  2. Feito isso, é preciso utilizá-la no componente, substituindo o texto de antes, "Teste Countdown" por um outro texto, através do Site Editor.

    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.

    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.

    // react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate }) => {
      return (
        <div>
          <h1>{ targetDate }</h1>
        </div>
      ) 
    }
  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:

    // react/Countdown.tsx
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {
    +   targetDate: {
    +      title: 'Data final',
    +      description: 'Data final utilizada no contador',
    +      type: 'string',
    +      default: null,
    +   },
      },
    }

Pronto! Agora você pode alterar o conteúdo do texto através do Site Editor. Vamos ver como ficou? 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.

image

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.

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.