diff --git a/client/src/components/Chat/DropDownOption.jsx b/client/src/components/Chat/DropDownOption.jsx index 227f5ad9..95323634 100644 --- a/client/src/components/Chat/DropDownOption.jsx +++ b/client/src/components/Chat/DropDownOption.jsx @@ -1,7 +1,7 @@ import { BiDotsVerticalRounded } from 'react-icons/bi'; import Dropdown from 'rsuite/Dropdown'; import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useMemo } from 'react'; import chatHelper from 'src/lib/chatHelper'; import { socket } from 'src/lib/socketConnection'; import { useApp } from 'src/context/AppContext'; @@ -9,6 +9,9 @@ import { useChat } from 'src/context/ChatContext'; import useChatUtils from 'src/lib/chatSocket'; import useCryptoKeys from 'src/hooks/useCryptoKeys'; +import { FIFTEEN_MINUTES } from '../../../../constants.json'; + + const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setReplyId }) => { const { app } = useApp(); @@ -17,7 +20,17 @@ const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setRe const { getMessage, messageExists, handleCopyToClipBoard } = chatHelper(state, app); const { deleteMessage } = useChatUtils(socket); + const message = getMessage(id, state, app); + + const isWithin15Minutes = useMemo(() => { + return Date.now() - new Date(message.time).getTime() <= FIFTEEN_MINUTES; + }, [message.time]) + const handleEdit = (id) => { + if (!isWithin15Minutes) { + return; + } + inputRef.current.focus(); const { message } = getMessage(id, state, app); @@ -31,7 +44,7 @@ const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setRe }; const handleDelete = async (id) => { - if (!messageExists(id)) { + if (!messageExists(id) || !isWithin15Minutes) { return; } @@ -78,13 +91,22 @@ const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setRe renderToggle={renderIconButton} NoCaret > - handleEdit(id)}>Edit + { + isWithin15Minutes && ( + handleEdit(id)}>Edit + ) + } handleCopyToClipBoard(id, importedPrivateKey)}> Copy setReplyId(id)}>Reply - handleDelete(id)}>Delete + + { + isWithin15Minutes && ( + handleDelete(id)}>Delete + ) + } ); } else if (!isSender) { diff --git a/constants.json b/constants.json index 86d599a7..831af1f5 100644 --- a/constants.json +++ b/constants.json @@ -19,5 +19,7 @@ "NEW_EVENT_CREATE_ROOM": "createRoom", "NEW_EVENT_READ_MESSAGE": "read_message", "NEW_EVENT_ONLINE_STATUS": "online_status", - "NEW_EVENT_REQUEST_PUBLIC_KEY": "requestPublicKey" + "NEW_EVENT_REQUEST_PUBLIC_KEY": "requestPublicKey", + + "FIFTEEN_MINUTES": 900000 } \ No newline at end of file diff --git a/server/sockets/deleteMessage.js b/server/sockets/deleteMessage.js index 756ecc21..b81af4c7 100644 --- a/server/sockets/deleteMessage.js +++ b/server/sockets/deleteMessage.js @@ -1,5 +1,5 @@ const { NEW_EVENT_DELETE_MESSAGE } = require('../../constants.json'); -const { getActiveUser, removeMessage } = require('../utils/lib'); +const { getActiveUser, removeMessage, isMessageEditableOrDeletable } = require('../utils/lib'); module.exports = (socket) => { socket.on( @@ -14,6 +14,12 @@ module.exports = (socket) => { return; } + // Check if message exists and is within the 15-minute editable window + if (!isMessageEditableOrDeletable(chatId, messageId)) { + messageWasDeletedSuccessfully(false); + return; + } + const messageDeleted = await removeMessage(chatId, messageId); socket.broadcast diff --git a/server/sockets/editMessage.js b/server/sockets/editMessage.js index 8136223b..a8b94844 100644 --- a/server/sockets/editMessage.js +++ b/server/sockets/editMessage.js @@ -17,6 +17,12 @@ module.exports = (socket) => { return; } + // Check if message exists and is within the 15-minute editable window + if (!isMessageEditableOrDeletable(chatId, messageId)) { + messageWasEditedSuccessfully(false); + return; + } + const messageEdited = await editMessage(chatId, { id: messageId, message: newMessage, diff --git a/server/utils/lib.js b/server/utils/lib.js index dc679010..3a741205 100644 --- a/server/utils/lib.js +++ b/server/utils/lib.js @@ -8,6 +8,9 @@ const User = require('../models/UserModel'); const Message = require('../models/MessageModel'); const { generateObjectId } = require('./helper'); +const { FIFTEEN_MINUTES } = require('../../constants.json'); + + /** * @typedef {{ * id: string, @@ -532,6 +535,17 @@ async function isUserBlocked(users) { } } + function isMessageEditableOrDeletable(chatId, messageId) { + const chat = chats[chatId]; + if (!chat || !chat.messages || !chat.messages[messageId]) { + return false; // Message doesn't exist + } + + const message = chat.messages[messageId]; + const timeSinceCreated = Date.now() - new Date(message.time).getTime(); + return timeSinceCreated <= FIFTEEN_MINUTES; // Check if within 15 minutes +} + module.exports = { init, createChat, @@ -552,5 +566,6 @@ module.exports = { delActiveUser, seenMessage, blockUser, - isUserBlocked + isUserBlocked, + isMessageEditableOrDeletable };