diff --git a/client/src/components/ChatMessages.tsx b/client/src/components/ChatMessages.tsx
index 76e4139..e10ff24 100644
--- a/client/src/components/ChatMessages.tsx
+++ b/client/src/components/ChatMessages.tsx
@@ -2,11 +2,11 @@ import React from "react";
import { useChatState } from "../contexts/ChatContext";
function ChatMessages() {
- const { messages } = useChatState();
+ const { state } = useChatState();
return (
<>
- {messages.map((message) => (
+ {state.messages.map((message) => (
{message.author.name}
diff --git a/client/src/components/ChatProvider.tsx b/client/src/components/ChatProvider.tsx
index f2b2349..d250e83 100644
--- a/client/src/components/ChatProvider.tsx
+++ b/client/src/components/ChatProvider.tsx
@@ -1,20 +1,26 @@
-import React from "react";
+import React, { useReducer } from "react";
import { ChatMessage, User } from "../../../shared";
import { ChatContext } from "../contexts/ChatContext";
+import { chatReducer } from "../reducers/chatReducers";
export function ChatProvider({ children }: { children: React.ReactNode }) {
- const [messages, setMessages] = React.useState([]);
- const [currentUser, setCurrentUser] = React.useState(null);
+ const [state, dispatch] = useReducer(chatReducer, {
+ messages: [],
+ currentUser: null,
+ isConnected: false,
+ });
- const addMessage = (message: ChatMessage) => {
- setMessages((prev) => [...prev, message]);
+ const value = {
+ state,
+ dispatch,
+ actions: {
+ addMessage: (message: ChatMessage) =>
+ dispatch({ type: "ADD_MESSAGE", payload: message }),
+ setUser: (user: User) => dispatch({ type: "SET_USER", payload: user }),
+ setConnected: (isConnected: boolean) =>
+ dispatch({ type: "SET_CONNECTED", payload: isConnected }),
+ },
};
- return (
-
- {children}
-
- );
+ return {children};
}
diff --git a/client/src/components/ConnectWithName.tsx b/client/src/components/ConnectWithName.tsx
index 9f40135..7d8c3f8 100644
--- a/client/src/components/ConnectWithName.tsx
+++ b/client/src/components/ConnectWithName.tsx
@@ -6,7 +6,7 @@ interface ConnectProps {
}
function Connect({ onConnect }: ConnectProps) {
- const { setCurrentUser } = useChatState();
+ const { actions } = useChatState();
const [name, setName] = useState("");
function handleConnect() {
@@ -14,8 +14,11 @@ function Connect({ onConnect }: ConnectProps) {
return;
}
- // leave userId empty for now, it is server generated
- setCurrentUser({ name, userId: "" });
+ actions.setUser({
+ name: name,
+ userId: "", // leave userId empty for now, it is server generated
+ });
+
onConnect(name);
}
diff --git a/client/src/contexts/ChatContext.tsx b/client/src/contexts/ChatContext.tsx
index b2a2b53..6049b29 100644
--- a/client/src/contexts/ChatContext.tsx
+++ b/client/src/contexts/ChatContext.tsx
@@ -1,17 +1,36 @@
-import { createContext, useContext } from "react";
+import { createContext, useContext, Dispatch } from "react";
import { ChatMessage, User } from "../../../shared";
-interface ChatContextType {
+export type ChatState = {
messages: ChatMessage[];
currentUser: User | null;
+ isConnected: boolean;
+};
+
+export type ChatAction =
+ | { type: "ADD_MESSAGE"; payload: ChatMessage }
+ | { type: "SET_USER"; payload: User }
+ | { type: "SET_CONNECTED"; payload: boolean }
+ | { type: "CLEAR_MESSAGES" };
+
+export type ChatActions = {
addMessage: (message: ChatMessage) => void;
- setCurrentUser: (user: User) => void;
+ setUser: (user: User) => void;
+ setConnected: (isConnected: boolean) => void;
+};
+
+interface ChatContextType {
+ state: ChatState;
+ dispatch: Dispatch;
+ actions: ChatActions;
}
export const ChatContext = createContext(null);
export const useChatState = () => {
const context = useContext(ChatContext);
- if (!context) throw new Error("useChat must be used within ChatProvider");
+ if (!context) {
+ throw new Error("useChatState must be used within ChatProvider");
+ }
return context;
};
diff --git a/client/src/hooks/useWebSocket.ts b/client/src/hooks/useWebSocket.ts
index 0500cc5..3a45d2a 100644
--- a/client/src/hooks/useWebSocket.ts
+++ b/client/src/hooks/useWebSocket.ts
@@ -9,7 +9,7 @@ import { useChatState } from "../contexts/ChatContext";
export function useWebSocket(roomId: string) {
const [ws, setWs] = useState(null);
const [isConnected, setIsConnected] = useState(false);
- const { addMessage, currentUser, setCurrentUser } = useChatState();
+ const { state, actions } = useChatState();
// Handle incoming messages
const handleMessage = useCallback(
@@ -19,18 +19,18 @@ export function useWebSocket(roomId: string) {
switch (message.type) {
case "USER_JOINED":
console.log("User joined", message.payload);
- if (message.payload.user.name === currentUser?.name) {
- setCurrentUser(message.payload.user);
+ if (message.payload.user.name === state.currentUser?.name) {
+ actions.setUser(message.payload.user);
}
break;
case "CHAT_MESSAGE":
- addMessage(message.payload);
+ actions.addMessage(message.payload);
break;
default:
console.error("Unknown message type", message);
}
},
- [currentUser, setCurrentUser, addMessage],
+ [state.currentUser, actions],
);
// Send a message to the server
diff --git a/client/src/pages/Room.tsx b/client/src/pages/Room.tsx
index 5036218..03b2f49 100644
--- a/client/src/pages/Room.tsx
+++ b/client/src/pages/Room.tsx
@@ -9,15 +9,15 @@ import { useChatState } from "../contexts/ChatContext";
function Room() {
const { roomId } = useParams();
const { isConnected, connect, sendMessage } = useWebSocket(roomId ?? "");
- const { currentUser } = useChatState();
+ const { state } = useChatState();
return (
Room ID: {roomId}
- {currentUser && (
- User: {currentUser?.name}
+ {state.currentUser && (
+ User: {state.currentUser?.name}
)}