Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show delivered and blue ticks like whats app

I have created an app using socket... I am able to manage the conversation between two persons using socket connection.

Here is the code for it

User model

const schema = new Mongoose.Schema({
  firstName: { type: String, default: '', trim: true },
  lastName: { type: String, default: '', trim: true }
})

Conversation model

const schema = new Mongoose.Schema({
  name: { type: String, trim: true },
  type: { type: String, required: true, enum: ['G', 'P'] },
  members: [{ type: Schema.Types.ObjectId, ref: 'Users' }]
}, { timestamps: true })

Message Model

const schema = new Mongoose.Schema({
  conversationId: { type: Schema.Types.ObjectId, ref: 'Conversations' },
  body: { type: String, trim: true },
  author: { type: Schema.Types.ObjectId, ref: 'Users' }
}, { timestamps: true })

Done with the chatting part with this socket connection

io.on('sendMessage', async(action2) => {
    action2.author = socket.decoded.id
    action2.markRead = markReadSocket
    const createMessage = await Message.create(action2)
    const messages = await Message.aggregate([
      { "$match": { "_id": mongoose.Types.ObjectId(createMessage._id) } },
      { "$lookup": {
        "from": "users",
        "let": { "author": "$author" },
        "pipeline": [
          { "$match": { "$expr": { "$eq": [ "$_id", "$$author" ] }}},
          { "$project": { "firstName": 1, "lastName": 1, "avatar": 1 } }
        ],
        "as": "author"
      }},
      { "$unwind": "$author" },
      { "$project": {
        "author": 1, "markRead": 1, "isDelivered": 1,
        "body": 1, "conversationId": 1,
        "isIncoming": { "$ne": [ "$author._id", mongoose.Types.ObjectId(socket.decoded.id) ] },
      }}
    ])
    io.emit(action2.conversationId, messages)
  })

The above code is working fine for the one to one conversation and also for the group conversation.

Now what I want to achieve is to show delivered(two gray) and read(two blue) ticks just like the what app. Do I need to make separate collections for readBy and deliveredTo and need to save time and userId in it?

How can I do this with the nodejs and socketio? If someone has done this before then please post your code I will manage to understand it.

Any help would be appreciated!!!

Thanks in advance!!!

like image 346
Ashh Avatar asked Aug 17 '18 05:08

Ashh


3 Answers

Client Side

Pseudocode

1. Register handler for 'newMessage' event, this will emit 'received' event
2. Function to emit 'markSeen' event, this will execute when the message is opened (chat window)
3. Register handler for 'delivered' event, this will display 'grey' ticks
4. Register handler for 'markedSeen' event, this will display 'blue' ticks

Functions

// Handler for 'newMessage' event
socket.on('newMessage', function(message) {
    chatMessages[message.MESSAGE_ID] = message;

    var options = {
        messageID: message.MESSAGE_ID,
        timetoken: moment().valueOf()
    };

    // Emit 'received' event
    socket.emit('received', options);
});

// function to emit 'markSeen' event
function markSeen(message) {
    var options = {
        messageID: message.MESSAGE_ID
    };

    // Emit 'markSeen' event
    socket.emit('markSeen', options);
}

// Handler for 'delivered' event
socket.on('delivered', function(message) {
    chatMessages[MESSAGE_ID].delivered = true;
});

// Handler for 'markedSeen' event
socket.on('markedSeen', function(message) {
    chatMessages[MESSAGE_ID].seen = true;
});

Server Side

Pseudocode

1. Register handler for 'received' event, this will emit 'delivered' event
2. Register handler for 'markSeen' event, this will emit 'markedSeen' event

Functions

// Handler for 'received' event
io.on('received', function(options) {
    var options = {
        timetoken: moment().valueOf(),
        userID: options.message.SENDER_ID,
        messageID: options.message.MESSAGE_ID
    };

    // Emit 'delivered' event
    socket.emit('delivered', options);
});

// Handler for 'markSeen' event
io.on('markSeen', function(options) {
    var options = {
        timetoken: moment().valueOf(),
        userID: options.message.SENDER_ID,
        messageID: options.message.MESSAGE_ID
    };

    // Emit 'markedSeen' event
    socket.emit('markedSeen', options);
});
like image 106
nkshio Avatar answered Nov 14 '22 23:11

nkshio


After creating a new message entity and sending it to the recipient, recipient should emit a new delivered event as soon as this message is received. If this message is opened, send another event with read topic. Both events have to contain the message id.

In the server side, after receiving above events, check the sender of the message is that you got and pass proper events no notify sender about the current state of the message.

like image 25
hsz Avatar answered Nov 15 '22 01:11

hsz


You'll need 2 distinct things you'll need to track. Once your server has received the message. in it's control when you're adding it to the database, this is when you're going to set the delivered tick to true. At this point you can emit a message back to the sending web-socket telling it that they're message has been delivered to the server, then the client sender can set their gray tick.

Similarly on the receiving side,once the receiver logs on, goes to the page where the message is/opens it. Basically as soon as it's visible for them, you can go through all the messages currently visible to them, if any do not have a "hasRead" checked to true, then you can send a call to to a controller that can set them to "hasRead=true". At this point your websocket can try update the sender(if they are online) that the message has been read. If they aren't online then you can just do the same thing i n reverse. E.G: If the sender comes online, pass along the "hasRead" attribute with each message and you can set the blue ticks accordingly"

like image 31
Prodigle Avatar answered Nov 15 '22 01:11

Prodigle