diff --git a/src/MessageQueueContext.tsx b/src/MessageQueueContext.tsx
index 499b10b..3727b03 100644
--- a/src/MessageQueueContext.tsx
+++ b/src/MessageQueueContext.tsx
@@ -53,6 +53,7 @@ export const MessageQueueProvider = ({ children }) => {
// Function to process the message queue
const processQueue = useCallback((newMessages = [], groupDirectId) => {
+
processingPromiseRef.current = processingPromiseRef.current
.then(() => processQueueInternal(newMessages, groupDirectId))
.catch((err) => console.error('Error in processQueue:', err));
@@ -61,33 +62,7 @@ export const MessageQueueProvider = ({ children }) => {
// Internal function to handle queue processing
const processQueueInternal = async (newMessages, groupDirectId) => {
// Remove any messages from the queue that match the specialId from newMessages
- if (newMessages.length > 0) {
- messageQueueRef.current = messageQueueRef.current.filter((msg) => {
- return !newMessages.some(newMsg => newMsg?.specialId === msg?.specialId);
- });
-
- // Remove corresponding entries in queueChats for the provided groupDirectId
- setQueueChats((prev) => {
- const updatedChats = { ...prev };
- if (updatedChats[groupDirectId]) {
- updatedChats[groupDirectId] = updatedChats[groupDirectId].filter((chat) => {
- return !newMessages.some(newMsg => newMsg?.specialId === chat?.message?.specialId);
- });
-
- // Remove messages with status 'failed-permanent'
- updatedChats[groupDirectId] = updatedChats[groupDirectId].filter((chat) => {
- return chat?.status !== 'failed-permanent';
- });
-
- // If no more chats for this group, delete the groupDirectId entry
- if (updatedChats[groupDirectId].length === 0) {
- delete updatedChats[groupDirectId];
- }
- }
- return updatedChats;
- });
- }
-
+
// If the queue is empty, no need to process
if (messageQueueRef.current.length === 0) return;
@@ -112,11 +87,11 @@ export const MessageQueueProvider = ({ children }) => {
try {
// Execute the function stored in the messageQueueRef
+
await currentMessage.func();
// Remove the message from the queue after successful sending
messageQueueRef.current.shift();
-
// Remove the message from queueChats
setQueueChats((prev) => {
const updatedChats = { ...prev };
@@ -167,7 +142,33 @@ export const MessageQueueProvider = ({ children }) => {
// Method to process with new messages and groupDirectId
const processWithNewMessages = (newMessages, groupDirectId) => {
- processQueue(newMessages, groupDirectId);
+ if (newMessages.length > 0) {
+ messageQueueRef.current = messageQueueRef.current.filter((msg) => {
+ return !newMessages.some(newMsg => newMsg?.specialId === msg?.specialId);
+ });
+
+ // Remove corresponding entries in queueChats for the provided groupDirectId
+ setQueueChats((prev) => {
+ const updatedChats = { ...prev };
+ if (updatedChats[groupDirectId]) {
+ updatedChats[groupDirectId] = updatedChats[groupDirectId].filter((chat) => {
+ return !newMessages.some(newMsg => newMsg?.specialId === chat?.message?.specialId);
+ });
+
+ // Remove messages with status 'failed-permanent'
+ updatedChats[groupDirectId] = updatedChats[groupDirectId].filter((chat) => {
+ return chat?.status !== 'failed-permanent';
+ });
+
+ // If no more chats for this group, delete the groupDirectId entry
+ if (updatedChats[groupDirectId].length === 0) {
+ delete updatedChats[groupDirectId];
+ }
+ }
+ return updatedChats;
+ });
+ }
+
};
return (
diff --git a/src/common/ErrorBoundary.tsx b/src/common/ErrorBoundary.tsx
new file mode 100644
index 0000000..58b3185
--- /dev/null
+++ b/src/common/ErrorBoundary.tsx
@@ -0,0 +1,36 @@
+import React, { ReactNode } from 'react'
+
+interface ErrorBoundaryProps {
+ children: ReactNode
+ fallback: ReactNode
+}
+
+interface ErrorBoundaryState {
+ hasError: boolean
+}
+
+class ErrorBoundary extends React.Component<
+ ErrorBoundaryProps,
+ ErrorBoundaryState
+> {
+ state: ErrorBoundaryState = {
+ hasError: false
+ }
+
+ static getDerivedStateFromError(_: Error): ErrorBoundaryState {
+ return { hasError: true }
+ }
+
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
+ // You can log the error and errorInfo here, for example, to an error reporting service.
+ console.error('Error caught in ErrorBoundary:', error, errorInfo)
+ }
+
+ render(): React.ReactNode {
+ if (this.state.hasError) return this.props.fallback
+
+ return this.props.children
+ }
+}
+
+export default ErrorBoundary
diff --git a/src/components/Chat/ChatDirect.tsx b/src/components/Chat/ChatDirect.tsx
index 634c83d..ab88847 100644
--- a/src/components/Chat/ChatDirect.tsx
+++ b/src/components/Chat/ChatDirect.tsx
@@ -28,6 +28,7 @@ const uid = new ShortUniqueId({ length: 5 });
export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance, close, setMobileViewModeKeepOpen}) => {
const { queueChats, addToQueue, processWithNewMessages} = useMessageQueue();
const [isFocusedParent, setIsFocusedParent] = useState(false);
+ const [onEditMessage, setOnEditMessage] = useState(null)
const [messages, setMessages] = useState([])
const [isSending, setIsSending] = useState(false)
@@ -38,6 +39,8 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
const [infoSnack, setInfoSnack] = React.useState(null);
const [publicKeyOfRecipient, setPublicKeyOfRecipient] = React.useState("")
const hasInitializedWebsocket = useRef(false)
+ const [chatReferences, setChatReferences] = useState({})
+
const editorRef = useRef(null);
const socketRef = useRef(null);
const timeoutIdRef = useRef(null);
@@ -66,10 +69,19 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
const tempMessages = useMemo(()=> {
if(!selectedDirect?.address) return []
if(queueChats[selectedDirect?.address]){
- return queueChats[selectedDirect?.address]
+ return queueChats[selectedDirect?.address]?.filter((item)=> !item?.chatReference)
}
return []
}, [selectedDirect?.address, queueChats])
+
+ const tempChatReferences = useMemo(()=> {
+ if(!selectedDirect?.address) return []
+ if(queueChats[selectedDirect?.address]){
+ return queueChats[selectedDirect?.address]?.filter((item)=> !!item?.chatReference)
+ }
+ return []
+ }, [selectedDirect?.address, queueChats])
+
useEffect(()=> {
if(selectedDirect?.address){
publicKeyOfRecipientRef.current = selectedDirect?.address
@@ -112,22 +124,54 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
res(response);
if (isInitiated) {
- const formatted = response.map((item) => ({
+ const formatted = response.filter((rawItem) => !rawItem?.chatReference).map((item) => ({
...item,
id: item.signature,
text: item.message,
unread: item?.sender === myAddress ? false : true,
}));
setMessages((prev) => [...prev, ...formatted]);
+ setChatReferences((prev) => {
+ const organizedChatReferences = { ...prev };
+
+ response.filter((rawItem) => !!rawItem?.chatReference && rawItem?.type === 'edit').forEach((item) => {
+ try {
+ organizedChatReferences[item.chatReference] = {
+ ...(organizedChatReferences[item.chatReference] || {}),
+ edit: item
+ };
+ } catch(error){
+
+ }
+ })
+ return organizedChatReferences
+ })
} else {
- const formatted = response.map((item) => ({
+ hasInitialized.current = true;
+ const formatted = response.filter((rawItem) => !rawItem?.chatReference)
+ .map((item) => ({
...item,
id: item.signature,
text: item.message,
unread: false,
}));
setMessages(formatted);
- hasInitialized.current = true;
+
+ setChatReferences((prev) => {
+ const organizedChatReferences = { ...prev };
+
+ response.filter((rawItem) => !!rawItem?.chatReference && rawItem?.type === 'edit').forEach((item) => {
+ try {
+ organizedChatReferences[item.chatReference] = {
+ ...(organizedChatReferences[item.chatReference] || {}),
+ edit: item
+ };
+ } catch(error){
+
+ }
+ })
+ return organizedChatReferences
+ })
}
return;
}
@@ -333,7 +377,7 @@ useEffect(() => {
const sendMessage = async ()=> {
try {
-
+
if(+balance < 4) throw new Error('You need at least 4 QORT to send a message')
if(isSending) return
@@ -355,12 +399,16 @@ useEffect(() => {
if (replyMessage?.chatReference) {
repliedTo = replyMessage?.chatReference
}
+ let chatReference = onEditMessage?.signature
+
const otherData = {
+ ...(onEditMessage?.decryptedData || {}),
specialId: uid.rnd(),
- repliedTo
+ repliedTo: onEditMessage ? onEditMessage?.repliedTo : repliedTo,
+ type: chatReference ? 'edit' : ''
}
const sendMessageFunc = async () => {
- return await sendChatDirect({ chatReference: undefined, messageText: htmlContent, otherData}, selectedDirect?.address, publicKeyOfRecipient, false)
+ return await sendChatDirect({ chatReference, messageText: htmlContent, otherData}, selectedDirect?.address, publicKeyOfRecipient, false)
};
@@ -368,13 +416,13 @@ useEffect(() => {
// Add the function to the queue
const messageObj = {
message: {
- text: htmlContent,
timestamp: Date.now(),
senderName: myName,
sender: myAddress,
- ...(otherData || {})
+ ...(otherData || {}),
+ text: htmlContent,
},
-
+ chatReference
}
addToQueue(sendMessageFunc, messageObj, 'chat-direct',
selectedDirect?.address );
@@ -383,6 +431,8 @@ useEffect(() => {
}, 150);
clearEditorContent()
setReplyMessage(null)
+ setOnEditMessage(null)
+
}
// send chat message
} catch (error) {
@@ -399,12 +449,22 @@ useEffect(() => {
}
}
- const onReply = useCallback((message)=> {
- setReplyMessage(message)
- editorRef?.current?.chain().focus()
-
- }, [])
-
+ const onReply = useCallback((message)=> {
+ if(onEditMessage){
+ editorRef.current.chain().focus().clearContent().run()
+ }
+ setReplyMessage(message)
+ setOnEditMessage(null)
+ editorRef?.current?.chain().focus()
+ }, [onEditMessage])
+
+
+ const onEdit = useCallback((message)=> {
+ setOnEditMessage(message)
+ setReplyMessage(null)
+ editorRef.current.chain().focus().setContent(message?.text).run();
+
+ }, [])
return (
{
>
)}
-
+
{
{
setReplyMessage(null)
+ setOnEditMessage(null)
+
+ }}
+ >
+
+
+
+ )}
+ {onEditMessage && (
+
+
+
+ {
+ setReplyMessage(null)
+ setOnEditMessage(null)
+
+ editorRef.current.chain().focus().clearContent().run()
+
}}
>
diff --git a/src/components/Chat/ChatGroup.tsx b/src/components/Chat/ChatGroup.tsx
index aa0b01e..3222d87 100644
--- a/src/components/Chat/ChatGroup.tsx
+++ b/src/components/Chat/ChatGroup.tsx
@@ -35,6 +35,9 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
const hasInitialized = useRef(false)
const [isFocusedParent, setIsFocusedParent] = useState(false);
const [replyMessage, setReplyMessage] = useState(null)
+ const [onEditMessage, setOnEditMessage] = useState(null)
+
+
const [messageSize, setMessageSize] = useState(0)
const hasInitializedWebsocket = useRef(false)
const socketRef = useRef(null); // WebSocket reference
@@ -218,52 +221,59 @@ const [messageSize, setMessageSize] = useState(0)
setChatReferences((prev) => {
const organizedChatReferences = { ...prev };
-
combineUIAndExtensionMsgs
- .filter((rawItem) => rawItem && rawItem.chatReference && rawItem.decryptedData?.type === "reaction")
+ .filter((rawItem) => rawItem && rawItem.chatReference && (rawItem.decryptedData?.type === "reaction" || rawItem.decryptedData?.type === "edit"))
.forEach((item) => {
try {
- const content = item.decryptedData?.content;
- const sender = item.sender;
- const newTimestamp = item.timestamp;
- const contentState = item.decryptedData?.contentState;
-
- if (!content || typeof content !== "string" || !sender || typeof sender !== "string" || !newTimestamp) {
- console.warn("Invalid content, sender, or timestamp in reaction data", item);
- return;
- }
-
- organizedChatReferences[item.chatReference] = {
- ...(organizedChatReferences[item.chatReference] || {}),
- reactions: organizedChatReferences[item.chatReference]?.reactions || {},
- };
-
- organizedChatReferences[item.chatReference].reactions[content] =
- organizedChatReferences[item.chatReference].reactions[content] || [];
-
- let latestTimestampForSender = null;
-
- organizedChatReferences[item.chatReference].reactions[content] =
- organizedChatReferences[item.chatReference].reactions[content].filter((reaction) => {
- if (reaction.sender === sender) {
- latestTimestampForSender = Math.max(latestTimestampForSender || 0, reaction.timestamp);
- }
- return reaction.sender !== sender;
- });
-
- if (latestTimestampForSender && newTimestamp < latestTimestampForSender) {
- return;
- }
-
- if (contentState !== false) {
- organizedChatReferences[item.chatReference].reactions[content].push(item);
- }
-
- if (organizedChatReferences[item.chatReference].reactions[content].length === 0) {
- delete organizedChatReferences[item.chatReference].reactions[content];
+ if(item.decryptedData?.type === "edit"){
+ organizedChatReferences[item.chatReference] = {
+ ...(organizedChatReferences[item.chatReference] || {}),
+ edit: item.decryptedData,
+ };
+ } else {
+ const content = item.decryptedData?.content;
+ const sender = item.sender;
+ const newTimestamp = item.timestamp;
+ const contentState = item.decryptedData?.contentState;
+
+ if (!content || typeof content !== "string" || !sender || typeof sender !== "string" || !newTimestamp) {
+ console.warn("Invalid content, sender, or timestamp in reaction data", item);
+ return;
+ }
+
+ organizedChatReferences[item.chatReference] = {
+ ...(organizedChatReferences[item.chatReference] || {}),
+ reactions: organizedChatReferences[item.chatReference]?.reactions || {},
+ };
+
+ organizedChatReferences[item.chatReference].reactions[content] =
+ organizedChatReferences[item.chatReference].reactions[content] || [];
+
+ let latestTimestampForSender = null;
+
+ organizedChatReferences[item.chatReference].reactions[content] =
+ organizedChatReferences[item.chatReference].reactions[content].filter((reaction) => {
+ if (reaction.sender === sender) {
+ latestTimestampForSender = Math.max(latestTimestampForSender || 0, reaction.timestamp);
+ }
+ return reaction.sender !== sender;
+ });
+
+ if (latestTimestampForSender && newTimestamp < latestTimestampForSender) {
+ return;
+ }
+
+ if (contentState !== false) {
+ organizedChatReferences[item.chatReference].reactions[content].push(item);
+ }
+
+ if (organizedChatReferences[item.chatReference].reactions[content].length === 0) {
+ delete organizedChatReferences[item.chatReference].reactions[content];
+ }
}
+
} catch (error) {
- console.error("Error processing reaction item:", error, item);
+ console.error("Error processing reaction/edit item:", error, item);
}
});
@@ -295,9 +305,15 @@ const [messageSize, setMessageSize] = useState(0)
const organizedChatReferences = { ...prev };
combineUIAndExtensionMsgs
- .filter((rawItem) => rawItem && rawItem.chatReference && rawItem.decryptedData?.type === "reaction")
+ .filter((rawItem) => rawItem && rawItem.chatReference && (rawItem.decryptedData?.type === "reaction" || rawItem.decryptedData?.type === "edit"))
.forEach((item) => {
try {
+ if(item.decryptedData?.type === "edit"){
+ organizedChatReferences[item.chatReference] = {
+ ...(organizedChatReferences[item.chatReference] || {}),
+ edit: item.decryptedData,
+ };
+ } else {
const content = item.decryptedData?.content;
const sender = item.sender;
const newTimestamp = item.timestamp;
@@ -337,6 +353,7 @@ const [messageSize, setMessageSize] = useState(0)
if (organizedChatReferences[item.chatReference].reactions[content].length === 0) {
delete organizedChatReferences[item.chatReference].reactions[content];
}
+ }
} catch (error) {
console.error("Error processing reaction item:", error, item);
}
@@ -549,13 +566,17 @@ const clearEditorContent = () => {
if (replyMessage?.chatReference) {
repliedTo = replyMessage?.chatReference
}
+ let chatReference = onEditMessage?.signature
+
const otherData = {
+ repliedTo,
+ ...(onEditMessage?.decryptedData || {}),
+ type: chatReference ? 'edit' : '',
specialId: uid.rnd(),
- repliedTo
}
const objectMessage = {
- message,
- ...(otherData || {})
+ ...(otherData || {}),
+ message
}
const message64: any = await objectToBase64(objectMessage)
@@ -563,7 +584,7 @@ const clearEditorContent = () => {
// const res = await sendChatGroup({groupId: selectedGroup,messageText: encryptSingle})
const sendMessageFunc = async () => {
- return await sendChatGroup({groupId: selectedGroup,messageText: encryptSingle})
+ return await sendChatGroup({groupId: selectedGroup,messageText: encryptSingle, chatReference})
};
// Add the function to the queue
@@ -575,7 +596,7 @@ const clearEditorContent = () => {
sender: myAddress,
...(otherData || {})
},
-
+ chatReference
}
addToQueue(sendMessageFunc, messageObj, 'chat',
selectedGroup );
@@ -584,6 +605,7 @@ const clearEditorContent = () => {
}, 150);
clearEditorContent()
setReplyMessage(null)
+ setOnEditMessage(null)
}
// send chat message
} catch (error) {
@@ -627,10 +649,21 @@ const clearEditorContent = () => {
}, [hide]);
const onReply = useCallback((message)=> {
+ if(onEditMessage){
+ editorRef.current.chain().focus().clearContent().run()
+ }
setReplyMessage(message)
+ setOnEditMessage(null)
editorRef?.current?.chain().focus()
- }, [])
+ }, [onEditMessage])
+
+ const onEdit = useCallback((message)=> {
+ setOnEditMessage(message)
+ setReplyMessage(null)
+ editorRef.current.chain().focus().setContent(message?.text).run();
+
+ }, [])
const handleReaction = useCallback(async (reaction, chatMessage, reactionState = true)=> {
try {
@@ -708,7 +741,7 @@ const clearEditorContent = () => {
left: hide && '-100000px',
}}>
-
+
{
{
setReplyMessage(null)
+
+ setOnEditMessage(null)
+
+ }}
+ >
+
+
+
+ )}
+ {onEditMessage && (
+
+
+
+ {
+ setReplyMessage(null)
+ setOnEditMessage(null)
+
+ editorRef.current.chain().focus().clearContent().run()
+
}}
>
diff --git a/src/components/Chat/ChatList.tsx b/src/components/Chat/ChatList.tsx
index eec5530..6e0e59a 100644
--- a/src/components/Chat/ChatList.tsx
+++ b/src/components/Chat/ChatList.tsx
@@ -9,8 +9,9 @@ import { useVirtualizer } from "@tanstack/react-virtual";
import { MessageItem } from "./MessageItem";
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
import { useInView } from "react-intersection-observer";
-import { Box } from "@mui/material";
+import { Box, Typography } from "@mui/material";
import { ChatOptions } from "./ChatOptions";
+import ErrorBoundary from "../../common/ErrorBoundary";
export const ChatList = ({
initialMessages,
@@ -18,6 +19,7 @@ export const ChatList = ({
tempMessages,
chatId,
onReply,
+ onEdit,
handleReaction,
chatReferences,
tempChatReferences,
@@ -155,7 +157,6 @@ export const ChatList = ({
// Check if the user is within 200px from the bottom
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
- console.log("distanceFromBottom", distanceFromBottom);
if (distanceFromBottom <= 700) {
scrollToBottom();
}
@@ -177,7 +178,6 @@ export const ChatList = ({
const goToMessage = useCallback((idx) => {
rowVirtualizer.scrollToIndex(idx);
}, []);
-
return (
+
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const index = virtualRow.index;
- let message = messages[index];
- let replyIndex = messages.findIndex(
- (msg) => msg?.signature === message?.repliedTo
- );
- let reply;
+ let message = messages[index] || null; // Safeguard against undefined
+ let replyIndex = -1;
+ let reply = null;
let reactions = null;
-
- if (message?.repliedTo && replyIndex !== -1) {
- reply = messages[replyIndex];
- }
-
- if (message?.message && message?.groupDirectId) {
- replyIndex = messages.findIndex(
- (msg) => msg?.signature === message?.message?.repliedTo
- );
- if (message?.message?.repliedTo && replyIndex !== -1) {
- reply = messages[replyIndex];
- }
- message = {
- ...(message?.message || {}),
- isTemp: true,
- unread: false,
- status: message?.status,
- };
- }
-
- if (chatReferences && chatReferences[message?.signature]) {
- if (chatReferences[message.signature]?.reactions) {
- reactions = chatReferences[message.signature]?.reactions;
- }
- }
-
let isUpdating = false;
- if (
- tempChatReferences &&
- tempChatReferences?.find(
- (item) => item?.chatReference === message?.signature
- )
- ) {
- isUpdating = true;
+
+ try {
+ // Safeguard for message existence
+ if (message) {
+ // Check for repliedTo logic
+ replyIndex = messages.findIndex(
+ (msg) => msg?.signature === message?.repliedTo
+ );
+
+ if (message?.repliedTo && replyIndex !== -1) {
+ reply = { ...(messages[replyIndex] || {}) };
+ if (chatReferences?.[reply?.signature]?.edit) {
+ reply.decryptedData = chatReferences[reply?.signature]?.edit;
+ reply.text = chatReferences[reply?.signature]?.edit?.message;
+ }
+ }
+
+ // GroupDirectId logic
+ if (message?.message && message?.groupDirectId) {
+ replyIndex = messages.findIndex(
+ (msg) => msg?.signature === message?.message?.repliedTo
+ );
+ if (message?.message?.repliedTo && replyIndex !== -1) {
+ reply = messages[replyIndex] || null;
+ }
+ message = {
+ ...(message?.message || {}),
+ isTemp: true,
+ unread: false,
+ status: message?.status,
+ };
+ }
+
+ // Check for reactions and edits
+ if (chatReferences?.[message.signature]) {
+ reactions = chatReferences[message.signature]?.reactions || null;
+
+ if (chatReferences[message.signature]?.edit?.message && message?.text) {
+ message.text = chatReferences[message.signature]?.edit?.message;
+ message.isEdit = true
+ }
+
+
+ }
+
+ // Check if message is updating
+ if (
+ tempChatReferences?.some(
+ (item) => item?.chatReference === message?.signature
+ )
+ ) {
+ isUpdating = true;
+ }
+ }
+ } catch (error) {
+ console.error("Error processing message:", error, { index, message });
+ // Gracefully handle the error by providing fallback data
+ message = null;
+ reply = null;
+ reactions = null;
}
+ // Render fallback if message is null
+ if (!message) {
+ return (
+
+ Error loading message.
+
+ );
+ }
+
return (
+
+ Error loading content: Invalid Data
+
+ }
+ >
+
);
})}
+
diff --git a/src/components/Chat/MessageItem.tsx b/src/components/Chat/MessageItem.tsx
index 51427ae..47d4417 100644
--- a/src/components/Chat/MessageItem.tsx
+++ b/src/components/Chat/MessageItem.tsx
@@ -16,6 +16,8 @@ import ReplyIcon from "@mui/icons-material/Reply";
import { Spacer } from "../../common/Spacer";
import { ReactionPicker } from "../ReactionPicker";
import KeyOffIcon from '@mui/icons-material/KeyOff';
+import EditIcon from '@mui/icons-material/Edit';
+
export const MessageItem = ({
message,
onSeen,
@@ -30,7 +32,8 @@ export const MessageItem = ({
handleReaction,
reactions,
isUpdating,
- lastSignature
+ lastSignature,
+ onEdit
}) => {
const { ref, inView } = useInView({
threshold: 0.7, // Fully visible
@@ -46,6 +49,7 @@ export const MessageItem = ({
}, [inView, message.id, isLast]);
+
return (
<>
{message?.divide && (
@@ -130,6 +134,15 @@ export const MessageItem = ({
gap: '10px',
alignItems: 'center'
}}>
+ {message?.sender === myAddress && !message?.isNotEncrypted && (
+ {
+ onEdit(message);
+ }}
+ >
+
+
+ )}
{!isShowingAsReply && (
{
@@ -289,6 +302,19 @@ export const MessageItem = ({
{message?.status === 'failed-permanent' ? 'Failed to send' : 'Sending...'}
) : (
+ <>
+ {message?.isEdit && (
+
+ Edited
+
+ )}
{formatTimestamp(message.timestamp)}
+ >
)}
@@ -320,7 +347,7 @@ export const MessageItem = ({
};
-export const ReplyPreview = ({message})=> {
+export const ReplyPreview = ({message, isEdit})=> {
return (
{
- Replied to {message?.senderName || message?.senderAddress}
+ {isEdit ? (
+ Editing Message
+ ) : (
+ Replied to {message?.senderName || message?.senderAddress}
+ )}
+
{message?.messageText && (