[FEAT] Como foi fazer um decodificador do zero para o projeto final da 1ª parte do OracleONE
Introdução
Olá meu nome é Paulo Victor, sou programador front-end , atulamente estou cursando o 3º período de ciência da computação na Faculdade Descomplica, estudo front-end a mais de 1 ano e gostaria de compartilhar como foi a idealiazação do meu codificador como projeto final da 1ª fase do Oracle ONE.
Requisitos do desafio
- Deve funcionar apenas com letras minúsculas
- Não devem ser utilizados letras com acentos nem caracteres especiais
- Deve ser possível converter uma palavra para a versão criptografada e também retornar uma palavra criptografada para a versão original.
Por exemplo:
"gato" => "gaitober"
gaitober" => "gato"
A página deve ter campos para inserção do texto a ser criptografado ou descriptografado, e a pessoa usuária deve poder escolher entre as duas opções
O resultado deve ser exibido na tela.
Extras:
- Um botão que copie o texto criptografado/descriptografado para a área de transferência - ou seja, que tenha a mesma funcionalidade do ctrl+C ou da opção "copiar" do menu dos aplicativos.
Modelo de encriptação
Letra | Chave |
---|---|
e | enter |
i | imes |
a | ai |
o | ober |
u | ufat |
Primeiras impressões
Pqp kjkj o front até vai, mas como krl eu vou fazer esse encriptador ?
Pow, mas eu posso fazer o encriptador pegando a string, transformando em array, filtrando e dps juntando tudo do mesmo jeito, só que encyptado.
Vai dar é certo krl, mas e o descriptador ? Ah fds dps eu penso nisso...
Foi exatamente isso que passou pela minha cabeça, e organizando de maneira mais "bonita" o que eu queria falar era basicamente isso daqui:
graph TD
A([Palavra/Frase]) --> B{O que fazer ?}
B --> C1(Encriptar)
C1 --> C2[/Valor do input/]
C2--> C3[Tranforma em array, separando palavras pelo espaçamento]
C3 --> C4[Trata o dado com alguma lógica de prog]
C4 --> C5([Devolve Frase Encriptada])
B --> D1(Decriptar)
D1 --> D2[/Valor do input/]
D2--> D3[??Dor e Sofrimento??]
D3 --> D4[Trata o dado com alguma lógica de prog]
D4 --> D5([Devolve Frase Descriptada])
Executando o front
Base
Peguei o layout no figma e fui imaginando como poderia fazer aquilo e optei por uma estrutura de:
<div id="app">
<header></header>
<main><main>
<section></section>
</div>
A partir dai fui seguindo botando a logo no header, estruturando o main com o input onde a frase ou palavra seria inserida e os 2 botões, um para descriptogravar e outro para criptografar.
Passando para o css comecei importando um arquivo de reset css que eu uso para não me surpreender com alguma estilização padrão do navegador, já no meu arquivo principal eu curto fazer isso:
:root {
font-size: 62.5%;
}
* {
text-decoration: none;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
body {
font-size: 1.6rem;
}
Basicamente eu deixo 1rem = 10px para ficar bem mais fácil de trabalhar com rem(aparentemente tem um método melhor, vou testar em algum outro projeto), retiro o text decoration de links, defino o tamanho de tudo para se ajustar a borda a fim de evitar erros no calculo de padding/margin e estou adicionando recentemente o font-smoothing com o text-rendering para deixar as fonts mais suaves.(Esse truque das fonts aprendi com o grande @Mayk Brito)
Conclusão
Nâo senti tanta dificuldade no front pois ele é relativamente "fácil", cores não foram um problema, usei variáveis css a fim de facilitar o meu trabalho.
Segui mobile first para deixar a aplicação o minimo estilizada e assim introduzir as funcionalidades
Obs:
Decidi não fazer alguma layout personalizado pois o projeto tem que ser entregue até prox semana.
Executando as Funcionalidades
Base
Descidi fazer todo o js em um local da aplicação, para depois modulariza-lo.
Comecei declarando todos os elementos do html que poderia usar:
const criptoButton = document.querySelector('.buttons #crypt')
const decryptButton = document.querySelector('.buttons #decrypt')
const copyButton = document.querySelector('.alt #copy')
const result = document.querySelector('#app .alt p')
const input = document.querySelector('#app main textarea')
let output = document.querySelector('section .alt p')
const outputBox = document.querySelector('section .alt')
const labelBox = document.querySelector('section .default')
E fui seguindo fazendo a base:
Base da função de alternar entre section default e section alt
-
Ao apertar o botão verifica se tem algum valor no input
-
Se tiver, exibe a section alternativa
-
Se não, exibe uma mensagem de erro e não muda a section
Base da função Decriptar/Criptar
- Pegar o valor do input
- Jogar em uma váriavel
- Retornar o valor do input na section
Ao fazer um tratamento de erros com a função alert padrão do js, estava achando esteticamnete feio o alert aparecendo e travando a aplição toda vez que dava um erro, descidi perguntar ao @Gabriel Santos qual o nome de uma libzinha top de modal que ele usou, ele me disse e foi ai que todos os erros da minha aplicação ficaram por responsabilidade de uma função alert que criei usando o toastify:
function alert(message) {
Toastify({
text: `${message}`,
duration: 3000,
close: true,
gravity: "top", // `top` or `bottom`
position: "right", // `left`, `center` or `right`
stopOnFocus: true, // Prevents dismissing of toast on hover
style: {
background: "linear-gradient(to right, #0a3871, #aab2d5)",
borderRadius:"15px",
},
}).showToast();
}
O tratamento de erros ficou bem mais dinâmico e bonito.
Sei que o texto ficou meio apagado na parte da direita, nâo encontrei uma forma melhor de fazer gradient na lib, vou estudar ela mais a fundo para evitar problemas na prox vez que for usar.
Chave de encriptação
Descidi fazer a referencia da chave de encriptação com object:
const cryptCode = {
e: ['e','enter'],
i:['i','imes'],
a: ['a','ai'],
o: ['o','ober'],
u: ['u','ufat']
}
Essa foi a forma que eu encontrei de inserir a chave de encriptação juntamente com a letra correspondente de maneira facilitada.
Encriptando o texto
Foi uma parte bem complicada, mas devido a um monte de desafios no CodeWars, me lembrei do método map e fiz dele meu melhor amigo:
criptografar() {
if(!input.value) {
appHandler.removeDivClass()
return alert('Insira um texto para criptografar')
}
if(!output.innerHTML) {
appHandler.toggleDivClass()
}
const cryptArray = []
const inputArray = input.value.split('')
inputArray.map((caractere) => {
let encryptCaractere
caractere.includes(crypt.a[0]) ? encryptCaractere = crypt.a[1] : caractere
caractere.includes(crypt.e[0]) ? encryptCaractere = crypt.e[1] : caractere
caractere.includes(crypt.i[0]) ? encryptCaractere = crypt.i[1] : caractere
caractere.includes(crypt.o[0]) ? encryptCaractere = crypt.o[1] : caractere
caractere.includes(crypt.u[0]) ? encryptCaractere = crypt.u[1] : caractere
cryptArray.push(!encryptCaractere ? caractere : encryptCaractere)
})
const cryptResult = cryptArray.join('')
return output.innerHTML = cryptResult
Na função eu basicamente separo o que vem no input com o split, pego cada caractere que foi separado e verfico se ele se encaixa em alguma condição de encriptação, depois faço uma verificação para inserir todos os caracteres e outro array e por fim fazer um join para juntar em uma string, retornando ele dentro do section alternativo.
Por incrivel que pareça isso foi bem mais "fácil" na minha cabeça, sei que deve ter outro mêtodo mais simples e fácil, mas me agarrei a esse e segui fazendo.
Decriptando o texto
Sem dúvidas a parte mais complicada da aplicação para mim e isso se deve a pessima decisão de tentar implementar tudo no mesmo dia, logo depois de terminar a encriptação eu estava estusiasmado e com vontade de me provar e conseguir implementar tudo em um dia.Por que diabos eu sou tão afobado ? kkkkj
Resultado, rodei e rodei feio, já estava "fadigado" de implementar o front e uma funcionalidade no mesmo dia. Me frustrei e deixei para lá, fui bater uma gameplay de Star Rail e relaxar.
No outro dia as coisas começaram a fluir e finalizei assim:
descriptografar(){
const arrayEncryptWords = input.value.split(' ')
const decryptArray = []
arrayEncryptWords.map( word => {
let decryptWord = word
while (decryptWord.includes(crypt.a[1])) {
decryptWord = decryptWord.replace(crypt.a[1], crypt.a[0])
}
while(decryptWord.includes(crypt.e[1])) {
decryptWord = decryptWord.replace(crypt.e[1], crypt.e[0])
}
while(decryptWord.includes(crypt.i[1])){
decryptWord = decryptWord.replace(crypt.i[1], crypt.i[0])
}
while(decryptWord.includes(crypt.o[1])){
decryptWord = decryptWord.replace(crypt.o[1], crypt.o[0])
}
while(decryptWord.includes(crypt.u[1])){
decryptWord = decryptWord.replace(crypt.u[1], crypt.u[0])
}
decryptArray.push(decryptWord)
})
const decryptString = decryptArray.join(' ')
if (input.value === decryptString) {
appHandler.removeDivClass
return alert('Nenhuma mensagem criptografada encontrada')
}
if(!input.value) {
appHandler.removeDivClass()
return alert('Insira um texto para descriptografar')
}
if(!output.innerHTML) {
appHandler.toggleDivClass()
}
return output.innerHTML = decryptString
}
}
Basicamente pego o input e separo por palavas em vez de letras, pois a encriptação se refere a uma letra especifica, rodo nas condições de verificação para saber se ela tem mais alguma encriptação naqeula letra especifica, pois pode ocorrer devido a plavras com letras repetidas. Essa parte final da função eu ainda estou corrigind, mas fica aqui de registro como eu fiz.
Passos Finais
Com a aplicação 100% funcional eu descidi modularizar varias partes da aplicação, finalizando e ficando assim as pastas:
Finalizando
Muito obrigado por ler ate aqui, não é meu objetivo ensinar alguém a fazer um decodificador ou algo do tipo, até porque esse não deve ser o melhor modo, porém se você retirar algo de bom desse "artigo" vai ser ótimo.
Você pode conferir o codigo aqui, qualquer dica ou sugestão construtiva será bem vida, me desculpem pelos erros de português.
Boa semana a todos