Última actualización: 6 abril, 2023¿Qué vamos a construir?
Vamos a construir una app de chat con sincronización en tiempo real, es decir, si dos personas están chateando, lo que escriba una y le envíe a la otra podrá ser visto por la otra prácticamente en el mismo momento de haber enviado el mensaje. Además, como usuario también podrás unirte a distintos canales de chat.
Otra de las características será el poder cambiar tu nombre de usuario cuando quieras.
Consideraciones previas y pre-requesitos
Para poder seguir este proyecto sin ir más perdido/a que un pulpo en un garaje, deberás tener conocimientos de:
Estructura inicial del proyecto
En cuanto a los scripts, app.js se encargará de conectar ui.js y chat.js entre sí para poder lanzar nuestra app.
Vamos a configurar el index.html.
1. Añadimos los scripts al final, en este orden: chat.js, ui.js y app.js.
2. Añadimos bootstrap y nuestro propio CSS.
Vamos a encargarnos ahora de crear nuestro esqueleto HTML en el <body>.
4. Usamos un container gigante que abarque toda la página y añadimos comentarios en el HTML a modo aclaratorio.
En la sección de chat window es donde se mostrará una conversación entera, diferenciando quién ha dicho qué. Cada vez que un usuario escriba un mensaje y lo mande, lo colocaremos en un <li> dentro del <ul>. Pero eso no lo vamos a escribir de manera estática (en adelante, harcoded) sino dinámica en nuestro código JavaScript (en adelante, JS).
La sección new chat form será la parte donde el usuario escriba su mensaje y se envíe a la base de datos (en inglés, database) que vamos a crear después.
Utilizamos tanto clases de bootstrap como clases propias.
Al final de la sección update name form tenemos un <div> que se encargará de darle al usuario un comentario sobre la acción que acabe de hacer. Vamos, de darle feedback.
Nuestra app debería tener una pinta como esta:


Vamos a darle un poco de vidilla con CSS, en el archivo styles.css.
.container {
max-width: 750px;
}
.btn {
background-color: rgb(11, 165, 192);
color: #fff;
}
.btn:hover,
.btn:active {
background-color: rgb(15, 132, 153);
color: #fff;
transition: all 0.2s;
}
.btn:focus {
box-shadow: none;
}
[membership level="0, -1"]
El resto del contenido es sólo para miembros del Club ACTech. Puedes unirte aquí o iniciar sesión si ya eres miembro.
[/membership]
[membership]
Cómo conectar nuestra app a Firebase
Terminado nuestro proceso de chapa y pintura, pasamos a configurar nuestra app
1. Para eso, creamos un proyecto en Firebase (en este post tienes los pasos necesarios). En algún momento de la configuración llegaremos a esta pantalla:


Así que no tenemos más que copiar ese snippet en nuestro index.html, justo arriba de nuestros scripts. Así Firebase sabrá a qué frontend conectarse.
Para añadir Cloud Firestore, seguimos las indicaciones de este link https://firebase.google.com/docs/firestore/quickstart.
2. Iniciamos nuestra database y la guardamos en una variable a la que llamaremos db.
Guarda los cambios y asegúrate de que no tienes ningún error en la consola antes de continuar.
Lo siguiente que haremos será crear una collection llamada chats. No es necesario crear una collection manualmente, ya que si a través de nuestro código creásemos un document e hiciésemos referencia a una collection que no existe, Firestore lo detectaría y crearía una collection por nosotros.
Pero en este caso, vamos a crearla nosotros, por aquello de "la práctica hace al maestro".
3. Creamos no solamente la chats collection, sino también un par de documents. Nuestros campos serán: message, username, channel y created_at. Dejamos el document ID en blanco para que Firebase le asigne un ID automáticamente.
Creación de la clase "Chatroom"
Con los documents creados en Firebase, vamos a pasar a la creación de nuestra primera clase de JS.
Cada vez que se construye un proyecto, es necesario estructurarlo previamente para saber qué pasos vamos a seguir para construirlo. Detallaré esos pasos al principio del chat.js, donde vamos a hacer toda la configuración durante esta sección.
Existen infinitas maneras de construir este tipo de app, y esta es una de tantas. Nuestro enfoque va a ser construir dos clases de JS, Chatroom y ChatUI. La clase Chatroom será la responsable de gestionar todos los datos que intercambiemos con Firebase, y la ChatUI, de mostrar en la UI de nuestra web todos los cambios que suceden en los datos.
// BUILDING PROCESS // - add new chat documents // - set up a real-time listener to get new chats // - update the username // - update the channel
Vamos a por esa primera clase.
1. Creamos el constructor dentro de la clase, que aceptará dos parámetros, channel y username. Le añadimos una propiedad que no le pasaremos por parámetro (chats), que será una referencia a nuestra chats collection.
2. Creamos una instance de nuestra clase. Hacemos un console.log para ver qué aspecto tiene.
class Chatroom {
constructor(channel, username) {
this.channel = channel;
this.username = username;
this.chats = db.collection('chats');
}
const chatroom = new Chatroom('music', 'Jim');
console.log(chatroom);
3. Lo siguiente que haremos será crear un método dentro de la clase para crear y añadir objetos con formato de documents. Será un método asíncrono, porque tardará cierto tiempo en completarse.
Recuerda que un objeto con aspecto de document no es más que un objeto normal de JS, y con ese formato debemos enviarlo a Firestore para que lo reconozca como un document.
Creamos una variable llamada now que equivaldrá a la fecha en la que te encuentres hoy. La utilizaremos para darle al mensaje una fecha de creación.
Creamos el objeto con un formato adecuado, conteniendo, igual que los campos que hemos creado manualmente en Firebase, un message, un username, un channel y una fecha de creación (created_at). Es como crear una cáscara para darle formato a un objeto que enviaremos a Firestore y que éste lo reconozca como un document válido. Lo llamamos chat.
async addChat(message) {
const now = new Date();
const chat = {
message: message,
channel: this.channel,
username: this.username,
created_at: firebase.firestore.Timestamp.fromDate(now)
};
}
Podemos usar ES6 y acortar los key-value pairs cuando la key tiene el mismo nombre que el value, como ocurre en el caso de message.
Añadiendo chats a la base de datos
Creado ya el método para generar documents, vamos a configurar la parte para guardar documents en Firestore. Para eso, creamos una variable llamada response y utilizamos await, porque el método addChat devuelve una promesa. Utilizamos nuestra chats collections para aplicarle el método add(), al que le pasamos nuestro objeto-cáscara (chat).
Hacemos un return de response.
Con estos cambios, ya podemos usar el método addChat().
Recordemos que el método addChat() devuelve una promesa, así que le enganchamos un método then() y un método catch().
async addChat(message) {
const now = new Date();
const chat = {
message,
channel: this.channel,
username: this.username,
created_at: firebase.firestore.Timestamp.fromDate(now)
};
// save documents in Firestore
const response = await this.chats.add(chat);
return response;
}
}
const chatroom = new Chatroom('music', 'Jim');
// console.log(chatroom);
chatroom.addChat('any rock music fan here?')
.then(() => console.log('chat added!'))
.catch(err => console.log(err));
Si vas a Firebase, ya deberías ver ese document añadido correctamente. ¡Genial!
[/membership]
THE END!
¡Y hasta aquí la primera parte de este proyecto de construcción de un chat en tiempo real! Espero que hayas aprendido algo nuevo
Si quieres seguir aprendiendo, nos vemos en la parte #2.
Sobre la autora de este post
Soy Rocío, una abogada reconvertida en programadora. Soy una apasionada de aprender cosas nuevas y ferviente defensora de que la única manera de ser feliz es alcanzando un equilibrio entre lo que te encanta hacer y lo que te saque de pobre. Mi historia completa, aquí.
Otros artículos que pueden interesarte