Added chat message clear
This commit is contained in:
parent
df88374999
commit
ec375730f0
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useRef, KeyboardEvent } from "react";
|
||||
import { Paper, TextField, List, ListItem, ListItemText, Typography, Box, IconButton } from "@mui/material";
|
||||
import { Paper, TextField, List, ListItem, ListItemText, Typography, Box, IconButton, Button } from "@mui/material";
|
||||
import SendIcon from "@mui/icons-material/Send";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import useWebSocket from "react-use-websocket";
|
||||
import { Session } from "./GlobalContext";
|
||||
import "./LobbyChat.css";
|
||||
@ -23,6 +24,7 @@ type LobbyChatProps = {
|
||||
const LobbyChat: React.FC<LobbyChatProps> = ({ socketUrl, session, lobbyId }) => {
|
||||
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
||||
const [newMessage, setNewMessage] = useState<string>("");
|
||||
const [isClearing, setIsClearing] = useState<boolean>(false);
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
@ -38,12 +40,16 @@ const LobbyChat: React.FC<LobbyChatProps> = ({ socketUrl, session, lobbyId }) =>
|
||||
switch (message.type) {
|
||||
case "chat_message":
|
||||
const chatMessage = data as ChatMessage;
|
||||
setMessages(prev => [...prev, chatMessage]);
|
||||
setMessages((prev) => [...prev, chatMessage]);
|
||||
break;
|
||||
case "chat_messages":
|
||||
const chatMessages = data.messages as ChatMessage[];
|
||||
setMessages(chatMessages);
|
||||
break;
|
||||
case "chat_cleared":
|
||||
// Clear the messages when receiving chat cleared event
|
||||
setMessages([]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -88,9 +94,9 @@ const LobbyChat: React.FC<LobbyChatProps> = ({ socketUrl, session, lobbyId }) =>
|
||||
const formatTimestamp = (timestamp: number): string => {
|
||||
const date = new Date(timestamp * 1000);
|
||||
return date.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
});
|
||||
};
|
||||
|
||||
@ -98,26 +104,57 @@ const LobbyChat: React.FC<LobbyChatProps> = ({ socketUrl, session, lobbyId }) =>
|
||||
return message.sender_session_id === session.id;
|
||||
};
|
||||
|
||||
const handleClearChat = async () => {
|
||||
if (!lobbyId || isClearing) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsClearing(true);
|
||||
// Use websocket instead of HTTP API to ensure all clients receive the clear event
|
||||
sendJsonMessage({
|
||||
type: "clear_chat_messages",
|
||||
});
|
||||
// Note: We don't clear messages locally here as we'll receive the chat_cleared event
|
||||
} catch (error) {
|
||||
console.error("Failed to clear chat messages:", error);
|
||||
} finally {
|
||||
setIsClearing(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper className="lobby-chat" sx={{ height: 400, display: "flex", flexDirection: "column", p: 1 }}>
|
||||
<Typography variant="h6" sx={{ mb: 1, textAlign: "center" }}>
|
||||
Chat
|
||||
</Typography>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1 }}>
|
||||
<Typography variant="h6" sx={{ textAlign: "center", flexGrow: 1 }}>
|
||||
Chat
|
||||
</Typography>
|
||||
{messages.length > 0 && (
|
||||
<Button
|
||||
size="small"
|
||||
startIcon={<ClearIcon />}
|
||||
onClick={handleClearChat}
|
||||
disabled={isClearing}
|
||||
sx={{ minWidth: "auto", ml: 1 }}
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
>
|
||||
{isClearing ? "Clearing..." : "Clear"}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box className="chat-messages" sx={{ flexGrow: 1, overflowY: "auto", mb: 1 }}>
|
||||
<List dense>
|
||||
{messages.length === 0 ? (
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary="No messages yet"
|
||||
sx={{ textAlign: "center", color: "text.secondary" }}
|
||||
/>
|
||||
<ListItemText primary="No messages yet" sx={{ textAlign: "center", color: "text.secondary" }} />
|
||||
</ListItem>
|
||||
) : (
|
||||
messages.map((message) => (
|
||||
<ListItem
|
||||
key={message.id}
|
||||
className={`chat-message ${isOwnMessage(message) ? 'own-message' : 'other-message'}`}
|
||||
className={`chat-message ${isOwnMessage(message) ? "own-message" : "other-message"}`}
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
alignItems: isOwnMessage(message) ? "flex-end" : "flex-start",
|
||||
@ -162,12 +199,7 @@ const LobbyChat: React.FC<LobbyChatProps> = ({ socketUrl, session, lobbyId }) =>
|
||||
multiline
|
||||
maxRows={3}
|
||||
/>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={handleSendMessage}
|
||||
disabled={!newMessage.trim()}
|
||||
sx={{ mb: 0.5 }}
|
||||
>
|
||||
<IconButton color="primary" onClick={handleSendMessage} disabled={!newMessage.trim()} sx={{ mb: 0.5 }}>
|
||||
<SendIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
@ -196,6 +196,29 @@ class Lobby:
|
||||
with self.lock:
|
||||
return self.chat_messages[-limit:] if self.chat_messages else []
|
||||
|
||||
def clear_chat_messages(self) -> None:
|
||||
"""Clear all chat messages from the lobby"""
|
||||
with self.lock:
|
||||
self.chat_messages.clear()
|
||||
|
||||
async def broadcast_chat_clear(self) -> None:
|
||||
"""Broadcast a chat clear event to all connected sessions in the lobby"""
|
||||
failed_sessions: List[Session] = []
|
||||
for peer in self.sessions.values():
|
||||
if peer.ws:
|
||||
try:
|
||||
logger.info(f"{self.getName()} -> chat_cleared({peer.getName()})")
|
||||
await peer.ws.send_json({"type": "chat_cleared", "data": {}})
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Failed to send chat clear message to {peer.getName()}: {e}"
|
||||
)
|
||||
failed_sessions.append(peer)
|
||||
|
||||
# Clean up failed sessions
|
||||
for failed_session in failed_sessions:
|
||||
failed_session.ws = None
|
||||
|
||||
async def broadcast_chat_message(self, chat_message: ChatMessageModel) -> None:
|
||||
"""Broadcast a chat message to all connected sessions in the lobby"""
|
||||
failed_sessions: List[Session] = []
|
||||
|
@ -262,6 +262,35 @@ class SendChatMessageHandler(MessageHandler):
|
||||
await lobby.broadcast_chat_message(chat_message)
|
||||
|
||||
|
||||
class ClearChatMessagesHandler(MessageHandler):
|
||||
"""Handler for clear_chat_messages messages"""
|
||||
|
||||
async def handle(
|
||||
self,
|
||||
session: "Session",
|
||||
lobby: "Lobby",
|
||||
data: Dict[str, Any],
|
||||
websocket: WebSocket,
|
||||
managers: Dict[str, Any],
|
||||
) -> None:
|
||||
if not session.name:
|
||||
logger.error(
|
||||
f"{session.getName()} - Cannot clear chat messages without name"
|
||||
)
|
||||
await websocket.send_json(
|
||||
{
|
||||
"type": "error",
|
||||
"data": {"error": "Must set name before clearing chat messages"},
|
||||
}
|
||||
)
|
||||
return
|
||||
|
||||
# Clear the messages and broadcast the clear event
|
||||
lobby.clear_chat_messages()
|
||||
logger.info(f"{session.getName()} -> clear_chat_messages({lobby.getName()})")
|
||||
await lobby.broadcast_chat_clear()
|
||||
|
||||
|
||||
class RelayICECandidateHandler(MessageHandler):
|
||||
"""Handler for relayICECandidate messages - WebRTC signaling"""
|
||||
|
||||
@ -337,6 +366,7 @@ class MessageRouter:
|
||||
self.register("list_users", ListUsersHandler())
|
||||
self.register("get_chat_messages", GetChatMessagesHandler())
|
||||
self.register("send_chat_message", SendChatMessageHandler())
|
||||
self.register("clear_chat_messages", ClearChatMessagesHandler())
|
||||
|
||||
# WebRTC signaling handlers
|
||||
self.register("relayICECandidate", RelayICECandidateHandler())
|
||||
|
Loading…
x
Reference in New Issue
Block a user