From b9cfcc799b878764fc76af3f85df9ee2ab9abe15 Mon Sep 17 00:00:00 2001 From: Dunsin <78784850+Dun-sin@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:23:57 +0100 Subject: [PATCH] fix: edit message not received (#163) * fix: close all chats not working * fix: edited message not received * fix: close all chats not working (#161) (#162) --- client/src/components/Chat.jsx | 24 +- client/src/lib/chat.js | 25 ++ server/index.js | 482 +++++++++++++++++---------------- 3 files changed, 302 insertions(+), 229 deletions(-) diff --git a/client/src/components/Chat.jsx b/client/src/components/Chat.jsx index 3911576c..0a133b84 100644 --- a/client/src/components/Chat.jsx +++ b/client/src/components/Chat.jsx @@ -31,7 +31,7 @@ const Chat = () => { const { auth, logout } = useAuth(); const socket = useContext(SocketContext); - const { sendMessage, deleteMessage } = useChatUtils(socket); + const { sendMessage, deleteMessage, editMessage } = useChatUtils(socket); const inputRef = useRef(''); senderId = auth.email ?? auth.loginId; @@ -61,14 +61,20 @@ const Chat = () => { removeMessage(id, chatId); }; + const editMessageHandler = ({ id, chatId, newMessage }) => { + editText(id, chatId, newMessage) + } + // This is used to recive message form other user. socket.on('receive_message', newMessageHandler); socket.on('delete_message', deleteMessageHandler); + socket.on('edit_message', editMessageHandler) setCurrentChatId(localStorage.getItem('currentChatId')); return () => { socket.off('receive_message', newMessageHandler); socket.off('delete_message', deleteMessageHandler); + socket.off('edit_message', editMessageHandler) }; }, []); @@ -177,7 +183,7 @@ const Chat = () => { // Here whenever user will submit message it will be send to the server - const handleSubmit = (e) => { + const handleSubmit = async (e) => { e.preventDefault(); const d = new Date(); @@ -187,7 +193,19 @@ const Chat = () => { } if (editing.isediting === true) { - editText(editing.messageID, currentChatId, message) + try { + await editMessage({ + id: editing.messageID, + chatId: currentChatId, + newMessage: message + }) + editText(editing.messageID, currentChatId, message) + const messageObject = getMessage(editing.messageID) + updateMessage(editing.messageID, messageObject) + } catch { + setEditing({ isediting: false, messageID: null }) + return; + } setEditing({ isediting: false, messageID: null }) } else { doSend({ diff --git a/client/src/lib/chat.js b/client/src/lib/chat.js index bb86296c..dbc47a6f 100644 --- a/client/src/lib/chat.js +++ b/client/src/lib/chat.js @@ -51,8 +51,33 @@ export default function useChatUtils(socket) { }); } + function editMessage({ id, chatId, newMessage }) { + return new Promise((resolve, reject) => { + if (!socket.connected) { + reject(null); + return; + } + + socket + .timeout(30000) + .emit( + 'edit_message', + { id, chatId, newMessage }, + (err, messageEdited) => { + if (err) { + reject(err); + return; + } + + resolve(messageEdited); + } + ); + }); + } + return { sendMessage, deleteMessage, + editMessage, }; } diff --git a/server/index.js b/server/index.js index 189a863f..ba45ca6c 100644 --- a/server/index.js +++ b/server/index.js @@ -151,233 +151,263 @@ const matchMaker = (io) => { }; // Sockets -io.on("connection", (socket) => { - /** - * This event is emitted once the user clicks on the Start button or - * navigates to the /founduser route - */ - socket.on("join", ({ loginId, email }) => { - /** - * This is necessary to enable us send notifications to users - * using multiple devices to chat - */ - socket.join(loginId); - // Email is possibly null for anonymous users - if (email) { - socket.join(email); - } - - /** - * First we check if user is already chatting. - * If user is already chatting, continue chat from where the user left - */ - if (isUserActive(email ?? loginId)) { - const user = getActiveUser({ - socketId: socket.id, - loginId, - email: email ?? null, - }); - - // First join user to lost chat - socket.join(user.currentChatId); - user.socketConnections.push(socket); - user.socketIds.push(socket.id); - - // Then return all chat messages - socket.emit("chat_restore", { - chats: user.chats, - currentChatId: user.currentChatId, - }); - return; - } - - // User was not having any previous chat. So add to waiting list - addToWaitingList({ loginId, email, socket }); - - // Finally, run matchMaker to pair all users on the waiting list - matchMaker(io); - }); - - socket.on( - "send_message", - ({ senderId, message, time, chatId }, returnMessageToSender) => { - // Below line is just a failed message simulator for testing purposes. - - // const rndInt = Math.floor(Math.random() * 6) + 1; - // if (rndInt % 2 !== 0) { - // return; - // } - - const user = getActiveUser({ - socketId: socket.id, - }); - - if (!user) { - socket.emit("send_failed", { - message: - "Hmmm. It seems your login session has expired. " + - "Re-login and try again", - messageId: id, - }); - - return; - } - - const id = uuid.v4(); - - /** - * Cache the sent message for each user in the chat. - * This is also the point, where we persist the message in the db - */ - user.chats[chatId].userIds.forEach((userId) => { - const user = getActiveUser({ - email: userId, - loginId: userId, - }); - - if (user) { - user.chats[chatId].messages[id] = { - id, - message, - time, - senderId, - type: "message", - }; - } - }); - - const sentMessage = { - senderId, - message, - time, - id, - room: chatId, - status: "sent", - }; - - returnMessageToSender(sentMessage); - - socket.broadcast.to(chatId).emit("receive_message", sentMessage); - } - ); - - socket.on( - "delete_message", - ({ id: messageId, chatId }, messageWasDeletedSuccessfully) => { - const user = getActiveUser({ - socketId: socket.id, - }); - - if (!user || !messageId || !chatId) { - messageWasDeletedSuccessfully(false); - return; - } - - user.chats[chatId].userIds.forEach((userId) => { - const user = getActiveUser({ - email: userId, - loginId: userId, - }); - - if (user) { - delete user.chats[chatId].messages[messageId]; - } - }); - - socket.broadcast - .to(chatId) - .emit("delete_message", { id: messageId, chatId }); - - messageWasDeletedSuccessfully(true); - } - ); - - socket.on("logout", () => { - const user = getActiveUser({ - socketId: socket.id, - }); - - if (!user) { - return; - } - - // User is an anonymous user, so close all active chats - if (!user.email) { - Object.values(user.chats).forEach((chat) => { - chat.userIds.forEach((userId) => { - const user = getActiveUser({ - email: userId, - loginId: userId, - }); - - if (!user) { - return; - } - - delete user.chats[chat.id]; - - // User does not have any open chats, so remove from active list - // So that the user can search for new buddies again - if (Object.values(user.chats).length == 0) { - delActiveUser(user); - io.to(user.emailOrLoginId).emit("inactive"); - } - }); - io.to(chat.id).emit("close", chat.id); - }); - } - }); - - socket.on("close", (chatId, setChatClosed) => { - const user = getActiveUser({ - socketId: socket.id, - }); - - if (!user || !user.chats[chatId]) { - setChatClosed(false); - return; - } - - const inactiveList = []; - - user.chats[chatId].userIds.forEach((userId) => { - const user = getActiveUser({ - email: userId, - loginId: userId, - }); - - if (!user) { - return; - } - - delete user.chats[chatId]; - - // User does not have any open chats, so remove from active list - // So that the user can search for new buddies again - if (Object.values(user.chats).length == 0) { - delActiveUser(user); - - if (!inactiveList.includes(user.emailOrLoginId)) { - inactiveList.push(user.emailOrLoginId); - } - } - }); - - setChatClosed(true); - socket.broadcast.to(chatId).emit("close", chatId); - inactiveList.forEach((emailOrLoginId) => { - socket.broadcast.to(emailOrLoginId).emit("inactive"); - }); - }); - // socket.on('adding', (data) => { - // if (data.userID.ID === '') return; - // userModule.allUsers(data.userID.ID); - // }); - - // socket.on('createRoom', () => { - // userModule.matchUsers(socket); - // }); +io.on('connection', (socket) => { + /** + * This event is emitted once the user clicks on the Start button or + * navigates to the /founduser route + */ + socket.on('join', ({ loginId, email }) => { + /** + * This is necessary to enable us send notifications to users + * using multiple devices to chat + */ + socket.join(loginId); + // Email is possibly null for anonymous users + if (email) { + socket.join(email); + } + + /** + * First we check if user is already chatting. + * If user is already chatting, continue chat from where the user left + */ + if (isUserActive(email ?? loginId)) { + const user = getActiveUser({ + socketId: socket.id, + loginId, + email: email ?? null, + }); + + // First join user to lost chat + socket.join(user.currentChatId); + user.socketConnections.push(socket); + user.socketIds.push(socket.id); + + // Then return all chat messages + socket.emit('chat_restore', { + chats: user.chats, + currentChatId: user.currentChatId, + }); + return; + } + + // User was not having any previous chat. So add to waiting list + addToWaitingList({ loginId, email, socket }); + + // Finally, run matchMaker to pair all users on the waiting list + matchMaker(io); + }); + + socket.on( + 'send_message', + ({ senderId, message, time, chatId }, returnMessageToSender) => { + // Below line is just a failed message simulator for testing purposes. + + // const rndInt = Math.floor(Math.random() * 6) + 1; + // if (rndInt % 2 !== 0) { + // return; + // } + + const user = getActiveUser({ + socketId: socket.id, + }); + + if (!user) { + socket.emit('send_failed', { + message: + 'Hmmm. It seems your login session has expired. ' + + 'Re-login and try again', + messageId: id, + }); + + return; + } + + const id = uuid.v4(); + + /** + * Cache the sent message for each user in the chat. + * This is also the point, where we persist the message in the db + */ + user.chats[chatId].userIds.forEach((userId) => { + const user = getActiveUser({ + email: userId, + loginId: userId, + }); + + if (user) { + user.chats[chatId].messages[id] = { + id, + message, + time, + senderId, + type: 'message', + }; + } + }); + + const sentMessage = { + senderId, + message, + time, + id, + room: chatId, + status: 'sent', + }; + + returnMessageToSender(sentMessage); + + socket.broadcast.to(chatId).emit('receive_message', sentMessage); + }, + ); + + socket.on( + 'delete_message', + ({ id: messageId, chatId }, messageWasDeletedSuccessfully) => { + const user = getActiveUser({ + socketId: socket.id, + }); + + if (!user || !messageId || !chatId) { + messageWasDeletedSuccessfully(false); + return; + } + + user.chats[chatId].userIds.forEach((userId) => { + const user = getActiveUser({ + email: userId, + loginId: userId, + }); + + if (user) { + delete user.chats[chatId].messages[messageId]; + } + }); + + socket.broadcast + .to(chatId) + .emit('delete_message', { id: messageId, chatId }); + messageWasDeletedSuccessfully(true); + }, + ); + + socket.on( + 'edit_message', + ({ id: messageId, chatId, newMessage }, messageWasEditedSuccessfully) => { + const user = getActiveUser({ + socketId: socket.id, + }); + + if (!user || !messageId || !chatId) { + messageWasEditedSuccessfully(false); + return; + } + + user.chats[chatId].userIds.forEach((userId) => { + const user = getActiveUser({ + email: userId, + loginId: userId, + }); + + if (user) { + user.chats[chatId].messages[messageId].message = newMessage; + } + }); + + socket.broadcast + .to(chatId) + .emit('edit_message', { id: messageId, chatId, newMessage }); + + messageWasEditedSuccessfully(true); + }, + ); + + socket.on('logout', () => { + const user = getActiveUser({ + socketId: socket.id, + }); + + if (!user) { + return; + } + + // User is an anonymous user, so close all active chats + if (!user.email) { + Object.values(user.chats).forEach((chat) => { + chat.userIds.forEach((userId) => { + const user = getActiveUser({ + email: userId, + loginId: userId, + }); + + if (!user) { + return; + } + + delete user.chats[chat.id]; + + // User does not have any open chats, so remove from active list + // So that the user can search for new buddies again + if (Object.values(user.chats).length == 0) { + delActiveUser(user); + io.to(user.emailOrLoginId).emit('inactive'); + } + }); + io.to(chat.id).emit('close', chat.id); + }); + } + }); + + socket.on('close', (chatId, setChatClosed) => { + const user = getActiveUser({ + socketId: socket.id, + }); + + if (!user || !user.chats[chatId]) { + setChatClosed(false); + return; + } + + const inactiveList = []; + + user.chats[chatId].userIds.forEach((userId) => { + const user = getActiveUser({ + email: userId, + loginId: userId, + }); + + if (!user) { + return; + } + + delete user.chats[chatId]; + + // User does not have any open chats, so remove from active list + // So that the user can search for new buddies again + if (Object.values(user.chats).length == 0) { + delActiveUser(user); + + if (!inactiveList.includes(user.emailOrLoginId)) { + inactiveList.push(user.emailOrLoginId); + } + } + }); + + setChatClosed(true); + socket.broadcast.to(chatId).emit('close', chatId); + inactiveList.forEach((emailOrLoginId) => { + socket.broadcast.to(emailOrLoginId).emit('inactive'); + }); + }); + // socket.on('adding', (data) => { + // if (data.userID.ID === '') return; + // userModule.allUsers(data.userID.ID); + // }); + + // socket.on('createRoom', () => { + // userModule.matchUsers(socket); + // }); }); app.use(cors());