Chat em Tempo Real: Conectando Código com a Realidade
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áriomessageDiv.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
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.