From 11c597e4ba5a7384f6100ff5c5beccbae8ab38a7 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 22 Jun 2024 13:31:45 +0530 Subject: [PATCH] Added Event Handler Handles different events and updates the game state accordingly Also Integrated with GameProvider to handle these events --- frontend/src/clientDispatch.ts | 123 ++++++++++++++++++++++++++ frontend/src/contexts/GameContext.tsx | 37 ++++---- 2 files changed, 140 insertions(+), 20 deletions(-) create mode 100644 frontend/src/clientDispatch.ts diff --git a/frontend/src/clientDispatch.ts b/frontend/src/clientDispatch.ts new file mode 100644 index 0000000..095fbc0 --- /dev/null +++ b/frontend/src/clientDispatch.ts @@ -0,0 +1,123 @@ +import { GameEvent, GameEventTypes } from '../../backend/src/types'; +import { GameState } from './contexts/GameContext'; +import { triggerEvent } from './channel'; + +export const clientDispatch = ( + gameState: GameState, + event: GameEvent +): GameState => { + let newGameState: GameState; + + switch (event.type) { + case GameEventTypes.JOIN_GAME: + newGameState = handleJoinGame(gameState, event); + break; + case GameEventTypes.LEAVE_GAME: + newGameState = handleLeaveGame(gameState, event); + break; + case GameEventTypes.DRAW_CARD: + newGameState = handleDrawCard(gameState, event); + break; + case GameEventTypes.THROW_CARD: + newGameState = handleThrowCard(gameState, event); + break; + case GameEventTypes.STATE_SYNC: + newGameState = handleStateSync(gameState, event); + break; + default: + throw new Error(`Unhandled event type: ${event}`); + } + + // Trigger the event to the server + triggerEvent(event); + + return newGameState; +}; + +const handleJoinGame = (gameState: GameState, event: GameEvent): GameState => { + if (event.type !== GameEventTypes.JOIN_GAME) { + throw new Error(`Invalid event type for handleJoinGame: ${event.type}`); + } + const { playerId } = event; + return { + ...gameState, + players: [...gameState.players, { id: playerId, cards: [] }], + }; +}; + +const handleLeaveGame = (gameState: GameState, event: GameEvent): GameState => { + if (event.type !== GameEventTypes.LEAVE_GAME) { + throw new Error( + `Invalid event type for handleLeaveGame: ${event.type}` + ); + } + const { playerId } = event; + return { + ...gameState, + players: gameState.players.filter((player) => player.id !== playerId), + }; +}; + +const handleDrawCard = (gameState: GameState, event: GameEvent): GameState => { + if (event.type !== GameEventTypes.DRAW_CARD) { + throw new Error(`Invalid event type for handleDrawCard: ${event.type}`); + } + + const { playerId } = event; + + // Find the player who drew the card + const updatedPlayers = gameState.players.map((player) => { + if (player.id === playerId) { + // Assume the last card in the player's deck is the drawn card + const drawnCardId = player.cards[player.cards.length - 1]; // Last drawn card + const updatedCards = [...player.cards, drawnCardId]; + return { ...player, cards: updatedCards }; + } + return player; + }); + + return { + ...gameState, + players: updatedPlayers, + }; +}; + +const handleThrowCard = (gameState: GameState, event: GameEvent): GameState => { + if (event.type !== GameEventTypes.THROW_CARD) { + throw new Error( + `Invalid event type for handleThrowCard: ${event.type}` + ); + } + const { playerId, data } = event; + const { cardId } = data; + return { + ...gameState, + players: gameState.players.map((player) => + player.id === playerId + ? { ...player, cards: player.cards.filter((c) => c !== cardId) } + : player + ), + lastThrownCard: cardId, + }; +}; + +const handleStateSync = (gameState: GameState, event: GameEvent): GameState => { + if (event.type !== GameEventTypes.STATE_SYNC) { + throw new Error( + `Invalid event type for handleStateSync: ${event.type}` + ); + } + const { data } = event; + const mappedPlayers = data.players.map((player) => ({ + id: player.id, + cards: player.cards.map((card) => card.id), + })); + + return { + ...gameState, + players: mappedPlayers, + cards: data.cards.map((card) => card.id), + currentTurn: data.currentTurn, + lastThrownCard: data.lastThrownCard, + }; +}; diff --git a/frontend/src/contexts/GameContext.tsx b/frontend/src/contexts/GameContext.tsx index 223736a..83adf00 100644 --- a/frontend/src/contexts/GameContext.tsx +++ b/frontend/src/contexts/GameContext.tsx @@ -5,8 +5,10 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { useAuth } from './AuthContext'; import { useToast } from '../library/toast/toast-context'; import * as channel from '../channel'; +import { clientDispatch } from '../clientDispatch'; +import { GameEvent } from '../../../backend/src/types'; -interface GameState { +export interface GameState { players: { id: string; cards: string[] }[]; cards: string[]; currentTurn: number; @@ -40,7 +42,11 @@ export const GameProvider = () => { const toast = useToast(); const auth = useAuth(); const backendUrl = process.env.REACT_APP_BACKEND_URL; - + const dispatchGameEvent = (event: GameEvent) => { + setGameState((prevState) => + clientDispatch(prevState as GameState, event) + ); + }; useEffect(() => { if (!auth.isLoggedIn()) { navigate('/'); @@ -109,25 +115,16 @@ export const GameProvider = () => { // polling useEffect(() => { - // add event listener to listen for the game state changes - channel.setGameEventsDispatcher((event) => { - // todo: this callback will be replaced by the event dispatcher - console.log('Handling event:', event); - if (event.type === 'STATE_SYNC') { - setGameState({ - players: event.data.players.map((player) => { - return { - id: player.id, - cards: player.cards.map((card) => card.id), - }; - }), - cards: event.data.cards.map((card) => card.id), - currentTurn: event.data.currentTurn, - lastThrownCard: event.data.lastThrownCard, - }); - } + channel.setGameEventsDispatcher((event: GameEvent) => { + dispatchGameEvent(event); }); - }, [gameState]); + + channel.startPolling(); + + return () => { + channel.stopPolling(); + }; + }, []); return (