---
# System prepended metadata

title: '![](https://i.imgur.com/VR9JUSk.png)'

---

# ![](https://i.imgur.com/VR9JUSk.png)


## Introdução

*Vetta DigitalUI* é uma arquitetura que reúne os conceitos e melhores práticas de frontend para criação de sistemas para qualquer plataforma, navegador ou dispositivo. 

Fornecemos um kit de interface do usuário completo que permite criar rapidamente sites responsivos, leves, com interfaces ricas, experiência do usuário de alta qualidade.

Esta é uma documentação para entedimento e utilização da arquitetura **Digital** produzida pela Vetta. 

Você poderá aprender aqui sobre os componentes, como fazer novo projeto, novas telas ou até mesmo como fazer seus próprios componentes utilizando o **React** e **TypeScript**.

## Principais bibliotecas e ferramentas

* React: (https://reactjs.org/)
* Easy peasy: State management lib under Redux implementation (https://github.com/ctrlplusb/easy-peasy)
* Apisauce: API client lib under Axios implementation (https://github.com/infinitered/apisauce)
* Typescript: Typed superset of Javascript (https://www.typescriptlang.org/)
* AntD: Basic components lib (https://ant.design/)
* Formik: Build forms in React (https://github.com/jaredpalmer/formik)
* Nodejs
* Yarn 
> * O template prevê a utilização de **Nodejs** por padrão mas o sistema pode ser acoplado a:
    *     .net Core
    *     Java
    *     PHP
    *     Entre outros

## Instalação

Antes de iniciar, caso exista proxy, na rede adicionar para instalar dependências de pacotes npm:

```bash
$ npm config set proxy http://<endereço proxy>:<porta>

$ npm config set https-proxy 
```

Ao trocar de repositório, executar o comando de clone de acordo com o projeto.

### Template
Projeto frontend Template.

```bash
# SCV
$ git clone https://<endereço template>
```

Nos projetos os comandos de instalação seguem o exemplo:

```bash
# Instalar as dependências
$ yarn front:install

# Ao rodar pela primeira vez, construir o projeto 
$ yarn front:build

# Executar o projeto
$ yarn front:start
```
## Estrutura dos Projetos

Internamente, os projetos apresentam a divisão abaixo:


![](https://i.imgur.com/PkteLuy.png)



* ***assets***: Recursos estáticos (CSS, HTML, fontes, imagens).
* ***api***: Definição das APIs que acessam o servidor.
* ***components***: Componentes reutilizados dentro do projeto.
* ***helpers***: Códigos utilitários para uso interno do projeto.
* ***i18n***: Arquivos de internacionalização.
* ***routes***: Componentes para configuração das rotas
* ***store***: Definição de store global da aplicação.
* ***views***: Componentes de View (telas).
* ***arquivo .tgz***: arquivo de build gerado.
* ***config.json***: Configurações gerais da aplicação (habilitar mock e configurações de API).
* ***menu.json***: Definição do menu estático da aplicação.
* ***arquivo .md***: documentação

Já o repositório Lib Digital possui algumas estruturas a mais:

![](https://i.imgur.com/v8QIVWM.png)

* ***constants***: declaração de constantes.
* ***contexts***: passagem global de contextos React.
* ***helpers***: arquivos de ajuda global.
* ***hooks***: criação de React hooks customizadas.
* ***changelog***: arquivo para log de versão da biblioteca.


## Layout

### Estilo

O layout do projeto é definido no arquivo css localizado no diretório ***assets***:

![](https://i.imgur.com/j2lPmXt.png)


### Workspace

O Workspace é a estrutura base da Aplicação, com layout pré-definido e alguns comportamentos configuráveis. O desenvolvedor é livre para criar suas views que serão mapeadas à um item de menu, e será exibido na ***ViewArea***, conforme ilustrado na figura abaixo: 

![](https://i.imgur.com/rFy8P7E.png)


### Menu

O menu é a estrutura lateral esquerda da aplicação, totalmente responsivo, que é configurado a partir do arquivo ***menu.json*** contido no projeto.

```json=
  "menu": [
    {
      "label": "Template Forms",
      "icon": "commons-settings",
      "items": [
        {
          "label": "Template View",
          "uri": "/template"
        }
      ]
    }
```


### Views 
Views são componentes que definem estruturas de layout padrões para renderizar outros componentes de forma concisa. As principais disponíveis atualmente são a SimpleView e a MasterDetailView.
![](https://i.imgur.com/zRV7JwN.png)

### MasterArea
A seguir um diagrama mais detalhado da MasterArea (componente lateral esquerdo que exibe uma lista de entidade mestre):
![](https://i.imgur.com/HXSIywX.png)


### Itens de formulário

Os itens de formulário são baseados nos componentes básicos do AntD incorporados ao framework de formulários Formik.

Todos os itens de formulário do Digital-UI estão implementados para interagir com um formulário e possuem mecanismos de validação e permissão de campo (leitura ou escrita). 

São exemplos:

![](https://i.imgur.com/jRHkmqY.png)

![](https://i.imgur.com/rX0IQTt.png)


Para conhecer todos os componentes acesse: 
> AntD: Basic components lib (https://ant.design/)
> Formik: Build forms in React (https://jaredpalmer.com/formik/)



## Modelos de Tela (Views) 

Os Modelos de Tela são desenvolvidos com o propósito de reuso e padronização visual e funcional das aplicações.
Com a componentização de código, promovida pelo React, a reutilização e composição de partes de um componente maior torna-se uma tarefa fácil e segura para futuras manutenções.

Os seguintes componentes são implementações criadas para atender alguns comportamentos comuns identificados no projeto.


### CrudMasterDetailView

Componente utlizado para criação de telas com representação de Mestre-Detalhe. Contém uma área de busca dinâmica  permite edição rápida dos itens.

![](https://i.imgur.com/jDAa6Gi.png)

**Utilização do componente**

```react
import React from "react";

import {
  CrudMasterDetailView,
  GridView,
  CompositeView,
  MasterDetailForm,
  FormSubmitButton,
  notification
} from "@digital/ui";
import equipmentApi, { Equipment } from "@app/api/equipment";
import FormEquipment, {
  initialValues,
  validationSchema
} from "./FormEquipment";

export default () => {
  const filterPredicate = (item: Equipment, value: string) => {
    return item.name.toLowerCase().includes(value.toLowerCase());
  };

  const handleSubmit = (values: Equipment) =>
    notification.success(`Submit values: ${JSON.stringify(values, null, 1)}`);

  return (
    <CrudMasterDetailView
      getAllItems={equipmentApi.getAllItems}
      createItem={equipmentApi.createItem}
      updateItem={equipmentApi.updateItem}
      deleteItem={equipmentApi.deleteItem}
      filterPredicate={filterPredicate}
      titleExtractor={item => item.name}
      descriptionExtractor={item => item.description}
    >
      <CompositeView>
        <GridView noform>
          <MasterDetailForm
            initialValues={initialValues}
            validationSchema={validationSchema}
            actions={[<FormSubmitButton />]}
            onSubmit={handleSubmit}
          >
            <FormEquipment />
          </MasterDetailForm>
        </GridView>
      </CompositeView>
    </CrudMasterDetailView>
  );
};

```

### CrudSimpleView

Utilizado para criação de edição de dados no formato tradicional contendo uma tela de listagem e outra de edição.

**Utilização do componente**

```react
import React from 'react';
import { CrudSimpleView, GridView, Widget } from '@digital/ui';
import exampleApi from '@app/api/example";

const CrudSimpleExampleView = () => {
  return (
    <CrudSimpleView
      table={{ columns, rowKey }}
      title={title}
      getAllItems={exampleApi.getAllItems}
      getItem={exampleApi.getItem}
      createItem={exampleApi.createItem}
      updateItem={exampleApi.updateItem}
      deleteItem={exampleApi.deleteItem}>
      <GridView>
        <Widget>
          <CreateForm />
        </Widget>
      </GridView>
    </CrudSimpleView>
  );
};

export default CrudSimpleExampleView;
```

### RegisterView

Utilizado para a construção de telas de cadastro do sistema.

**Declaração de Colunas, Formulário de Criação e Formulário de Filtro**
```react
const columns = [{ title: 'Número', dataIndex: 'numero' }, { title: 'Descrição', dataIndex: 'descricao' }];

const CreateForm = () => (
  <Row>
    <Col span={6}>
      <FormInput name="numero" label="Número da Locomotiva" />
    </Col>
    <Col span={6}>
      <FormInput name="descricao" label="Descrição" />
    </Col>
  </Row>
);

const FilterForm = () => (
  <Row>
    <Col span={2}>
      <FormInput name="numero" label="Número da Locomotiva" />
    </Col>
  </Row>
);
```
**Utilização do componente**

```react
export default () => {
  return (
    <RegisterView
      title="Cadastro de Locomotiva"
      resourceUrl="cadastroLocomotiva"
      columns={columns}
      filterForm={<FilterForm />}
      createForm={<CreateForm />}
    />
  );
};
```

### ReportView

Utilizado para a construção de telas de relatório do sistema.

**Utilização do componente**

```react
export default () => {
  return (
    <ReportView
      reportUrl="relatorioAderenciaFerroviaria"
      title="Aderência da Programação Ferroviária"
      initialValues={{
        mesAno: Date.now(),
      }}>
      <FormDatePicker label="Mês/Ano:" name="mesAno" />
    </ReportView>
  );
};
```

### QueryView

Utilizado para a construção de telas de consulta do sistema.

**Utilização do componente**

```react
export default () => {
  return (
    <ReportView
      reportUrl="relatorioAderenciaFerroviaria"
      title="Aderência da Programação Ferroviária"
      initialValues={{
        mesAno: Date.now(),
      }}>
      <FormDatePicker label="Mês/Ano:" name="mesAno" />
    </ReportView>
  );
};
```

### LegacyView

Utilizado para incorporar e exibir telas da aplicação legado e ter uma rápida visualização na estrutura moderna, dispensando a criação de novas telas.

O mesmo conceito é utilizado para integrar visualizações como, por exemplo, PowerBI na aplicação.


## Tutoriais


### Criação de Chaves Internacionalizadas

Na criação de projeto via CLI, a pasta com o modelo fica disponível em src/i18n.  

![](https://i.imgur.com/BASHUar.png)

Cria-se um arquivo index.ts contendo os exports das mensagens. 

Exemplo de arquivo de mensagens:

```react
export default {
'cadastro.cadastrovagao.numeroVagao': 'Número do Vagão',
};
```
Exemplo de uso de mensagem em um campo do formulário:

```react
<FormInput name="numero" label="cadastro.cadastrovagao.numeroVagao" span={2} />
```

### Adicionar View e Rota

Para inserir um novo caminho para a sua View na aplicação, abra o arquivo menu.json e crie o nome e acesso para a sua rota:

```react
{
  "topArea": [],
  "menu": [
    {
      "label": "Examples",
      "icon": "ui-form",
      "items": [
        {
          "label": "Simple View",
          "uri": "/example/simpleExampleView"
        },
        {
          "label": "MasterDetail View",
          "uri": "/example/masterDetailExampleView"
        }
      ]
    }
  ]
}

```

Abra o arquivo src/App.tsx e adicione o componente 
```react
<Route path="caminho/para/view" component={MyComponent} />
```
dentro do Workspace como sugere o exemplo abaixo:

```react
import React from "react";

...

import SimpleExampleView from "@app/views/SimpleExampleView";
import MasterDetailExampleView from '@app/views/MasterDetailExampleView';

...

export default () => (
<AppContainer models={models} header={headerData} translationConfig={translations}>
  <Router>
    <Workspace menu={addLoggedUserToMenu(menuData, username)}>
      {/** Add your menu routes here. */}
      <Switch>
        <Route path="/example/simpleExampleView" component={SimpleExampleView} />
        <Route path="/example/masterDetailExampleView" component={MasterDetailExampleView} />
      </Switch>
    </Workspace>
  </Router>
</AppContainer>
);
```

### Form

*FormatText*: componente de formatação de texto.

```react
<FormatText id="ui.commons.insert" uppercase />
```

*FormCheckbox*
Recebe o nome do campo e o valor relacionado

*FormDatePicker*
Formatação do componente de data. Pode ser configurada a exibição e o envio à Api. 

```react
<FormDatePicker name="dia" label="Dia" format={dateFormat} valueFormat={ISOStringFormat} span={3} />
```

*FormEmail*
Componente que valida entradas de email.

*FormInput*
Componente para campos de input manual. Pode ser validado obrigatoriedade e span. 

```react
<FormInput label="Número Vagão" name="numeroVagao" span={2} required />
```

*FormItem*
Componente encapsulado nos outros forms. 

*FormMonthPicker*
Componente de formatação para mês e ano. Semelhante ao FormDatePicker, tem propriedades de formatação. 

```react
<FormMonthPicker name="mesAno" label="Mês/Ano" format={monthYearFormat} span={2} required />
```

*FormNumber*
Componente para inserção de campos somente número. 

```react
<FormNumber name="capacidade" label="Capacidade" span={2} maxLength={10} />
```
*FormRadio*
Componente encapsulando Radio button. Permite inserir opções via array 

```react
<FormRadio
      label="Posso perguntar?"
      name="pergunta"
      options={[{ value: '0', text: 'Sim' }, { value: '1', text: 'Não' }]}
      span={4}
    />
```

*FormRangePicker*
Componente de data para validação de intervalos.

```react
<FormRangePicker startName="dataInicio" endName="dataFim" label="Período" span={2} />
```

*FormResetButton*


*FormSelect*
Componente para campos de select combobox. O atributo de opções (getOptions) aceita respostas vindas da Api.

```react
<FormSelect name="tipo" label="Tipo" span={2} getOptions={getAllTipoProduto} />
```

*FormSubmitButton*
Componente de botão para submissão.

```react
<FormSubmitButton responsive icon="commons-delete" {...props}>
    <FormatText id="ui.commons.delete" uppercase />
  </FormSubmitButton>
```

*FormSwitch*
Componente encapsulando switch button.

```react
<FormSwitch label="Não Retirados" name="isNaoRetirados" span={2} />
```

*FormTextArea*
Componente text area com validação de caracteres e span.

```react
<FormTextArea name="descricao" label="cadastro.cadastrovagao.descricao" span={4} maxLength={20} />
```

*FormTimePicker*
Componente de formatação de horas.

```react
<FormTimePicker format={time24hrFormat} name="inicio" label="Início" span={2} required />
```

### Validação no Form
Formulário utilizando a validação da biblioteca Yup:

```react

export const validationSchema = Yup.object().shape({
  name: Yup.string().required("The input field is required."),
  description: Yup.string().required("The input field is required."),
  type: Yup.string().required("The select field is required."),
  date: Yup.string().required("The date field is required.")
});

const FormEquipment = () => {
  return (
    <Widget>
      <Row>
        <FormInput label="Name" name="name" span={3} />
        <FormSwitch label="Closed" name="closeStatus" span={3} />
      </Row>
      <Row>
        <FormDatePicker
          label="Date Field"
          name="date"
          format="DD/MM/YYYY"
          span={3}
        />
        <FormSelect label="Type" name="type" options={options} span={3} />
      </Row>
      <Row>
        <FormTextArea label="Description" name="description" span={6} />
      </Row>
    </Widget>
  );
};

export default FormEquipment;
```

Dentro do componente GridView, a propriedade *validationSchema* chama a validação criada no Form. 
```react
import React from "react";

import {
  CrudMasterDetailView,
  GridView,
  CompositeView,
  notification
} from "@digital/ui";
import FormEquipment, { validationSchema } from "./FormEquipment";

export default () => {
  return (
    <CrudMasterDetailView>
      <CompositeView>
        <GridView validationSchema={validationSchema}>
          <FormEquipment />
        </GridView>
      </CompositeView>
    </CrudMasterDetailView>
  );
};
```

### Mock
Criação de chamadas mockadas à Api pode ser feita na pasta /src/api. Geração de dados usando a biblioteca Faker Js (https://github.com/marak/Faker.js/)
```react
import MockAdapter from "axios-mock-adapter";
import faker from "faker";

/**
 * Create mocked Equipment list
 */
const Equipment = Array(20)
  .fill(0)
  .map((v, index) => ({
    id: index,
    name: faker.company.companyName(),
    description: faker.lorem.paragraph(),
    type: faker.random.arrayElement([1, 2, 3]),
    closeStatus: faker.random.boolean(),
    date: faker.date.past().toISOString()
  }));

/**
 * Mock equipmentApi endpoints
 */
export default (mock: MockAdapter) => {
  mock.onGet("/equipmentApi/:id").reply(200, Equipment[0]);
  mock.onGet("/equipmentApi").reply(200, Equipment);
  mock.onPost("/equipmentApi").reply(200, Equipment[0]);
  mock.onPut("/equipmentApi").reply(200, true);
  mock.onDelete("/equipmentApi").reply(200, true);
};
```

















