diff --git a/components/molecules/LobbyStatus.tsx b/components/molecules/LobbyStatus.tsx new file mode 100644 index 0000000..7ef8f19 --- /dev/null +++ b/components/molecules/LobbyStatus.tsx @@ -0,0 +1,20 @@ +import { Card } from "@zeit-ui/react"; +import { JellyfishSpinner } from "react-spinners-kit"; +import { ClientGame } from "../../types/types"; + +const LobbyStatus = ({ selectedGame }: LobbyStatusProps): JSX.Element => ( + + + + {selectedGame + ? selectedGame.name + " selected! Waiting for host to start..." + : "Waiting for host to select a game..."} + + +); + +type LobbyStatusProps = { + selectedGame: ClientGame; +}; + +export default LobbyStatus; diff --git a/components/organisms/Lobby.tsx b/components/organisms/LobbyScreen.tsx similarity index 76% rename from components/organisms/Lobby.tsx rename to components/organisms/LobbyScreen.tsx index dd18d9c..6bed520 100644 --- a/components/organisms/Lobby.tsx +++ b/components/organisms/LobbyScreen.tsx @@ -5,14 +5,13 @@ import { Spacer } from "@zeit-ui/react"; import GameSelector from "./GameSelector"; import { Player, ClientGameLibrary } from "../../types/types"; import { useState } from "react"; -import NameBox from "../atoms/NameBox"; -import GameDetailBox from "../atoms/GameDetailBox"; +import LobbyStatus from "../molecules/LobbyStatus"; const Lobby = ({ playerList, gameLibrary, onSelectGame, - selectedGame, + selectedGameId, onStartGame, resetName, meId, @@ -32,18 +31,11 @@ const Lobby = ({ ) : ( <> - {selectedGame ? ( - id === selectedGame - )} - allCategories={gameLibrary.categories} - readyToPlay={true} - showOnlyHostMessage={false} - /> - ) : ( - - )} + id === selectedGameId + )} + /> ; gameLibrary: ClientGameLibrary; onSelectGame: (gameId: string) => void; - selectedGame: string; + selectedGameId: string; onStartGame: () => void; resetName: () => void; meId: number; diff --git a/components/templates/GameLayout.tsx b/components/templates/GameLayout.tsx index e797d5f..9dc519b 100644 --- a/components/templates/GameLayout.tsx +++ b/components/templates/GameLayout.tsx @@ -10,7 +10,7 @@ import PlayerList from "../molecules/PlayerList"; const GameLayout = ({ gameState, path, - selectedGame, + selectedGameId, onExitGame, onStartGame, onHostGameLoaded, @@ -24,7 +24,7 @@ const GameLayout = ({ } = gameState; const { renameParams } = gameLibrary.gameList.find( - ({ id }) => id == selectedGame + ({ id }) => id == selectedGameId ); const { name, isHost } = thisPlayer; @@ -245,7 +245,7 @@ const GameLayout = ({ type GameLayoutProps = { gameState: GameState; - selectedGame: string; + selectedGameId: string; path: string; onExitGame: () => void; onStartGame: () => void; diff --git a/package-lock.json b/package-lock.json index 14cf68e..519067d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1442,6 +1442,24 @@ "minimist": "^1.2.0" } }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -4085,6 +4103,17 @@ "@types/babel__traverse": "^7.0.6" } }, + "babel-plugin-styled-components": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.11.1.tgz", + "integrity": "sha512-YwrInHyKUk1PU3avIRdiLyCpM++18Rs1NgyMXEAQC33rIXs/vro0A+stf4sT0Gf22Got+xRWB8Cm0tw+qkRzBA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-module-imports": "^7.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11" + } + }, "babel-plugin-syntax-jsx": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", @@ -4680,6 +4709,11 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -5308,6 +5342,11 @@ } } }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -5392,6 +5431,23 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "css-to-react-native": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.2.tgz", + "integrity": "sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, "css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -8124,6 +8180,11 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-what": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.11.2.tgz", + "integrity": "sha512-m7LzBsC9TqUhkBrozSmmWfVO7VYnjk9UHu0U+Y8BiJRnc1TYIK/3Qv4DteuiBpn2S4K7n3N4WNC4pe6wEx2xYg==" + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -12023,6 +12084,11 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoize-one": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", + "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -12038,6 +12104,14 @@ "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", "dev": true }, + "merge-anything": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-2.4.4.tgz", + "integrity": "sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ==", + "requires": { + "is-what": "^3.3.1" + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -13355,6 +13429,11 @@ "ts-pnp": "^1.1.6" } }, + "polished": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/polished/-/polished-1.9.3.tgz", + "integrity": "sha512-4NmSD7fMFlM8roNxs7YXPv7UFRbYzb0gufR5zBxJLRzY54+zFsavxBo6zsQzP9ep6Hh3pC2pTyrpSTBEaB6IkQ==" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -14169,6 +14248,18 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" }, + "react-spinners-kit": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/react-spinners-kit/-/react-spinners-kit-1.9.1.tgz", + "integrity": "sha512-QtAvSD7b1WkThY3pRKu6Sr+DZafnEufoOvug/uHprkKyZK6bg6TG5LC3Sy3JaRh6A/HACIcTNEWG+Ls0YDoSHg==", + "requires": { + "polished": "^1.9.3", + "prop-types": "^15.6.2", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "styled-components": "^4.4.1" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -15616,6 +15707,36 @@ } } }, + "styled-components": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-4.4.1.tgz", + "integrity": "sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@emotion/is-prop-valid": "^0.8.1", + "@emotion/unitless": "^0.7.0", + "babel-plugin-styled-components": ">= 1", + "css-to-react-native": "^2.2.2", + "memoize-one": "^5.0.0", + "merge-anything": "^2.2.4", + "prop-types": "^15.5.4", + "react-is": "^16.6.0", + "stylis": "^3.5.0", + "stylis-rule-sheet": "^0.0.10", + "supports-color": "^5.5.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "styled-jsx": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-3.3.0.tgz", diff --git a/package.json b/package.json index ff48359..66e5946 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-ga": "^3.1.2", + "react-spinners-kit": "^1.9.1", "socket.io": "^2.3.0", "ws": "^7.3.1" }, diff --git a/pages/[code].tsx b/pages/[code].tsx index 39f8971..e5c0f62 100644 --- a/pages/[code].tsx +++ b/pages/[code].tsx @@ -4,15 +4,21 @@ import { useRouter } from "next/router"; import socketIOClient from "socket.io-client"; import PageLayout from "../components/templates/PageLayout"; -import Lobby from "../components/organisms/Lobby"; +import LobbyScreen from "../components/organisms/LobbyScreen"; import NameEntry from "../components/organisms/NameEntry"; import GameLayout from "../components/templates/GameLayout"; -import { GameState, ClientGameLibrary, JoinGameURL } from "../types/types"; +import { + GameState, + ClientGameLibrary, + JoinGameURL, + ClientLobby, +} from "../types/types"; import { getClientGameLibrary } from "../config"; import { parseCookies, setCookie as setNookie } from "nookies"; import Connecting from "../components/atoms/Connecting"; import { logEvent } from "../utils/analytics"; +import { LobbyStatus } from "../types/enums"; const CLIENT_GAME_LIBRARY = getClientGameLibrary(); const socket = socketIOClient(); @@ -27,7 +33,7 @@ export const Code = ({ const [lobbyState, setLobbyState] = useState(initLobbyState()); const [showReconnecting, setShowReconnecting] = useState(false); - const { status, me, playerList, selectedGame, gameState } = lobbyState; + const { status, me, playerList, selectedGameId, gameState } = lobbyState; const { isHost } = me; @@ -35,7 +41,7 @@ export const Code = ({ useEffect(() => { socket.open(); - socket.on("update", (newLobbyState) => { + socket.on("update", (newLobbyState: ClientLobby) => { setLobbyState(newLobbyState); setShowReconnecting(false); }); @@ -98,7 +104,7 @@ export const Code = ({ socket.emit("game-start"); logEvent("lobby-numberOfPlayers", playerList.length.toString()); - logEvent("lobby-game", selectedGame); + logEvent("lobby-game", selectedGameId); }; const onExitGame = () => { @@ -131,11 +137,11 @@ export const Code = ({ )} {showLobby && ( - onNameEntry("")} meId={me.id} @@ -149,7 +155,7 @@ export const Code = ({ ({ - status: "loading" as string, +const initLobbyState = (): ClientLobby => ({ + status: LobbyStatus.loading, playerList: [], me: { id: undefined, name: undefined, isHost: undefined }, - selectedGame: "", + selectedGameId: "", gameState: { status: undefined, joinGameURL: {} as JoinGameURL, diff --git a/server/api.ts b/server/api.ts index e736816..882057b 100644 --- a/server/api.ts +++ b/server/api.ts @@ -43,10 +43,10 @@ export default (server: Application, { lobbyList }: RocketCrab): void => { server.get("/api/stats", (req: Request, res: Response) => { res.json( lobbyList.map( - ({ status, gameState, selectedGame, playerList }) => ({ + ({ status, gameState, selectedGameId, playerList }) => ({ lobbyStatus: status, gameStatus: gameState.status, - selectedGame, + selectedGameId, numberOfPlayers: playerList.length, }) ) diff --git a/server/rocketcrab.ts b/server/rocketcrab.ts index 6b4ed0a..17171d2 100644 --- a/server/rocketcrab.ts +++ b/server/rocketcrab.ts @@ -22,7 +22,7 @@ export const newLobby = ( playerList: [], code, uuid, - selectedGame: "", + selectedGameId: "", gameState: { status: GameStatus.loading, joinGameURL: { playerURL: "", hostURL: "" }, @@ -133,15 +133,15 @@ export const setName = ( export const setGame = (gameId: string, lobby: Lobby): void => { if (findGameById(gameId)) { - lobby.selectedGame = gameId; + lobby.selectedGameId = gameId; } }; export const startGame = async (lobby: Lobby): Promise => { // TODO: check if ready - const { gameState, selectedGame, playerList } = lobby; + const { gameState, selectedGameId, playerList } = lobby; - const game: ServerGame = findGameById(selectedGame); + const game: ServerGame = findGameById(selectedGameId); if (!game) return; lobby.status = LobbyStatus.ingame; diff --git a/test/server/api.test.ts b/test/server/api.test.ts index 8016e8f..68d35fb 100644 --- a/test/server/api.test.ts +++ b/test/server/api.test.ts @@ -48,7 +48,9 @@ describe("server/api.ts", () => { handler(req, res); expect(rocketcrab.lobbyList[0].uuid).toEqual(req.params.uuid); - expect(rocketcrab.lobbyList[0].selectedGame).toEqual(req.params.gameid); + expect(rocketcrab.lobbyList[0].selectedGameId).toEqual( + req.params.gameid + ); expect(res.cookie.mock.calls[0][1]).toEqual(req.query.name); }); @@ -118,7 +120,9 @@ describe("server/api.ts", () => { }; handler(req, res); - expect(rocketcrab.lobbyList[0].selectedGame).toEqual(req.params.gameid); + expect(rocketcrab.lobbyList[0].selectedGameId).toEqual( + req.params.gameid + ); }); it("/transfer works without uuid even if gameid invalid", () => { @@ -134,6 +138,6 @@ describe("server/api.ts", () => { }; handler(req, res); - expect(rocketcrab.lobbyList[0].selectedGame).toBe(""); + expect(rocketcrab.lobbyList[0].selectedGameId).toBe(""); }); }); diff --git a/test/server/rocketcrab.test.ts b/test/server/rocketcrab.test.ts index adf74ee..170b09b 100644 --- a/test/server/rocketcrab.test.ts +++ b/test/server/rocketcrab.test.ts @@ -188,7 +188,7 @@ describe("server/rocketcrab.ts", () => { status: LobbyStatus.lobby, playerList: jsonPlayerList, code: "efgh", - selectedGame: "FooGame", + selectedGameId: "FooGame", gameState: {} as GameState, nextPlayerId: 1, idealHostId: 0, @@ -272,7 +272,7 @@ describe("server/rocketcrab.ts", () => { setGame("lk-coolgame", mockLobby); - expect(mockLobby.selectedGame).toBe("lk-coolgame"); + expect(mockLobby.selectedGameId).toBe("lk-coolgame"); }); it("setName works", () => { @@ -302,7 +302,7 @@ describe("server/rocketcrab.ts", () => { it("startGame works", async () => { const mockLobby = generateMockLobby({ status: LobbyStatus.lobby, - selectedGame: "jd-foogame", + selectedGameId: "jd-foogame", gameState: { status: undefined, }, @@ -326,7 +326,7 @@ describe("server/rocketcrab.ts", () => { it("startGame fails if game doesn't exist", () => { const mockLobby = generateMockLobby({ status: LobbyStatus.lobby, - selectedGame: "GameThatDoesntExist", + selectedGameId: "GameThatDoesntExist", gameState: { status: undefined, }, @@ -341,7 +341,7 @@ describe("server/rocketcrab.ts", () => { it("exitGame works", () => { const mockLobby = generateMockLobby({ status: LobbyStatus.ingame, - selectedGame: "FooGame", + selectedGameId: "FooGame", gameState: { status: GameStatus.inprogress, joinGameURL: { @@ -364,7 +364,7 @@ const generateMockLobby = ({ status = LobbyStatus.lobby, playerList = [], code = "efgh", - selectedGame = "FooGame", + selectedGameId = "FooGame", gameState = {} as GameState, nextPlayerId = 1, idealHostId = 0, @@ -372,7 +372,7 @@ const generateMockLobby = ({ status, playerList, code, - selectedGame, + selectedGameId, gameState, nextPlayerId, idealHostId, diff --git a/types/types.ts b/types/types.ts index 2facf3c..71262c2 100644 --- a/types/types.ts +++ b/types/types.ts @@ -10,10 +10,19 @@ export type Lobby = { playerList: Array; code: string; uuid?: string; - selectedGame: string; + selectedGameId: string; gameState: GameState; nextPlayerId: number; idealHostId: number; + me?: Player; +}; + +export type ClientLobby = { + status: LobbyStatus; + playerList: Array; + me: Player; + selectedGameId: ""; + gameState: GameState; }; export type Player = {