diff --git a/frontend/src/ui/components/chat/ChatInputWrapper.tsx b/frontend/src/ui/components/chat/ChatInputWrapper.tsx
index 0f5ad47..8833746 100644
--- a/frontend/src/ui/components/chat/ChatInputWrapper.tsx
+++ b/frontend/src/ui/components/chat/ChatInputWrapper.tsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { RichTextArea } from "../core/RichTextArea";
import type { Message } from "../../../core/types";
import Quote from "../core/Quote";
@@ -6,27 +6,57 @@ import AnimatedHeight from "../core/animations/AnimatedHeight";
interface ChatInputWrapperProps {
onSendMessage: (message: string) => void;
+ onSaveEdit?: (content: string) => void;
replyTo?: Message | null;
replyToVisible: boolean;
onClearReply?: () => void;
onCloseReply?: () => void;
+ editingMessage?: Message | null;
+ editVisible?: boolean;
+ onClearEdit?: () => void;
+ onCloseEdit?: () => void;
}
-export function ChatInputWrapper({ onSendMessage, replyTo, replyToVisible, onClearReply, onCloseReply }: ChatInputWrapperProps) {
+export function ChatInputWrapper({ onSendMessage, onSaveEdit, replyTo, replyToVisible, onClearReply, onCloseReply, editingMessage, editVisible = false, onClearEdit, onCloseEdit }: ChatInputWrapperProps) {
const [message, setMessage] = useState("");
+ // When entering edit mode, preload the message content
+ useEffect(() => {
+ if (editingMessage) {
+ setMessage(editingMessage.content || "");
+ }
+ }, [editingMessage]);
+
const handleSubmit = async (e: React.FormEvent | Event) => {
e.preventDefault();
if (message.trim()) {
- onSendMessage(message);
- setMessage("");
- if (onClearReply) onClearReply();
+ if (editingMessage && onSaveEdit) {
+ onSaveEdit(message);
+ setMessage("");
+ if (onClearEdit) onClearEdit();
+ } else {
+ onSendMessage(message);
+ setMessage("");
+ if (onClearReply) onClearReply();
+ }
}
};
return (
diff --git a/frontend/src/ui/components/chat/ChatMessages.tsx b/frontend/src/ui/components/chat/ChatMessages.tsx
index 80f824c..048caf8 100644
--- a/frontend/src/ui/components/chat/ChatMessages.tsx
+++ b/frontend/src/ui/components/chat/ChatMessages.tsx
@@ -15,9 +15,10 @@ interface ChatMessagesProps {
isDm?: boolean;
children?: ReactNode;
onReplySelect?: (message: MessageType) => void;
+ onEditSelect?: (message: MessageType) => void;
}
-export function ChatMessages({ messages: propMessages, children, isDm = false, onReplySelect }: ChatMessagesProps) {
+export function ChatMessages({ messages: propMessages, children, isDm = false, onReplySelect, onEditSelect }: ChatMessagesProps) {
const { messages: hookMessages } = useChat();
const { user } = useAppState();
@@ -67,25 +68,8 @@ export function ChatMessages({ messages: propMessages, children, isDm = false, o
}));
};
- const handleEdit = async (message: MessageType) => {
- // This will be called when the edit dialog is saved
- if (!user.authToken) return;
-
- try {
- await request({
- type: "editMessage",
- data: {
- message_id: message.id,
- content: message.content // This should be updated content from the dialog
- },
- credentials: {
- scheme: "Bearer",
- credentials: user.authToken
- }
- });
- } catch (error) {
- console.error("Failed to edit message:", error);
- }
+ const handleEdit = (message: MessageType) => {
+ if (onEditSelect) onEditSelect(message);
};
const handleReply = (message: MessageType) => {
diff --git a/frontend/src/ui/components/chat/EditMessageDialog.tsx b/frontend/src/ui/components/chat/EditMessageDialog.tsx
deleted file mode 100644
index 9ff7b20..0000000
--- a/frontend/src/ui/components/chat/EditMessageDialog.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { useState, useEffect } from "react";
-import type { Message } from "../../../core/types";
-import { MaterialDialog } from "../core/Dialog";
-
-interface EditMessageDialogProps {
- isOpen: boolean;
- onOpenChange: (value: boolean) => void;
- message: Message | null;
- onSave: (messageId: number, newContent: string) => void;
-}
-
-export function EditMessageDialog({ isOpen, onOpenChange, message, onSave }: EditMessageDialogProps) {
- const [editContent, setEditContent] = useState("");
-
- useEffect(() => {
- if (message) {
- setEditContent(message.content);
- }
- }, [message]);
-
- const handleSave = () => {
- if (message && editContent.trim()) {
- onSave(message.id, editContent.trim());
- onOpenChange(false);
- }
- };
-
- const handleCancel = () => {
- onOpenChange(false);
- setEditContent("");
- };
-
- if (!message) return null;
-
- return (
-
-
-
Edit Message
-
setEditContent((e.target as HTMLInputElement).value)}
- label="Edit Message"
- variant="outlined"
- placeholder="Edit your message..."
- maxlength={1000}>
-
-
- Cancel
- Save
-
-
-
- );
-}
diff --git a/frontend/src/ui/components/chat/MessageContextMenu.tsx b/frontend/src/ui/components/chat/MessageContextMenu.tsx
index 5374239..8249ab7 100644
--- a/frontend/src/ui/components/chat/MessageContextMenu.tsx
+++ b/frontend/src/ui/components/chat/MessageContextMenu.tsx
@@ -1,6 +1,5 @@
import { useState, useEffect } from "react";
import type { Message, Size2D } from "../../../core/types";
-import { EditMessageDialog } from "./EditMessageDialog";
interface MessageContextMenuProps {
message: Message;
@@ -29,8 +28,7 @@ export function MessageContextMenu({
isOpen,
onOpenChange
}: MessageContextMenuProps) {
- // Internal state for dialogs and closing animation
- const [editDialogOpen, setEditDialogOpen] = useState(false);
+ // Internal state for closing animation
const [isClosing, setIsClosing] = useState(false);
const [calculatedPosition, setCalculatedPosition] = useState(position);
const [animationClass, setAnimationClass] = useState('entering');
@@ -76,7 +74,7 @@ export function MessageContextMenu({
// Effect to handle clicks outside the context menu
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
- if (isOpen && !isClosing && !editDialogOpen) {
+ if (isOpen && !isClosing) {
// Check if the click is on a context menu element
const target = event.target as Element;
if (!target.closest('.context-menu')) {
@@ -86,14 +84,14 @@ export function MessageContextMenu({
};
const handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === 'Escape' && isOpen && !isClosing && !editDialogOpen) {
+ if (event.key === 'Escape' && isOpen && !isClosing) {
handleClose();
}
};
const handleWindowBlur = () => {
// Close context menu when browser window loses focus
- if (isOpen && !isClosing && !editDialogOpen) {
+ if (isOpen && !isClosing) {
handleClose();
}
};
@@ -109,7 +107,7 @@ export function MessageContextMenu({
document.removeEventListener('keydown', handleKeyDown);
window.removeEventListener('blur', handleWindowBlur);
};
- }, [isOpen, isClosing, editDialogOpen]);
+ }, [isOpen, isClosing]);
const handleAction = (action: string) => {
switch (action) {
@@ -118,9 +116,7 @@ export function MessageContextMenu({
handleClose();
break;
case "edit":
- if (isAuthor) {
- setEditDialogOpen(true);
- }
+ if (isAuthor) onEdit(message);
break;
case "delete":
if (isAuthor) {
@@ -145,12 +141,7 @@ export function MessageContextMenu({
}, 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 };
- onEdit(updatedMessage);
- setEditDialogOpen(false);
- };
+ // Inline edit handled by parent via onEdit
const content = (
@@ -185,19 +176,11 @@ export function MessageContextMenu({
)
// Don't render if not open
- if (!isOpen && !editDialogOpen) return null;
+ if (!isOpen) return null;
return (
<>
{isOpen ? content : null}
-
- {/* Edit Dialog */}
-
>
);
}
diff --git a/frontend/src/ui/components/chat/MessagePanelRenderer.tsx b/frontend/src/ui/components/chat/MessagePanelRenderer.tsx
index b442436..062511c 100644
--- a/frontend/src/ui/components/chat/MessagePanelRenderer.tsx
+++ b/frontend/src/ui/components/chat/MessagePanelRenderer.tsx
@@ -18,6 +18,9 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
const messagesEndRef = useRef
(null);
const [replyTo, setReplyTo] = useState(null);
const [replyToVisible, setReplyToVisible] = useState(Boolean(replyTo));
+ const [editMessage, setEditMessage] = useState(null);
+ const [editVisible, setEditVisible] = useState(Boolean(editMessage));
+ const [pendingAction, setPendingAction] = useState(null);
useEffect(() => {
if (replyTo) {
@@ -25,6 +28,12 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
}
}, [replyTo]);
+ useEffect(() => {
+ if (editMessage) {
+ setEditVisible(true);
+ }
+ }, [editMessage]);
+
// Handle panel state changes
useEffect(() => {
if (panel) {
@@ -141,7 +150,26 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
): (
-