Game: surrender

This commit is contained in:
djmil 2023-11-16 09:17:07 +01:00
parent cacc8c99d8
commit 576556afe7
7 changed files with 64 additions and 15 deletions

View File

@ -1,11 +1,14 @@
package djmil.cordacheckers.api;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -16,8 +19,8 @@ import djmil.cordacheckers.user.User;
@RestController
@RequestMapping("api/games")
public class GameStateController {
@RequestMapping("api/game")
public class GameController {
@Autowired
CordaClient cordaClient;
@ -26,7 +29,7 @@ public class GameStateController {
HoldingIdentityResolver holdingIdentityResolver;
@GetMapping
public ResponseEntity<List<GameView>> gameStateList(
public ResponseEntity<List<GameView>> list(
@AuthenticationPrincipal User player
) {
final List<GameView> gsList = cordaClient.gameStateList(player.getHoldingIdentity());
@ -34,4 +37,17 @@ public class GameStateController {
return ResponseEntity.ok(gsList);
}
@PutMapping("/{uuid}/surrender")
public ResponseEntity<GameView> surrender(
@AuthenticationPrincipal User issuer,
@PathVariable UUID uuid
) {
final GameView finishedGame = cordaClient.gameBoardSurrender(
issuer.getHoldingIdentity(),
uuid
);
return ResponseEntity
.ok(finishedGame);
}
}

View File

@ -9,7 +9,7 @@ export default function useGamesApi(gamesReducer, config) {
dispatchGames({ type: 'next', gamesList });
}
const isPollingGamesList = usePolling('/api/games', onSuccess, config.intervalMode(30));
const isPollingGamesList = usePolling('/api/game', onSuccess, config.intervalMode(30));
if (games.isPollingGamesList !== isPollingGamesList) {
dispatchGames({ type: 'next', isPollingGamesList });
}
@ -43,6 +43,12 @@ export default function useGamesApi(gamesReducer, config) {
onPushing: (isPushingGameProposalAccept) => dispatchGames({ type: 'next', isPushingGameProposalAccept }),
onSuccess: (acceptedGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(acceptedGame), proposal: gamesInitialState.proposal })
}),
pushGameSurrender: ({ uuid }) => ifNot(games.isPushingActiveGameSurrender) &&
doPushing(`/api/game/${uuid}/surrender`, 'PUT', null, {
onPushing: (isPushingActiveGameSurrender) => dispatchGames({ type: 'next', isPushingActiveGameSurrender }),
onSuccess: (finishedGame) => dispatchGames({ type: 'next', gamesList: games.nextGameList(finishedGame), proposal: gamesInitialState.active })
}),
}
}

View File

@ -102,7 +102,7 @@
margin: 2px;
}
.ActionPanel .Create.ready { /* , */ /* OR .game-action.busy */
.ActionPanel .Create.ready {
background-color:#00b0ff30;
}
@ -115,17 +115,23 @@
}
.ActionPanel .Cancel.ready,
.ActionPanel .Reject.ready {
.ActionPanel .Reject.ready,
.ActionPanel .Surrender.ready
{
background-color:#ffaaaa60
}
.ActionPanel .Cancel.ready:hover,
.ActionPanel .Reject.ready:hover {
.ActionPanel .Reject.ready:hover,
.ActionPanel .Surrender.ready:hover
{
background-color:#ff000060
}
.ActionPanel .Cancel.ready:active,
.ActionPanel .Reject.ready:active {
.ActionPanel .Reject.ready:active,
.ActionPanel .Surrender.ready:active
{
background-color:#ff0000a0
}

View File

@ -96,11 +96,15 @@ function ActionPanel({ players, gamesApi }) {
/>
} />
<Route path='proposal' element={[
<Accept key={1} onClick={(uuid) => gamesApi.pushGameProposalAccept({ uuid })}/>,
<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} />]} />
<Route path='active' element={[
<DrawReq key={1} />,
<DrawAcq key={2} />,
<Surrender key={3} onClick={(uuid) => gamesApi.pushGameSurrender({ uuid })}/>
]} />
<Route path='archive' element={[<Backward key={1} />, <Forward key={2} />]} />
</Routes>
</div>

View File

@ -1,6 +1,22 @@
import React from 'react';
import React, { useContext } from 'react';
import Wobler from '../../../components/Wobler';
import { GamesContext } from '../../../context/games';
export default function Surrender() {
export default function Surrender({ onClick }) {
const games = useContext(GamesContext);
return <button className='Surrender'>Surrender</button>
}
const selectedGame = games.findGame({ uuid: games.active.selectedUUID });
const gameStatus = selectedGame?.status;
const isReady = (gameStatus === 'GAME_BOARD_WAIT_FOR_OPPONENT' || gameStatus === 'GAME_BOARD_WAIT_FOR_YOU') ? true : '';
if (gameStatus === 'DRAW_REQUEST_WAIT_FOR_YOU' || gameStatus === 'DRAW_REQUEST_WAIT_FOR_OPPONENT')
return; // You shall not surrender if there is an active tie negotiations
return (
<button className={'Surrender' + (isReady && ' ready')}
onClick={() => isReady ? onClick(selectedGame.uuid) : alert('You have to select some game')}
>
<Wobler text="Surrender" dance={games.isPushingActiveGameSurrender} />
</button>
)
}

View File

@ -40,7 +40,7 @@ export function ActiveGameSelector({ onSelect }) {
if (games.gamesList === null)
return <Loading />
const isSelected = (uuid) => uuid === games.proposal.selectedUUID;
const isSelected = (uuid) => uuid === games.active.selectedUUID;
const onClick = (uuid) => {
if (isSelected(uuid))

View File

@ -30,6 +30,7 @@ export const gamesInitialState = {
isPushingGameProposalCancel: false,
isPushingGameProposalReject: false,
isPushingGameProposalAccept: false,
isPushingActiveGameSurrender: false,
findGame,
nextGameList,