diff --git a/src/components/Game/GameStart/index.tsx b/src/components/Game/GameStart/index.tsx index 51676b9e..c02ea600 100644 --- a/src/components/Game/GameStart/index.tsx +++ b/src/components/Game/GameStart/index.tsx @@ -19,6 +19,7 @@ import useFireFetch from "../../../hooks/useFireFetch"; interface GameStartProps { gameId: string; socket: Socket; + socketMain: Socket; status: string; users: string[]; host: string; @@ -32,6 +33,7 @@ interface UserWithSort { const GameStart: React.FC = ({ gameId, socket, + socketMain, status, users, host, @@ -100,7 +102,7 @@ const GameStart: React.FC = ({ // 모든 클라이언트에게 게임 정보를 포함하는 이벤트 전송 socket.emit("message-to-server", gameInfo + "~!@##"); - + socketMain.emit("message-to-server", gameId + ":" + "~!@##"); // setShowStartModal(true); }; @@ -118,6 +120,8 @@ const GameStart: React.FC = ({ fireFetch.updateData("game", gameId as string, { votedFor: [] }); fireFetch.updateData("game", gameId as string, { status: "대기중" }); + socketMain.emit("message-to-server", gameId + ":" + "~!a%2@##"); + // setShowStartModal(false); }; diff --git a/src/components/Main/GameCard/index.tsx b/src/components/Main/GameCard/index.tsx index 31131666..2315b0a8 100644 --- a/src/components/Main/GameCard/index.tsx +++ b/src/components/Main/GameCard/index.tsx @@ -10,6 +10,11 @@ import { Text, } from "@chakra-ui/react"; import { DocumentData } from "firebase/firestore"; +import { useNavigate } from "react-router-dom"; +import { userState } from "../../../recoil/atoms/userState"; +import { useRecoilValue } from "recoil"; +import useFetch from "../../../hooks/useFetch"; +import useFireFetch from "../../../hooks/useFireFetch"; interface Game { name: string; @@ -21,11 +26,49 @@ interface Game { id: string; } +interface Socket { + on(event: string, callback: any): void; + emit(event: string, data: any): void; +} + interface Props { game: Game | DocumentData; + socket: Socket; } -const GameCard = ({ game: { bg, name, num, status, users } }: Props) => { +const GameCard = ({ + game: { id, bg, name, num, status, users }, + socket, +}: Props) => { + const fireFetch = useFireFetch(); + const navigate = useNavigate(); + const user = useRecoilValue(userState); + + // 입장 요청 선언 + const join = useFetch({ + url: "https://fastcampus-chat.net/chat/participate", + method: "PATCH", + data: { + chatId: id, + }, + start: false, + }); + + // // 게임 정보 조회 + // const gameInfo = useFetch({ + // url: `https://fastcampus-chat.net/chat/only?chatId=${id}`, + // method: "GET", + // start: true, + // }); + + // 게임 입장 함수 + const joinGame = () => { + socket.emit("message-to-server", `${user.id}:${id}:!#%&(`); + join.refresh(); + fireFetch.updateData("game", id, { users: [...users, user.id] }); + navigate(`/game?gameId=${id}`); + }; + return ( { bg="blackAlpha.800" color="white" _hover={{ bg: "blackAlpha.900" }} + onClick={joinGame} > 입장하기 diff --git a/src/components/Main/GameLists/index.tsx b/src/components/Main/GameLists/index.tsx index b7e3c64e..9166c95f 100644 --- a/src/components/Main/GameLists/index.tsx +++ b/src/components/Main/GameLists/index.tsx @@ -12,26 +12,25 @@ import { } from "@chakra-ui/react"; import { IoSettingsOutline } from "react-icons/io5"; import { BiBell } from "react-icons/bi"; -import { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from "react"; +import { KeyboardEvent, useEffect, useRef, useState } from "react"; import useFetch from "../../../hooks/useFetch"; import useFireFetch from "../../../hooks/useFireFetch"; import { DocumentData } from "firebase/firestore"; -import GameCard from "../GameCard"; import { useNavigate } from "react-router-dom"; import { useRecoilValue } from "recoil"; import UserConfigModal from "../../../components/Main/UserConfigModal"; import { useAuth } from "../../../hooks/useAuth"; import { authState } from "../../../recoil/atoms/authState"; -import CreateGameModal from "../CreateGameModal"; +import { userState } from "../../../recoil/atoms/userState"; import connect from "../../../socket/socket"; +import ToastNotice from "../../common/ToastNotice"; +import CreateGameModal from "../CreateGameModal"; +import GameCard from "../GameCard"; import useInput from "../../../hooks/useInput"; -import ChatBubble from "../../common/ChatBubble"; import MyChatBubble from "../../common/MyChatBubble"; interface Message { - userId: string; text: string; - createdAt: Date; id: string; } @@ -81,45 +80,169 @@ interface GameRoom { id: string; } +interface MessageInfo { + id: string; + text: string; +} + type ChatResponseValue = { chats: Chat[] }; const GameLists = () => { + // 페이지 입장시 자동으로 해당 채팅방으로 입장 + useFetch({ + url: "https://fastcampus-chat.net/chat/participate", + method: "PATCH", + data: { + chatId: "9984747e-389a-4aef-9a8f-968dc86a44e4", + }, + start: true, + }); + + const fireFetch = useFireFetch(); + const navigate = useNavigate(); + const { isAuthenticated } = useRecoilValue(authState); + const user = useRecoilValue(userState); const { logout } = useAuth(); - const navigate = useNavigate(); + const [isUserConfigModalOpen, setIsUserConfigModalOpen] = useState(false); const [token, setToken] = useState(); const [gameLists, setGameLists] = useState<(GameRoom | DocumentData)[]>([]); + + // 메세지 데이터 + const [messages, setMessages] = useState([]); + + useEffect(() => { + console.log(messages); + }, [messages]); + + // 초대방 정보 데이터 + const [roomData, setRoomData] = useState({ + id: "", + name: "", + host: "", + bg: "", + users: [""], + }); + + // 팝업 데이터 + const [toastUser, setToastUser] = useState([""]); + + // 토스트 모달 + const [toast, setToast] = useState(false); const [modal, setModal] = useState(false); + const { value, onChange } = useInput(""); - const [messages, setMessages] = useState([]); const inputRef = useRef(null); - const fireFetch = useFireFetch(); // 소켓 연결 const socket = connect("9984747e-389a-4aef-9a8f-968dc86a44e4"); useEffect(() => { socket.on("message-to-client", (messageObject) => { - setMessages((prev) => [...prev, messageObject]); + // 메시지 구분 + if (messageObject.text.slice(-5, -2) === "*&^") { + // 초대 상태 저장 + const usersArr = JSON.parse(messageObject.text); + const users = [...usersArr]; + users.pop(); + users.pop(); + const room = usersArr[usersArr.length - 2]; + + const copy = [...gameLists]; + copy.push(room); + + setGameLists(copy); + setToastUser(users); + setRoomData(room); + } else if (messageObject.text.endsWith("!#%&(")) { + // 유저 입장 구분 + const arr = messageObject.text.split(":"); + const gameId = arr[1]; + const userData = arr[0]; + + const copy = [...gameLists]; + const index = copy.findIndex((value) => value.id === gameId); + + copy[index].users = [...copy[index].users, userData]; + + setGameLists(copy); + } else if (messageObject.text.endsWith(")*^$@")) { + // 유저 퇴장 구분 + const arr = messageObject.text.split(":"); + const gameId = arr[1]; + const userData = arr[0]; + + const copy = [...gameLists]; + const index = copy.findIndex((value) => value.id === gameId); + + copy[index].users = copy[index].users.filter( + (value: any) => value !== userData, + ); + + setGameLists(copy); + } else if (messageObject.text.endsWith("~!@##")) { + const arr = messageObject.text.split(":"); + const gameId = arr[0]; + + const copy = [...gameLists]; + const index = copy.findIndex((value) => value.id === gameId); + + copy[index].status = "게임중"; + setGameLists(copy); + } else if (messageObject.text.endsWith("~!a%2@##")) { + const arr = messageObject.text.split(":"); + const gameId = arr[0]; + + const copy = [...gameLists]; + const index = copy.findIndex((value) => value.id === gameId); + + copy[index].status = "대기중"; + setGameLists(copy); + } else { + // 메시지 데이터, 작성 유저 상태 저장 + const message = { + id: messageObject.userId, + text: messageObject.text, + }; + + console.log(message); + setMessages((prev) => [...prev, message]); + } + }); + + // 채팅 기록 확인 + socket.on("messages-to-client", (messagesObject) => { + console.log(messagesObject); + }); + + // 유저 join확인 + socket.on("join", (users) => { + console.log(users); + }); + + // 유저 leave확인 + socket.on("leave", (users) => { + console.log(users); }); + return () => { socket.off("message-to-client"); + socket.off("join"); + socket.off("leave"); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [socket]); - const onKeyDown = (e: KeyboardEvent) => { - if (e.key === "Enter") { - handleMessage(); - } - }; - const handleMessage = () => { - if (!value) { - return alert("전송할 메시지를 입력해주세요:)"); + //팝업 변화 감지 + useEffect(() => { + if (toastUser[0] !== "" && user.id) { + if (toastUser.includes(user.id)) { + console.log(roomData); + setToast(true); + } } - // 메시지 전송하는 부분 구현 - socket.emit("message-to-server", value); - inputRef?.current?.focus(); - }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [toastUser]); const { result: userInfo }: FetchResultUser = useFetch({ url: `https://fastcampus-chat.net/user?userId=${token?.id}`, @@ -178,6 +301,20 @@ const GameLists = () => { } }, []); + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Enter") { + handleMessage(); + } + }; + const handleMessage = () => { + if (!value) { + return alert("전송할 메시지를 입력해주세요:)"); + } + // 메시지 전송하는 부분 구현 + socket.emit("message-to-server", value); + inputRef?.current?.focus(); + }; + if (isAuthenticated) { return ( { {gameLists.map((game) => ( - + ))} - {messages.map((message: Message, index) => ( + {messages.map((message, index) => ( ))} @@ -334,6 +471,13 @@ const GameLists = () => { {modal ? : null} + {toast && roomData ? ( + + ) : null} ); } diff --git a/src/pages/Game/index.tsx b/src/pages/Game/index.tsx index 6ac34e8a..3ac2fde9 100644 --- a/src/pages/Game/index.tsx +++ b/src/pages/Game/index.tsx @@ -80,7 +80,7 @@ const Game = () => { // 게임 소켓 서버 연결 const socket = connect(gameId as string); // 메인 소켓 서버 연결 (메인페이지 상태 변경 통신) - const socketMain = connect("b5275c5d-6561-413b-b828-5c66646a940f"); + const socketMain = connect("9984747e-389a-4aef-9a8f-968dc86a44e4"); const [category, setCategory] = useState(""); const [keyword, setKeyword] = useState(""); @@ -184,6 +184,7 @@ const Game = () => {