1. Descripción general
En este codelab, aprenderás algunos conceptos básicos de Firebase para crear aplicaciones web interactivas. Compilarás una app de chat de RSVP de eventos y libro de visitas con varios productos de Firebase.
Qué aprenderás
- Autentica usuarios con Firebase Authentication y FirebaseUI.
- Sincronizar datos con Cloud Firestore
- Escribe reglas de seguridad de Firebase para proteger una base de datos.
Requisitos
- Un navegador de tu elección, como Chrome
- Acceso a stackblitz.com (no es necesario tener una cuenta ni acceder).
- Una Cuenta de Google, como una cuenta de Gmail Te recomendamos que uses la cuenta de correo electrónico que ya usas para tu cuenta de GitHub. Esto te permite usar funciones avanzadas en StackBlitz.
- Es el código de muestra del codelab. Consulta el siguiente paso para obtener el código.
2. Obtén el código de partida
En este codelab, compilarás una app con StackBlitz, un editor en línea que tiene varios flujos de trabajo de Firebase integrados. StackBlitz no requiere instalación de software ni una cuenta especial de StackBlitz.
StackBlitz te permite compartir proyectos con otras personas. Otras personas que tengan la URL de tu proyecto de StackBlitz pueden ver tu código y crear una bifurcación de tu proyecto, pero no pueden editarlo.
- Ve a esta URL para obtener el código inicial: https://stackblitz.com/edit/firebase-gtk-web-start
- En la parte superior de la página de StackBlitz, haz clic en Fork:
Ahora tienes una copia del código inicial como tu propio proyecto de StackBlitz, que tiene un nombre único y una URL única. Todos tus archivos y cambios se guardan en este proyecto de StackBlitz.
3. Cómo editar la información del evento
Los materiales iniciales de este codelab proporcionan cierta estructura para la app web, incluidas algunas hojas de estilo y un par de contenedores HTML para la app. Más adelante en este codelab, conectarás estos contenedores a Firebase.
Para comenzar, familiaricémonos un poco más con la interfaz de StackBlitz.
- En StackBlitz, abre el archivo
index.html
. - Ubica
event-details-container
ydescription-container
, y, luego, intenta editar algunos detalles del evento.
A medida que editas el texto, la recarga automática de la página en StackBlitz muestra los nuevos detalles del evento. Genial, ¿verdad?
<!-- ... -->
<div id="app">
<img src="..." />
<section id="event-details-container">
<h1>Firebase Meetup</h1>
<p><i class="material-icons">calendar_today</i> October 30</p>
<p><i class="material-icons">location_city</i> San Francisco</p>
</section>
<hr>
<section id="firebaseui-auth-container"></section>
<section id="description-container">
<h2>What we'll be doing</h2>
<p>Join us for a day full of Firebase Workshops and Pizza!</p>
</section>
</div>
<!-- ... -->
La vista previa de tu app debería verse de la siguiente manera:
Vista previa de la app
4. Crea y configura un proyecto de Firebase
Mostrar la información del evento es excelente para tus invitados, pero solo mostrar los eventos no es muy útil para nadie. Agreguemos algunas funciones dinámicas a esta app. Para ello, deberás conectar Firebase a tu app. Para comenzar con Firebase, deberás crear y configurar un proyecto de Firebase.
Crea un proyecto de Firebase
- Accede a la consola de Firebase con tu Cuenta de Google.
- Haz clic en el botón para crear un proyecto nuevo y, luego, ingresa un nombre (por ejemplo,
Firebase-Web-Codelab
). - Haz clic en Continuar.
- Si se te solicita, revisa y acepta las Condiciones de Firebase y, luego, haz clic en Continuar.
- (Opcional) Habilita la asistencia de IA en Firebase console (llamada "Gemini en Firebase").
- Para este codelab, no necesitas Google Analytics, por lo que debes desactivar la opción de Google Analytics.
- Haz clic en Crear proyecto, espera a que se aprovisione y, luego, haz clic en Continuar.
Para obtener más información sobre los proyectos de Firebase, consulta Información sobre los proyectos de Firebase.
Habilita y configura los productos de Firebase en la consola
La app que estás compilando usa varios productos de Firebase que están disponibles para aplicaciones web:
- Firebase Authentication y la IU de Firebase para permitir que los usuarios accedan a tu app con facilidad
- Cloud Firestore, a fin de guardar datos estructurados en la nube y recibir notificaciones al instante cuando se modifiquen los datos
- Reglas de seguridad de Firebase para proteger tu base de datos
Algunos de estos productos necesitan una configuración especial o deben habilitarse a través de Firebase console.
Habilita el acceso por correo electrónico para Firebase Authentication
Para permitir que los usuarios accedan a la aplicación web, usarás el método de acceso Correo electrónico/contraseña en este codelab:
- En el panel lateral izquierdo de Firebase console, haz clic en Build > Authentication. Luego, haz clic en Comenzar. Ahora estás en el panel de autenticación, donde puedes ver los usuarios registrados, configurar proveedores de acceso y administrar la configuración.
- Selecciona la pestaña Método de acceso (o haz clic aquí para ir directamente a la pestaña).
- Haz clic en Correo electrónico/contraseña en las opciones del proveedor, activa el interruptor en Habilitar y, luego, haz clic en Guardar.
Configura Cloud Firestore
La app web usa Cloud Firestore para guardar mensajes de chat y recibir mensajes nuevos.
Sigue estos pasos para configurar Cloud Firestore en tu proyecto de Firebase:
- En el panel izquierdo de Firebase console, expande Compilación y, luego, selecciona Base de datos de Firestore.
- Haz clic en Crear base de datos.
- Deja el ID de la base de datos establecido en
(default)
. - Selecciona una ubicación para tu base de datos y, luego, haz clic en Siguiente.
Para una app real, debes elegir una ubicación cercana a tus usuarios. - Haz clic en Comenzar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad.
Más adelante en este codelab, agregarás reglas de seguridad para proteger tus datos. No distribuyas ni expongas una app de forma pública sin agregar reglas de seguridad para tu base de datos. - Haz clic en Crear.
5. Agrega y configura Firebase
Ahora que creaste tu proyecto de Firebase y habilitaste algunos servicios, debes indicarle al código que quieres usar Firebase y qué proyecto de Firebase usar.
Agrega las bibliotecas de Firebase
Para que tu app use Firebase, debes agregar las bibliotecas de Firebase a la app. Hay varias formas de hacerlo, como se describe en la documentación de Firebase. Por ejemplo, puedes agregar las bibliotecas desde la CDN de Google o instalarlas de forma local con npm y, luego, empaquetarlas en tu app si usas Browserify.
StackBlitz proporciona la agrupación automática, por lo que puedes agregar las bibliotecas de Firebase con instrucciones de importación. Usarás las versiones modulares (v9) de las bibliotecas, que ayudan a reducir el tamaño general de la página web a través de un proceso llamado "eliminación de código no utilizado". Puedes obtener más información sobre los SDKs modulares en la documentación.
Para compilar esta app, usarás las bibliotecas de Firebase Authentication, FirebaseUI y Cloud Firestore. En este codelab, las siguientes instrucciones de importación ya se incluyen en la parte superior del archivo index.js
, y, a medida que avancemos, importaremos más métodos de cada biblioteca de Firebase:
// Import stylesheets
import './style.css';
// Firebase App (the core Firebase SDK) is always required
import { initializeApp } from 'firebase/app';
// Add the Firebase products and methods that you want to use
import {} from 'firebase/auth';
import {} from 'firebase/firestore';
import * as firebaseui from 'firebaseui';
Agrega una app web de Firebase a tu proyecto de Firebase
- Vuelve a Firebase console y navega a la página de descripción general de tu proyecto haciendo clic en Project Overview en la esquina superior izquierda.
- En el centro de la página de descripción general del proyecto, haz clic en el ícono de Web
para crear una nueva app web de Firebase.
- Registra la app con el apodo Web App.
- En este codelab, NO marques la casilla junto a Also set up Firebase Hosting for this app. Por ahora, usarás el panel de vista previa de StackBlitz.
- Haz clic en Registrar app.
- Copia el objeto de configuración de Firebase en el portapapeles.
- Haz clic en Ir a la consola.Agrega el objeto de configuración de Firebase a tu app:
- De vuelta en StackBlitz, ve al archivo
index.js
. - Busca la línea de comentario
Add Firebase project configuration object here
y, luego, pega el fragmento de configuración justo debajo del comentario. - Agrega la llamada a la función
initializeApp
para configurar Firebase con la configuración única de tu proyecto de Firebase.// ... // Add Firebase project configuration object here const firebaseConfig = { apiKey: "random-unique-string", authDomain: "your-projectId.firebaseapp.com", databaseURL: "https://your-projectId.firebaseio.com", projectId: "your-projectId", storageBucket: "your-projectId.firebasestorage.app", messagingSenderId: "random-unique-string", appId: "random-unique-string", }; // Initialize Firebase initializeApp(firebaseConfig);
6. Agregar acceso de usuarios (confirmación de asistencia)
Ahora que agregaste Firebase a la app, puedes configurar un botón de confirmación de asistencia que registre a las personas con Firebase Authentication.
Autentica a tus usuarios con el acceso por correo electrónico y FirebaseUI
Necesitarás un botón de RSVP que le solicite al usuario que acceda con su dirección de correo electrónico. Para ello, conecta FirebaseUI a un botón de confirmación de asistencia.FirebaseUI es una biblioteca que te proporciona una IU prediseñada sobre Firebase Auth.
FirebaseUI requiere una configuración (consulta las opciones en la documentación) que hace dos cosas:
- Indica a FirebaseUI que deseas usar el método de acceso Correo electrónico/contraseña.
- Controla la devolución de llamada para un acceso exitoso y devuelve false para evitar un redireccionamiento. No quieres que se actualice la página porque estás creando una app web de una sola página.
Agrega el código para inicializar FirebaseUI Auth
- En StackBlitz, ve al archivo
index.js
. - En la parte superior, busca la instrucción de importación
firebase/auth
y, luego, agregagetAuth
yEmailAuthProvider
, de la siguiente manera:// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider } from 'firebase/auth'; import {} from 'firebase/firestore';
- Guarda una referencia al objeto de autenticación inmediatamente después de
initializeApp
, de la siguiente manera:initializeApp(firebaseConfig); auth = getAuth();
- Ten en cuenta que la configuración de FirebaseUI ya se proporciona en el código inicial. Ya está configurado para usar el proveedor de autenticación por correo electrónico.
- En la parte inferior de la función
main()
enindex.js
, agrega la sentencia de inicialización de FirebaseUI, como se indica a continuación:async function main() { // ... // Initialize the FirebaseUI widget using Firebase const ui = new firebaseui.auth.AuthUI(auth); } main();
Agrega un botón de confirmación de asistencia al código HTML
- En StackBlitz, ve al archivo
index.html
. - Agrega el código HTML de un botón de confirmación de asistencia dentro del
event-details-container
, como se muestra en el siguiente ejemplo.
Ten cuidado de usar los mismos valores deid
que se muestran a continuación, ya que, para este codelab, ya hay hooks para estos IDs específicos en el archivoindex.js
.
Ten en cuenta que, en el archivoindex.html
, hay un contenedor con el IDfirebaseui-auth-container
. Este es el ID que pasarás a FirebaseUI para mantener tu acceso. Vista previa de la app<!-- ... --> <section id="event-details-container"> <!-- ... --> <!-- ADD THE RSVP BUTTON HERE --> <button id="startRsvp">RSVP</button> </section> <hr> <section id="firebaseui-auth-container"></section> <!-- ... -->
- Configura un objeto de escucha en el botón de confirmación de asistencia y llama a la función de inicio de FirebaseUI. Esto le indica a FirebaseUI que quieres ver la ventana de acceso.
Agrega el siguiente código al final de la funciónmain()
enindex.js
:async function main() { // ... // Listen to RSVP button clicks startRsvpButton.addEventListener("click", () => { ui.start("#firebaseui-auth-container", uiConfig); }); } main();
Prueba acceder a la app
- En la ventana de vista previa de StackBlitz, haz clic en el botón RSVP para acceder a la app.
- En este codelab, puedes usar cualquier dirección de correo electrónico, incluso una falsa, ya que no configurarás un paso de verificación de correo electrónico.
- Si ves un mensaje de error que indica
auth/operation-not-allowed
oThe given sign-in provider is disabled for this Firebase project
, verifica que hayas habilitado Correo electrónico/contraseña como proveedor de acceso en Firebase console.
- Ve al panel de Authentication en Firebase console. En la pestaña Usuarios, deberías ver la información de la cuenta que ingresaste para acceder a la app.
Agrega el estado de autenticación a la IU
A continuación, asegúrate de que la IU refleje el hecho de que accediste a tu cuenta.
Usarás la devolución de llamada del objeto de escucha del estado de Firebase Authentication, que recibe notificaciones cada vez que cambia el estado de acceso del usuario. Si actualmente hay un usuario que accedió a su cuenta, tu app cambiará el botón "Confirmar asistencia" por un botón de "Salir".
- En StackBlitz, ve al archivo
index.js
. - En la parte superior, busca la instrucción de importación
firebase/auth
y, luego, agregasignOut
yonAuthStateChanged
, de la siguiente manera:// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import {} from 'firebase/firestore';
- Agrega el siguiente código en la parte inferior de la función
main()
:async function main() { // ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; } else { startRsvpButton.textContent = 'RSVP'; } }); } main();
- En el objeto de escucha del botón, verifica si hay un usuario actual y cierra su sesión. Para ello, reemplaza el
startRsvpButton.addEventListener
actual por lo siguiente:// ... // Called when the user clicks the RSVP button startRsvpButton.addEventListener('click', () => { if (auth.currentUser) { // User is signed in; allows user to sign out signOut(auth); } else { // No user is signed in; allows user to sign in ui.start('#firebaseui-auth-container', uiConfig); } });
Ahora, el botón de tu app debería mostrar CERRAR SESIÓN y volver a CONFIRMAR ASISTENCIA cuando se haga clic en él.
Vista previa de la app
7. Escriba mensajes en Cloud Firestore
Saber que los usuarios están llegando es genial, pero démosles a los invitados algo más para hacer en la app. ¿Qué tal si pudieran dejar mensajes en un libro de visitas? Pueden compartir por qué les entusiasma asistir o a quién esperan conocer.
Para almacenar los mensajes de chat que escriben los usuarios en la app, usarás Cloud Firestore.
Modelo de datos
Cloud Firestore es una base de datos NoSQL, y los datos almacenados en ella se dividen en colecciones, documentos, campos y subcolecciones. Almacenarás cada mensaje del chat como un documento en una colección de nivel superior llamada guestbook
.
Agrega mensajes a Firestore
En esta sección, agregarás la funcionalidad para que los usuarios escriban mensajes nuevos en la base de datos. Primero, agrega el código HTML para los elementos de la IU (campo de mensaje y botón de envío). Luego, agregarás el código que conecta estos elementos a la base de datos.
Para agregar los elementos de la IU de un campo de mensaje y un botón de envío, haz lo siguiente:
- En StackBlitz, ve al archivo
index.html
. - Ubica
guestbook-container
y, luego, agrega el siguiente código HTML para crear un formulario con el campo de entrada de mensajes y el botón de envío.<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form id="leave-message"> <label>Leave a message: </label> <input type="text" id="message"> <button type="submit"> <i class="material-icons">send</i> <span>SEND</span> </button> </form> </section> <!-- ... -->
Vista previa de la app
Los usuarios que hagan clic en el botón ENVIAR activarán el fragmento de código que aparece abajo. Agrega el contenido del campo de entrada de mensaje a la colección guestbook
de la base de datos. Específicamente, el método addDoc
agrega el contenido del mensaje a un documento nuevo (con un ID generado automáticamente) en la colección guestbook
.
- En StackBlitz, ve al archivo
index.js
. - En la parte superior, busca la instrucción de importación
firebase/firestore
y, luego, agregagetFirestore
,addDoc
ycollection
, de la siguiente manera:// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, addDoc, collection } from 'firebase/firestore';
- Ahora guardaremos una referencia al objeto
db
de Firestore justo después deinitializeApp
:initializeApp(firebaseConfig); auth = getAuth(); db = getFirestore();
- En la parte inferior de la función
main()
, agrega el siguiente código.
Ten en cuenta queauth.currentUser.uid
es una referencia al ID único generado automáticamente que Firebase Authentication proporciona para todos los usuarios que accedieron.async function main() { // ... // Listen to the form submission form.addEventListener('submit', async e => { // Prevent the default form redirect e.preventDefault(); // Write a new message to the database collection "guestbook" addDoc(collection(db, 'guestbook'), { text: input.value, timestamp: Date.now(), name: auth.currentUser.displayName, userId: auth.currentUser.uid }); // clear message input field input.value = ''; // Return false to avoid redirect return false; }); } main();
Mostrar el libro de visitas solo a los usuarios que accedieron a la cuenta
No quieres que cualquier persona vea el chat de los invitados. Una forma de proteger el chat es permitir que solo los usuarios registrados vean el libro de visitas. Dicho esto, para tus propias apps, también deberás proteger tu base de datos con las reglas de seguridad de Firebase. (Encontrarás más información sobre las reglas de seguridad más adelante en el codelab).
- En StackBlitz, ve al archivo
index.js
. - Edita el objeto de escucha
onAuthStateChanged
para ocultar y mostrar el libro de visitas.// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; } });
Prueba el envío de mensajes
- Asegúrate de haber accedido a la app.
- Escribe un mensaje, como "Hola", y haz clic en ENVIAR.
Esta acción escribe el mensaje en tu base de datos de Cloud Firestore. Sin embargo, todavía no verás el mensaje en tu propia aplicación web porque te falta implementar la recuperación de datos. Lo harás a continuación.
Sin embargo, puedes ver el mensaje recién agregado en Firebase console.
En el panel de Firestore Database de Firebase console, deberías ver la colección guestbook
con el mensaje nuevo que agregaste. Si sigues enviando mensajes, tu colección de libros de visitas contendrá muchos documentos, como se muestra a continuación:
Firebase console
8. Lea los mensajes
Sincronizar mensajes
Es genial que los invitados puedan escribir mensajes en la base de datos, pero aún no pueden verlos en la app.
Para mostrar mensajes, deberás agregar objetos de escucha que se activen cuando cambien los datos y, luego, crear un elemento de la IU que muestre los mensajes nuevos.
Agregarás código que detecte los mensajes recién agregados de la app. Primero, agrega una sección en el código HTML para mostrar los mensajes:
- En StackBlitz, ve al archivo
index.html
. - En
guestbook-container
, agrega una sección nueva con el ID deguestbook
.<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form><!-- ... --></form> <section id="guestbook"></section> </section> <!-- ... -->
A continuación, registra el objeto de escucha que detecta los cambios realizados en los datos:
- En StackBlitz, ve al archivo
index.js
. - En la parte superior, busca la instrucción de importación
firebase/firestore
y, luego, agregaquery
,orderBy
yonSnapshot
, de la siguiente manera:// ... import { getFirestore, addDoc, collection, query, orderBy, onSnapshot } from 'firebase/firestore';
- En la parte inferior de la función
main()
, agrega el siguiente código para recorrer todos los documentos (mensajes del libro de visitas) de la base de datos. Para obtener más información sobre lo que sucede en este código, lee la información que se encuentra debajo del fragmento.async function main() { // ... // Create query for messages const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); } main();
Para escuchar los mensajes en la base de datos, creaste una consulta en una colección específica con la función collection
. El código anterior escucha los cambios en la colección guestbook
, que es donde se almacenan los mensajes del chat. Los mensajes también se ordenan por fecha, con orderBy('timestamp', 'desc')
para mostrar los mensajes más recientes en la parte superior.
La función onSnapshot
toma dos parámetros: la consulta que se usará y una función de devolución de llamada. La función de devolución de llamada se activa cuando se realizan cambios en los documentos que coinciden con la consulta. por ejemplo, cuando se borre, se modifique o se agregue un mensaje. Para obtener más información, consulta la documentación de Cloud Firestore.
Cómo probar la sincronización de mensajes
Cloud Firestore sincroniza los datos de forma automática e instantánea con los clientes suscritos a la base de datos.
- En la app, se deberían mostrar los mensajes que creaste antes en la base de datos. Puedes escribir mensajes nuevos, que deberían aparecer al instante.
- Si abres tu espacio de trabajo en varias ventanas o pestañas, los mensajes se sincronizarán en tiempo real en todas las pestañas.
- (Opcional) Puedes intentar borrar, modificar o agregar mensajes nuevos de forma manual y directamente en la sección Database de Firebase console. Los cambios deberían aparecer en la IU.
¡Felicitaciones! ¡Estás leyendo documentos de Cloud Firestore en tu app!
Vista previa de la app
9. Configura reglas de seguridad básicas
Inicialmente, configuraste Cloud Firestore para usar el modo de prueba, lo que significa que tu base de datos está abierta para lecturas y escrituras. Sin embargo, solo debes usar el modo de prueba durante las primeras etapas del desarrollo. Como práctica recomendada, debes configurar reglas de seguridad para tu base de datos a medida que desarrollas tu app. La seguridad debe ser integral para la estructura y el comportamiento de tu app.
Las reglas de seguridad te permiten controlar el acceso a los documentos y las colecciones de tu base de datos. La sintaxis de reglas flexibles te permite crear reglas que coincidan con todo, desde todas las operaciones de escritura en la base de datos hasta las operaciones en un documento específico.
Puedes escribir reglas de seguridad para Cloud Firestore en Firebase console:
- En la sección Compilación de Firebase console, haz clic en Base de datos de Firestore y, luego, selecciona la pestaña Reglas (o haz clic aquí para ir directamente a la pestaña Reglas).
- Deberías ver las siguientes reglas de seguridad predeterminadas, con un límite de tiempo de acceso público de un par de semanas a partir de hoy.
Identifica colecciones
Primero, identifica las colecciones en las que la app escribe datos.
- Borra la cláusula
match /{document=**}
existente para que tus reglas se vean de la siguiente manera:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { } }
- En
match /databases/{database}/documents
, identifica la colección que deseas proteger:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { // You'll add rules here in the next step. } }
Cómo agregar reglas de seguridad
Como usaste el UID de Authentication como un campo en cada documento del libro de visitas, puedes obtener el UID de Authentication y verificar que cualquier persona que intente escribir en el documento tenga un UID de Authentication coincidente.
- Agrega las reglas de lectura y escritura a tu conjunto de reglas como se muestra a continuación:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId; } } }
- Haz clic en Publicar para implementar las reglas nuevas.Ahora, en el libro de visitas, solo los usuarios que accedan a su cuenta podrán leer mensajes (cualquier mensaje), pero solo podrás crear un mensaje con tu ID de usuario. Tampoco permitimos que se editen o borren los mensajes.
Cómo agregar reglas de validación
- Agrega validación de datos para asegurarte de que todos los campos esperados estén presentes en el documento:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId && "name" in request.resource.data && "text" in request.resource.data && "timestamp" in request.resource.data; } } }
- Haz clic en Publicar para implementar las reglas nuevas.
Restablece los objetos de escucha
Como ahora tu app solo permite que accedan los usuarios autenticados, debes mover la consulta firestore
del libro de visitas dentro del objeto de escucha de autenticación. De lo contrario, se producirán errores de permisos y la app se desconectará cuando el usuario salga de su cuenta.
- En StackBlitz, ve al archivo
index.js
. - Extrae el objeto de escucha de la colección
onSnapshot
del libro de visitas en una función nueva llamadasubscribeGuestbook
. Además, asigna los resultados de la funciónonSnapshot
a la variableguestbookListener
.
El objeto de escuchaonSnapshot
de Firestore devuelve una función de cancelación de suscripción que podrás usar para cancelar el objeto de escucha de instantáneas más adelante.// ... // Listen to guestbook updates function subscribeGuestbook() { const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); guestbookListener = onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); }
- Agrega una nueva función debajo llamada
unsubscribeGuestbook
. Verifica si la variableguestbookListener
no es nula y, luego, llama a la función para cancelar el objeto de escucha.// ... // Unsubscribe from guestbook updates function unsubscribeGuestbook() { if (guestbookListener != null) { guestbookListener(); guestbookListener = null; } }
Por último, agrega las nuevas funciones a la devolución de llamada onAuthStateChanged
.
- Agrega
subscribeGuestbook()
en la parte inferior deif (user)
. - Agrega
unsubscribeGuestbook()
en la parte inferior de la sentenciaelse
.// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); } });
10. Paso adicional: Practica lo que aprendiste
Cómo registrar el estado de confirmación de asistencia de un asistente
Por el momento, tu app solo permite que las personas comiencen a chatear si les interesa el evento. Además, la única forma de saber si alguien viene es si lo publica en el chat. Organicemos todo y avisemos a las personas cuántas asistirán.
Agregarás un botón de activación para registrar a las personas que quieran asistir al evento y, luego, recopilarás un recuento de cuántas personas asistirán.
- En StackBlitz, ve al archivo
index.html
. - En
guestbook-container
, agrega un conjunto de botones SÍ y NO, de la siguiente manera:<!-- ... --> <section id="guestbook-container"> <h2>Are you attending?</h2> <button id="rsvp-yes">YES</button> <button id="rsvp-no">NO</button> <h2>Discussion</h2> <!-- ... --> </section> <!-- ... -->
Vista previa de la app
A continuación, registra el objeto de escucha para los clics en el botón. Si el usuario hace clic en SÍ, usa su UID de autenticación para guardar la respuesta en la base de datos.
- En StackBlitz, ve al archivo
index.js
. - En la parte superior, busca la instrucción de importación
firebase/firestore
y, luego, agregadoc
,setDoc
ywhere
, de la siguiente manera:// ... // Add the Firebase products and methods that you want to use import { getFirestore, addDoc, collection, query, orderBy, onSnapshot, doc, setDoc, where } from 'firebase/firestore';
- En la parte inferior de la función
main()
, agrega el siguiente código para detectar el estado de la confirmación de asistencia:async function main() { // ... // Listen to RSVP responses rsvpYes.onclick = async () => { }; rsvpNo.onclick = async () => { }; } main();
- A continuación, crea una nueva colección llamada
attendees
y, luego, registra una referencia de documento si se hace clic en alguno de los botones de RSVP. Establece esa referencia entrue
ofalse
según el botón en el que se haga clic.
Primero, pararsvpYes
: Luego, lo mismo para// ... // Listen to RSVP responses rsvpYes.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attendi()ng: true try { await setDoc(userRef, { attending: true }); } catch (e) { console.error(e); } };
rsvpNo
, pero con el valorfalse
:rsvpNo.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attending: true try { await setDoc(userRef, { attending: false }); } catch (e) { console.error(e); } };
Actualiza tus reglas de seguridad
Como ya tienes algunas reglas configuradas, se rechazarán los datos nuevos que agregues con los botones.
Permitir adiciones a la colección de attendees
Deberás actualizar las reglas para permitir que se agreguen elementos a la colección attendees
.
- En el caso de la colección
attendees
, como usaste el UID de autenticación como nombre del documento, puedes tomarlo y verificar que eluid
del remitente sea el mismo que el del documento que está escribiendo. Permitirás que todos lean la lista de asistentes (ya que no hay datos privados allí), pero solo el creador podrá actualizarla.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId; } } }
- Haz clic en Publicar para implementar las reglas nuevas.
Cómo agregar reglas de validación
- Agrega algunas reglas de validación de datos para asegurarte de que todos los campos esperados estén presentes en el documento:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId && "attending" in request.resource.data; } } }
- No olvides hacer clic en Publicar para implementar tus reglas.
(Opcional) Ahora puedes ver los resultados de hacer clic en los botones. Ve al panel de Cloud Firestore en Firebase console.
Leer el estado de confirmación de asistencia
Ahora que grabaste las respuestas, veamos quiénes vendrán y reflejemos esa información en la IU.
- En StackBlitz, ve al archivo
index.html
. - En
description-container
, agrega un elemento nuevo con el ID denumber-attending
.<!-- ... --> <section id="description-container"> <!-- ... --> <p id="number-attending"></p> </section> <!-- ... -->
A continuación, registra el objeto de escucha para la colección attendees
y cuenta la cantidad de respuestas YES:
- En StackBlitz, ve al archivo
index.js
. - En la parte inferior de la función
main()
, agrega el siguiente código para detectar el estado de la confirmación de asistencia y contar los clics en SÍ.async function main() { // ... // Listen for attendee list const attendingQuery = query( collection(db, 'attendees'), where('attending', '==', true) ); const unsubscribe = onSnapshot(attendingQuery, snap => { const newAttendeeCount = snap.docs.length; numberAttending.innerHTML = newAttendeeCount + ' people going'; }); } main();
Por último, destaquemos el botón correspondiente al estado actual.
- Crea una función que verifique si el UID de autenticación actual tiene una entrada en la colección
attendees
y, luego, establece la clase del botón enclicked
.// ... // Listen for attendee list function subscribeCurrentRSVP(user) { const ref = doc(db, 'attendees', user.uid); rsvpListener = onSnapshot(ref, doc => { if (doc && doc.data()) { const attendingResponse = doc.data().attending; // Update css classes for buttons if (attendingResponse) { rsvpYes.className = 'clicked'; rsvpNo.className = ''; } else { rsvpYes.className = ''; rsvpNo.className = 'clicked'; } } }); }
- Además, creemos una función para cancelar la suscripción. Se usará cuando el usuario cierre la sesión.
// ... function unsubscribeCurrentRSVP() { if (rsvpListener != null) { rsvpListener(); rsvpListener = null; } rsvpYes.className = ''; rsvpNo.className = ''; }
- Llama a las funciones desde el objeto de escucha de autenticación.
// ... // Listen to the current Auth state // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); // Subscribe to the user's RSVP subscribeCurrentRSVP(user); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none' ; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); // Unsubscribe from the guestbook collection unsubscribeCurrentRSVP(); } });
- Intenta acceder como varios usuarios y observa cómo aumenta el recuento con cada clic adicional en el botón SÍ.
Vista previa de la app
11. ¡Felicitaciones!
Usaste Firebase para compilar una aplicación web interactiva en tiempo real.
Temas abordados
- Firebase Authentication
- FirebaseUI
- Cloud Firestore
- Reglas de seguridad de Firebase
Próximos pasos
- ¿Quieres obtener más información sobre el flujo de trabajo para desarrolladores de Firebase? Consulta el codelab del emulador de Firebase para obtener información sobre cómo probar y ejecutar tu app de forma completamente local.
- ¿Quieres obtener más información sobre otros productos de Firebase? ¿Quizás quieres almacenar los archivos de imagen que suben los usuarios? ¿O enviar notificaciones a tus usuarios? Consulta el codelab de Firebase para la Web para obtener un codelab que profundice en muchos más productos de Firebase para la Web.
- ¿Quieres obtener más información sobre Cloud Firestore? ¿Quizás quieras obtener información sobre las subcolecciones y las transacciones? Dirígete al codelab web de Cloud Firestore para obtener más información sobre Cloud Firestore. También puedes consultar esta serie de YouTube para conocer Cloud Firestore.
Más información
- Sitio de Firebase: firebase.google.com
- Canal de YouTube de Firebase
¿Cómo te fue?
Nos encantaría recibir tus comentarios. Completa un formulario (muy) breve aquí.