types for client/server interaction
This commit is contained in:
@@ -6,37 +6,48 @@ import { socket } from "@/socket";
|
|||||||
|
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
|
|
||||||
import type { GameCard } from '@/types';
|
import type { GameCard, GameUpdate, ClientUpdate } from '@/types';
|
||||||
|
|
||||||
export default function GamePage() {
|
export default function GamePage() {
|
||||||
const { gameID } = useParams();
|
const { gameID: gameIDParam } = useParams();
|
||||||
|
|
||||||
|
const [gameID, setGameID] = useState('');
|
||||||
const [cards, setCards] = useState<GameCard[]>([]);
|
const [cards, setCards] = useState<GameCard[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (gameIDParam) {
|
||||||
|
setGameID(Array.isArray(gameIDParam) ? gameIDParam[0] : gameIDParam);
|
||||||
|
}
|
||||||
|
}, [gameIDParam])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (gameID) {
|
||||||
socket.emit('join', gameID);
|
socket.emit('join', gameID);
|
||||||
|
|
||||||
socket.on('init', data => {
|
socket.on('init', (data: GameUpdate) => {
|
||||||
console.log('init', data);
|
console.log('init', data);
|
||||||
setCards(data.cards);
|
setCards(data.cards);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('card-flipped', (data) => {
|
socket.on('card-flipped', (data: GameUpdate) => {
|
||||||
console.log('>>>', data);
|
console.log('>>>', data);
|
||||||
setCards(data.cards);
|
setCards(data.cards);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return gameID ? () => {
|
||||||
socket.off('init');
|
socket.off('init');
|
||||||
socket.off('card-flipped');
|
socket.off('card-flipped');
|
||||||
};
|
} : undefined;
|
||||||
}, []);
|
}, [gameID]);
|
||||||
|
|
||||||
const flipCard = (cardID: string) => {
|
const flipCard = (cardID: string) => {
|
||||||
socket.emit('flip-card', {
|
const flip: ClientUpdate = {
|
||||||
cardID,
|
|
||||||
gameID,
|
gameID,
|
||||||
});
|
cardID,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit('flip-card', flip);
|
||||||
};
|
};
|
||||||
|
|
||||||
return cards.length ? (
|
return cards.length ? (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Cards from './Cards'
|
import Cards from './Cards'
|
||||||
|
|
||||||
import { GameState } from '../types'
|
import { GameState, GameUpdate } from '../types'
|
||||||
|
|
||||||
const deck = new Cards();
|
const deck = new Cards();
|
||||||
|
|
||||||
@@ -26,13 +26,13 @@ export default class GameStore {
|
|||||||
return newGame;
|
return newGame;
|
||||||
}
|
}
|
||||||
|
|
||||||
joinGame(gameID: string, playerID: string): GameState {
|
joinGame(gameID: string, playerID: string): GameUpdate {
|
||||||
const game = this.games.get(gameID) || this.createGame(gameID);
|
const game = this.games.get(gameID) || this.createGame(gameID);
|
||||||
|
|
||||||
game.players.add(playerID);
|
game.players.add(playerID);
|
||||||
game.lastUpdated = Date.now();
|
game.lastUpdated = Date.now();
|
||||||
|
|
||||||
return game;
|
return this.gameUpdate(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveGame(gameID: string, playerID: string): GameState {
|
leaveGame(gameID: string, playerID: string): GameState {
|
||||||
@@ -44,7 +44,7 @@ export default class GameStore {
|
|||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
flipCard(gameID: string, cardID: string): GameState {
|
flipCard(gameID: string, cardID: string): GameUpdate {
|
||||||
const game = this.getGame(gameID);
|
const game = this.getGame(gameID);
|
||||||
const card = game.cards.find(c => c.id === cardID);
|
const card = game.cards.find(c => c.id === cardID);
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ export default class GameStore {
|
|||||||
card.flipped = !card.flipped;
|
card.flipped = !card.flipped;
|
||||||
game.lastUpdated = Date.now();
|
game.lastUpdated = Date.now();
|
||||||
|
|
||||||
return game;
|
return this.gameUpdate(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
getGame(gameID: string): GameState {
|
getGame(gameID: string): GameState {
|
||||||
@@ -64,6 +64,11 @@ export default class GameStore {
|
|||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameUpdate(game: GameState): GameUpdate {
|
||||||
|
const { id, cards } = game;
|
||||||
|
return { id, cards };
|
||||||
|
}
|
||||||
|
|
||||||
deleteGame(gameID: string): void {
|
deleteGame(gameID: string): void {
|
||||||
this.games.delete(gameID);
|
this.games.delete(gameID);
|
||||||
}
|
}
|
||||||
|
|||||||
13
server.ts
13
server.ts
@@ -3,6 +3,7 @@ import { createServer } from 'http';
|
|||||||
import { Server as SocketIOServer, type Socket } from 'socket.io';
|
import { Server as SocketIOServer, type Socket } from 'socket.io';
|
||||||
|
|
||||||
import GameStore from './lib/GameStore';
|
import GameStore from './lib/GameStore';
|
||||||
|
import type { ClientUpdate } from './types';
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV !== 'production';
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
const hostname = 'localhost';
|
const hostname = 'localhost';
|
||||||
@@ -24,17 +25,19 @@ app.prepare().then(() => {
|
|||||||
|
|
||||||
socket.on('join', (gameID) => {
|
socket.on('join', (gameID) => {
|
||||||
socket.join(gameID);
|
socket.join(gameID);
|
||||||
const game = gameStore.joinGame(gameID, socket.id);
|
const gameUpdate = gameStore.joinGame(gameID, socket.id);
|
||||||
|
|
||||||
console.log(`Socket ${socket.id} joined game ${gameID}`)
|
console.log(`Socket ${socket.id} joined game ${gameID}`)
|
||||||
|
|
||||||
socket.emit('init', { cards: game.cards });
|
socket.emit('init', gameUpdate);
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('flip-card', ({ gameID, cardID }) => {
|
socket.on('flip-card', ({ gameID, cardID }: ClientUpdate) => {
|
||||||
console.log('Card flipped:', { gameID, cardID });
|
console.log('Card flipped:', { gameID, cardID });
|
||||||
const game = gameStore.flipCard(gameID, cardID);
|
|
||||||
io.to(gameID).emit('card-flipped', { gameID, cards: game.cards });
|
const gameUpdate = gameStore.flipCard(gameID, cardID);
|
||||||
|
|
||||||
|
io.to(gameID).emit('card-flipped', gameUpdate);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "ES2020",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|||||||
@@ -17,3 +17,13 @@ export interface GameState {
|
|||||||
cards: GameCard[];
|
cards: GameCard[];
|
||||||
lastUpdated: number;
|
lastUpdated: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GameUpdate {
|
||||||
|
id: string;
|
||||||
|
cards: GameCard[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientUpdate {
|
||||||
|
gameID: string;
|
||||||
|
cardID: string;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user