We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel 🚀.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Login or register
to save articles!

Login to see the application

Engineers who find a new job through JavaScript Works average a 15% increase in salary 🚀

You will be redirected back to this page right after signin

Blog hero image

Firebase and Ionic React Chat app (Fire Chat) Part 5: Creating Read receipts

King Somto 5 November, 2021 | 5 min read

Introduction

Chat applications are fun to use they enable us to send messages to other users old and new alike, Our series started at us just building simple react components then progressed to us being able to implement firebase-cloud functions in our application , using firebase-cloud functions we realized that we are able to offload some firebase operations we might have done on the frontend to the backend, this enables to perform some powerful and sensitive operations on the backend examples would be

  • Validate login
  • Validate Signup form
  • Filter friends
  • Perform operations when saving messages
  • Load ChatId
  • Handle payments (if needed)
  • Many more operations

We set out to build a messaging app using only firebase (as a database) and react, so far we have been able to go from building an app that was similar to a forum app to adding personalized chat messages between individual users to our application, now we would like to add more features to our application to make the application more like WhatsApp, and we are going to start with adding Read receipts just like apps like WhatsApp and Facebook messenger.

Let's get to work

To build this we have to be able to have a flag in every message telling us if the message has been read or not so we can render a tic on the messages sent after they are viewed. Our database would resemble the below image. Screen Shot 2021-10-06 at 1.47.10 AM.png

We have to set the read flag to true whenever a message component has been rendered, ideally, this is meant to be done on the backend, but I think this method is the cleanest considering our current previous implementations also firebase doesn't offer a `onread hook for objects, (so if you're a firebase engineer reading this help a bro out and add that, thanks).

Our approach

Our approach would be to look create a function that is able to find our message object in the chat collection and append a read flag as `true, this can only be done by the user receiving the message, once done it would be rendered by our application, thanks to the way firebase libraries handles database updates

Step 1

Add the Tick component to our project folder To do that download any Tick SVG of your choice and store it in the assets folder, then create an index.js file in that folder to help export the SVG element as a React component.

Paste​​

import {ReactComponent as Tic} from './tic.svg';
 
export {Tic}
Join our newsletter
Join over 111,000 others and get access to exclusive content, job opportunities and more!

Step 2

Edit our messagesBox.jsx component to render the Tick component. Let's start by adding some styling and adding the Tick Component

import React from 'react';
import style from 'styled-components';
import { Tic } from '../assets';
import { db } from '../config/firebase'; 
 
export default function Message({ data, name, chatId }) {
 const { message, id, sender, ...rest } = data;
 
 
 const Message = style.div`
   min-height: 21px;
   max-width: 90%;
   min-width: 50%;
   position: relative;
   width: max-content;
   background: ${sender !== name ? 'pink' : 'blue'};;
   text-align: left;
   padding: 10px;
   border-radius: 10px;
   color: white;
   margin: 15px 0;
   float: ${sender !== name ? 'left' : 'right'};
 
   div {
 
   }
 
   svg{
     height: 15px;
     width: 15px;
     position: absolute;
     color: pink;
     bottom: -7px;
     right: 10px;
     background: white;
     border-radius: 50%;
     padding: 3px;
   }
 
 
   `;
 return <Message><div>
   <p>
   {message}
   </p>
   { seen &&  sender === name &&  <Tic/>}
   </div></Message>;
}
 
   { seen &&  sender === name &&  <Tic/>}

Here the Tick SVG does not render except if the message has been marked as seen.

Step 3

We pass more logic data into the component so it can make a database call to mark a message as seen. We need to edit the messages.jsx to pass in the chatId into the messageBox component.

export default function Messages({ name }) {
 const Messages = style.div`
   padding: 20px;
   height: calc(100% - 64px);
   overflow-y: scroll;
   `;
 
 
 const [messages, setMessages] = React.useState([]);
 const [chatId, setchatId] = React.useState(false);
 React.useEffect(() => {
   const receiver = window.location.href.split('/')[4]
 
   try {
     allFunctions.getChatID({
       userName: receiver
     }).then(({ data }) => {
       const { chatId = '' } = data;
       setchatId(chatId)
       db.ref('chats').child(chatId).on('value', (snapShot) => {
         let chats = [];
         snapShot.forEach((snap) => {
 
 
        const dataToShoww =  {
           ...snap.val(),
           id:snap.key
         }
           chats.push(dataToShoww);
         });
 
 
         setMessages(chats);
         var element = document.getElementById('messages');
         element.scrollTop = element.scrollHeight - element.clientHeight;
       });
 
     }).catch((error) => {
       console.log(error)
     })
 
   } catch (error) {
     console.log(error)
   }
 
 }, []);
 
 return (
   <Messages id='messages' >
     {messages.map((data) => {
       return <Message name={name} data={data} chatId={chatId} />;
     })}
   </Messages>
 );
}
 

Breaking it down

 const { chatId = '' } = data;
       setchatId(chatId)

Here we set the chatId variable to be passed on to the message components after we run the getChatID function. Now we are able to pass all the data to the messageBox.jsx component and perform a function call to mark the message as read.

Step 4

Our approach for this implementation is to mark a message object as seen when we render it on the app, we have only 2 conditions that perform an indication that a message should be marked as seen.

  • This message hasn't been marked as seen
  • And you are the receiver of the message
    const [seen, setSeen] = React.useState(rest.seen)
     React.useEffect(() => {
       console.log({data,sender,name})
       if (seen || sender === name) {///sen this guys or am the sender meaning i need a read receipt
          
         return
       }
     
       markAsSeen(id, chatId)
       ///check if seen?
     }, [])
     
    
const markAsSeen = (messageId, chatId) => { try { console.log({ messageId,chatId }) //mark the message as read const messageeRef = db .ref('chats').child(chatId).child(messageId) console.log({ messageeRef }) messageeRef.update({///update the message using the referece seen: true///updates the }) } catch (error) { console.log(error) console.log('Can not update the state of the object'); } }

Let's break it down

 React.useEffect(() => {
   console.log({data,sender,name})
   if (seen || sender === name) {///sen this guys or am the sender meaning i need a read receipt
      
     return
   }
 
   markAsSeen(id, chatId)
   ///check if seen?
 }, [])

The markAsSeen function is run in the useEffect function, it checks if the message is marked as seen or if am the sender if any of the conditions are met it calls the return function.

  //mark the message as read
   const messageeRef = db
     .ref('chats').child(chatId).child(messageId)
 
     console.log({
       messageeRef
     })
 
   messageeRef.update({///update the message using the referece
     seen: true///updates the
   })

The code above uses the information passed in the component to create a message ref messageeRef using this reference we are able to update our database by adding a read flag and setting the value of the object to true.

Now we can run our codebase for our frontend and backend if you are not able to remember the commands for the application(frontend or backend) I suggest you check out my previous articles on firebase functions and just set up the frontend app

Now let's look at our output to see what we have.

Screen Shot 2021-10-29 at 5.11.49 AM.png
Screen Shot 2021-10-29 at 5.11.36 AM.png

Conclusion

Side by side we can see that we can now see a Tic component rendered if our message has been viewed by our recipient.

We do this by updating the message object whenever a message has been rendered on a user's device by passing the chatID and the messageId in our component and making it call firebase to update the chat object.

Moving further, this series has been a steady progression of implementing simple firebase features to be able to achieve or simulate activities we can find on a chat application, the next tutorial would focus on sending other users images and 30-sec videos, and also possibly audio notes. Stay tuned

Author's avatar
King Somto
I really dont know much but am willing to try and learn

Related Issues

open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 4
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 4
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 5
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 1
  • Intermediate
  • HTML

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through JavaScript Works average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email