Por: Juan Andrés Núñez
Juan Andrés Núñez - juanwmedia

Especialista en tecnologías Web. Me dedico a enseñar desarrollo Web moderno a cualquier persona (físicamente en clase y a través de Internet) desde una perspectiva holística: teniendo en cuenta las competencias técnicas necesarias, junto a las habilidades personales o soft skills. Tienes más información en mi Web.

  • Como punto de partida tenemos que realizar varios ajustes en nuestra store. Más concretamente en el módulo user.js para gestionar los metadatos del usuario donde guardaremos la sala a la que está conectado y cuándo fue la última conexión. Adeás haremos uso de los nuevos métodos Firestore para tratar con matrices.
const actions = {
  async updateMeta(context, { roomID, exit, uid }) {
    const ref = db.collection("users").doc(uid);
    const userDoc = await ref.get();
    if (!userDoc.exists) await ref.set({});
    const method = exit ? "arrayRemove" : "arrayUnion";
    await ref.update({
      connected: firebase.firestore.FieldValue[method](roomID),
      [`joined.${roomID}`]: Date.now()
    });
  },

  async getMeta({ state, commit }) {
    const ref = db.collection("users").doc(state.user.uid);
    await ref.update({ connected: [] });
    const query = ref.onSnapshot(doSnapshot);
    commit("setUserListener", query);
    function doSnapshot(doc) {
      commit("setMeta", doc.data());
    }
  },
}
  • Ahora debemos invocar la acción updateMeta al acceder y al salir de nuestro componente/vista ViewRoom.vue.
async created() {
  this.userUid = this.$store.state.user.user.uid; // IMPORTANTE 🔥
  try {
    await this.$store.dispatch("user/updateMeta", {
      roomID: this.id,
      exit: false,
      uid: this.userUid
    });
    ...
  } catch (error) {
    ...
  }
},

async destroyed() {
  try {
    await this.$store.dispatch("user/updateMeta", {
      roomID: this.id,
      exit: true,
      uid: this.userUid
    });
  } catch (error) {
    ...
  }
},
  • Ya no podemos seguir escuchando los mensajes sólo cuando estamos conectados a una sala de conversación, sino que debemos hacerlo siempre. Es la única forma de saber si hay mensajes nuevos para un usuario que no está conectado a ninguna sala.
  • Debemos ajustar nuestro módulo messages.js para hacer uso de collectionGroup.
const actions = {
  async getMessages({ commit }) {
    const query = db
      .collectionGroup("messages") // IMPORTANTE 🔥
      .orderBy("createdAt", "desc")
      .onSnapshot(doSnapShot);
      ...
    }
  },

  async createMessage({ rootState }, { roomID, message }) {
    await db
      .collection("rooms")
      .doc(roomID)
      .collection("messages")
      .add({
        ...
        userName: rootState.user.user.displayName,
        roomId: roomID, // IMPORTANTE 🔥
        message,
        ...
      });
  }
};
  • Con todo listo debemos decicir qué mensajes se consideran "no leídos" para el usuario. La forma más sencilla es crear una propiedad computada en RoomsView.vue y pasarle la información como custom prop al componente RoomsComponent.vue.
<RoomsComponent :unread-messages="unreadMessages" :rooms="rooms" />

export default {
  name: "RoomsView",
  computed: {
    ...
    ...mapState("messages", ["messages"]),
    unreadMessages() {
      return this.messages.filter(message => {
        return (
          // User participated
          this.meta.joined[message.roomId] &&
          // Message sent after user last connection
          this.meta.joined[message.roomId] < message.createdAt
        );
      });
    }
  },
  components: {
    RoomsComponent
  }
};
  • Ya casi lo tenemos. En este momento debemos ir al componente RoomsComponent.vue y actuar con la nueva información de mensajes sin leer mostrando la alerta. Todo depende de un nuevo método que indique si cada sala de conversación tiene mensajes sin leer.
methods: {
    hasUnreadMessages(roomId) {
        return this.unreadMessages.filter(message => {
            return message.roomId === roomId;
        });
    }
}
  • Por último queda ajustar nuestra de store index.js para invocar y desactivar los módulos cuando haya y no haya autentificación respectivamente.
actions: {
    checkAuth({ dispatch, commit }) {
        auth.onAuthStateChanged(async function(user) {
        if (user) {
            commit("user/setUser", user);
            try {
                await dispatch("user/getMeta");
                await dispatch("rooms/getRooms");
                await dispatch("messages/getMessages");
            } catch (error) {
                ...
            }
        } else {
            commit("user/setMeta", {});
            commit("user/setUserListener", () => {});
            commit("rooms/setRooms", []);
            commit("rooms/setRoomsListener", () => {});
            commit("messages/setMessages", []);
            commit("messages/setMessagesListener", () => {});
            commit("user/setUser", null);
        }
        });
    }
},

Presentación


Firebase Auth


Cloud Firestore 🔥


Cloud Storage 🗄


No te pierdas ninguna novedad

Escuela Vue en Twitter

Participa en la Comunidad Escuela Vue

Comunidad Escuela Vue