Bad Move error message displayed over the board #47

Merged
djmil merged 1 commits from 11-game-message into main 2023-11-30 14:46:56 +01:00
7 changed files with 71 additions and 16 deletions

View File

@ -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: '' });
},
})
}

View File

@ -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);
}

View File

@ -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}
/>
} />

View 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>
)
}

View File

@ -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>
)
}

View File

@ -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);
}

View File

@ -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);
}