Skip to content
Advertisement

Show a badge notification with Firestore

Hi I am creating a chat app with Firestore. I saw a lot of information about creating a badge notification with cloud messaging but not a lot of information with creating a badge notification without cloud message. Does anyone know how to do this? I am trying to show a dot on an icon when a user receives a message that they have not read. It would be even better if I could could the total number of messages that they have not read too.

Firestore Structure

 users
      |
      ---- chatList (subcollection)
              ---- chatFrom: user1_Id
              ---- chatWith: user2_Id
              ---- chatRoomId: smallerUserID_biggerUserID
chatRooms
      |
      ---- smallerUserID_biggerUserID (subcollection)
              ---- content: "Hello"
              ---- id: 1613422354427
              ---- idFrom: user1_Id
              ---- timestamp: 1613422354427
                    

Getting and Sending a messages in chatRooms Collection

getMessages() {
  this.listMessage = []; 
  
  db.collection('chatRooms').doc(this.chatRoomId).collection(this.chatRoomId)
    .onSnapshot((snapshot) => {
      snapshot.docChanges().forEach((change) => {
        if (change.type === 'added') {
          this.listMessage.push(change.doc.data());
        }
     });
  });
},

async sendMessage(content) {
  if (content.trim() === '') { return }
  
  const timestamp = moment().valueOf().toString();
  const idFrom = this.authUser.userId;
  const idTo = this.currentPeerUser.userId;
  const message = { id: timestamp, idFrom, idTo, timestamp, content };

  const chatRoomRef = db.collection('chatRooms').doc(this.chatRoomId)
                        .collection(this.chatRoomId).doc(timestamp);
  await chatRoomRef.set(message);

  this.inputValue = '';
},

Advertisement

Answer

As mentioned by @John, a better option would be to have an extra field in your objects that tells if the message has been read or not and it can be done with some simple changes like this to you getMessages():

getMessages() {
  this.listMessage = []; 
  
  db.collection('chatRooms').doc(this.chatRoomId).collection(this.chatRoomId)
    .onSnapshot((snapshot) => {
      snapshot.docChanges().forEach((change) => {
        if (change.type === 'added') {
          this.listMessage.push({
              isNew: true,
              message: change.doc.data()
          });
        }
     });
  });
}

You can use isNew to show or not show a newMessage icon and to change it’s value when the message is read you can use Intersection Observer by adding the following to your code:

//options to your observer
let options = {
  root: document.querySelector('#YOUR_ROOT_ELEMENT_HERE'),
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

let target = document.querySelector('#YOUR_TARGET_ELEMENT_HERE');
observer.observe(target);

let callback = (entries, observer) => {
    this.listMessage.forEach(function(messageItem) {
        messageItem.isNew = false;
    });
};

In this example YOUR_ROOT_ELEMENT_HERE will be the parent of your element, I assume in this case it could be a Scroll and YOUR_TARGET_ELEMENT_HERE will be the unread message. When the intersection happened all messages will be marked as read, but you can refine that logic as you see fit.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement