- {!myProfile.isPlayer && !myProfile.isAdmin ? (
+ {!isPlayer && !isAdmin ? (
@@ -60,18 +25,18 @@ const Home = () => {
) : (
- {myProfile.isPlayer ? (
+ {isPlayer ? (
) : null}
- {myProfile.isPlayer && !myProfile.isAdmin ? (
+ {isPlayer && !isAdmin ? (
) : null}
- {myProfile.isAdmin ? : null}
+ {isAdmin ? : null}
)}
diff --git a/src/pages/Layout/Layout.tsx b/src/pages/Layout/Layout.tsx
index 9d1dfc9..ae85345 100644
--- a/src/pages/Layout/Layout.tsx
+++ b/src/pages/Layout/Layout.tsx
@@ -1,17 +1,16 @@
import { useAuth0 } from "@auth0/auth0-react"
import { Outlet } from "react-router"
-import { useAppSelector } from "caches/hooks"
-import { getAccessToken } from "caches/MyProfileSlice"
import DefaultHeader from "components/Header/Header"
import { useEffect } from "react"
import Loading from "components/icons/Loading"
import { Box } from "@mui/material"
+import useAccessToken from "auth/accessToken"
const AUTH0_AUDIENCE = process.env.REACT_APP_AUTH0_AUDIENCE as string
const AUTH0_SCOPE = process.env.REACT_APP_AUTH0_SCOPE as string
const Layout = () => {
- const accessToken = useAppSelector(getAccessToken)
+ const { accessToken } = useAccessToken()
const { isLoading, isAuthenticated, loginWithRedirect } = useAuth0()
useEffect(() => {
diff --git a/src/services/GameService.ts b/src/services/GameService.ts
deleted file mode 100644
index 045ad23..0000000
--- a/src/services/GameService.ts
+++ /dev/null
@@ -1,209 +0,0 @@
-import { Card } from "model/Cards"
-import { CreateGame, Game, GameState } from "model/Game"
-import { Suit } from "model/Suit"
-import axios from "axios"
-import { getDefaultConfig } from "utils/AxiosUtils"
-import { Player, PlayerProfile } from "model/Player"
-import { AppThunk } from "caches/caches"
-import { updateGame, updatePlayers } from "caches/GameSlice"
-import { getAccessToken } from "caches/MyProfileSlice"
-import { addMyGame, removeMyGame, updateMyGames } from "caches/MyGamesSlice"
-import { updatePlayerProfiles } from "caches/PlayerProfilesSlice"
-import {
- clearSelectedCards,
- removeCard,
- updateMyCards,
-} from "caches/MyCardsSlice"
-import { clearAutoPlay } from "caches/PlayCardSlice"
-
-const getGame =
- (gameId: string): AppThunk
> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/game?gameId=${gameId}`,
- getDefaultConfig(accessToken),
- )
- return response.data
- }
-
-const refreshGameState =
- (gameId: string, iamSpectator: boolean): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/gameState?gameId=${gameId}`,
- getDefaultConfig(accessToken),
- )
- dispatch(updateGame(response.data))
- if (!iamSpectator) {
- dispatch(updateMyCards(response.data.cards))
- dispatch(clearAutoPlay())
- }
- }
-
-const getAll = (): AppThunk> => async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/game/all`,
- getDefaultConfig(accessToken),
- )
- dispatch(updateMyGames(response.data))
- return response.data
-}
-
-const getAllPlayers =
- (): AppThunk> => async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/admin/game/players/all`,
- getDefaultConfig(accessToken),
- )
- dispatch(updatePlayerProfiles(response.data))
- return response.data
- }
-
-const getPlayersForGame =
- (gameId: string): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/game/players?gameId=${gameId}`,
- getDefaultConfig(accessToken),
- )
-
- dispatch(updatePlayers(response.data))
-
- return response.data
- }
-
-const put =
- (createGame: CreateGame): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- const response = await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/admin/game`,
- createGame,
- getDefaultConfig(accessToken),
- )
-
- dispatch(addMyGame(response.data))
- return response.data
- }
-
-const finish =
- (gameId: string): AppThunk> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/admin/game/finish?gameId=${gameId}`,
- null,
- getDefaultConfig(accessToken),
- )
- }
-
-const cancel =
- (gameId: string): AppThunk> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/admin/game/cancel?gameId=${gameId}`,
- null,
- getDefaultConfig(accessToken),
- )
- }
-
-const deleteGame =
- (gameId: string): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.delete(
- `${process.env.REACT_APP_API_URL}/api/v1/admin/game?gameId=${gameId}`,
- getDefaultConfig(accessToken),
- )
- dispatch(removeMyGame(gameId))
- }
-
-const replay =
- (gameId: string): AppThunk> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/replay?gameId=${gameId}`,
- null,
- getDefaultConfig(accessToken),
- )
- }
-
-const call =
- (gameId: string, call: number): AppThunk> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/call?gameId=${gameId}&call=${call}`,
- null,
- getDefaultConfig(accessToken),
- )
- }
-
-const buyCards =
- (gameId: string, cards: Card[] | string[]): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/buyCards?gameId=${gameId}`,
- cards.map(c => (typeof c === "string" ? c : c.name)),
- getDefaultConfig(accessToken),
- )
- dispatch(clearSelectedCards)
- }
-
-const chooseFromDummy =
- (gameId: string, cards: Card[], suit: Suit): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/chooseFromDummy?gameId=${gameId}&suit=${suit}`,
- cards.map(c => c.name),
- getDefaultConfig(accessToken),
- )
- dispatch(clearSelectedCards)
- }
-
-const playCard =
- (gameId: string, card: string): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/playCard?gameId=${gameId}&card=${card}`,
- null,
- getDefaultConfig(accessToken),
- )
-
- dispatch(removeCard(card))
- dispatch(clearAutoPlay())
- }
-
-export default {
- getGame,
- refreshGameState,
- getAll,
- getAllPlayers,
- getPlayersForGame,
- deleteGame,
- playCard,
- chooseFromDummy,
- buyCards,
- call,
- replay,
- put,
- finish,
- cancel,
-}
diff --git a/src/services/ProfileService.ts b/src/services/ProfileService.ts
deleted file mode 100644
index 2f8d2ed..0000000
--- a/src/services/ProfileService.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { getDefaultConfig } from "utils/AxiosUtils"
-
-import axios from "axios"
-import jwt_decode from "jwt-decode"
-import { AppThunk } from "caches/caches"
-import { getAccessToken, updateMyProfile } from "caches/MyProfileSlice"
-
-const hasProfile = (): AppThunk> => async (_, getState) => {
- const accessToken = getAccessToken(getState())
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/profile/has`,
- getDefaultConfig(accessToken),
- )
- return response.data
-}
-
-export interface UpdateProfilePayload {
- name: string
- picture: string
- forceUpdate?: boolean
-}
-
-interface ProfileResponse {
- id: string
- name: string
- picture: string
- pictureLocked: boolean
- lastAccess: string
-}
-
-interface JWTToken {
- permissions: string[]
-}
-
-const updateProfile =
- (
- payload: UpdateProfilePayload,
- accessToken?: string,
- ): AppThunk> =>
- async (dispatch, getState) => {
- const token = accessToken ?? getAccessToken(getState())
- if (!token) throw Error("No access token found")
-
- const response = await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/profile`,
- payload,
- getDefaultConfig(token),
- )
- const decodedAccessToken = jwt_decode(token)
- dispatch(
- updateMyProfile({
- id: response.data.id,
- name: response.data.name,
- picture: response.data.picture,
- isPlayer:
- decodedAccessToken.permissions.indexOf("read:game") !== -1,
- isAdmin:
- decodedAccessToken.permissions.indexOf("read:admin") !== -1,
- accessToken: token,
- lastAccess: response.data.lastAccess,
- }),
- )
- }
-
-export default { hasProfile, updateProfile }
diff --git a/src/services/SettingsService.ts b/src/services/SettingsService.ts
deleted file mode 100644
index 8db7254..0000000
--- a/src/services/SettingsService.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import axios from "axios"
-import { AppThunk } from "caches/caches"
-import { getAccessToken } from "caches/MyProfileSlice"
-import { PlayerSettings } from "model/PlayerSettings"
-import { getDefaultConfig } from "utils/AxiosUtils"
-import { updateSettings as updateSettingsCache } from "caches/SettingsSlice"
-
-const getSettings =
- (): AppThunk> => async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
-
- const response = await axios.get(
- `${process.env.REACT_APP_API_URL}/api/v1/settings`,
- getDefaultConfig(accessToken),
- )
- dispatch(updateSettingsCache(response.data))
- return response.data
- }
-
-const updateSettings =
- (settings: PlayerSettings): AppThunk> =>
- async (dispatch, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/settings`,
- settings,
- getDefaultConfig(accessToken),
- )
-
- dispatch(updateSettingsCache(settings))
- }
-
-export default { getSettings, updateSettings }
diff --git a/src/services/SpectatorService.ts b/src/services/SpectatorService.ts
deleted file mode 100644
index 8dea8f0..0000000
--- a/src/services/SpectatorService.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import axios from "axios"
-import { AppThunk } from "caches/caches"
-import { getAccessToken } from "caches/MyProfileSlice"
-import { getDefaultConfig } from "utils/AxiosUtils"
-
-const register =
- (gameId: string): AppThunk> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- await axios.put(
- `${process.env.REACT_APP_API_URL}/api/v1/spectator/register?gameId=${gameId}`,
- null,
- getDefaultConfig(accessToken),
- )
- }
-
-export default { register }
diff --git a/src/services/StatsService.ts b/src/services/StatsService.ts
deleted file mode 100644
index 6b9441e..0000000
--- a/src/services/StatsService.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import axios from "axios"
-import { AppThunk } from "caches/caches"
-import { getAccessToken } from "caches/MyProfileSlice"
-import { PlayerGameStats } from "model/Player"
-import { getDefaultConfig } from "utils/AxiosUtils"
-
-const gameStatsForPlayer =
- (playerId?: string): AppThunk> =>
- async (_, getState) => {
- const accessToken = getAccessToken(getState())
-
- const url = playerId
- ? `${
- process.env.REACT_APP_API_URL
- }/api/v1/admin/stats/gameStatsForPlayer?playerId=${encodeURIComponent(
- playerId,
- )}`
- : `${process.env.REACT_APP_API_URL}/api/v1/stats/gameStatsForPlayer`
-
- const response = await axios.get(url, getDefaultConfig(accessToken))
-
- return response.data
- }
-
-export default { gameStatsForPlayer }
diff --git a/src/test/data/buy-cards/after-buy-cards.json b/src/test/data/buy-cards/after-buy-cards.json
new file mode 100644
index 0000000..ccc9a39
--- /dev/null
+++ b/src/test/data/buy-cards/after-buy-cards.json
@@ -0,0 +1,65 @@
+{
+ "id": "game1",
+ "revision": 24,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": false,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "currentPlayerId": "player2",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/test/data/buy-cards/before-buy-cards.json b/src/test/data/buy-cards/before-buy-cards.json
new file mode 100644
index 0000000..58d71d5
--- /dev/null
+++ b/src/test/data/buy-cards/before-buy-cards.json
@@ -0,0 +1,65 @@
+{
+ "id": "game1",
+ "revision": 22,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "BUYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/test/data/call/after-call.json b/src/test/data/call/after-call.json
new file mode 100644
index 0000000..b34ab65
--- /dev/null
+++ b/src/test/data/call/after-call.json
@@ -0,0 +1,63 @@
+{
+ "id": "game1",
+ "revision": 0,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": false,
+ "iamGoer": false,
+ "iamDealer": true,
+ "iamAdmin": true,
+ "maxCall": 0,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T09:25:58.651Z",
+ "number": 1,
+ "dealerId": "player1",
+ "status": "CALLING",
+ "currentHand": {
+ "timestamp": "2024-01-25T09:25:58.651Z",
+ "currentPlayerId": "player2",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "QUEEN_HEARTS",
+ "SIX_DIAMONDS",
+ "TEN_CLUBS",
+ "FIVE_DIAMONDS",
+ "TWO_SPADES"
+ ]
+}
diff --git a/src/test/data/call/before-call.json b/src/test/data/call/before-call.json
new file mode 100644
index 0000000..b34ab65
--- /dev/null
+++ b/src/test/data/call/before-call.json
@@ -0,0 +1,63 @@
+{
+ "id": "game1",
+ "revision": 0,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": false,
+ "iamGoer": false,
+ "iamDealer": true,
+ "iamAdmin": true,
+ "maxCall": 0,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T09:25:58.651Z",
+ "number": 1,
+ "dealerId": "player1",
+ "status": "CALLING",
+ "currentHand": {
+ "timestamp": "2024-01-25T09:25:58.651Z",
+ "currentPlayerId": "player2",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "QUEEN_HEARTS",
+ "SIX_DIAMONDS",
+ "TEN_CLUBS",
+ "FIVE_DIAMONDS",
+ "TWO_SPADES"
+ ]
+}
diff --git a/src/test/data/card-played/after-card-played.json b/src/test/data/card-played/after-card-played.json
new file mode 100644
index 0000000..899b458
--- /dev/null
+++ b/src/test/data/card-played/after-card-played.json
@@ -0,0 +1,71 @@
+{
+ "id": "game1",
+ "revision": 25,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "leadOut": "NINE_CLUBS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "NINE_CLUBS"
+ }
+ ]
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/test/data/card-played/before-card-played.json b/src/test/data/card-played/before-card-played.json
new file mode 100644
index 0000000..ccc9a39
--- /dev/null
+++ b/src/test/data/card-played/before-card-played.json
@@ -0,0 +1,65 @@
+{
+ "id": "game1",
+ "revision": 24,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": false,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "currentPlayerId": "player2",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/test/data/game-end/after-game-end.json b/src/test/data/game-end/after-game-end.json
new file mode 100644
index 0000000..f94c132
--- /dev/null
+++ b/src/test/data/game-end/after-game-end.json
@@ -0,0 +1,135 @@
+{
+ "id": "game1",
+ "revision": 188,
+ "status": "COMPLETED",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 125,
+ "rings": 2,
+ "teamId": "1",
+ "winner": true
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 125,
+ "rings": 2,
+ "teamId": "1",
+ "winner": true
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 65,
+ "rings": 2,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T12:49:33.956Z",
+ "number": 14,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "HEARTS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T13:51:22.941201+01:00",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": [
+ {
+ "timestamp": "2024-01-25T12:49:33.956Z",
+ "leadOut": "QUEEN_HEARTS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "QUEEN_HEARTS"
+ },
+ {
+ "playerId": "player1",
+ "card": "THREE_HEARTS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:18.778Z",
+ "leadOut": "FOUR_HEARTS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "FOUR_HEARTS"
+ },
+ {
+ "playerId": "player1",
+ "card": "SIX_HEARTS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:33.96Z",
+ "leadOut": "FIVE_HEARTS",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "FIVE_HEARTS"
+ },
+ {
+ "playerId": "player2",
+ "card": "FOUR_DIAMONDS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:42.35Z",
+ "leadOut": "SEVEN_HEARTS",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "SEVEN_HEARTS"
+ },
+ {
+ "playerId": "player2",
+ "card": "SEVEN_CLUBS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:53.224Z",
+ "leadOut": "THREE_DIAMONDS",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "THREE_DIAMONDS"
+ },
+ {
+ "playerId": "player2",
+ "card": "FIVE_SPADES"
+ }
+ ]
+ }
+ ]
+ },
+ "cards": null
+}
diff --git a/src/test/data/game-end/before-game-end.json b/src/test/data/game-end/before-game-end.json
new file mode 100644
index 0000000..067047d
--- /dev/null
+++ b/src/test/data/game-end/before-game-end.json
@@ -0,0 +1,126 @@
+{
+ "id": "game1",
+ "revision": 187,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 105,
+ "rings": 2,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": false,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 105,
+ "rings": 2,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 60,
+ "rings": 2,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T12:49:33.956Z",
+ "number": 14,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "HEARTS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T12:50:53.224Z",
+ "leadOut": "THREE_DIAMONDS",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "THREE_DIAMONDS"
+ }
+ ]
+ },
+ "dealerSeeingCall": false,
+ "completedHands": [
+ {
+ "timestamp": "2024-01-25T12:49:33.956Z",
+ "leadOut": "QUEEN_HEARTS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "QUEEN_HEARTS"
+ },
+ {
+ "playerId": "player1",
+ "card": "THREE_HEARTS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:18.778Z",
+ "leadOut": "FOUR_HEARTS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "FOUR_HEARTS"
+ },
+ {
+ "playerId": "player1",
+ "card": "SIX_HEARTS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:33.96Z",
+ "leadOut": "FIVE_HEARTS",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "FIVE_HEARTS"
+ },
+ {
+ "playerId": "player2",
+ "card": "FOUR_DIAMONDS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T12:50:42.35Z",
+ "leadOut": "SEVEN_HEARTS",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "SEVEN_HEARTS"
+ },
+ {
+ "playerId": "player2",
+ "card": "SEVEN_CLUBS"
+ }
+ ]
+ }
+ ]
+ },
+ "cards": null
+}
diff --git a/src/test/data/hand-end/after-hand-end.json b/src/test/data/hand-end/after-hand-end.json
new file mode 100644
index 0000000..8451e2e
--- /dev/null
+++ b/src/test/data/hand-end/after-hand-end.json
@@ -0,0 +1,80 @@
+{
+ "id": "game1",
+ "revision": 26,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T12:55:15.854232+01:00",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": [
+ {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "leadOut": "NINE_CLUBS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "NINE_CLUBS"
+ },
+ {
+ "playerId": "player1",
+ "card": "FOUR_CLUBS"
+ }
+ ]
+ }
+ ]
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS"
+ ]
+}
diff --git a/src/test/data/hand-end/before-hand-end.json b/src/test/data/hand-end/before-hand-end.json
new file mode 100644
index 0000000..899b458
--- /dev/null
+++ b/src/test/data/hand-end/before-hand-end.json
@@ -0,0 +1,71 @@
+{
+ "id": "game1",
+ "revision": 25,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "leadOut": "NINE_CLUBS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "NINE_CLUBS"
+ }
+ ]
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/test/data/pass/after-pass.json b/src/test/data/pass/after-pass.json
new file mode 100644
index 0000000..97547dc
--- /dev/null
+++ b/src/test/data/pass/after-pass.json
@@ -0,0 +1,63 @@
+{
+ "id": "game1",
+ "revision": 80,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 40,
+ "rings": 1,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": false,
+ "iamGoer": false,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 0,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 40,
+ "rings": 1,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 5,
+ "rings": 1,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:57:48.548Z",
+ "number": 6,
+ "dealerId": "player2",
+ "status": "CALLING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:57:48.548Z",
+ "currentPlayerId": "player2",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "FOUR_HEARTS",
+ "NINE_HEARTS",
+ "THREE_DIAMONDS",
+ "SEVEN_SPADES",
+ "TEN_CLUBS"
+ ]
+}
diff --git a/src/test/data/pass/before-pass.json b/src/test/data/pass/before-pass.json
new file mode 100644
index 0000000..d7be93c
--- /dev/null
+++ b/src/test/data/pass/before-pass.json
@@ -0,0 +1,63 @@
+{
+ "id": "game1",
+ "revision": 79,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 40,
+ "rings": 1,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": false,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 0,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 40,
+ "rings": 1,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 5,
+ "rings": 1,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T12:57:48.548711+01:00",
+ "number": 6,
+ "dealerId": "player2",
+ "status": "CALLING",
+ "currentHand": {
+ "timestamp": "2024-01-25T12:57:48.548711+01:00",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "FOUR_HEARTS",
+ "NINE_HEARTS",
+ "THREE_DIAMONDS",
+ "SEVEN_SPADES",
+ "TEN_CLUBS"
+ ]
+}
diff --git a/src/test/data/round-end/after-round-end.json b/src/test/data/round-end/after-round-end.json
new file mode 100644
index 0000000..9594e4c
--- /dev/null
+++ b/src/test/data/round-end/after-round-end.json
@@ -0,0 +1,63 @@
+{
+ "id": "game1",
+ "revision": 19,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": false,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 0,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T12:38:38.687034+01:00",
+ "number": 2,
+ "dealerId": "player2",
+ "status": "CALLING",
+ "currentHand": {
+ "timestamp": "2024-01-25T12:38:38.687034+01:00",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "FOUR_HEARTS",
+ "KING_CLUBS",
+ "TWO_DIAMONDS"
+ ]
+}
diff --git a/src/test/data/round-end/before-round-end.json b/src/test/data/round-end/before-round-end.json
new file mode 100644
index 0000000..b2eeab3
--- /dev/null
+++ b/src/test/data/round-end/before-round-end.json
@@ -0,0 +1,128 @@
+{
+ "id": "game1",
+ "revision": 18,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": false,
+ "iamDealer": true,
+ "iamAdmin": true,
+ "maxCall": 25,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 25,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T09:25:58.651Z",
+ "number": 1,
+ "dealerId": "player1",
+ "goerId": "player2",
+ "suit": "SPADES",
+ "status": "PLAYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:37:15.895Z",
+ "leadOut": "TEN_HEARTS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "TEN_HEARTS"
+ }
+ ]
+ },
+ "dealerSeeingCall": false,
+ "completedHands": [
+ {
+ "timestamp": "2024-01-25T09:25:58.651Z",
+ "leadOut": "TWO_SPADES",
+ "currentPlayerId": "player2",
+ "playedCards": [
+ {
+ "playerId": "player1",
+ "card": "TWO_SPADES"
+ },
+ {
+ "playerId": "player2",
+ "card": "QUEEN_SPADES"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T11:37:01.996Z",
+ "leadOut": "FIVE_SPADES",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "FIVE_SPADES"
+ },
+ {
+ "playerId": "player1",
+ "card": "EIGHT_CLUBS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T11:37:07.397Z",
+ "leadOut": "JACK_SPADES",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "JACK_SPADES"
+ },
+ {
+ "playerId": "player1",
+ "card": "THREE_HEARTS"
+ }
+ ]
+ },
+ {
+ "timestamp": "2024-01-25T11:37:11.393Z",
+ "leadOut": "JACK_HEARTS",
+ "currentPlayerId": "player1",
+ "playedCards": [
+ {
+ "playerId": "player2",
+ "card": "JACK_HEARTS"
+ },
+ {
+ "playerId": "player1",
+ "card": "FIVE_HEARTS"
+ }
+ ]
+ }
+ ]
+ },
+ "cards": [
+ "SIX_HEARTS"
+ ]
+}
diff --git a/src/test/data/select-suit/after-select-suit.json b/src/test/data/select-suit/after-select-suit.json
new file mode 100644
index 0000000..58d71d5
--- /dev/null
+++ b/src/test/data/select-suit/after-select-suit.json
@@ -0,0 +1,65 @@
+{
+ "id": "game1",
+ "revision": 22,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "suit": "CLUBS",
+ "status": "BUYING",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "KING_CLUBS",
+ "ACE_CLUBS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/test/data/select-suit/before-select-suit.json b/src/test/data/select-suit/before-select-suit.json
new file mode 100644
index 0000000..8f426b2
--- /dev/null
+++ b/src/test/data/select-suit/before-select-suit.json
@@ -0,0 +1,69 @@
+{
+ "id": "game1",
+ "revision": 21,
+ "status": "ACTIVE",
+ "me": {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ "iamSpectator": false,
+ "isMyGo": true,
+ "iamGoer": true,
+ "iamDealer": false,
+ "iamAdmin": true,
+ "maxCall": 15,
+ "players": [
+ {
+ "id": "player1",
+ "seatNumber": 1,
+ "call": 15,
+ "cardsBought": 0,
+ "score": 0,
+ "rings": 0,
+ "teamId": "1",
+ "winner": false
+ },
+ {
+ "id": "player2",
+ "seatNumber": 2,
+ "call": 0,
+ "cardsBought": 0,
+ "score": 25,
+ "rings": 0,
+ "teamId": "2",
+ "winner": false
+ }
+ ],
+ "round": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "number": 2,
+ "dealerId": "player2",
+ "goerId": "player1",
+ "status": "CALLED",
+ "currentHand": {
+ "timestamp": "2024-01-25T11:38:38.687Z",
+ "currentPlayerId": "player1",
+ "playedCards": []
+ },
+ "dealerSeeingCall": false,
+ "completedHands": []
+ },
+ "cards": [
+ "JACK_CLUBS",
+ "JOKER",
+ "FOUR_HEARTS",
+ "KING_CLUBS",
+ "TWO_DIAMONDS",
+ "KING_SPADES",
+ "ACE_CLUBS",
+ "SIX_HEARTS",
+ "FOUR_DIAMONDS",
+ "FOUR_CLUBS"
+ ]
+}
diff --git a/src/utils/AxiosUtils.ts b/src/utils/AxiosUtils.ts
index a13a7ac..d62748f 100644
--- a/src/utils/AxiosUtils.ts
+++ b/src/utils/AxiosUtils.ts
@@ -1,7 +1,6 @@
import { AxiosRequestConfig } from "axios"
export const getDefaultConfig = (accessToken?: string): AxiosRequestConfig => {
- if (!accessToken) throw Error("No access token found")
return {
headers: {
Authorization: `Bearer ${accessToken}`,
diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts
new file mode 100644
index 0000000..b27b4c5
--- /dev/null
+++ b/src/utils/EventUtils.ts
@@ -0,0 +1,117 @@
+import { Actions } from "model/Events"
+import { GameStateResponse, GameStatus } from "model/Game"
+import { RoundStatus } from "model/Round"
+import { Player } from "model/Player"
+
+const callsChanged = (prev: Player[], curr: Player[]): boolean => {
+ let changed = false
+ prev.forEach(p => {
+ curr.forEach(c => {
+ if (p.id === c.id && p.call !== c.call && c.call !== 0) {
+ changed = true
+ }
+ })
+ })
+
+ return changed
+}
+
+export const isCallEvent = (
+ prevState: GameStateResponse,
+ currState: GameStateResponse,
+): boolean => {
+ return (
+ prevState.round?.status === RoundStatus.CALLING &&
+ prevState.round.currentHand?.currentPlayerId !==
+ currState.round?.currentHand?.currentPlayerId &&
+ callsChanged(prevState.players, currState.players)
+ )
+}
+
+export const isPassEvent = (
+ prevState: GameStateResponse,
+ currState: GameStateResponse,
+): boolean => {
+ return (
+ prevState.round?.status === RoundStatus.CALLING &&
+ prevState.round.currentHand?.currentPlayerId !==
+ currState.round?.currentHand?.currentPlayerId &&
+ !callsChanged(prevState.players, currState.players)
+ )
+}
+
+export const isSelectSuitEvent = (prevState: GameStateResponse): boolean => {
+ return prevState.round?.status === RoundStatus.CALLED
+}
+
+export const isBuyCardsEvent = (prevState: GameStateResponse): boolean => {
+ return prevState.round?.status === RoundStatus.BUYING
+}
+
+export const isCardPlayedEvent = (prevState: GameStateResponse): boolean => {
+ return prevState.round?.status === RoundStatus.PLAYING
+}
+
+export const isHandEndEvent = (
+ prevState: GameStateResponse,
+ currState: GameStateResponse,
+): boolean => {
+ return (
+ prevState.round?.status === RoundStatus.PLAYING &&
+ currState.round?.status === RoundStatus.PLAYING &&
+ prevState.round?.completedHands.length !==
+ currState.round?.completedHands.length
+ )
+}
+
+export const isRoundEndEvent = (
+ prevState: GameStateResponse,
+ currState: GameStateResponse,
+): boolean => {
+ return (
+ prevState.round?.status === RoundStatus.PLAYING &&
+ currState.round?.status === RoundStatus.PLAYING &&
+ prevState.round?.number !== currState.round?.number
+ )
+}
+
+export const isGameOverEvent = (
+ prevState: GameStateResponse,
+ currState: GameStateResponse,
+): boolean => {
+ return (
+ prevState.status === GameStatus.ACTIVE &&
+ currState.status === GameStatus.COMPLETED
+ )
+}
+
+export const determineEvent = (
+ prevState: GameStateResponse,
+ currState: GameStateResponse,
+): Actions => {
+ if (isCallEvent(prevState, currState)) {
+ return Actions.Call
+ }
+ if (isPassEvent(prevState, currState)) {
+ return Actions.Pass
+ }
+ if (isSelectSuitEvent(prevState)) {
+ return Actions.SelectSuit
+ }
+ if (isBuyCardsEvent(prevState)) {
+ return Actions.BuyCards
+ }
+ if (isRoundEndEvent(prevState, currState)) {
+ return Actions.RoundEnd
+ }
+ if (isHandEndEvent(prevState, currState)) {
+ return Actions.HandEnd
+ }
+ if (isCardPlayedEvent(prevState)) {
+ return Actions.CardPlayed
+ }
+ if (isGameOverEvent(prevState, currState)) {
+ return Actions.GameOver
+ }
+ return Actions.Unknown
+}
diff --git a/src/utils/GameUtils.ts b/src/utils/GameUtils.ts
index bfa7080..ff49ce8 100644
--- a/src/utils/GameUtils.ts
+++ b/src/utils/GameUtils.ts
@@ -53,7 +53,7 @@ export const processOrderedCardsAfterGameUpdate = (
// Find the delta between the existing cards and the updated cards we got from the api
const delta = currentCardsNoBlanks.filter(
- x => !updatedCardNames.includes(x.name),
+ x => !updatedCardNames?.includes(x.name),
)
// 1. If cards in payload match ordered cards then don't change orderedCards
@@ -160,7 +160,7 @@ export const bestCardLead = (round: Round) => {
// Remove played trump cards
round.completedHands.forEach(hand => {
- hand.playedCards.forEach(p => {
+ hand.playedCards?.forEach(p => {
const card = CARDS[p.card]
if (
(card && card.suit === round.suit) ||