From 051484e5be1540f260f6cdf41785d7bbb1d1863e Mon Sep 17 00:00:00 2001 From: ritwik-69 <72665321+ritwik-69@users.noreply.github.com> Date: Mon, 24 Jun 2024 19:42:06 +0530 Subject: [PATCH] Game:Add support for replying to messages in Message box This commit enables replying to others in chat during game and rendering the message being replied to in the chatbox. fixes #153 --- backend/src/controllers/gameControllers.ts | 15 +-- backend/src/types.ts | 1 - frontend/src/library/chatbox/Chatbox.tsx | 11 ++- frontend/src/library/chatbox/Message.tsx | 33 ++++++- frontend/src/library/chatbox/MessageInput.tsx | 98 +++++++++++++------ frontend/src/library/chatbox/MessageList.tsx | 17 +++- 6 files changed, 128 insertions(+), 47 deletions(-) diff --git a/backend/src/controllers/gameControllers.ts b/backend/src/controllers/gameControllers.ts index 67e650be..bf792c32 100644 --- a/backend/src/controllers/gameControllers.ts +++ b/backend/src/controllers/gameControllers.ts @@ -9,13 +9,14 @@ import { export async function handleGameJoin(req: AuthRequest, res: Response) { const gameCode = req.body.code; - const activeGameId = req.user.activeGameId; - if (activeGameId) { - res.status(400).send({ - error: 'User is already playing a game', - }); - return; - } + //todo: uncomment this when we have the system to end games + // const activeGameId = req.user.activeGameId; + // if (activeGameId) { + // res.status(400).send({ + // error: 'User is already playing a game', + // }); + // return; + // } const game = retrieveGame(gameCode); if (!game) { res.status(404).send({ error: 'Game not found' }); diff --git a/backend/src/types.ts b/backend/src/types.ts index 79bc17ab..6bf8f2f9 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -163,7 +163,6 @@ export type AppEventType = GameEventTypes | ChatEventTypes; // Represent all the events that can be sent to the client // a workaround for now to make things work - this will be refactored later export type AppEvent = GameEvent | ChatEvent; - export type ChatMessage = { content: string; id: string; diff --git a/frontend/src/library/chatbox/Chatbox.tsx b/frontend/src/library/chatbox/Chatbox.tsx index 0c066386..0c34c1b4 100644 --- a/frontend/src/library/chatbox/Chatbox.tsx +++ b/frontend/src/library/chatbox/Chatbox.tsx @@ -12,6 +12,7 @@ import { useToast } from '../toast/toast-context'; const Chatbox: React.FC = () => { const [messages, setMessages] = useState<{ [k: string]: ChatMessage }>({}); const [isVisible, setIsVisible] = useState(false); + const [replyMessage, setReplyMessage] = useState(null); const toast = useToast(); useEffect(() => { @@ -78,10 +79,16 @@ const Chatbox: React.FC = () => { >
- +
- +
diff --git a/frontend/src/library/chatbox/Message.tsx b/frontend/src/library/chatbox/Message.tsx index 705eb1d8..9fd88688 100644 --- a/frontend/src/library/chatbox/Message.tsx +++ b/frontend/src/library/chatbox/Message.tsx @@ -3,13 +3,16 @@ import EmojiPicker, { EmojiClickData } from 'emoji-picker-react'; import { ChatEventTypes, ChatMessage } from '../../../../backend/src/types'; import { FaRegSmile } from 'react-icons/fa'; import { triggerEvent } from '../../channel'; - interface MessageProps { - message: ChatMessage; + id: string; + messages: { [k: string]: ChatMessage }; + replyCallback?: (message: ChatMessage) => void; } -const Message: React.FC = ({ message }) => { +const Message: React.FC = ({ id, messages, replyCallback }) => { const [showEmojiPicker, setShowEmojiPicker] = useState(false); + const message = messages[id]; + const replyingTo = messages[message.ref || '']; const handleEmojiClick = (emojiData: EmojiClickData) => { triggerEvent({ @@ -21,12 +24,30 @@ const Message: React.FC = ({ message }) => { }); setShowEmojiPicker(false); }; + const handleReply = () => { + replyCallback?.(message); + }; return (
{message.playerName}
+ + {replyingTo && ( +
+

+ {replyingTo?.playerName} +

+ +

+ {replyingTo.content.length > 35 + ? replyingTo.content.slice(0, 35) + '...' + : replyingTo.content} +

+
+ )} +
{message.content}
@@ -46,6 +67,12 @@ const Message: React.FC = ({ message }) => {
)} +
); diff --git a/frontend/src/library/chatbox/MessageInput.tsx b/frontend/src/library/chatbox/MessageInput.tsx index 73dfcdbb..b98d8940 100644 --- a/frontend/src/library/chatbox/MessageInput.tsx +++ b/frontend/src/library/chatbox/MessageInput.tsx @@ -1,16 +1,26 @@ import React, { useState } from 'react'; import EmojiPicker, { EmojiClickData } from 'emoji-picker-react'; import Button from '../button'; -import { ChatEventTypes } from '../../../../backend/src/types'; +import { ChatEventTypes, ChatMessage } from '../../../../backend/src/types'; import { triggerEvent } from '../../channel'; import { useAuth } from '../../contexts/AuthContext'; -const MessageInput: React.FC = () => { +interface MessageInputProps { + replyMessage: ChatMessage | null; + setReplyMessage: React.Dispatch>; +} + +const MessageInput: React.FC = ({ + replyMessage, + setReplyMessage, +}) => { const [content, setContent] = useState(''); const [showEmojiPicker, setShowEmojiPicker] = useState(false); const auth = useAuth(); const handleSend = async () => { + handleClose(); + console.log(replyMessage?.id); if (content.trim() !== '') { triggerEvent({ type: ChatEventTypes.SEND_MESSAGE, @@ -18,9 +28,11 @@ const MessageInput: React.FC = () => { id: Date.now().toString(), content: content.trim(), playerName: auth.getUser()?.name || 'Unknown user', + ref: replyMessage?.id, }, }); setContent(''); + setReplyMessage(null); } }; @@ -34,38 +46,64 @@ const MessageInput: React.FC = () => { handleSend(); } }; + const handleClose = () => { + setReplyMessage(null); + }; return ( -
- - {showEmojiPicker && ( -
- +
+ {replyMessage && ( +
+
+

+ Replying to: {replyMessage.playerName} +

+ +

+ {replyMessage && replyMessage.content.length > 35 + ? replyMessage.content.slice(0, 35) + '...' + : replyMessage.content} +

+ +
)} - setContent(e.target.value)} - onKeyDown={handleKeyDown} - className="flex-0.5 px-1 py-1 border-2 border-gray-500 rounded-xl font-kavoon text-sm" - placeholder="Type a message..." - /> - +
+ + {showEmojiPicker && ( +
+ +
+ )} + setContent(e.target.value)} + onKeyDown={handleKeyDown} + className="flex-1 px-1 py-1 border-2 border-gray-500 rounded-xl font-kavoon text-sm" + placeholder="Type a message..." + /> + +
); }; diff --git a/frontend/src/library/chatbox/MessageList.tsx b/frontend/src/library/chatbox/MessageList.tsx index e84d7d35..01248c7d 100644 --- a/frontend/src/library/chatbox/MessageList.tsx +++ b/frontend/src/library/chatbox/MessageList.tsx @@ -2,14 +2,23 @@ import React from 'react'; import Message from './Message'; import { ChatMessage } from '../../../../backend/src/types'; interface MessageListProps { - messages: ChatMessage[]; + messages: { [k: string]: ChatMessage }; + setReplyMessage: React.Dispatch>; } -const MessageList: React.FC = ({ messages }) => { +const MessageList: React.FC = ({ + messages, + setReplyMessage, +}) => { return (
- {messages.map((message, index) => ( - + {Object.values(messages).map((message, index) => ( + setReplyMessage(k)} + /> ))}
);