Fix dialog click closing the context menu

This commit is contained in:
2025-09-04 21:55:28 +03:00
Unverified
parent 3194379eb1
commit 46dd8887cc
7 changed files with 142 additions and 162 deletions
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import type { Message } from "../../../core/types";
import { EditMessageDialog } from "./EditMessageDialog";
import { ReplyMessageDialog } from "./ReplyMessageDialog";
@@ -9,9 +9,9 @@ interface MessageContextMenuProps {
onEdit: (message: Message) => void;
onReply: (message: Message) => void;
onDelete: (message: Message) => void;
onClose: () => void;
position: { x: number; y: number };
isClosing: boolean;
isOpen: boolean;
onOpenChange: (isOpen: boolean) => void;
}
export interface ContextMenuState {
@@ -26,15 +26,54 @@ export function MessageContextMenu({
onEdit,
onReply,
onDelete,
onClose,
position,
isClosing
isOpen,
onOpenChange
}: MessageContextMenuProps) {
console.log("MessageContextMenu rendered with position:", position, "message:", message.id);
// Internal state for dialogs
// Internal state for dialogs and closing animation
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [replyDialogOpen, setReplyDialogOpen] = useState(false);
const [isClosing, setIsClosing] = useState(false);
// Effect to handle clicks outside the context menu
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (isOpen && !isClosing && !editDialogOpen && !replyDialogOpen) {
// Check if the click is on a context menu element
const target = event.target as Element;
if (!target.closest('.context-menu')) {
handleClose();
}
}
};
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && isOpen && !isClosing && !editDialogOpen && !replyDialogOpen) {
handleClose();
}
};
const handleWindowBlur = () => {
// Close context menu when browser window loses focus
if (isOpen && !isClosing && !editDialogOpen && !replyDialogOpen) {
handleClose();
}
};
// Add event listeners
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('keydown', handleKeyDown);
window.addEventListener('blur', handleWindowBlur);
// Cleanup
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('keydown', handleKeyDown);
window.removeEventListener('blur', handleWindowBlur);
};
}, [isOpen, isClosing, editDialogOpen, replyDialogOpen]);
const handleAction = (action: string) => {
console.log("Context menu action triggered:", action);
@@ -50,12 +89,21 @@ export function MessageContextMenu({
case "delete":
if (isAuthor) {
onDelete(message);
onClose();
handleClose();
}
break;
}
};
const handleClose = () => {
setIsClosing(true);
// Wait for animation to complete before calling onOpenChange
setTimeout(() => {
onOpenChange(false);
setIsClosing(false);
}, 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 };
@@ -70,36 +118,45 @@ export function MessageContextMenu({
setReplyDialogOpen(false);
};
const content = (
<div
className={`context-menu ${isClosing ? 'closing' : 'entering'}`}
style={{
position: "fixed",
display: "block",
top: position.y,
left: position.x,
zIndex: 1000
}}
onClick={(e) => e.stopPropagation()}
>
<div className="context-menu-item" onClick={() => handleAction("reply")}>
<span className="material-symbols">reply</span>
Reply
</div>
{isAuthor && (
<>
<div className="context-menu-item" onClick={() => handleAction("edit")}>
<span className="material-symbols">edit</span>
Edit
</div>
<div className="context-menu-item" onClick={() => handleAction("delete")}>
<span className="material-symbols">delete</span>
Delete
</div>
</>
)}
</div>
)
// Don't render if not open
if (!isOpen && !editDialogOpen && !replyDialogOpen) return null;
return (
<>
<div
className={`context-menu ${isClosing ? 'closing' : 'entering'}`}
style={{
position: "fixed",
display: "block",
top: position.y,
left: position.x,
zIndex: 1000
}}
onClick={(e) => e.stopPropagation()}
>
<div className="context-menu-item" onClick={() => handleAction("reply")}>
<span className="material-symbols">reply</span>
Reply
</div>
{isAuthor && (
<>
<div className="context-menu-item" onClick={() => handleAction("edit")}>
<span className="material-symbols">edit</span>
Edit
</div>
<div className="context-menu-item" onClick={() => handleAction("delete")}>
<span className="material-symbols">delete</span>
Delete
</div>
</>
)}
</div>
{isOpen ? content : null}
{/* Edit Dialog */}
<EditMessageDialog