diff --git a/src/caches/GameSlice.ts b/src/caches/GameSlice.ts index f9061be..6caabd6 100644 --- a/src/caches/GameSlice.ts +++ b/src/caches/GameSlice.ts @@ -45,12 +45,12 @@ export const getHasGame = createSelector( getGameStatus, status => status === GameStatus.ACTIVE || status === GameStatus.NONE, ) -export const isGameActive = createSelector( +export const getIsGameActive = createSelector( getGameStatus, status => status === GameStatus.ACTIVE, ) -export const isGameFinished = createSelector( +export const getIsGameFinished = createSelector( getGameStatus, status => status === GameStatus.FINISHED, ) @@ -73,7 +73,7 @@ export const getIsRoundPlaying = createSelector( status => status === RoundStatus.PLAYING, ) -export const isDoublesGame = createSelector( +export const getIsDoublesGame = createSelector( getGamePlayers, players => players.length === 6, ) diff --git a/src/caches/MyCardsSlice.ts b/src/caches/MyCardsSlice.ts index 8eb559b..d3d8210 100644 --- a/src/caches/MyCardsSlice.ts +++ b/src/caches/MyCardsSlice.ts @@ -1,4 +1,4 @@ -import { createSlice, PayloadAction } from "@reduxjs/toolkit" +import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit" import { BLANK_CARD, SelectableCard } from "../model/Cards" import { processOrderedCardsAfterGameUpdate } from "../utils/GameUtils" import { RootState } from "./caches" @@ -56,5 +56,7 @@ export const { } = myCardsSlice.actions export const getMyCards = (state: RootState) => state.myCards.cards -export const getMyCardsWithoutBlanks = (state: RootState) => - state.myCards.cards.filter(c => c.name !== BLANK_CARD.name) + +export const getMyCardsWithoutBlanks = createSelector(getMyCards, cards => + cards.filter(c => c.name !== BLANK_CARD.name), +) diff --git a/src/caches/MyProfileSlice.ts b/src/caches/MyProfileSlice.ts index d7dabb9..caf022c 100644 --- a/src/caches/MyProfileSlice.ts +++ b/src/caches/MyProfileSlice.ts @@ -1,4 +1,4 @@ -import { createSlice, PayloadAction } from "@reduxjs/toolkit" +import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit" import { MyProfile } from "../model/Player" import { RootState } from "./caches" @@ -24,4 +24,8 @@ export const myProfileSlice = createSlice({ export const { updateMyProfile } = myProfileSlice.actions export const getMyProfile = (state: RootState) => state.myProfile -export const getAccessToken = (state: RootState) => state.myProfile.accessToken + +export const getAccessToken = createSelector( + getMyProfile, + myProfile => myProfile.accessToken, +) diff --git a/src/components/Game/GameWrapper.tsx b/src/components/Game/GameWrapper.tsx index 4f6580b..cac3b9e 100644 --- a/src/components/Game/GameWrapper.tsx +++ b/src/components/Game/GameWrapper.tsx @@ -5,7 +5,6 @@ import PlayersAndCards from "./PlayersAndCards" import Calling from "./Calling" import Buying from "./Buying" import SelectSuit from "./SelectSuit" -import AutoActionManager from "./AutoActionManager" import WebsocketManager from "./WebsocketManager" import { useAppSelector } from "../../caches/hooks" @@ -17,7 +16,6 @@ const GameWrapper = () => { return ( - diff --git a/src/components/Game/MyCards.tsx b/src/components/Game/MyCards.tsx index bcc7cef..c203a37 100644 --- a/src/components/Game/MyCards.tsx +++ b/src/components/Game/MyCards.tsx @@ -152,7 +152,7 @@ const MyCards: React.FC = () => { {provided => (
diff --git a/src/components/Game/WebsocketManager.tsx b/src/components/Game/WebsocketManager.tsx index f7d7017..0b81b1b 100644 --- a/src/components/Game/WebsocketManager.tsx +++ b/src/components/Game/WebsocketManager.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from "react" +import React, { useCallback, useEffect, useState } from "react" import { StompSessionProvider, useSubscription } from "react-stomp-hooks" import { useAppDispatch, useAppSelector } from "../../caches/hooks" @@ -15,6 +15,7 @@ import shuffleAudioFile from "../../assets/sounds/shuffle.ogg" import playCardAudioFile from "../../assets/sounds/play_card.ogg" import callAudioFile from "../../assets/sounds/call.ogg" import passAudioFile from "../../assets/sounds/pass.ogg" +import AutoActionManager from "./AutoActionManager" const shuffleAudio = new Audio(shuffleAudioFile) const playCardAudio = new Audio(playCardAudioFile) @@ -49,11 +50,19 @@ interface ActionEvent { const WebsocketHandler = () => { const dispatch = useAppDispatch() + const [autoActionEnabled, setAutoActionEnabled] = useState(false) const playerProfiles = useAppSelector(getPlayerProfiles) const { enqueueSnackbar } = useSnackbar() const [previousAction, updatePreviousAction] = useState() + // Enable the auto action manager after a delay if it isn't already active + useEffect(() => { + setTimeout(() => { + if (!autoActionEnabled) setAutoActionEnabled(true) + }, 4000) + }, [autoActionEnabled]) + const handleWebsocketMessage = useCallback( (message: string) => { if (previousAction === "LAST_CARD_PLAYED") { @@ -79,6 +88,9 @@ const WebsocketHandler = () => { const gameState = actionEvent.content as GameState dispatch(updateGame(gameState)) } + + // Only enable the auto action manager when we have successfully processed a message + if (!autoActionEnabled) setAutoActionEnabled(true) } const reloadCards = (payload: unknown) => { @@ -142,7 +154,7 @@ const WebsocketHandler = () => { handleWebsocketMessage(message.body), ) - return null + return <>{autoActionEnabled && } } const WebsocketManager = () => { diff --git a/src/components/Header/NavBar.tsx b/src/components/Header/NavBar.tsx index b44eef4..bab4ac2 100644 --- a/src/components/Header/NavBar.tsx +++ b/src/components/Header/NavBar.tsx @@ -10,12 +10,12 @@ import ProfilePictureEditor from "../Avatar/ProfilePictureEditor" import GameHeader from "../Game/GameHeader" import { Col, Container, Row } from "reactstrap" import LeaderboardModal from "../Leaderboard/LeaderboardModal" -import { isGameActive } from "../../caches/GameSlice" +import { getIsGameActive } from "../../caches/GameSlice" const NavBar = () => { const { logout } = useAuth0() - const gameActive = useAppSelector(isGameActive) + const isGameActive = useAppSelector(getIsGameActive) const [showEditAvatar, setShowEditAvatar] = useState(false) const myProfile = useAppSelector(getMyProfile) @@ -40,10 +40,10 @@ const NavBar = () => { - {gameActive && } + {isGameActive && } - {gameActive && } + {isGameActive && }
diff --git a/src/components/Leaderboard/DoublesLeaderboard.tsx b/src/components/Leaderboard/DoublesLeaderboard.tsx index cd69646..91d6ef6 100644 --- a/src/components/Leaderboard/DoublesLeaderboard.tsx +++ b/src/components/Leaderboard/DoublesLeaderboard.tsx @@ -3,13 +3,11 @@ import DataTable, { TableColumn } from "react-data-table-component" import TrophyImage from "../../assets/icons/trophy.png" import { useAppSelector } from "../../caches/hooks" import { - getGame, getGamePlayers, getRound, - isGameFinished, + getIsGameFinished, } from "../../caches/GameSlice" import { getPlayerProfiles } from "../../caches/PlayerProfilesSlice" -import { GameStatus } from "../../model/Game" import { compareScore, compareTeamIds } from "../../utils/PlayerUtils" import { Player } from "../../model/Player" import { customStyles } from "../Tables/CustomStyles" @@ -34,7 +32,7 @@ const DoublesLeaderboard = () => { const round = useAppSelector(getRound) const players = useAppSelector(getGamePlayers) const playerProfiles = useAppSelector(getPlayerProfiles) - const gameOver = useAppSelector(isGameFinished) + const isGameFinished = useAppSelector(getIsGameFinished) const previousHand = useMemo(() => { if (round) return round.completedHands[round.completedHands.length - 1] @@ -111,7 +109,7 @@ const DoublesLeaderboard = () => { className="avatar" /> - {!gameOver && !!row.player1.previousCard ? ( + {!isGameFinished && !!row.player1.previousCard ? (
{previousHand ? ( {
) : null} - {!gameOver ? ( + {!isGameFinished ? (
{!!row.player1.cardsBought ? `Bought: ${row.player1.cardsBought}` @@ -148,7 +146,7 @@ const DoublesLeaderboard = () => { className="avatar" /> - {!gameOver && previousHand ? ( + {!isGameFinished && previousHand ? (
{previousHand ? ( {
) : null} - {!gameOver ? ( + {!isGameFinished ? (
{!!row.player2.cardsBought ? `Bought: ${row.player2.cardsBought}` @@ -195,7 +193,7 @@ const DoublesLeaderboard = () => {
), center: true, - omit: !gameOver, + omit: !isGameFinished, }, ] diff --git a/src/components/Leaderboard/Leaderboard.tsx b/src/components/Leaderboard/Leaderboard.tsx index c1c1221..2ca10ba 100644 --- a/src/components/Leaderboard/Leaderboard.tsx +++ b/src/components/Leaderboard/Leaderboard.tsx @@ -1,12 +1,12 @@ import SinglesLeaderboard from "./SinglesLeaderboard" import DoublesLeaderboard from "./DoublesLeaderboard" import { useAppSelector } from "../../caches/hooks" -import { isDoublesGame } from "../../caches/GameSlice" +import { getIsDoublesGame } from "../../caches/GameSlice" const Leaderboard = () => { - const isDoubles = useAppSelector(isDoublesGame) + const isDoublesGame = useAppSelector(getIsDoublesGame) - if (isDoubles) return + if (isDoublesGame) return return } diff --git a/src/pages/Game/Game.tsx b/src/pages/Game/Game.tsx index 0845aae..abd2dfd 100644 --- a/src/pages/Game/Game.tsx +++ b/src/pages/Game/Game.tsx @@ -10,7 +10,7 @@ import { useParams } from "react-router-dom" import { useAppDispatch, useAppSelector } from "../../caches/hooks" import { useSnackbar } from "notistack" -import { getHasGame, resetGame } from "../../caches/GameSlice" +import { getIsGameActive, resetGame } from "../../caches/GameSlice" import { clearAutoPlay } from "../../caches/AutoPlaySlice" import { clearMyCards } from "../../caches/MyCardsSlice" import RefreshingData from "../../components/icons/RefreshingData" @@ -19,7 +19,7 @@ const Game = () => { const dispatch = useAppDispatch() let { id } = useParams() const { enqueueSnackbar } = useSnackbar() - const hasGame = useAppSelector(getHasGame) + const isGameActive = useAppSelector(getIsGameActive) const fetchData = async () => { if (id) @@ -50,7 +50,7 @@ const Game = () => {
- {hasGame ? : } + {isGameActive ? : }
diff --git a/src/pages/Game/_game.scss b/src/pages/Game/_game.scss index ac59142..9037145 100644 --- a/src/pages/Game/_game.scss +++ b/src/pages/Game/_game.scss @@ -16,6 +16,13 @@ filter: drop-shadow(16px 16px 20px red); } +.myCards { + border-style: solid; + border-width: 5px; + border-radius: 10px; + padding: 2px; +} + // .carpet { // background-image: url("/assets/img/carpet2.jpg"); // }