feat: add system messages

This commit is contained in:
Alexander Daichendt 2025-02-12 12:29:16 +01:00
parent 748e154ec4
commit 230a9560a5
4 changed files with 55 additions and 17 deletions

View file

@ -1,6 +1,6 @@
import React, { useReducer } from "react"; import React, { useReducer } from "react";
import { ChatMessage, User } from "../../../shared"; import { User } from "../../../shared";
import { ChatContext } from "../contexts/ChatContext"; import { ChatContext, Message } from "../contexts/ChatContext";
import { chatReducer } from "../reducers/chatReducers"; import { chatReducer } from "../reducers/chatReducers";
export function ChatProvider({ children }: { children: React.ReactNode }) { export function ChatProvider({ children }: { children: React.ReactNode }) {
@ -14,7 +14,7 @@ export function ChatProvider({ children }: { children: React.ReactNode }) {
state, state,
dispatch, dispatch,
actions: { actions: {
addMessage: (message: ChatMessage) => addMessage: (message: Message) =>
dispatch({ type: "ADD_MESSAGE", payload: message }), dispatch({ type: "ADD_MESSAGE", payload: message }),
setUser: (user: User) => dispatch({ type: "SET_USER", payload: user }), setUser: (user: User) => dispatch({ type: "SET_USER", payload: user }),
setConnected: (isConnected: boolean) => setConnected: (isConnected: boolean) =>

View file

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import { ServerMessage } from "../../../shared";
import { useChatState } from "../contexts/ChatContext"; import { useChatState } from "../contexts/ChatContext";
import ChatMessage from "./ChatMessage"; import ChatMessage from "./ChatMessage";
@ -6,13 +7,40 @@ function ChatMessages() {
const { state } = useChatState(); const { state } = useChatState();
const userId = state.currentUser?.userId; const userId = state.currentUser?.userId;
return ( function renderMessage(message: ServerMessage) {
<> switch (message.type) {
{state.messages.map((message) => ( case "CHAT_MESSAGE":
<ChatMessage message={message} userId={userId} /> return (
))} <ChatMessage
</> message={message.payload}
); userId={userId}
key={message.payload.id}
/>
);
case "USER_JOINED":
return (
<div
className="text-center text-gray-500 my-2"
key={`join-${message.payload.user.name}-${new Date()}`}
>
{message.payload.user.name} joined!
</div>
);
case "USER_LEFT":
return (
<div
className="text-center text-gray-500 my-2"
key={`leave-${message.payload.user.name}-${new Date()}`}
>
{message.payload.user.name} left!
</div>
);
default:
return null;
}
}
return <>{state.messages.map(renderMessage)}</>;
} }
export default React.memo(ChatMessages); export default React.memo(ChatMessages);

View file

@ -1,20 +1,30 @@
import { createContext, useContext, Dispatch } from "react"; import { createContext, useContext, Dispatch } from "react";
import { ChatMessage, User } from "../../../shared"; import {
ServerChatMessage,
ServerUserJoinedMessage,
ServerUserLeftMessage,
User,
} from "../../../shared";
export type Message =
| ServerChatMessage
| ServerUserJoinedMessage
| ServerUserLeftMessage;
export type ChatState = { export type ChatState = {
messages: ChatMessage[]; messages: Message[];
currentUser: User | null; currentUser: User | null;
isConnected: boolean; isConnected: boolean;
}; };
export type ChatAction = export type ChatAction =
| { type: "ADD_MESSAGE"; payload: ChatMessage } | { type: "ADD_MESSAGE"; payload: Message }
| { type: "SET_USER"; payload: User } | { type: "SET_USER"; payload: User }
| { type: "SET_CONNECTED"; payload: boolean } | { type: "SET_CONNECTED"; payload: boolean }
| { type: "CLEAR_MESSAGES" }; | { type: "CLEAR_MESSAGES" };
export type ChatActions = { export type ChatActions = {
addMessage: (message: ChatMessage) => void; addMessage: (message: Message) => void;
setUser: (user: User) => void; setUser: (user: User) => void;
setConnected: (isConnected: boolean) => void; setConnected: (isConnected: boolean) => void;
}; };

View file

@ -21,11 +21,11 @@ export function useWebSocket(roomId: string) {
actions.setUser(message.payload.user); actions.setUser(message.payload.user);
break; break;
// intentional fallthrough
case "USER_JOINED": case "USER_JOINED":
break; case "USER_LEFT":
case "CHAT_MESSAGE": case "CHAT_MESSAGE":
actions.addMessage(message.payload); actions.addMessage(message);
break; break;
default: default: