Show delivered and blue ticks like whats app
Asked Answered
M

3

5

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!!!

Marniemaro answered 17/8, 2018 at 5:13 Comment(2)
You'll have to send acknowledgements. Just client asking another client, have you received my message? Did you see it? You should always send a received message acknowledgements just to make sure messages have been send correctly.Unstrap
@Unstrap Did not get youMarniemaro
S
3

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);
});
Saldivar answered 23/8, 2018 at 16:11 Comment(9)
thank you very much for the answer... I will let you know after integrating this code...Marniemaro
No problemo! It was a nice exercise for me to review the code written an year ago :)Saldivar
@AnthonyWinzlet is your query resolved? take advantage of losing hard-earned points :)Saldivar
I didn't check yet... I will confirm you after few hoursMarniemaro
Hi suppose I have multiple messageIds then how do I mark all of them seen?Marniemaro
that's simple. pass array of message_ids from client to server, server updates status for all of the messages at once, sends an array of message_ids in markedSeen event.Saldivar
Hi mehtankush!!! Today I am going to integrate your code so can you please help me to do soMarniemaro
Hey @AnthonyWinzlet. Happy to help :) pls you open a chat room?Saldivar
Is it necessary to store 'received' and 'seen' for every message? Isn't it a fact that if you've received the last message, you've received all those before them? Same goes for seen messages. That way you can also emit sending arrays of mesasge_ids back and forth for users that have been longer inactive. I'm thinking out loud here: maybe I'm missing something.Oily
A
3

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.

Allieallied answered 17/8, 2018 at 5:21 Comment(1)
thanks for the answer... If you will explain it expensively then I will surely set it for bounty after two days.Marniemaro
S
3

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);
});
Saldivar answered 23/8, 2018 at 16:11 Comment(9)
thank you very much for the answer... I will let you know after integrating this code...Marniemaro
No problemo! It was a nice exercise for me to review the code written an year ago :)Saldivar
@AnthonyWinzlet is your query resolved? take advantage of losing hard-earned points :)Saldivar
I didn't check yet... I will confirm you after few hoursMarniemaro
Hi suppose I have multiple messageIds then how do I mark all of them seen?Marniemaro
that's simple. pass array of message_ids from client to server, server updates status for all of the messages at once, sends an array of message_ids in markedSeen event.Saldivar
Hi mehtankush!!! Today I am going to integrate your code so can you please help me to do soMarniemaro
Hey @AnthonyWinzlet. Happy to help :) pls you open a chat room?Saldivar
Is it necessary to store 'received' and 'seen' for every message? Isn't it a fact that if you've received the last message, you've received all those before them? Same goes for seen messages. That way you can also emit sending arrays of mesasge_ids back and forth for users that have been longer inactive. I'm thinking out loud here: maybe I'm missing something.Oily
C
1

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"

Chirurgeon answered 20/8, 2018 at 8:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.