diff --git a/src/components/Game/GameChat/index.tsx b/src/components/Game/GameChat/index.tsx index a3945b11..128dd00e 100644 --- a/src/components/Game/GameChat/index.tsx +++ b/src/components/Game/GameChat/index.tsx @@ -9,6 +9,8 @@ import { import { useEffect, useRef, useState } from "react"; import { io } from "socket.io-client"; import ChatBubble from "../../common/ChatBubble"; +import SystemChat from "../../common/SystemChat"; +import Vote from "../Vote"; interface Message { id: string; @@ -17,9 +19,17 @@ interface Message { interface GameChatProps { gameId: string; + gameData: any; } -const GameChat: React.FC = ({ gameId }) => { +interface UserResponse { + users: string[]; + joiners?: string[]; + leaver?: string; +} + +const GameChat: React.FC = ({ gameId, gameData }) => { + console.log("GameChat/ gameData:", gameData); const token = JSON.parse(localStorage.getItem("token") as string); const socket = io(`https://fastcampus-chat.net/chat?chatId=${gameId}`, { @@ -35,6 +45,26 @@ const GameChat: React.FC = ({ gameId }) => { }); const [messages, setMessages]: any = useState([]); const messageRef = useRef(null); + const [users, setUsers] = useState([]); + console.log("users: ", users); + const [showVoteModal, setShowVoteModal] = useState(false); + const [selectedUser, setSelectedUser] = useState(""); + + const handleOpenVoteModal = () => { + setShowVoteModal(true); + }; + + const handleCloseVoteModal = (selectedUser: string) => { + setShowVoteModal(false); + setSelectedUser(selectedUser); + }; + + // const handleCalculateVoteClose = (finalLiar: string) => { + // // finalLiar를 이용하여 특정 동작 수행 (SystemChat) + + // // 선택한 결과 초기화 + // setSelectedUser(""); + // }; useEffect(() => { socket.on("message-to-client", (messageObject) => { @@ -48,6 +78,25 @@ const GameChat: React.FC = ({ gameId }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [socket]); + useEffect(() => { + // 유저 입장 메시지 수신 + socket.on("join", (responseData: UserResponse) => { + const systemMessage = `${responseData.joiners!.join( + ", ", + )} 님이 입장했습니다.`; + + setMessages([...messages, { id: "system", text: systemMessage }]); + setUsers(responseData.users); + }); + + // 유저 퇴장 메시지 수신 + socket.on("leave", (responseData: UserResponse) => { + const systemMessage = `${responseData.leaver} 님이 퇴장했습니다.`; + setMessages([...messages, { id: "system", text: systemMessage }]); + setUsers(responseData.users); + }); + }, []); + // 메시지 값 변화시(소켓 통신 시) 콘솔에 메시지 데이터 출력 useEffect(() => { if (message.id !== "") { @@ -74,9 +123,23 @@ const GameChat: React.FC = ({ gameId }) => { return ( - {messages.map((message: Message, index: number) => ( - - ))} + {messages.map((message: Message, index: number) => + // 시스템 메시지인 경우 SystemMessage 컴포넌트 사용 + message.id === "system" ? ( + + ) : ( + + ), + )} + + {showVoteModal && ( + + )} + {selectedUser && ( + + )} void; + gameId: string; +} + +const CalculateVote: React.FC = ({ + voteResults, + onClose, + gameId, +}) => { + const [finalLiar, setFinalLiar] = useState(""); + const fireFetch = useFireFetch(); + + // 투표 결과 계산 로직 + useEffect(() => { + const calculateFinalLiar = async () => { + const gameData = await fireFetch.useGetSome("game", "id", gameId); + const { users, votedFor } = gameData.data[0]; + + const votesCount: Record = {}; + users.forEach((user: string) => { + if (votedFor.includes(user)) { + votesCount[user] = (votesCount[user] || 0) + 1; + } + }); + + let maxVotes = 0; + for (const user in votesCount) { + if (votesCount[user] > maxVotes) { + maxVotes = votesCount[user]; + setFinalLiar(user); + } + } + }; + + calculateFinalLiar(); + }, [voteResults, gameId, fireFetch]); + + // 투표 결과 계산 후 최종 라이어를 부모 컴포넌트로 전달 + useEffect(() => { + if (finalLiar) { + onClose(finalLiar); + } + }, [finalLiar, onClose]); + + return ( + {}}> + + + 투표 결과 계산 중 + + + 투표 결과 계산 중입니다... + + + {finalLiar && ( + + )} + + + + ); +}; + +export default CalculateVote; diff --git a/src/components/Game/Vote/index.tsx b/src/components/Game/Vote/index.tsx index bfcea1eb..a7216940 100644 --- a/src/components/Game/Vote/index.tsx +++ b/src/components/Game/Vote/index.tsx @@ -1,5 +1,82 @@ -const Vote = () => { - return
Vote
; +import { useState } from "react"; +import { + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalCloseButton, + ModalBody, + ModalFooter, + Button, + Radio, + RadioGroup, + Stack, +} from "@chakra-ui/react"; +import useFireFetch from "../../../hooks/useFireFetch"; +import { arrayUnion } from "firebase/firestore"; + +interface GameData { + id: string; + users: string[]; +} + +interface VoteProps { + onClose: (selectedUser: string) => void; + gameData: GameData; +} + +const Vote: React.FC = ({ + onClose, + gameData, +}): React.ReactElement => { + const [selectedUser, setSelectedUser] = useState(""); + const fireFetch = useFireFetch(); + + const storedToken = localStorage.getItem("token"); + const tokenData = storedToken ? JSON.parse(storedToken) : null; + + const handleUserChange = (value: string) => { + setSelectedUser(value); + }; + + const handleVoteSubmit = () => { + if (selectedUser !== null) { + const myId = tokenData.id; + fireFetch.updateData("game", gameData.id, { + votedFor: arrayUnion({ by: myId, liar: selectedUser }), + }); + console.log(selectedUser + "에 투표했습니다."); + onClose(selectedUser); + } + }; + + return ( + <> + onClose(selectedUser)}> + + + 라이어 투표하기 + + + + + {gameData.users.map((user) => ( + + {user} + + ))} + + + + + + + + + + ); }; export default Vote; diff --git a/src/components/common/SystemChat.tsx b/src/components/common/SystemChat.tsx new file mode 100644 index 00000000..ef252e42 --- /dev/null +++ b/src/components/common/SystemChat.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import { Box } from "@chakra-ui/react"; + +interface SystemChatProps { + text: string; +} + +const SystemChat: React.FC = ({ text }) => { + return ( + + {text} + + ); +}; + +export default SystemChat; diff --git a/src/pages/Game/index.tsx b/src/pages/Game/index.tsx index ef611e87..fcce1f9e 100644 --- a/src/pages/Game/index.tsx +++ b/src/pages/Game/index.tsx @@ -114,17 +114,17 @@ const Game = () => { - + - + - +