From 451827698792549f778d8b42142fc7746dc54b85 Mon Sep 17 00:00:00 2001 From: Lee-Dongwook Date: Mon, 21 Oct 2024 18:43:32 +0900 Subject: [PATCH] feat : Video Chat with Chatting --- client/src/app/chat/page.tsx | 7 -- client/src/app/peer/page.tsx | 7 -- client/src/app/videochat/page.tsx | 7 ++ client/src/components/Chat/index.tsx | 116 +++++++++++++++++--------- client/src/constants/index.ts | 3 +- client/src/middleware.ts | 2 +- client/src/template/VideoChatPage.tsx | 27 ++++++ 7 files changed, 111 insertions(+), 58 deletions(-) delete mode 100644 client/src/app/chat/page.tsx delete mode 100644 client/src/app/peer/page.tsx create mode 100644 client/src/app/videochat/page.tsx create mode 100644 client/src/template/VideoChatPage.tsx diff --git a/client/src/app/chat/page.tsx b/client/src/app/chat/page.tsx deleted file mode 100644 index a54c709..0000000 --- a/client/src/app/chat/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from "react"; - -const page = () => { - return
page
; -}; - -export default page; diff --git a/client/src/app/peer/page.tsx b/client/src/app/peer/page.tsx deleted file mode 100644 index a54c709..0000000 --- a/client/src/app/peer/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from "react"; - -const page = () => { - return
page
; -}; - -export default page; diff --git a/client/src/app/videochat/page.tsx b/client/src/app/videochat/page.tsx new file mode 100644 index 0000000..658b798 --- /dev/null +++ b/client/src/app/videochat/page.tsx @@ -0,0 +1,7 @@ +import VideoChatPage from "@/template/VideoChatPage"; + +export default function Page({ params }: { params: { roomId: string } }) { + const { roomId } = params; + + return ; +} diff --git a/client/src/components/Chat/index.tsx b/client/src/components/Chat/index.tsx index 726fc2b..fc6c605 100644 --- a/client/src/components/Chat/index.tsx +++ b/client/src/components/Chat/index.tsx @@ -1,64 +1,98 @@ "use client"; -import { useEffect, useState } from "react"; -import toast from "react-hot-toast"; -import socket from "@/lib/socket"; +import React, { useEffect, useState, useRef } from "react"; +import { io } from "socket.io-client"; +import { Button } from "@/components/ui/button"; + +const socket = io("http://localhost:4000"); // Signaling 서버 주소 interface ChatProps { - id: string; + roomId: string; } -export default function Chat({ id }: ChatProps) { - const [message, setMessage] = useState(""); - const [messages, setMessages] = useState([]); +interface Message { + sender: string; + text: string; +} - const handleSendMessage = () => { - if (message.trim()) { - socket.emit("message", message); - setMessages((prevMessages) => [...prevMessages, `You : ${message}`]); - setMessage(""); - } - }; +export default function Chat({ roomId }: ChatProps) { + const [message, setMessage] = useState(""); + const [messages, setMessages] = useState([]); + const messageEndRef = useRef(null); - const handleReceiveMessage = (receivedMessage: string) => { - toast.success("New message received"); - setMessages((prevMessages) => [ - ...prevMessages, - `Other: ${receivedMessage}`, - ]); + const scrollToBottom = () => { + messageEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; useEffect(() => { - socket.on("message", handleReceiveMessage); + socket.on("receive-message", (message: Message) => { + setMessages((prevMessages) => [...prevMessages, message]); + }); + + socket.emit("join-room", roomId); return () => { - socket.off("message", handleReceiveMessage); + socket.off("receive-message"); + socket.emit("leave-room", roomId); }; - }, [id]); + }, [roomId]); + + const sendMessage = () => { + if (message.trim() === "") return; + + const newMessage = { + sender: "You", + text: message, + }; + + socket.emit("send-message", { ...newMessage, roomId }); + setMessages((prevMessages) => [...prevMessages, newMessage]); + setMessage(""); + scrollToBottom(); + }; return ( -
-

Chat

-
+
+
{messages.map((msg, index) => ( -
- {msg} +
+
+ {msg.sender}: + {msg.text} +
))} +
+
+
+ setMessage(e.target.value)} + placeholder="Type a message..." + className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" + onKeyDown={(e) => { + if (e.key === "Enter") sendMessage(); + }} + /> +
- setMessage(e.target.value)} - className="border p-2 w-full mt-2" - placeholder="Type a message..." - onKeyDown={(e) => e.key === "Enter" && handleSendMessage()} - /> -
); } diff --git a/client/src/constants/index.ts b/client/src/constants/index.ts index 4beadf7..b531417 100644 --- a/client/src/constants/index.ts +++ b/client/src/constants/index.ts @@ -2,6 +2,5 @@ export const mainNavLinks = [ { title: "Home", url: "/" }, { title: "My Documents", url: "/document" }, { title: "Create Document", url: "/document/new" }, - { title: "Real-time Collaboration", url: "/document/realtime" }, - { title: "Peer Call", url: "/peer" }, + { title: "VideoChat", url: "/videochat" }, ]; diff --git a/client/src/middleware.ts b/client/src/middleware.ts index 73b81de..6783d12 100644 --- a/client/src/middleware.ts +++ b/client/src/middleware.ts @@ -18,5 +18,5 @@ export default withAuth( ); export const config = { - matcher: ["/document/:path*", "/profile", "/setting", "/chat", "/peer"], + matcher: ["/document/:path*", "/profile", "/setting", "/videochat"], }; diff --git a/client/src/template/VideoChatPage.tsx b/client/src/template/VideoChatPage.tsx new file mode 100644 index 0000000..5f4f5e6 --- /dev/null +++ b/client/src/template/VideoChatPage.tsx @@ -0,0 +1,27 @@ +"use client"; + +import React from "react"; +import VideoChat from "@/components/VideoChat"; +import Chat from "@/components/Chat"; + +interface VideoChatPageProps { + roomId: string; +} + +export default function VideoChatPage({ roomId }: VideoChatPageProps) { + return ( +
+
+
+ +
+
+
+

+ 채팅 +

+ +
+
+ ); +}