Skip to content

Commit

Permalink
feature: integrate new chat component with web socket
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnsonMao committed Oct 5, 2024
1 parent e83c387 commit f28e5f9
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 19 deletions.
10 changes: 7 additions & 3 deletions components/shared/Chat/v2/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,22 @@ import Icon from "../../Icon";

export type ChatProps = {
userId: string;
roomId?: string;
lobbyMessages: MessageType[];
friendList: FriendType[];
roomMessages: MessageType[];
maxHeight?: string;
onSubmit: (message: Pick<MessageType, "content" | "target">) => void;
};

export default function Chat({
userId,
roomId,
lobbyMessages,
friendList,
roomMessages,
maxHeight = "calc(100vh - 168px)",
onSubmit,
}: Readonly<ChatProps>) {
const [messages, setMessages] = useState(lobbyMessages);
const [target, setTarget] = useState<[ChatTab["id"], string | null]>([
Expand Down Expand Up @@ -64,9 +68,9 @@ export default function Chat({
const handleToggleTarget = (id: FriendType["target"]) =>
setTarget(["friend", id]);

const handleSubmit = (message: MessageType) => {
const handleSubmit = (message: Pick<MessageType, "content" | "target">) => {
if (activeTab === "friend" && !friendRoom) return;
setMessages((pre) => [...pre, message]);
onSubmit(message);
};

return (
Expand Down Expand Up @@ -108,7 +112,7 @@ export default function Chat({
)}
</div>
<ChatInput
userId={userId}
roomId={roomId}
onSubmit={handleSubmit}
disabled={isFriendList}
/>
Expand Down
9 changes: 4 additions & 5 deletions components/shared/Chat/v2/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import Icon from "../../Icon";
import type { MessageType } from "./ChatMessages";

type ChatInputProps = {
userId: string;
roomId?: string;
disabled: boolean;
onSubmit: (message: MessageType) => void;
onSubmit: (message: Pick<MessageType, "content" | "target">) => void;
};

export default function ChatInput({
userId,
roomId,
disabled,
onSubmit,
}: Readonly<ChatInputProps>) {
Expand All @@ -24,8 +24,7 @@ export default function ChatInput({
if (!content) return;
setValue("");
onSubmit({
from: userId,
target: "",
target: roomId ? `ROOM_${roomId}` : "TODO:OTHER",
content,
});
};
Expand Down
20 changes: 15 additions & 5 deletions components/shared/Chat/v2/ChatMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
import Avatar from "../../Avatar";
import Avatar from "@/components/shared/Avatar";
import type { UserInfo } from "@/requests/users";

type User = Pick<UserInfo, "id" | "nickname">;

export type MessageType = {
from: string;
target: string;
/** The source of the message. */
from: "SYSTEM" | User;
/** The content of the user message. */
content: string;
/** The recipient of the message.
* @ "LOBBY" | "ROOM_[:roomId]" -
*/
target: string;
/** The timestamp of the message. */
timestamp: string;
};

type ChatMessageProps = {
Expand All @@ -31,7 +41,7 @@ export default function ChatMessages({
<div ref={messagesRef} className="overflow-y-scroll scrollbar">
<div className="p-4 pr-0">
{messages.map(({ from, content }, index) => {
const isSystem = from === "System";
const isSystem = from === "SYSTEM";
const isMe = from === userId;
const isSameUser = from === messages[index + 1]?.from;

Expand Down Expand Up @@ -71,7 +81,7 @@ export default function ChatMessages({
isMe && "text-right mt-1"
)}
>
{isMe ? "我" : from}
{isMe ? "我" : from.nickname}
</div>
</div>
</>
Expand Down
18 changes: 12 additions & 6 deletions containers/layout/AppLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { PropsWithChildren, useReducer } from "react";
import { PropsWithChildren } from "react";
import Header from "@/components/shared/Header";
import Sidebar from "@/components/shared/Sidebar";
import Chat from "@/components/shared/Chat/v2/Chat";
import useChat from "@/hooks/useChat";

export default function Layout({ children }: PropsWithChildren) {
const [isChatVisible, toggleChatVisibility] = useReducer(
(preState) => !preState,
false
);
const {
roomId,
messageList,
isChatVisible,
toggleChatVisibility,
handleSubmitText,
} = useChat();

return (
<div className="inset-0 flex flex-col w-full h-full">
Expand All @@ -21,9 +25,11 @@ export default function Layout({ children }: PropsWithChildren) {
<div className="shrink-0">
<Chat
userId=""
roomId={roomId}
friendList={[]}
lobbyMessages={[]}
roomMessages={[]}
roomMessages={messageList}
onSubmit={handleSubmitText}
/>
</div>
)}
Expand Down
53 changes: 53 additions & 0 deletions hooks/useChat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useEffect, useReducer, useState } from "react";
import type { MessageType } from "@/components/shared/Chat/v2/ChatMessages";
import useChatroom from "./context/useChatroom";
import useSocketCore from "./context/useSocketCore";
import useUser from "./useUser";

export default function useChat() {
const { lastMessage, sendChatMessage, joinChatroom, leaveChatroom } =
useChatroom();
const [isChatVisible, toggleChatVisibility] = useReducer(
(preState: boolean) => !preState,
false
);
const { socket } = useSocketCore();
const [messageList, setMessageList] = useState<MessageType[]>([]);
const { getRoomId } = useUser();
const roomId = getRoomId();

// join chatroom by roomId
useEffect(() => {
if (!roomId) return;
if (!socket || !socket.connected) return;
joinChatroom(roomId);
return () => leaveChatroom(roomId);
}, [joinChatroom, leaveChatroom, roomId, socket, socket?.connected]);

// update message list while received new message from websocket
useEffect(() => {
if (!lastMessage || !roomId) return;
if (lastMessage.target === `ROOM_${roomId}`) {
setMessageList((prev) => [...prev, lastMessage]);
}
}, [lastMessage, roomId]);

const handleSubmitText = (
message: Pick<MessageType, "content" | "target">
) => {
if (!message.content) return;
const data: Pick<MessageType, "content" | "target"> = {
content: message.content,
target: message.target,
};
sendChatMessage(data);
};

return {
roomId,
messageList,
isChatVisible,
toggleChatVisibility,
handleSubmitText,
};
}

0 comments on commit f28e5f9

Please sign in to comment.