diff --git a/frontend/src/ui/components/chat/ChatMessages.tsx b/frontend/src/ui/components/chat/ChatMessages.tsx index e718c6c..de1703e 100644 --- a/frontend/src/ui/components/chat/ChatMessages.tsx +++ b/frontend/src/ui/components/chat/ChatMessages.tsx @@ -23,11 +23,12 @@ export function ChatMessages() { message: null, position: { x: 0, y: 0 } }); + const [isContextMenuClosing, setIsContextMenuClosing] = useState(false); // Effect to handle clicks outside the context menu useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if (contextMenu.isOpen) { + if (contextMenu.isOpen && !isContextMenuClosing) { // Check if the click is on a context menu element const target = event.target as Element; if (!target.closest('.context-menu')) { @@ -37,14 +38,14 @@ export function ChatMessages() { }; const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === 'Escape' && contextMenu.isOpen) { + if (event.key === 'Escape' && contextMenu.isOpen && !isContextMenuClosing) { handleContextMenuClose(); } }; const handleWindowBlur = () => { // Close context menu when browser window loses focus - if (contextMenu.isOpen) { + if (contextMenu.isOpen && !isContextMenuClosing) { handleContextMenuClose(); } }; @@ -60,7 +61,7 @@ export function ChatMessages() { document.removeEventListener('keydown', handleKeyDown); window.removeEventListener('blur', handleWindowBlur); }; - }, [contextMenu.isOpen]); + }, [contextMenu.isOpen, isContextMenuClosing]); const handleProfileClick = async (username: string) => { if (!user.authToken) return; @@ -82,6 +83,7 @@ export function ChatMessages() { const handleContextMenu = (e: React.MouseEvent, message: MessageType) => { e.preventDefault(); console.log("Context menu triggered for message:", message.id, "at position:", e.clientX, e.clientY); + setIsContextMenuClosing(false); setContextMenu({ isOpen: true, message, @@ -90,11 +92,16 @@ export function ChatMessages() { }; const handleContextMenuClose = () => { - setContextMenu({ - isOpen: false, - message: null, - position: { x: 0, y: 0 } - }); + setIsContextMenuClosing(true); + // Wait for animation to complete before removing from DOM + setTimeout(() => { + setContextMenu({ + isOpen: false, + message: null, + position: { x: 0, y: 0 } + }); + setIsContextMenuClosing(false); + }, 200); // Match the animation duration from _animations.scss }; const handleEdit = async (message: MessageType) => { @@ -193,6 +200,7 @@ export function ChatMessages() { onDelete={handleDelete} onClose={handleContextMenuClose} position={contextMenu.position} + isClosing={isContextMenuClosing} /> )} diff --git a/frontend/src/ui/components/chat/MessageContextMenu.tsx b/frontend/src/ui/components/chat/MessageContextMenu.tsx index b7228f3..01329ad 100644 --- a/frontend/src/ui/components/chat/MessageContextMenu.tsx +++ b/frontend/src/ui/components/chat/MessageContextMenu.tsx @@ -11,6 +11,7 @@ interface MessageContextMenuProps { onDelete: (message: Message) => void; onClose: () => void; position: { x: number; y: number }; + isClosing: boolean; } export interface ContextMenuState { @@ -26,14 +27,14 @@ export function MessageContextMenu({ onReply, onDelete, onClose, - position + position, + isClosing }: MessageContextMenuProps) { console.log("MessageContextMenu rendered with position:", position, "message:", message.id); // Internal state for dialogs const [editDialogOpen, setEditDialogOpen] = useState(false); const [replyDialogOpen, setReplyDialogOpen] = useState(false); - const [isClosing, setIsClosing] = useState(false); const handleAction = (action: string) => { console.log("Context menu action triggered:", action); @@ -49,20 +50,12 @@ export function MessageContextMenu({ case "delete": if (isAuthor) { onDelete(message); - handleClose(); + onClose(); } break; } }; - const handleClose = () => { - setIsClosing(true); - // Wait for animation to complete before calling onClose - setTimeout(() => { - onClose(); - }, 200); // Match the animation duration from _animations.scss - }; - const handleEditSave = (messageId: number, newContent: string) => { // Create a temporary message object with the updated content const updatedMessage = { ...message, content: newContent };