Game Draw: req/acq/rej

This commit is contained in:
djmil 2023-11-16 11:49:12 +01:00
parent 576556afe7
commit 671e13a41d
11 changed files with 186 additions and 30 deletions

View File

@ -50,4 +50,46 @@ public class GameController {
return ResponseEntity
.ok(finishedGame);
}
@PutMapping("/{uuid}/drawreq")
public ResponseEntity<GameView> drawRequest(
@AuthenticationPrincipal User issuer,
@PathVariable UUID uuid
) {
final GameView drawReqGame = cordaClient.gameDrawRequest(
issuer.getHoldingIdentity(),
uuid
);
return ResponseEntity
.ok(drawReqGame);
}
@PutMapping("/{uuid}/drawacc")
public ResponseEntity<GameView> drawAccept(
@AuthenticationPrincipal User issuer,
@PathVariable UUID uuid
) {
final GameView drawAccGame = cordaClient.gameDrawAccept(
issuer.getHoldingIdentity(),
uuid
);
return ResponseEntity
.ok(drawAccGame);
}
@PutMapping("/{uuid}/drawrej")
public ResponseEntity<GameView> drawReject(
@AuthenticationPrincipal User issuer,
@PathVariable UUID uuid
) {
final GameView drawRejGame = cordaClient.gameDrawReject(
issuer.getHoldingIdentity(),
uuid
);
return ResponseEntity
.ok(drawRejGame);
}
}

View File

@ -44,11 +44,29 @@ export default function useGamesApi(gamesReducer, config) {
onSuccess: (acceptedGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(acceptedGame), proposal: gamesInitialState.proposal })
}),
pushGameSurrender: ({ uuid }) => ifNot(games.isPushingActiveGameSurrender) &&
pushGameSurrender: ({ uuid }) => ifNot(games.isPushingGameSurrender) &&
doPushing(`/api/game/${uuid}/surrender`, 'PUT', null, {
onPushing: (isPushingActiveGameSurrender) => dispatchGames({ type: 'next', isPushingActiveGameSurrender }),
onPushing: (isPushingGameSurrender) => dispatchGames({ type: 'next', isPushingGameSurrender }),
onSuccess: (finishedGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(finishedGame), proposal: gamesInitialState.active })
}),
pushGameDrawRequest: ({ uuid }) => ifNot(games.isPushingGameDrawRequest) &&
doPushing(`/api/game/${uuid}/drawreq`, 'PUT', null, {
onPushing: (isPushingGameDrawRequest) => dispatchGames({ type: 'next', isPushingGameDrawRequest }),
onSuccess: (drawReqGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(drawReqGame), proposal: gamesInitialState.active })
}),
pushGameDrawAccept: ({ uuid }) => ifNot(games.isPushingGameDrawAccept) &&
doPushing(`/api/game/${uuid}/drawacc`, 'PUT', null, {
onPushing: (isPushingGameDrawAccept) => dispatchGames({ type: 'next', isPushingGameDrawAccept }),
onSuccess: (drawAccGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(drawAccGame), proposal: gamesInitialState.active })
}),
pushGameDrawReject: ({ uuid }) => ifNot(games.isPushingGameDrawReject) &&
doPushing(`/api/game/${uuid}/drawrej`, 'PUT', null, {
onPushing: (isPushingGameDrawReject) => dispatchGames({ type: 'next', isPushingGameDrawReject }),
onSuccess: (drawRejGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(drawRejGame), proposal: gamesInitialState.active })
}),
}
}

View File

@ -145,4 +145,37 @@
.ActionPanel .Accept.ready:active {
background-color:#00af00a0;
}
/*
* Draw
*/
.ActionPanel .Draw.ready,
.ActionPanel .Draw.accept,
.ActionPanel .Draw.reject {
background-color: #ffff0018;
}
.ActionPanel .Draw.ready:hover {
background-color:#ffff0040;
}
.ActionPanel .Draw.ready:active {
background-color:#ffff00a0;
}
.ActionPanel .Draw.accept:hover {
background-color:#a4ff4a50;
}
.ActionPanel .Draw.accept:active {
background-color:#10ff0080;
}
.ActionPanel .Draw.reject:hover {
background-color:#ffaaaa60;
}
.ActionPanel .Draw.reject:active {
background-color:#ff000090;
}

View File

@ -9,9 +9,8 @@ import Create from './games/action/Create';
import Reject from './games/action/Reject';
import Cancel from './games/action/Cancel';
import Accept from './games/action/Accept';
import DrawReq from './games/action/DrawReq';
import DrawAcq from './games/action/DrawAcq';
import Surrender from './games/action/Surrender';
import { DrawRequest, DrawAccept, DrawReject } from './games/action/Draw';
import Backward from './games/action/Backward';
import Forward from './games/action/Forward';
@ -27,18 +26,19 @@ export default function Games({ context: { gamesReducer, gamesApi }, players })
return (
<GamesContext.Provider value={games} >
<div className='Games'>
<div className='left-side'>
<ViewSelector games={games} />
<ViewProvider gamesReducer={gamesReducer} players={players} />
</div>
<div className='right-side'>
<ActionPanel gamesApi={gamesApi} players={players} />
{/* <GameMessage /> */}
<GameBoard />
<Message2Opponent dispatchGames={dispatchGames} />
{/*
<GameMessage />
*/}
</div>
</div >
</GamesContext.Provider>
)
@ -81,6 +81,7 @@ function ViewProvider({ gamesReducer, players }) {
<Route path='archive' element={
<GameArchiveSelector onSelect={(selectedUUID) => dispatchGames({ type: 'nextArchive', selectedUUID })} />
} />
</Routes>
</div>
)
@ -90,22 +91,31 @@ function ActionPanel({ players, gamesApi }) {
return (
<div className='ActionPanel'>
<Routes>
<Route path='new' element={
<Create isCurrentUser={players.isCurrentUser}
onClick={(reqParams) => gamesApi.pushNewGame(reqParams)}
/>
} />
<Route path='proposal' element={[
<Accept key={1} onClick={(uuid) => gamesApi.pushGameProposalAccept({ uuid })} />,
<Reject key={2} onClick={(uuid) => gamesApi.pushGameProposalReject({ uuid })} />,
<Cancel key={3} onClick={(uuid) => gamesApi.pushGameProposalCancel({ uuid })} />
]} />
<Route path='active' element={[
<DrawReq key={1} />,
<DrawAcq key={2} />,
<Surrender key={3} onClick={(uuid) => gamesApi.pushGameSurrender({ uuid })}/>
<DrawRequest key={1} onClick={(uuid) => gamesApi.pushGameDrawRequest({ uuid })} />,
<DrawAccept key={2} onClick={(uuid) => gamesApi.pushGameDrawAccept({ uuid })} />,
<DrawReject key={3} onClick={(uuid) => gamesApi.pushGameDrawReject({ uuid })} />,
<Surrender key={4} onClick={(uuid) => gamesApi.pushGameSurrender({ uuid })} />
]} />
<Route path='archive' element={[<Backward key={1} />, <Forward key={2} />]} />
<Route path='archive' element={[
<Backward key={1} />,
<Forward key={2} />
]} />
</Routes>
</div>
)
@ -127,7 +137,7 @@ function countGames(gamesList) {
awaiting.proposals++;
break;
case 'GAME_BOARD_WAIT_FOR_YOU':
case 'DRAW_REQUEST_WAIT_FOR_YO':
case 'DRAW_REQUEST_WAIT_FOR_YOU':
awaiting.active++;
break;
default:

View File

@ -56,7 +56,7 @@ export default function Message2Opponent({ dispatchGames }) {
return (
<input className='Message2Opponent'
placeholder='Message to opponent'
placeholder='Message'
value={value}
maxLength={150}
onChange={e => update(e.target.value)}

View File

@ -0,0 +1,60 @@
import React, { useContext } from 'react';
import Wobler from '../../../components/Wobler';
import { GamesContext } from '../../../context/games';
export function DrawRequest({ onClick }) {
const games = useContext(GamesContext);
const selectedGame = games.findGame({ uuid: games.active.selectedUUID });
const gameStatus = selectedGame?.status;
const isReady = gameStatus === 'GAME_BOARD_WAIT_FOR_YOU' ? true : '';
const checkStatus = () => {
if (!selectedGame)
return alert('You have to select a game');
if (gameStatus === 'DRAW_REQUEST_WAIT_FOR_OPPONENT')
return alert('A draw was alredy offered to the opponent');
if (!isReady)
return alert('You can ask for a draw only during your turn');
onClick(selectedGame.uuid);
}
if (gameStatus === 'DRAW_REQUEST_WAIT_FOR_YOU')
return; // You can not send counter draw request
return (
<button className={'Draw' + (isReady && ' ready')} onClick={() => checkStatus()} >
<Wobler text="Draw?" dance={games.isPushingGameDrawRequest} />
</button >
)
}
export function DrawAccept({ onClick }) {
const games = useContext(GamesContext);
const selectedGame = games.findGame({ uuid: games.active.selectedUUID });
const gameStatus = selectedGame?.status;
if (gameStatus === 'DRAW_REQUEST_WAIT_FOR_YOU')
return (
<button className='Draw accept' onClick={() => onClick(selectedGame.uuid)} >
<Wobler text="Draw accept" dance={games.isPushingGameDrawAccept} />
</button>
)
}
export function DrawReject({ onClick }) {
const games = useContext(GamesContext);
const selectedGame = games.findGame({ uuid: games.active.selectedUUID });
if (selectedGame?.status === 'DRAW_REQUEST_WAIT_FOR_YOU')
return (
<button className='Draw reject' onClick={() => onClick(selectedGame.uuid)} >
<Wobler text="Reject" dance={games.isPushingGameDrawReject} />
</button>
)
}

View File

@ -1,6 +0,0 @@
import React from 'react';
export default function DrawAcq() {
return <button className='DrawAcq'>Draw accept</button>
}

View File

@ -1,6 +0,0 @@
import React from 'react';
export default function DrawReq() {
return <button className='DrawReq'>Draw request</button>
}

View File

@ -14,9 +14,9 @@ export default function Surrender({ onClick }) {
return (
<button className={'Surrender' + (isReady && ' ready')}
onClick={() => isReady ? onClick(selectedGame.uuid) : alert('You have to select some game')}
onClick={() => isReady ? onClick(selectedGame.uuid) : alert('You have to select a game')}
>
<Wobler text="Surrender" dance={games.isPushingActiveGameSurrender} />
<Wobler text="Surrender" dance={games.isPushingGameSurrender} />
</button>
)
}

View File

@ -49,10 +49,10 @@ export function ActiveGameSelector({ onSelect }) {
onSelect(uuid);
}
const yoursList = games.gamesList.filter(game => game.status === 'GAME_BOARD_WAIT_FOR_YOU')
const yoursList = games.gamesList.filter(game => (game.status === 'GAME_BOARD_WAIT_FOR_YOU' || game.status === 'DRAW_REQUEST_WAIT_FOR_YOU'))
.map(game => <Selectable game={game} key={game.uuid} selected={isSelected(game.uuid)} onClick={onClick} />)
const opponentsList = games.gamesList.filter(game => game.status === 'GAME_BOARD_WAIT_FOR_OPPONENT')
const opponentsList = games.gamesList.filter(game => (game.status === 'GAME_BOARD_WAIT_FOR_OPPONENT' || game.status === 'DRAW_REQUEST_WAIT_FOR_OPPONENT'))
.map(game => <Selectable game={game} key={game.uuid} selected={isSelected(game.uuid)} onClick={onClick} />)
return (

View File

@ -27,10 +27,15 @@ export const gamesInitialState = {
// Network
isPollingGamesList: false,
isPushingNewGame: false,
isPushingGameProposalCancel: false,
isPushingGameProposalReject: false,
isPushingGameProposalAccept: false,
isPushingActiveGameSurrender: false,
isPushingGameSurrender: false,
isPushingGameDrawRequest: false,
isPushingGameDrawAccept: false,
isPushingGameDrawReject: false,
findGame,
nextGameList,