Handle game not found errors in landing page

landing-page-layout
MiguelMLorente 2025-02-09 22:52:15 +01:00
parent 1d777f74ff
commit e7ea4269d7
7 changed files with 51 additions and 11 deletions

View File

@ -17,6 +17,7 @@ import {
} from 'interface'; } from 'interface';
import { createWsExceptionFilter } from './websocket-exception-filter'; import { createWsExceptionFilter } from './websocket-exception-filter';
import { import {
GameNotFoundException,
InvalidPlayerNameException, InvalidPlayerNameException,
MissingPlayerNameException, MissingPlayerNameException,
PlayerNotFoundException, PlayerNotFoundException,
@ -62,6 +63,7 @@ export class AppService implements OnGatewayConnection {
PlayerNotFoundException, PlayerNotFoundException,
MissingPlayerNameException, MissingPlayerNameException,
InvalidPlayerNameException, InvalidPlayerNameException,
GameNotFoundException,
]), ]),
) )
@SubscribeMessage(ClientEvent.JOIN_LOBBY) @SubscribeMessage(ClientEvent.JOIN_LOBBY)

View File

@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { Game } from './game'; import { Game } from './game';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { Player } from 'src/players/player'; import { Player } from 'src/players/player';
import { GameNotFoundException } from 'src/exceptions';
@Injectable() @Injectable()
export class GameService { export class GameService {
@ -19,7 +20,7 @@ export class GameService {
joinGame(player: Player, gameCode: string): Game { joinGame(player: Player, gameCode: string): Game {
const game = this.games.get(gameCode); const game = this.games.get(gameCode);
if (game === undefined) { if (game === undefined) {
throw Error('No se ha encontrado el Lobby'); throw new GameNotFoundException(gameCode);
} }
game.players.push(player); game.players.push(player);
return game; return game;

View File

@ -11,7 +11,7 @@ import { Socket } from 'socket.io/dist/socket';
export class PlayerService { export class PlayerService {
private readonly logger = new Logger(PlayerService.name); private readonly logger = new Logger(PlayerService.name);
private readonly players: Map<string, Player> = new Map(); private readonly players: Map<string, Player> = new Map();
private readonly userNameValidator: RegExp = /(^[a-zA-Z]){1,20}$/; private readonly userNameValidator: RegExp = /^[a-zA-Z\s]{1,20}$/;
createPlayer(socket: Socket) { createPlayer(socket: Socket) {
const player: Player = new Player(socket); const player: Player = new Player(socket);

View File

@ -3,7 +3,7 @@ import { BaseWsExceptionFilter } from '@nestjs/websockets';
import { WebSocketException } from './exceptions'; import { WebSocketException } from './exceptions';
import { Socket } from 'socket.io'; import { Socket } from 'socket.io';
import { ClientEvent } from 'interface'; import { ClientEvent } from 'interface';
import { emitCreateLobbyError } from 'interface'; import { emitCreateLobbyError, emitJoinLobbyError } from 'interface';
export const createWsExceptionFilter: ( export const createWsExceptionFilter: (
exceptionList: (typeof WebSocketException)[], exceptionList: (typeof WebSocketException)[],
@ -27,6 +27,8 @@ export const createWsExceptionFilter: (
case ClientEvent.CREATE_LOBBY: case ClientEvent.CREATE_LOBBY:
emitCreateLobbyError(socket, { error: exception.errorCode }); emitCreateLobbyError(socket, { error: exception.errorCode });
break; break;
case ClientEvent.JOIN_LOBBY:
emitJoinLobbyError(socket, { error: exception.errorCode });
} }
} }
} }

View File

@ -5,6 +5,7 @@ export * from "./constants/InternalNodeType";
export * from "./constants/Pieces"; export * from "./constants/Pieces";
export * from "./constants/TrackType"; export * from "./constants/TrackType";
export * from "./server-events/CreateLobbyError"; export * from "./server-events/CreateLobbyError";
export * from "./server-events/JoinLobbyError";
export * from "./server-events/ServerError"; export * from "./server-events/ServerError";
export * from "./server-events/ServerEvent"; export * from "./server-events/ServerEvent";
export * from "./server-events/StartRoundEvent"; export * from "./server-events/StartRoundEvent";

View File

@ -0,0 +1,22 @@
import { Socket as ServerSocket } from "socket.io";
import { Socket as ClientSocket } from "socket.io-client";
import { ErrorCode, ServerError } from "./ServerError";
export type JoinLobbyError = {
error: ErrorCode;
};
export const emitJoinLobbyError = (
socket: ServerSocket,
payload: JoinLobbyError,
) => {
socket.emit(ServerError.JOIN_LOBBY_ERROR, payload);
};
export const attachHandlerToJoinLobbyError = (
socket: ClientSocket,
handler: (payload: JoinLobbyError) => void,
): (() => void) => {
socket.on(ServerError.JOIN_LOBBY_ERROR, handler);
return () => socket.off(ServerError.JOIN_LOBBY_ERROR);
};

View File

@ -1,12 +1,13 @@
import { import {
attachHandlerToCreateLobbyError, attachHandlerToCreateLobbyError,
attachHandlerToJoinLobbyError,
CreateLobbyEvent, CreateLobbyEvent,
ErrorCode, ErrorCode,
handleCreateLobby, handleCreateLobby,
handleJoinLobby, handleJoinLobby,
JoinLobbyEvent, JoinLobbyEvent,
} from "interface"; } from "interface";
import React, { ChangeEvent, useState } from "react"; import { ChangeEvent, useState } from "react";
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
import "./LandingPage.scss"; import "./LandingPage.scss";
@ -17,14 +18,14 @@ export interface LandingPageProps {
const LandingPage = (props: LandingPageProps) => { const LandingPage = (props: LandingPageProps) => {
const { socket } = props; const { socket } = props;
const createLobbyPayload: CreateLobbyEvent = { userName: "" }; const [userName, setUsername] = useState("");
const joinLobbyPayload: JoinLobbyEvent = { userName: "", lobbyId: "" }; const [lobbyId, setLobbyId] = useState("");
const registerUsername = (event: ChangeEvent<HTMLInputElement>) => { const createLobbyPayload: CreateLobbyEvent = { userName };
createLobbyPayload.userName = event.target.value; const joinLobbyPayload: JoinLobbyEvent = { userName, lobbyId };
joinLobbyPayload.userName = event.target.value; const registerUsername = (event: ChangeEvent<HTMLInputElement>) =>
}; setUsername(event.target.value);
const registerLobbyId = (event: ChangeEvent<HTMLInputElement>) => const registerLobbyId = (event: ChangeEvent<HTMLInputElement>) =>
(joinLobbyPayload.lobbyId = event.target.value); setLobbyId(event.target.value);
const [receivedError, setReceivedError] = useState("" as ErrorCode); const [receivedError, setReceivedError] = useState("" as ErrorCode);
const userNameErrorCodesToMessageMap = new Map([ const userNameErrorCodesToMessageMap = new Map([
@ -36,10 +37,18 @@ const LandingPage = (props: LandingPageProps) => {
]); ]);
const userNameErrorMessage = const userNameErrorMessage =
userNameErrorCodesToMessageMap.get(receivedError); userNameErrorCodesToMessageMap.get(receivedError);
const gameCodeErrorCodesToMessageMap = new Map([
[ErrorCode.GAME_NOT_FOUND, "No game found with such lobby ID"],
]);
const gameCodeErrorMessage =
gameCodeErrorCodesToMessageMap.get(receivedError);
attachHandlerToCreateLobbyError(socket, (event) => attachHandlerToCreateLobbyError(socket, (event) =>
setReceivedError(event.error), setReceivedError(event.error),
); );
attachHandlerToJoinLobbyError(socket, (event) =>
setReceivedError(event.error),
);
return ( return (
<div className="landing-page"> <div className="landing-page">
@ -66,6 +75,9 @@ const LandingPage = (props: LandingPageProps) => {
onChange={registerLobbyId} onChange={registerLobbyId}
maxLength={5} maxLength={5}
></input> ></input>
{gameCodeErrorMessage && (
<small id="error-message">{gameCodeErrorMessage}</small>
)}
<button <button
className="secondary" className="secondary"
onClick={() => handleJoinLobby(socket, joinLobbyPayload)} onClick={() => handleJoinLobby(socket, joinLobbyPayload)}