import { useChat } from "../../hooks/useChat"; import { Message } from "./Message"; import { useAppState } from "../../state"; import type { Message as MessageType } from "../../../core/types"; import type { UserProfile } from "../../../core/types"; import { UserProfileDialog } from "./UserProfileDialog"; import { MessageContextMenu, type ContextMenuState } from "./MessageContextMenu"; import { fetchUserProfile } from "../../api/profileApi"; import { useState, type ReactNode } from "react"; import { delay } from "../../../utils/utils"; import { request } from "../../../websocket"; interface ChatMessagesProps { messages?: MessageType[]; isDm?: boolean; children?: ReactNode; } export function ChatMessages({ messages: propMessages, children, isDm = false }: ChatMessagesProps) { const { messages: hookMessages } = useChat(); const { user } = useAppState(); // Use prop messages if provided, otherwise use hook messages const messages = propMessages || hookMessages; const [profileDialogOpen, setProfileDialogOpen] = useState(false); const [selectedUserProfile, setSelectedUserProfile] = useState(null); const [isLoadingProfile, setIsLoadingProfile] = useState(false); // Context menu state const [contextMenu, setContextMenu] = useState({ isOpen: false, message: null, position: { x: 0, y: 0 } }); const handleProfileClick = async (username: string) => { if (!user.authToken) return; setIsLoadingProfile(true); try { const profile = await fetchUserProfile(user.authToken, username); if (profile) { setSelectedUserProfile(profile); setProfileDialogOpen(true); } } catch (error) { console.error("Failed to fetch user profile:", error); } finally { setIsLoadingProfile(false); } }; const handleContextMenu = (e: React.MouseEvent, message: MessageType) => { e.preventDefault(); setContextMenu({ isOpen: true, message, position: { x: e.clientX, y: e.clientY } }); }; const handleContextMenuOpenChange = (isOpen: boolean) => { setContextMenu(prev => ({ ...prev, isOpen })); }; 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 handleReply = async (message: MessageType) => { // This will be called when the reply dialog is sent if (!user.authToken) return; try { await request({ type: "replyMessage", data: { content: message.content, // This should be the reply content from the dialog reply_to_id: message.id }, credentials: { scheme: "Bearer", credentials: user.authToken } }); } catch (error) { console.error("Failed to send reply:", error); } }; const handleDelete = async (message: MessageType) => { if (!user.authToken) return; try { await request({ type: "deleteMessage", data: { message_id: message.id }, credentials: { scheme: "Bearer", credentials: user.authToken } }); } catch (error) { console.error("Failed to delete message:", error); } }; return ( <>
{messages.map((message) => ( ))} {children}
{ setProfileDialogOpen(value); if (!value) { await delay(1000); setSelectedUserProfile(null); } }} userProfile={selectedUserProfile} /> {/* Context Menu */} {contextMenu.message && ( )} ); }