refactor join_game_request to require unique users
This commit is contained in:
parent
eeca5480ec
commit
f0c0b9a0f6
12 changed files with 191 additions and 16 deletions
|
@ -3,12 +3,53 @@ import { Link } from 'react-router-dom';
|
|||
import './Game.scss';
|
||||
|
||||
const GameButton = (props) => {
|
||||
const gameData = props.game;
|
||||
const { game, dispatch } = props;
|
||||
|
||||
const requestJoinGame = () => {
|
||||
console.log(`request to Join Game ${game.id}!`)
|
||||
const requestAction = {
|
||||
type: 'GAMES',
|
||||
message: 'JOIN_REQUEST',
|
||||
body: {id: game.id}
|
||||
}
|
||||
dispatch(requestAction);
|
||||
}
|
||||
|
||||
const renderOpenGame = () => {
|
||||
return (
|
||||
<>
|
||||
<a onClick={() => requestJoinGame()} >Request to Join Game</a>
|
||||
|
||||
<div className="Game__playerData">
|
||||
<span className="Game__playerData__name">{game.playerBlack}</span>
|
||||
<span className="Game__playerData__rank">{game.playerBlackRank}</span>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const renderInProgressGame = () => {
|
||||
const gameLinkText = game.winType ? 'Study Game' : 'Watch Game'
|
||||
return (
|
||||
<>
|
||||
<Link to={`/games/${game.id}`}>{gameLinkText}</Link>
|
||||
|
||||
<div className="Game__playerData">
|
||||
<span className="Game__playerData__name">{game.playerBlack}</span>
|
||||
<span className="Game__playerData__rank">{game.playerBlackRank}</span>
|
||||
</div>
|
||||
|
||||
<div className="Game__playerData">
|
||||
<span className="Game__playerData__name">{game.playerWhite}</span>
|
||||
<span className="Game__playerData__rank">{game.playerWhiteRank}</span>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="GameButton" data-testid="GameButton">
|
||||
<Link to={`/games/${gameData.id}`}>View Game</Link>
|
||||
<p>{gameData.playerBlack} - {gameData.playerBlackRank}</p>
|
||||
<p>{gameData.playerWhite} - {gameData.playerWhiteRank}</p>
|
||||
{game.open ? renderOpenGame() : renderInProgressGame()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
div.Game__playerData {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import './ActionError.scss';
|
||||
|
||||
const ActionError = (props) => {
|
||||
const errorMessage = props.error;
|
||||
return (
|
||||
<span data-testid="ActionError" className="ActionError">
|
||||
{errorMessage}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default ActionError;
|
|
@ -0,0 +1,5 @@
|
|||
@import '../../../../public/stylesheets/partials/variables';
|
||||
|
||||
span.FormError {
|
||||
color: map-get($colors, "error");;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import ActionError from './ActionError';
|
||||
|
||||
test('renders ActionError without crashing', () => {
|
||||
const { getByTestId } = render(<ActionError />);
|
||||
const ActionErrorSpan = getByTestId('ActionError');
|
||||
expect(ActionErrorSpan).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders ActionError with error message', () => {
|
||||
const errorMessage = "User already exists!";
|
||||
const { getByTestId } = render(<ActionError error={errorMessage}/>);
|
||||
const ActionErrorSpan = getByTestId('ActionError');
|
||||
expect(ActionErrorSpan).toHaveTextContent(errorMessage);
|
||||
|
||||
})
|
|
@ -6,6 +6,7 @@ import config from '../../config';
|
|||
import roomsServices from '../../services/api/roomsServices';
|
||||
import GameButton from '../../components/Button/Game/Game';
|
||||
import Message from '../../components/Display/Message/Message';
|
||||
import ActionError from '../../components/Error/ActionError/ActionError';
|
||||
|
||||
import Development from '../../components/Display/Development/Development';
|
||||
|
||||
|
@ -13,8 +14,7 @@ const Room = (props) => {
|
|||
const state = props.state;
|
||||
const dispatch = props.dispatch;
|
||||
const roomId = parseInt(useParams().id) || 0;
|
||||
const [ socketData, setSocketData ] = useState();
|
||||
const [ messages, setMessages ] = useState();
|
||||
const [ socketData, setSocketData ] = useState(false);
|
||||
|
||||
const fetchRoomAPI = async () => {
|
||||
const response = await roomsServices.getRoomService(roomId);
|
||||
|
@ -38,15 +38,36 @@ const Room = (props) => {
|
|||
const roomSocketConnect = () => {
|
||||
roomSocket.emit('connect');
|
||||
// ! dispatch data
|
||||
roomSocket.on('connected', data => setSocketData('room socket connected'));
|
||||
roomSocket.on('connect_error', err => console.log(err));
|
||||
roomSocket.on('error', err => console.log(err));
|
||||
roomSocket.on('connect', socket => {
|
||||
setSocketData(true)
|
||||
});
|
||||
roomSocket.on('join_game_request', data => {
|
||||
console.log(data)
|
||||
})
|
||||
roomSocket.on('connect_error', err => {
|
||||
setSocketData(false)
|
||||
console.log(err);
|
||||
});
|
||||
roomSocket.on('error', err => {
|
||||
setSocketData(false)
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
roomSocketConnect();
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const data = {
|
||||
user: state.user,
|
||||
game: state.joinGame
|
||||
};
|
||||
console.log('emitting request')
|
||||
console.log(data)
|
||||
roomSocket.emit('join_game_request', data)
|
||||
}, [state.joinGame])
|
||||
|
||||
// ! [end]
|
||||
|
||||
const renderGames = () => {
|
||||
|
@ -56,6 +77,7 @@ const Room = (props) => {
|
|||
<GameButton
|
||||
key={`game-${gameData.id}`}
|
||||
game={gameData}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
@ -78,7 +100,11 @@ const Room = (props) => {
|
|||
|
||||
return (
|
||||
<div className="Room" data-testid="Room">
|
||||
<div className="Room__heading">
|
||||
<h2>{state.currentRoom ? state.currentRoom.name : 'Loading'}</h2>
|
||||
<span className="Room__connection">{socketData ? '✓' : ' ⃠'}</span>
|
||||
{state.errors.joinGame ? <ActionError error={state.errors.joinGame}/> : <></>}
|
||||
</div>
|
||||
|
||||
<div className="Room__game-container">
|
||||
{renderGames()}
|
||||
|
|
|
@ -9,6 +9,9 @@ export const errorReducer = (state: state, action: action):state => {
|
|||
case 'JOIN_ROOM_ERROR':
|
||||
return joinRoomErrorReducer(state, action);
|
||||
|
||||
case 'JOIN_GAME_ERROR':
|
||||
return joinGameErrorReducer(state, action);
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -23,3 +26,8 @@ function joinRoomErrorReducer(state: state, action: action): state {
|
|||
const joinRoom = action.body.joinRoomError;
|
||||
return { ...state, errors: {joinRoom} }
|
||||
}
|
||||
|
||||
function joinGameErrorReducer(state: state, action: action): state {
|
||||
const joinGame = action.body.joinGameError;
|
||||
return { ...state, errors: {joinGame} }
|
||||
}
|
|
@ -6,11 +6,51 @@ export const gamesReducer = (state: state, action: action):state => {
|
|||
switch(action.message) {
|
||||
|
||||
case 'SET_GAMES':
|
||||
const games = action.body;
|
||||
const games = formatGames(action);;
|
||||
return {...state, games};
|
||||
|
||||
case 'JOIN_REQUEST':
|
||||
if (!Object.entries(state.user).length) {
|
||||
const errAction = {
|
||||
type: 'ERR',
|
||||
message: 'JOIN_GAME_ERROR',
|
||||
body: {joinGameError: 'user not logged in'}
|
||||
}
|
||||
return stateReducer(state, errAction)
|
||||
}
|
||||
const id = action.body;
|
||||
return {...state, joinGame: id};
|
||||
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function parseRank(rank: string): string {
|
||||
switch(rank[0]) {
|
||||
case 'D':
|
||||
return `${rank.slice(1)}${rank[0].toLowerCase()}`
|
||||
case 'K':
|
||||
return `${rank.slice(1)}${rank[0].toLowerCase()}`
|
||||
case 'U':
|
||||
return '?'
|
||||
}
|
||||
}
|
||||
|
||||
function formatGames(action: action): Array<{}> {
|
||||
const games = [...action.body].map(game => {
|
||||
|
||||
if (game.playerBlackRank) {
|
||||
game.playerBlackRank = parseRank(game.playerBlackRank)
|
||||
}
|
||||
|
||||
if (game.playerWhiteRank) {
|
||||
game.playerWhiteRank = parseRank(game.playerWhiteRank)
|
||||
}
|
||||
|
||||
return game;
|
||||
})
|
||||
|
||||
return games;
|
||||
}
|
|
@ -5,6 +5,10 @@ import type { state } from '../stateReducer';
|
|||
export const initState = (): state => {
|
||||
return {
|
||||
user: {},
|
||||
errors: {}
|
||||
errors: {},
|
||||
currentRoom: {},
|
||||
messages: {},
|
||||
games: {},
|
||||
joinGame: {}
|
||||
};
|
||||
}
|
|
@ -32,6 +32,7 @@ const getRoomService = async (roomIndex) => {
|
|||
delete Object.assign(game, {playerBlackRank: game.player_black_rank }).player_black_rank;
|
||||
delete Object.assign(game, {playerWhite: game.player_white }).player_white;
|
||||
delete Object.assign(game, {playerWhiteRank: game.player_white_rank }).player_white_rank;
|
||||
delete Object.assign(game, {winType: game.win_type }).win_type;
|
||||
return game;
|
||||
})
|
||||
return obj;
|
||||
|
|
|
@ -18,6 +18,8 @@ const getAll = async (req, res, next) => {
|
|||
const show = async (req, res, next) => {
|
||||
try {
|
||||
const roomId = req.params.id;
|
||||
if (!roomId) throw('missing room parameter')
|
||||
|
||||
// TODO eventually add check for user's private rooms
|
||||
enableRoomSocket(roomId);
|
||||
|
||||
|
|
|
@ -11,12 +11,18 @@ io.on('connection', ()=> {
|
|||
enableRoomSocket = (roomId) => {
|
||||
const roomSocket = io.of(roomId);
|
||||
roomSocket.on('connection', (socket) => {
|
||||
// socket.emit('connected');
|
||||
console.log(`Socket connected at room ${roomId}`);
|
||||
|
||||
//! Join Game Request queries db for game, ensures unique player joining
|
||||
socket.on('join_game_request', async data => {
|
||||
const gameRequest = await logJoinGameRequest(data);
|
||||
|
||||
if (gameRequest.err) {
|
||||
roomSocket.emit('join_game_request_error', gameRequest.err);
|
||||
}
|
||||
|
||||
roomSocket.emit('join_game_request', gameRequest);
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
return roomSocket;
|
||||
}
|
||||
|
@ -29,5 +35,12 @@ module.exports = {
|
|||
async function logJoinGameRequest (data) {
|
||||
const {user, game} = data;
|
||||
const requestedGame = await gameQueries.findGameById(game.id);
|
||||
return { user, requestedGame }
|
||||
|
||||
if (requestedGame.user_black === user.id) {
|
||||
return { err: 'players must be unique' }
|
||||
}
|
||||
|
||||
const requestingUser = {...user};
|
||||
delete requestingUser.email;
|
||||
return { requestingUser, requestedGame }
|
||||
}
|
Loading…
Reference in a new issue