Bad Move error message displayed over the board #47
@ -73,11 +73,12 @@ export default function useGamesApi() {
|
||||
|
||||
const pushGameMove = ({ uuid, move, message }) => {
|
||||
doPushing(`/api/game/${uuid}/move`, 'PUT', { move, message }, {
|
||||
onPushing: (isPushing) => dispatchGuide({ type: 'UUIDpushing', uuid, what: isPushing && {moveFrom: move[0], moveTo: move[1]} }),
|
||||
onPushing: (isPushing) => dispatchGuide({ type: 'UUIDpushing', uuid, what: isPushing && { moveFrom: move[0], moveTo: move[1] } }),
|
||||
onBadReq: (message) => dispatchGuide({ type: 'UUIDerror', uuid, error: { message, moveFrom: move[0], moveTo: move[1] } }),
|
||||
onSuccess: (game) => {
|
||||
dispatchState({ type: 'update', game });
|
||||
dispatchGuide({ type: 'UUIDmessage', uuid, message: ''});
|
||||
}
|
||||
dispatchGuide({ type: 'UUIDmessage', uuid, message: '' });
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -97,10 +97,25 @@
|
||||
|
||||
.GameBoard {
|
||||
padding-left: 30px;
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.Message2Opponent {
|
||||
margin: 10px;
|
||||
margin-left: 30px;
|
||||
width: 270px;
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.BadMove {
|
||||
position: fixed;
|
||||
width: 275px;
|
||||
top: 250px;
|
||||
cursor: default; /* disable 'I beam' cursor change */
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
background-color: rgba(255, 80, 80, 0.3);
|
||||
}
|
||||
|
||||
.BadMove:hover {
|
||||
background-color: rgba(255, 80, 80, 0.7);
|
||||
}
|
@ -34,7 +34,6 @@ export default function Games({ games, players }) {
|
||||
<ActionPanel gamesApi={games.api} />
|
||||
<GameBoardRoutes dispatchGuide={gamesDispatchGuide} gamesApi={games.api} username={players.user.name} />
|
||||
<Message2OpponentRoutes dispatchGuide={gamesDispatchGuide} />
|
||||
{/* <GameMessage /> */}
|
||||
</div>
|
||||
|
||||
</div >
|
||||
@ -156,10 +155,11 @@ function GameBoardRoutes({ dispatchGuide, gamesApi, username }) {
|
||||
const games = useContext(GamesStateContext);
|
||||
const guide = useContext(GamesGuideContext);
|
||||
|
||||
const fromUUID = (uuid) => (!uuid) ? [{}, null] :
|
||||
const fromUUID = (uuid) => (!uuid) ? [{}, null, null] :
|
||||
[
|
||||
games.find((game) => game.uuid === uuid) || {}, // game
|
||||
guide.UUIDpushing[uuid] // pushing
|
||||
guide.UUIDpushing[uuid], // pushing
|
||||
guide.UUIDerror[uuid] // error (aka bad move)
|
||||
];
|
||||
|
||||
const onStoneClick = (uuid, cellId) => {
|
||||
@ -191,6 +191,7 @@ function GameBoardRoutes({ dispatchGuide, gamesApi, username }) {
|
||||
username={username}
|
||||
getGame={() => fromUUID(guide.selectedUUID.active)}
|
||||
onStoneMove={(uuid, move) => gamesApi.pushGameMove({ uuid, move, message: guide.UUIDmessage[uuid] })}
|
||||
dispatchGuide={dispatchGuide}
|
||||
/>
|
||||
} />
|
||||
|
||||
|
14
webapp/src/container/games/BadMove.jsx
Normal file
14
webapp/src/container/games/BadMove.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function BadMove({ dispatchGuide, uuid, message }) {
|
||||
if (!dispatchGuide || !uuid || !message)
|
||||
return;
|
||||
|
||||
return (
|
||||
<div className='BadMove'
|
||||
onClick={() => dispatchGuide({ type: 'UUIDerror', uuid, error: {} })}
|
||||
>
|
||||
{message}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Color, Player, Board } from '../../components/Checkers';
|
||||
import './GameBoard.css';
|
||||
import BadMove from './BadMove';
|
||||
|
||||
export default function GameBoard({ username, getGame, onStoneClick, onStoneMove }) {
|
||||
const [game, isPushing] = getGame();
|
||||
export default function GameBoard({ dispatchGuide, username, getGame, onStoneClick, onStoneMove }) {
|
||||
const [game, isPushing, error] = getGame();
|
||||
|
||||
const myName = game.opponentName ? username : '';
|
||||
const opponentColor = Color.opposite(game.myColor);
|
||||
@ -14,11 +14,17 @@ export default function GameBoard({ username, getGame, onStoneClick, onStoneMove
|
||||
(cellId) => onStoneClick(game.uuid, cellId);
|
||||
|
||||
const optionalOnStoneMove = (typeof onStoneMove !== 'function' || isPushing) ? null :
|
||||
(move) => {
|
||||
(move) => {
|
||||
if (move[0] !== move[1] && game.board[move[1]] === undefined)
|
||||
onStoneMove(game.uuid, move)
|
||||
};
|
||||
|
||||
const currMove = (() => {
|
||||
if (isPushing) return [isPushing.moveFrom, isPushing.moveTo];
|
||||
if (error?.moveFrom && error?.moveTo) return [error.moveFrom, error.moveTo];
|
||||
return [];
|
||||
})(); // <<-- execute
|
||||
|
||||
return (
|
||||
<div className='GameBoard'>
|
||||
<Player
|
||||
@ -29,7 +35,7 @@ export default function GameBoard({ username, getGame, onStoneClick, onStoneMove
|
||||
board={game.board}
|
||||
flip={flipBoard}
|
||||
prevMove={game.previousMove}
|
||||
currMove={[isPushing?.moveFrom, isPushing?.moveTo]}
|
||||
currMove={currMove}
|
||||
onStoneClick={optionalOnStoneClick}
|
||||
onStoneMove={optionalOnStoneMove}
|
||||
/>
|
||||
@ -37,6 +43,7 @@ export default function GameBoard({ username, getGame, onStoneClick, onStoneMove
|
||||
color={game.myColor || Color.white}
|
||||
name={myName}
|
||||
/>
|
||||
<BadMove dispatchGuide={dispatchGuide} uuid={game?.uuid} message={error?.message} />
|
||||
</div>
|
||||
)
|
||||
}
|
@ -21,7 +21,7 @@ export function usePolling(uri, { onSuccess, onPolling }, mode = null) {
|
||||
setPolling(true);
|
||||
if (onPolling)
|
||||
onPolling(true);
|
||||
|
||||
|
||||
initialPollRef.current = false;
|
||||
|
||||
fetch(uri)
|
||||
@ -62,7 +62,7 @@ export function usePolling(uri, { onSuccess, onPolling }, mode = null) {
|
||||
}, [initialPoll, mode, intervalTimerId, isPolling, pollData, stopPollInterval]);
|
||||
}
|
||||
|
||||
export async function doPushing(uri, method, data, { onSuccess, onPushing }) {
|
||||
export async function doPushing(uri, method, data, { onSuccess, onBadReq, onPushing }) {
|
||||
if (onPushing)
|
||||
onPushing(true);
|
||||
|
||||
@ -75,14 +75,22 @@ export async function doPushing(uri, method, data, { onSuccess, onPushing }) {
|
||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||
});
|
||||
|
||||
if (response.status === 400 && onBadReq) {
|
||||
const content = (response.headers.get('Content-Type') === "application/json")
|
||||
? await response.json()
|
||||
: {};
|
||||
|
||||
return onBadReq(content.message);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
return console.warn(`Unexpected response status: ${response.status}`, response);
|
||||
}
|
||||
|
||||
if (onSuccess) {
|
||||
var content = (response.headers.get('Content-Type') === "application/json")
|
||||
const content = (response.headers.get('Content-Type') === "application/json")
|
||||
? await response.json()
|
||||
: null;
|
||||
: {};
|
||||
|
||||
onSuccess(content);
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ export const gamesGuideTemplate = {
|
||||
UUIDpushing: { // UUIDpushing[uuid]
|
||||
},
|
||||
|
||||
UUIDerror: { // UUIDerror[uuid]
|
||||
},
|
||||
|
||||
isPolling: false,
|
||||
};
|
||||
|
||||
@ -116,6 +119,12 @@ function gamesGuideReducer(state, action) {
|
||||
return next;
|
||||
}
|
||||
|
||||
case 'UUIDerror': {
|
||||
const next = { ...state };
|
||||
next.UUIDerror[action.uuid] = action.error;
|
||||
return next;
|
||||
}
|
||||
|
||||
default:
|
||||
throw Error('GamesGuide: unknown action.type: ' + action.type);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user