[Dashboard] Máscara de Campo
Tags: rails, ruby, mask, javascript
Published: 2022-12-20 19:17:30

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnqrg8ttpwf93a0k0zbv.png)

### Neste artigo vamos explicar como foi realizada a implementação do projeto de Máscara de Campo no nosso Dashboard

Como tudo que fazemos aqui na INK, o nosso Dashboard 2.0 lançado no mês passado (Jun/ 2021) foi feito na base do MVP...Let's make nossa V0. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dso15ze1ra2jinu7f7r7.png)

**imagem da seção 'Financeiro' do novo dashboard**


Como toda v0, muitas partes da aplicação não foram implementadas; e, uma muita importante que implementamos recentemente, foi a máscara de campo e neste artigo vamos documentar como pensamos este projeto.

---

### Escopo do Artigo

* Estratégia do projeto
* Biblioteca de Máscara de Campo
* Uso da Biblioteca
* Máscara de Campo criadas
* Implementação no Projeto

---

### Estratégia do projeto

Recentemente no nosso time de Tech, estamos enfrentando um momento muito especial que acomete todo o time de tecnologia: **como os Devs podem organizar o pensamento e criar uma gestão de conhecimento dentro do time?**

Se algum Dev que estiver lendo este artigo e achar que a resposta é óbvia, estamos abertos a ouvi-la através do jose.sobral@reserva.ink. 

Contudo, aqui na INK a resposta à esta pergunta ainda está em construção e nesta seção do artigo, vamos explicitar como estamos construindo esta resposta

A melhor forma, até então, que estamos pensando esta gestão de conhecimentos é através de Mapas Mentais. Com eles, podemos pensar e compartilhar o pensamento visualmente através de conceitos com relacionamentos, cores e identidades próprias. 

No projeto de Máscara de Campo, construimos um mapa onde no centro temos todas seções do Dashboard (Painel INK, Financeiro, Produtos e etc) e uma ramificação para cada uma destas seções contendo os formulários presentes nesta seção. 

Então, por exemplo, temos um fórmulário dentro de seção de Cupom para criação de cupom. Nele, mapeamos todos os inputs presentes nesta seção e quais as máscaras de cada campo levaria

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzaqaqe9y1pzs92tp0jw.png)

**No pensamos na cor salmão, temos o nome do campo, o datatype do campo e o nome do component_id que levaria as propriedades de máscara de campo através de um jQuery**  

Dessa forma, qualquer Dev que quiser ver a estruturação do projeto pode acessar a publicação do mapa:
* [Mapa Mental - Mask Field] (https://www.figma.com/community/file/1004055413396117089)

E, até então, essa é a nossa primeira resposta (a tal da V0) para a gestão de conhecimentos no time de tecnologia da INK :) 

---

### Biblioteca de Máscara de Campo

Para este projeto usamos a [biblioteca de máscara de campo criada pelo Igor Escobar](https://igorescobar.github.io/jQuery-Mask-Plugin/docs.html)

Além de uma documentação fácil, a biblioteca é construída usando jQuery que é uma ferramenta bem difundida na arquitetura da INK.

---

### Uso da Biblioteca

Para implementarmos a máscara de campo com o uso desta biblioteca, alguns _tricks_ foram necessários.


1) **Como trazer um regex para um caracter?**

Para trazermos um [regex](https://regexr.com/) para um caracter, podemos usar o conceito de `pattern` da [documentação](https://igorescobar.github.io/jQuery-Mask-Plugin/docs.html#translation).

Com ele, conseguimos desenhar um regex para cada um dos caracteres do campo que estamos aplicando a máscara!

Olha o exemplo de máscara que aplicamos para um campo que deve aceitar um hexadecimal color (#000000)

```
  $('.hexadecimal-mask').mask(`BAAAAAAA`, {'translation': {
    B: {pattern: /[#]/},
    A: {pattern: /[A-Za-Z0-9]/}
  }});
```

Com ele, garantimos que o primeiro caracter chegue com o regex /[#]/, ou seja, só aceite # e os demais caracteres sejam letras do alfabeto, maiúsculas ou minúsculas ([A-Za-Z]) ou números [0-9].


2) **O que fazer quando queremos aplicar a máscara de campo em um campo que não sabemos o número de caracteres necessários?**

No caso da máscara do CPF, sabemos que precisaremos de 11 dígitos; o mesmo é válido para o telefone, data de nascimento, etc. 

Agora, é campos como "primeiro nome"? Ou "valor do desconto"?

Aqui entrou o segundo _trick_ no uso da biblioteca!

Quando não sabemos o número de caracteres necessários, podemos ativar a flag de `optional: true` e colocar tantos caracteres quanto for o limite permitido pelo campo.

Por exemplo:

```
  $(".alphanumeric-single-word-mask").mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /^[a-zA-Z0-9çÇ]/, optional: true},
  }});
```

Aqui criamos uma máscara que permite até 200 caracteres - _fazemos isso usando o `${'A'.repeat(200)}`_ e, como eles são opcionais, podemos colocar quantos caracteres desejarmos num range de 1 há 200 caracteres.

---

### Máscara de Campo criadas

Como já exposto anteriormente no artigo, criamos a Máscara de Campo através do jQuery, fazendo com que uma classe levasse a um input as propriedades da máscara daquele campo.

Por exemplo, na seção de Cadastro de Loja da nossa plataforma, o usuário precisa colocar o seu CPF, no formato XXX.XXX.XXX-XX. 

Neste exemplo, precisamos de um campo que aceite apenas números e que haja uma pontuação no lugar desejado, conforme o formato do CPF. Por isso, para este campo, será atribuído a máscara:

`cpf-mask`
**Campo só aceitará números e terá o formato XXX.XXX.XXX-XX**

As classes que criamos para este projeto foram:

```
app > assets > javascipts > dashboard > utils > mask.js

$(".alphabetic-multiple-words-with-accent-mask").mask(`${'A'.repeat(500)}`, {'translation': {
    A: {pattern: /^[a-zA-ZàèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇ_ ]/, optional: true},
  }});
  
  $(".alphabetic-single-word-with-accent-mask").mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /^[a-zA-ZàèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇ]/, optional: true},
  }});
  
  $(".numeric-mask").mask(`${'0'.repeat(20)}`);
  
  $('.phone-mask').mask('(00) 00000-0000');
  
  $('.cpf-mask').mask('000.000.000-00', {reverse: true});
  
  $('.cnpj-mask').mask('00.000.000/0000-00', {reverse: true});
  
  $('.cep-mask').mask('00000-000');
  
  $(".alphanumeric-single-word-mask").mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /^[a-zA-Z0-9çÇ]/, optional: true},
  }});
  
  $(".alphanumeric-single-word-with-accent-mask").mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /^[a-zA-Z0-9àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇ]/, optional: true},
  }});
  
  $(".alphanumeric-single-word-uppercase-mask").mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /^[A-Z0-9Ç]/, optional: true},
  }});
  
  $(".alphanumeric-single-word-lowercase-mask").mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /[a-z0-9]/, optional: true},
  }});
  
  $(".alphanumeric-multiple-word-with-accent-mask").mask(`${'A'.repeat(500)}`, {'translation': {
    A: {pattern: /^[a-zA-Z0-9àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇ_ ]/, optional: true},
  }});
  
  $(".alphanumeric-multiple-word-with-accent-up-to-15-char-mask").mask(`${'A'.repeat(15)}`, {'translation': {
    A: {pattern: /^[a-zA-Z0-9àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇ_ ]/, optional: true},
  }});
  
  $('.float-mask').mask(`1${'1'.repeat(50)}.11`, {'translation': {
    1: {pattern: /[0-9]/, optional: true}
  }});
  
  $('.art-price-mask').mask(`211.11`, {'translation': {
    1: {pattern: /[0-9]/, optional: true},
    2: {pattern: /[1]/, optional: true}
  }});
  
  $(".art-range-price").attr('type', 'number');
  
  $(".art-range-price").attr({
    "max" : 159,        
    "min" : 59          
  });
  
  
  $('.hexadecimal-mask').mask(`BAAAAAAA`, {'translation': {
    B: {pattern: /[#]/},
    A: {pattern: /[A-Z0-9]/}
  }});
  
  $('.social-media-mask').mask(`${'A'.repeat(200)}`, {'translation': {
    A: {pattern: /[A-Za-z0-9(),-_.,]/, optional: true}
  }});

```
 

---

### Implementação no Projeto

Por fim, para implementarmos a máscara no projeto, aplicamos em cada _component_ de input da aplicação o devido _component_class_

Dessa forma:

```
<div class="col s12 m12 l6">
  <%= render partial: 'user/dashboard/components/input/text_field_with_helper', locals: {
    title: 'Valor do desconto',
    helper_text: 'Valor em R$',
    name:'coupon[value]',
    component_class: "float-mask"
  } %> 
</div>
```

---

### Com amor e carinho,
Sobral, INK