From b70735fff81c12fd43cd84bada31cddc898b9eb6 Mon Sep 17 00:00:00 2001 From: Shaochang Tan <478710209@qq.com> Date: Mon, 6 May 2024 18:15:37 +0200 Subject: [PATCH 1/6] Fix input null initial value warning issue --- src/components/ui/Button.tsx | 2 +- src/components/views/Lobby.tsx | 4 ++-- src/components/views/Login.tsx | 4 ++-- src/components/views/Register.tsx | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index f9e8b83..fa79bfa 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -13,7 +13,7 @@ export const Button = props => ( Button.propTypes = { - width: PropTypes.number, + width: PropTypes.string, style: PropTypes.object || PropTypes.string, className: PropTypes.string, children: PropTypes.node, diff --git a/src/components/views/Lobby.tsx b/src/components/views/Lobby.tsx index c5b5071..df70750 100644 --- a/src/components/views/Lobby.tsx +++ b/src/components/views/Lobby.tsx @@ -186,8 +186,8 @@ const Lobby = () => { const changeAvatarPopRef = useRef(null); const infoPopRef = useRef(null); const [rooms, setRooms] = useState([]); - const [user, setUser] = useState([]); - const [username, setUsername] = useState(null); + const [user, setUser] = useState(null); + const [username, setUsername] = useState(""); const [avatar, setAvatar] = useState(null); const [roomName, setRoomName] = useState(""); const [maxRoomPlayers, SetMaxRoomPlayers] = useState(DEFAULT_MIN_PLAYERS); diff --git a/src/components/views/Login.tsx b/src/components/views/Login.tsx index f10959a..c400f81 100644 --- a/src/components/views/Login.tsx +++ b/src/components/views/Login.tsx @@ -39,8 +39,8 @@ FormField.propTypes = { const Login = () => { const navigate = useNavigate(); - const [username, setUsername] = useState(null); - const [password, setPassword] = useState(null); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); const doLogin = async () => { try { diff --git a/src/components/views/Register.tsx b/src/components/views/Register.tsx index 8dcc49c..d665b6d 100644 --- a/src/components/views/Register.tsx +++ b/src/components/views/Register.tsx @@ -40,8 +40,8 @@ FormField.propTypes = { const Register = () => { const navigate = useNavigate(); - const [username, setUsername] = useState(null); - const [password, setPassword] = useState(null); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); const doRegister = async () => { try { From 9a85c769927da2ebfcb1cbfe592ef7b318f3296e Mon Sep 17 00:00:00 2001 From: Shaochang Tan <478710209@qq.com> Date: Mon, 6 May 2024 18:21:00 +0200 Subject: [PATCH 2/6] Fix error handle logic and toast msg --- src/components/views/Lobby.tsx | 31 ++++++++++++++++++++----------- src/components/views/Login.tsx | 3 +++ src/components/views/Register.tsx | 3 +++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/components/views/Lobby.tsx b/src/components/views/Lobby.tsx index df70750..97e71a9 100644 --- a/src/components/views/Lobby.tsx +++ b/src/components/views/Lobby.tsx @@ -206,7 +206,8 @@ const Lobby = () => { console.log(response); sessionStorage.clear(); } catch (error) { - alert(`Something went wrong during the logout: \n${handleError(error)}`); + // alert(`Something went wrong during the logout: \n${handleError(error)}`); + showToast(`Something went wrong during the logout: \n${handleError(error)}`, "error"); } navigate("/login"); }; @@ -215,15 +216,16 @@ const Lobby = () => { const userId = sessionStorage.getItem("id"); if (userId) { // Get current user's information - try { + /// handle error outside + // try { const userResponse = await api.get(`/users/${userId}`); setUser(userResponse.data); // Set user data from API console.log("User data:", userResponse.data); - } catch (error) { - handleError(error); + // } catch (error) { + // handleError(error); return; - } + // } } else { console.error("User ID not found in sessionStorage!"); } @@ -323,7 +325,8 @@ const Lobby = () => { const createRoom = async () => { // if not chrome, alert the user if (!navigator.userAgent.includes("Chrome")) { - alert("Your browser is currently not supported, please use Chrome to play this game!"); + // alert("Your browser is currently not supported, please use Chrome to play this game!"); + showToast("Your browser is currently not supported, please use Chrome to play this game!", "error"); return; } @@ -443,14 +446,19 @@ const Lobby = () => { /// if error is network error, clear the session and navigate to login page /// const handleError = (error) => { + // if(!error.message){ + // // if error message is undefined + // showToast("Something went wrong, please try again later.", "error"); + // } if(error.message.match(/Network Error/)) { console.error(`The server cannot be reached.\nDid you start it?\n${error}`); - alert(`The server cannot be reached.\nDid you start it?\n${error}`); + showToast(`The server cannot be reached.\nDid you start it?\n${error}`); sessionStorage.clear(); navigate("/login"); + showToast("The server cannot be reached.\nDid you start it?", "error"); } else { console.error(`Something went wrong: \n${error}`); - alert(`Something went wrong: \n${error}`); + showToast(`Something went wrong: \n${error}`); } } @@ -465,15 +473,16 @@ const Lobby = () => { .then(() => { //alert(currentId); if(Room.roomPlayersList.length===Room.maxPlayersNum) - alert("Room is Full, please enter another room!"); + showToast("Room is Full, please enter another room!", "error"); else if(Room.status==="In Game") - alert("Game is already started, please enter another room!"); + showToast("Game is already started, please enter another room!", "error"); else navigate(`/rooms/${Room.roomId}/${Room.roomName}`); }) .catch(error => { console.error(`Something went wrong during the enterRoom: \n${error}`); - alert(`Something went wrong during the enterRoom: \n${error}`); + // alert(`Something went wrong during the enterRoom: \n${error}`); + showToast(`Something went wrong during the enterRoom: \n${error}`, "error"); }); }}> diff --git a/src/components/views/Login.tsx b/src/components/views/Login.tsx index c400f81..94d88fd 100644 --- a/src/components/views/Login.tsx +++ b/src/components/views/Login.tsx @@ -70,6 +70,9 @@ const Login = () => { default: message = `Login failed: ${error.response.data.reason || "Please try again later."}`; } + } else { + // No response from the server + message = "The server cannot be reached. Did you start it?"; } showToast(message, "error"); } diff --git a/src/components/views/Register.tsx b/src/components/views/Register.tsx index d665b6d..cd839e0 100644 --- a/src/components/views/Register.tsx +++ b/src/components/views/Register.tsx @@ -67,6 +67,9 @@ const Register = () => { default: message = `Register failed: ${error.response.data.reason || "Please try again later."}`; } + } else { + // if no response from the server + message = "The server cannot be reached. Please try again later." } showToast(message, "error"); } From 3030622487b92a110404941dcd0823a13be53444 Mon Sep 17 00:00:00 2001 From: Shaochang Tan <478710209@qq.com> Date: Mon, 6 May 2024 19:12:59 +0200 Subject: [PATCH 3/6] 1.fix enterRoom typo 2.remove previous enterRoom function using put --- src/components/views/Lobby.tsx | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/components/views/Lobby.tsx b/src/components/views/Lobby.tsx index 97e71a9..027de05 100644 --- a/src/components/views/Lobby.tsx +++ b/src/components/views/Lobby.tsx @@ -257,7 +257,18 @@ const Lobby = () => { const onLobbyInfoReceived = (message) => { const message_lobby = JSON.parse(message.body); if (message_lobby && message_lobby.message) { - setRooms(message_lobby.message); // 确保这里是数组 + // make sure message.message is timestamped + const payload: RoomInfo[] = message_lobby.message; + // if me is in the room, redirect to the room + // const meIngameRoom = payload.some(room => room.roomPlayersList.some(user => user.userId === sessionStorage.getItem("id"))) + // if (meIngameRoom) { + // console.log("[DEBUG] Found me in the room, redirecting to the room page" + payload); + // const Room = payload.find(room => room.roomPlayersList.some(user => user.userId === sessionStorage.getItem("id"))); + // navigate(`/rooms/${Room.roomId}/${Room.roomName}`); + // showToast("Reconnect to your previous room!", "success"); + // } + + setRooms(payload); // 确保这里是数组 console.log("Rooms updated:", message_lobby.message); } else { console.error("Received data is not in expected format:", message_lobby); @@ -465,25 +476,24 @@ const Lobby = () => { const renderRoomLists = () => { return rooms.map((Room) => ( -
{ +
{ e.preventDefault(); - - const currentId = sessionStorage.getItem("id"); - enterRoom(Room.roomId, currentId) - .then(() => { - //alert(currentId); - if(Room.roomPlayersList.length===Room.maxPlayersNum) + // const currentId = sessionStorage.getItem("id"); + // console.error("RoomMaxPlayers:", Room.roomMaxNum); + // console.error("RoomPlayersList.length:", Room.roomPlayersList.length); + try { + if (Room.roomPlayersList.length === Room.roomMaxNum) showToast("Room is Full, please enter another room!", "error"); - else if(Room.status==="In Game") + else if (Room.status === "In Game") showToast("Game is already started, please enter another room!", "error"); else navigate(`/rooms/${Room.roomId}/${Room.roomName}`); - }) - .catch(error => { + } + catch (error) { console.error(`Something went wrong during the enterRoom: \n${error}`); // alert(`Something went wrong during the enterRoom: \n${error}`); showToast(`Something went wrong during the enterRoom: \n${error}`, "error"); - }); + }; }}>
From f8a98a68e71745c6793f5e3e74564c7766f9ad07 Mon Sep 17 00:00:00 2001 From: Shaochang Tan <478710209@qq.com> Date: Mon, 6 May 2024 19:19:30 +0200 Subject: [PATCH 4/6] add redirect logic if user is already in a room. --- src/components/views/Gameroom.tsx | 10 +-- src/components/views/Lobby.tsx | 117 +++++++++++++++++------------- src/stomp_types.ts | 16 ++++ 3 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/components/views/Gameroom.tsx b/src/components/views/Gameroom.tsx index 869f1be..47d27b0 100644 --- a/src/components/views/Gameroom.tsx +++ b/src/components/views/Gameroom.tsx @@ -6,9 +6,9 @@ import PropTypes from "prop-types"; import "styles/views/Gameroom.scss"; import "styles/views/Header.scss"; import "styles/twemoji-amazing.css"; -import Header from "./Header"; +import Header from "./Header" import { FFmpeg } from "@ffmpeg/ffmpeg"; -import { Roundstatus, RoundstatusProps} from "components/views/GameroomRoundStatus"; +import { Roundstatus, RoundstatusProps } from "components/views/GameroomRoundStatus"; import { PlayerList } from "components/views/GameroomPlayerList"; import { ValidateAnswerForm } from "components/views/GameroomAnswerForm"; // Stomp related imports @@ -174,7 +174,7 @@ const Gameroom = () => { const myInfo = payloadData.message.find(item => item.user.id === user.id); //console.log("set info for myself") //console.log(myInfo); - if (myInfo.roundFinished !== null){ + if (myInfo && myInfo.roundFinished !== null){ roundFinished.current = myInfo.roundFinished; //console.log("roundFinished?") //console.log(roundFinished.current); @@ -188,7 +188,7 @@ const Gameroom = () => { const onGameInfoReceived = (payload) => { const payloadData = JSON.parse(payload.body); - console.error("GameInfo received", JSON.stringify(payloadData.message)); + // console.error("GameInfo received", JSON.stringify(payloadData.message)); if (JSON.stringify(gameInfoRef.current) === JSON.stringify(payloadData.message)) { console.log("Same game info received, ignore"); @@ -593,7 +593,7 @@ const Gameroom = () => { }; - if (playerLists === null) { + if (playerLists === null || playerLists.length === 0) { return
Loading...
; } diff --git a/src/components/views/Lobby.tsx b/src/components/views/Lobby.tsx index 027de05..b73032b 100644 --- a/src/components/views/Lobby.tsx +++ b/src/components/views/Lobby.tsx @@ -1,4 +1,6 @@ -import React, { useRef, useEffect, useState } from "react"; +import React, { useCallback, useRef, useEffect, useState } from "react"; +import { showToast } from "helpers/toastService"; +import { v4 as uuidv4 } from "uuid"; import { api, handleError } from "helpers/api"; import { Button } from "components/ui/Button"; import { useLocation, useNavigate } from "react-router-dom"; @@ -13,6 +15,7 @@ import "styles/ui/Popup.scss"; import { MAX_USERNAME_LENGTH, MAX_ROOM_NAME_LENGTH } from "../../constants/constants"; import SockJS from "sockjs-client"; import { over } from "stompjs"; +import { Timestamped, RoomInfo, RoomPlayer, PlayerAndRoomID } from "stomp_types"; const DEFAULT_MAX_PLAYERS = 5; const DEFAULT_MIN_PLAYERS = 2; @@ -186,7 +189,7 @@ const Lobby = () => { const changeAvatarPopRef = useRef(null); const infoPopRef = useRef(null); const [rooms, setRooms] = useState([]); - const [user, setUser] = useState(null); + const [user, setUser] = useState(null); const [username, setUsername] = useState(""); const [avatar, setAvatar] = useState(null); const [roomName, setRoomName] = useState(""); @@ -218,13 +221,13 @@ const Lobby = () => { // Get current user's information /// handle error outside // try { - const userResponse = await api.get(`/users/${userId}`); - setUser(userResponse.data); // Set user data from API - console.log("User data:", userResponse.data); + const userResponse = await api.get(`/users/${userId}`); + setUser(userResponse.data); // Set user data from API + console.log("User data:", userResponse.data); // } catch (error) { // handleError(error); - - return; + + return; // } } else { console.error("User ID not found in sessionStorage!"); @@ -248,7 +251,7 @@ const Lobby = () => { onLobbyInfoReceived ); stompClientRef.current?.send( - "/app/message/lobby/info",{ receiptId: "" } + "/app/message/lobby/info", { receiptId: "" } ); @@ -277,7 +280,11 @@ const Lobby = () => { const onError = (error) => { console.error("WebSocket Error:", error); - handleError(error); + // handleError(error); + // if error is network error, clear the session and navigate to login page + showToast("Whoops! Lost connection to sever!", "error"); + sessionStorage.clear(); + navigate("/login"); }; fetchData().catch(error => { @@ -301,22 +308,27 @@ const Lobby = () => { }, []); // when user get navigated back to this page, fetch data again - const location = useLocation(); + // const location = useLocation(); // console.warn("Location:", location); const RELOAD_TIME_MS = 500; + // when first time loading the page, check if the user is in the room useEffect(() => { // wait for 1 second before fetching data const timeoutId = setTimeout(() => { - console.log("========fetchData========"); - fetchData().catch(error => { - handleError(error); - }); + console.log("========check if already in room========"); + const meInRoom = rooms.some(room => room.roomPlayersList.some(user => user.userId === sessionStorage.getItem("id"))) + if (meInRoom) { + console.log("[DEBUG] Found me in the room, redirecting to the room page" + rooms); + const Room = rooms.find(room => room.roomPlayersList.some(user => user.userId === sessionStorage.getItem("id"))); + navigate(`/rooms/${Room.roomId}/${Room.roomName}`); + showToast("Reconnect to your previous room!", "success"); + } }, RELOAD_TIME_MS); return () => { clearTimeout(timeoutId); } - }, [location]); + }, []); const doEdit = async () => { try { @@ -328,7 +340,7 @@ const Lobby = () => { toggleProfilePop(); } catch (error) { handleError(error); - + return; } }; @@ -338,7 +350,7 @@ const Lobby = () => { if (!navigator.userAgent.includes("Chrome")) { // alert("Your browser is currently not supported, please use Chrome to play this game!"); showToast("Your browser is currently not supported, please use Chrome to play this game!", "error"); - + return; } try { @@ -359,7 +371,7 @@ const Lobby = () => { //toggleRoomCreationPop(); // 关闭创建房间的弹窗 } catch (error) { handleError(error); - + return; } }; @@ -386,16 +398,16 @@ const Lobby = () => { : profilePopRef.current.showModal(); }; - async function enterRoom(roomId, userId) { - try { - const requestBody = JSON.stringify({ id: userId }); - // await api.put(`/games/${roomId}`, requestBody); - } catch (error) { - handleError(error); - - return; - } - } + // async function enterRoom(roomId, userId) { + // try { + // const requestBody = JSON.stringify({ id: userId }); + // // await api.put(`/games/${roomId}`, requestBody); + // } catch (error) { + // handleError(error); + + // return; + // } + // } const toggleAvatarPop = () => { // if the ref is not set, do nothing @@ -420,7 +432,7 @@ const Lobby = () => { : infoPopRef.current.showModal(); }; - const changeAvatar = async (newAvatar) =>{ + const changeAvatar = async (newAvatar) => { try { // 更新本地状态 setAvatar(newAvatar); @@ -434,7 +446,7 @@ const Lobby = () => { updateAvatar(newAvatar); } catch (error) { handleError(error); - + return; } } @@ -461,7 +473,7 @@ const Lobby = () => { // // if error message is undefined // showToast("Something went wrong, please try again later.", "error"); // } - if(error.message.match(/Network Error/)) { + if (error.message.match(/Network Error/)) { console.error(`The server cannot be reached.\nDid you start it?\n${error}`); showToast(`The server cannot be reached.\nDid you start it?\n${error}`); sessionStorage.clear(); @@ -483,33 +495,32 @@ const Lobby = () => { // console.error("RoomPlayersList.length:", Room.roomPlayersList.length); try { if (Room.roomPlayersList.length === Room.roomMaxNum) - showToast("Room is Full, please enter another room!", "error"); + showToast("Room is Full, please enter another room!", "error"); else if (Room.status === "In Game") - showToast("Game is already started, please enter another room!", "error"); - else - navigate(`/rooms/${Room.roomId}/${Room.roomName}`); + showToast("Game is already started, please enter another room!", "error"); + else + navigate(`/rooms/${Room.roomId}/${Room.roomName}`); } catch (error) { - console.error(`Something went wrong during the enterRoom: \n${error}`); - // alert(`Something went wrong during the enterRoom: \n${error}`); - showToast(`Something went wrong during the enterRoom: \n${error}`, "error"); + console.error(`Something went wrong during the enterRoom: \n${error}`); + // alert(`Something went wrong during the enterRoom: \n${error}`); + showToast(`Something went wrong during the enterRoom: \n${error}`, "error"); }; }}>
{Room.roomPlayersList?.map((user, index) => (
- +
{user.userName}
))}
-
{Room.roomName}
+
{Room.roomName}
{Room.theme}
{Room.status} @@ -519,14 +530,18 @@ const Lobby = () => { )); }; + if (user === null) { + return Loading...; + } return (
{user.username}
@@ -553,13 +568,13 @@ const Lobby = () => {
- +
{ toggleAvatarPop(); toggleProfilePop(); }}> - +
{ className="room-creation-popup" >
- {avatarList?.map((avatar,index) => ( + {avatarList?.map((avatar, index) => (
- { + { changeAvatar(avatar).then(r => toggleAvatarPop); toggleAvatarPop(); - }}/> + }} />
))}
@@ -652,7 +667,7 @@ const Lobby = () => { prompt="Select Theme" // defaultValue={roomTheme} options={[ - { value: "JOB", label: "JOB"}, + { value: "JOB", label: "JOB" }, { value: "FOOD", label: "FOOD" }, { value: "SUPERHERO", label: "SUPERHERO" }, { value: "SPORTS", label: "SPORTS" }, diff --git a/src/stomp_types.ts b/src/stomp_types.ts index b25c1f6..2e134b1 100644 --- a/src/stomp_types.ts +++ b/src/stomp_types.ts @@ -26,6 +26,22 @@ export type AnswerGuess = { currentSpeakerID: string; } +export type RoomInfo = { + roomMaxNum: number; + roomOwnerId: string; + theme: string; + roomPlayersList: RoomPlayer[]; + roomId: string; + roomName: string; + status: string; +} + +export type RoomPlayer = { + avatar: string; + userName: string; + userId: string; +} + export type StompResponse = { success: boolean; message: string; // error message From 0c725fbf32491a386407e9da5d9e86cd6a13a21a Mon Sep 17 00:00:00 2001 From: Shaochang Tan <478710209@qq.com> Date: Mon, 6 May 2024 20:11:06 +0200 Subject: [PATCH 5/6] fix reconnect logic by add dependency in reconnection useEffect --- src/components/views/Lobby.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/views/Lobby.tsx b/src/components/views/Lobby.tsx index b73032b..ba7d259 100644 --- a/src/components/views/Lobby.tsx +++ b/src/components/views/Lobby.tsx @@ -287,12 +287,14 @@ const Lobby = () => { navigate("/login"); }; + // make sure user was fetched before set timeoutId fetchData().catch(error => { handleError(error); }); connectWebSocket(); + return () => { if (lobbyInfoSuber) { lobbyInfoSuber.unsubscribe(); @@ -316,7 +318,9 @@ const Lobby = () => { // wait for 1 second before fetching data const timeoutId = setTimeout(() => { console.log("========check if already in room========"); + console.warn("Rooms:", rooms); const meInRoom = rooms.some(room => room.roomPlayersList.some(user => user.userId === sessionStorage.getItem("id"))) + console.log("Me in room:", meInRoom); if (meInRoom) { console.log("[DEBUG] Found me in the room, redirecting to the room page" + rooms); const Room = rooms.find(room => room.roomPlayersList.some(user => user.userId === sessionStorage.getItem("id"))); @@ -327,8 +331,8 @@ const Lobby = () => { return () => { clearTimeout(timeoutId); - } - }, []); + }; + }, [rooms]); const doEdit = async () => { try { From 15133fb7dba0551b0ec14e90bde56aa23d103cc0 Mon Sep 17 00:00:00 2001 From: Shaochang Tan <478710209@qq.com> Date: Mon, 6 May 2024 20:25:46 +0200 Subject: [PATCH 6/6] remove "navigation back logic when response received" --- src/components/views/Gameroom.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/Gameroom.tsx b/src/components/views/Gameroom.tsx index 47d27b0..2bdffce 100644 --- a/src/components/views/Gameroom.tsx +++ b/src/components/views/Gameroom.tsx @@ -158,8 +158,8 @@ const Gameroom = () => { const onResponseReceived = (payload) => { const payloadData = JSON.parse(payload.body); console.error("Response received", payloadData.message); - alert("Response server side receive!"+payloadData.message) - navigate("/lobby"); + // alert("Response server side receive!"+payloadData.message) + // navigate("/lobby"); // TODO: handle response /// 1. filter the response by the receiptId /// 2. if the response is success, do nothing