firstday logo
Início
O que fazemos
Como fazemos
Cases
Blog

Chat em Tempo Real: Conectando Código com a Realidade

Lucas Matheus

6 min de leitura

25/07/2023

Introdução

Olá dev, neste post quero te mostrar o processo de construção de uma aplicação que resolve um problema real. Vamos entender como criar um chat em tempo real utilizando Firebase, mas este não será só mais um chat em tempo real, o objetivo será focar no lado prático das coisas.

Vamos criar um chat em tempo real para uma clínica médica e isso vem com uma série de desafios únicos. Ao final da leitura você vai entender melhor tanto a parte técnica relacionada a criação de aplicações em tempo real, quanto a parte prática relacionada a resolver problemas do mundo real.

O Problema

Imagine o seguinte cenário: uma clínica médica recentemente começou a oferecer serviços online para seus clientes. Depois de um tempo perceberam que precisariam de um aplicativo para que os atendentes da clínica pudessem conversar com os clientes em tempo real. O principal desafio é que enquanto um cliente conversa com apenas um atendente, um atendente pode conversar com vários clientes ao mesmo tempo, e a aplicação precisa refletir isso.

Ou seja, precisamos criar um aplicação que responda em tempo real e que faça essa lógica, que é um pouco mais complicada do que um chat comum, funcionar.

A Solução

Para resolver esse problema vamos criar uma site em HTML e CSS, vamos utilizar JavaScript junto com Firebase para fazer as funcionalidades do sistema

Durante o post vou focar mais na parte de regras de negócio e lógica do sistema, para ver o passo completo, você pode ver esse vídeo onde abordo com mais detalhes todo o processo desde a configuração do projeto até a finalização

A melhor maneira de enfrentar um problema difícil como esse é pensar no caso mais simples e resolver ele primeiro, no nosso contexto o caso mais simples seria um usuário mandando mensagens para outro usuário e conseguindo ver as mensagens sendo atualizadas em tempo real, vamos resolver esse problema primeiro e depois vamos fazer os casos mais complicados.

A partir de agora vou assumir que você já tem o HTML e CSS prontos e já configurou o Firebase.

O Primeiro passo é importar as funções do Firebase que vamos utilizar e criar as variáveis globais do script

import {
db,
set,
ref,
push,
onChildAdded,
createUserWithEmailAndPassword,
auth,
signInWithEmailAndPassword,
updateProfile,
signOut,
} from "./configFirebase.js";
let userId = window.localStorage.getItem("userId");
let name = window.localStorage.getItem("name");
let email = window.localStorage.getItem("email");
const refUser = ref(db, "user/");
let currentId;

Agora podemos fazer a parte de autenticação do sistema, vamos fazer algo bem simples mesmo porque esse não o foco, mas é necessário para que o Firebase funcione da maneira que a gente quer.

Vamos colocar uma lógica de verificação simples, se não existe nenhum usuário no local storage do navegador então seguiremos com o procedimento de criação de usuário, mas se já existe um usuário vamos logar o usuário no sistema

if (!userId) {
email = prompt("Qual seu e-mail?");
const password = prompt("Digite seu password?");
if (email && password) {
login(email, password, name);
}
}
if (email === "atendimento@gmail.com") {
// código que será executado penas para o atendente da clínica
} else {
loadMessage(userId);
setUser(name, email);
}

Agora vamos definir as funções login, loadMessage , setUser e logout

async function login(email, password) {
try {
const res = await signInWithEmailAndPassword(auth, email, password);
window.localStorage.setItem("userId", res.user.uid);
window.localStorage.setItem("email", res.user.email);
window.localStorage.setItem("name", res.user.displayName);
userId = res.user.uid;
email = res.user.email;
name = res.user.displayName;
if (res.user.email === "atendimento@gmail.com") {
loadListClients();
} else {
loadMessage(res.user.uid);
setUser(name, email);
}
} catch (error) {
const errorCode = error.code;
if (errorCode === "auth/user-not-found") {
createUser(email, password);
} else {
alert("Houve um erro. Tente novamente!");
}
}
}
function loadMessage(uid) {
const messageDiv = document.getElementById("messages");
messageDiv.innerText = "";
const refMessageLoad = ref(db, "messages/" + uid);
onChildAdded(refMessageLoad, (snapshot) => {
const message = snapshot.val();
const messageDiv = document.createElement("div");
const messageText = document.createElement("p");
const messageTime = document.createElement("span");
if (message.email === email) {
messageDiv.classList.add("self");
messageText.innerText = `${message.message}`;
messageTime.innerText = `${message.time}`;
messageText.appendChild(messageTime);
} else {
// Se a mensagem for de outro usuário
messageDiv.classList.add("other");
messageText.innerText = `${message.message}`;
messageTime.innerText = `${message.time}`;
messageText.appendChild(messageTime);
}
messageDiv.appendChild(messageText);
const messagesContainer = document.getElementById("messages");
const messageContainer2 = document.getElementById("messagesContainer");
messagesContainer.appendChild(messageDiv);
messageContainer2.scrollTop = messagesContainer.scrollHeight;
});
}
function setUser(name, email) {
const userLogged = document.getElementById("user-header");
userLogged.innerHTML = "";
const userNameElement = document.createElement("h2");
const userEmailElement = document.createElement("span");
userNameElement.innerText = name;
userEmailElement.innerText = email;
userLogged.appendChild(userNameElement);
userLogged.appendChild(userEmailElement);
}
async function logout() {
try {
await signOut(auth);
window.localStorage.removeItem("userId");
window.localStorage.removeItem("name");
window.localStorage.removeItem("email");
location.reload();
} catch (error) {
console.log(error);
}
}

Com todo o sistema de autenticação funcionando podemos criar a funcionalidade principal que seria enviar as mensagens de fato, para isso vamos definir mais duas funções sendMessage e getCurrentTime

function sendMessage(event) {
event.preventDefault();
const inputField = document.getElementById("user-input");
const id = currentId ? currentId : userId;
const refMessage = ref(db, "messages/" + id);
const newMessage = push(refMessage);
const time = getCurrentTime();
set(newMessage, {
name: currentId ? "Atendimento" : name,
email: email,
message: inputField.value,
time: time,
});
inputField.value = "";
}
function getCurrentTime() {
const date = new Date();
let hours = date.getHours();
let minutes = date.getMinutes();
// Adiciona um zero à esquerda se as horas ou minutos forem de um dígito.
hours = hours < 10 ? "0" + hours : hours;
minutes = minutes < 10 ? "0" + minutes : minutes;
return `${hours}:${minutes}`;
}

Vamos também colocar as funções sendMessage e logout no objeto global para facilitar a utilização

window.sendMessage = sendMessage;
window.logout = logout;

Agora que a gente já tem algo funcionando vamos, resolver o próximo problema, caso o usuário tenha o email atendimento@gmail.com vamos tratar esse usuário como o Atendente, para isso precisamos carregar a lista de conversas com os clientes, vamos definir uma função que faz exatamente isso

function loadListClients() {
const clientListElement = document.getElementById("client-list");
const containerList = document.getElementById("text-client");
clientListElement.innerHTML = "";
containerList.innerHTML = "";
const headerClients = document.createElement("h3");
headerClients.innerHTML = "Lista de Clientes";
containerList.appendChild(headerClients);
onChildAdded(refUser, (snapshot) => {
const listItem = document.createElement("button");
listItem.innerText = snapshot.val().name;
listItem.addEventListener("click", () => {
currentId = snapshot.val().uid;
setUser(snapshot.val().name, snapshot.val().email);
loadMessage(snapshot.val().uid);
});
clientListElement.appendChild(listItem);
});
}

Agora é só atualizar aquele if else do começo da seguinte forma, adicionamos a chamada para a função loadListClients quando o email é de um usuário Atendente

if (email === "atendimento@gmail.com") {
+ loadListClients();
} else {
loadMessage(userId);
setUser(name, email);
}

E assim finalizamos todos os requisitos do problema inicial.

Principais tópicos de aprendizado

  • Focar em problemas reais nos ajuda a aprender mais rápido: se a fosse fazer só mais um chat em tempo real, poderíamos acabar perdendo interesse no projeto. Quando nos propomos a resolver um problema mais realista como criar um chat de atendimentos para uma clínica médica, a gente consegue se concentrar em resolver o problema, assim fica mais fácil decidir a próxima coisas que precisamos aprender.
  • Pessoas usam tecnologia, não o contrário: programadores iniciantes podem acabar ficando perdidos em meio a tantas opções e tantas tecnologias diferentes, mas no final do dia é importante entender que tudo que fazemos tem o objetivo de resolver os problemas de pessoas no mundo real. Quando a gente entende isso fica mais fácil decidir por exemplo qual tecnologia devemos aprender, ou outras coisas assim.
  • Suba no ombro de gigantes: especialmente no começo é importante aprender a subir no ombro de gigantes e criar coisas em cima do que outros já criaram. Fazer um sistema em tempo real é uma tarefa complicada, conseguimos tornar o processo mais fácil ao nos aproveitar de soluções já existentes como o Firebase. Alguém já teve o trabalho de criar e testar todo o Firebase a gente só precisa aprender a usar essa tecnologia

Conclusão

Conseguimos transformar um simples chat em tempo real em uma aplicação prática e relevante para uma clínica médica. Como disse no começo este post foi bem mais focado na lógica da aplicação se você quiser ver um passo a passo do começo ao fim assista esse vídeo aqui.

Assim como esse projeto, que foca em problemas reais, na Firstday você encontra formações completas com essa temática. Na Firstday acreditamos que a melhor maneira de aprender é trazendo os conceitos para a prática e focando em resolver problemas reais, de uma conferida nas nossos projetos.

Muito obrigado pela leitura, espero que este post tenha te ajudado de alguma forma, nos vemos em breve!

Lucas Matheus

Lucas Matheus

Sou uma pessoa apaixonada no impacto e em ensinar pessoas. Criei a Firstday com o objetivo de impactar vidas e ensinar pessoas a se tornarem desenvolvedores web experientes por meio da prática. Oferecemos uma formação completa em tecnologias de front-end, com projetos desafiadores e mentoria personalizada para ajudar nossos alunos a se destacarem no mercado de trabalho.


firstday logo

CNPJ: 49.793.271/0001-30

Links

Início

O que fazemos

Como fazemos

Cases

Blog