front: gamestate polling + gameproposal tab
- gamestate controller - css for gameproposal tab
This commit is contained in:
parent
6c885bfa68
commit
72daeddb9d
@ -0,0 +1,37 @@
|
|||||||
|
package djmil.cordacheckers.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import djmil.cordacheckers.cordaclient.CordaClient;
|
||||||
|
import djmil.cordacheckers.cordaclient.dao.GameState;
|
||||||
|
import djmil.cordacheckers.user.HoldingIdentityResolver;
|
||||||
|
import djmil.cordacheckers.user.User;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("api/gamestate")
|
||||||
|
public class GameStateController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
CordaClient cordaClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HoldingIdentityResolver holdingIdentityResolver;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<List<GameState>> gameStateList(
|
||||||
|
@AuthenticationPrincipal User player
|
||||||
|
) {
|
||||||
|
final List<GameState> gsList = cordaClient.gameStateList(player.getHoldingIdentity());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(gsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,23 +1,51 @@
|
|||||||
import './App.css';
|
import './App.css';
|
||||||
import Leaderboard from "./Leaderboard";
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import React from 'react';
|
|
||||||
import {
|
import {
|
||||||
BrowserRouter,
|
BrowserRouter,
|
||||||
Routes, //replaces "Switch" used till v5
|
Routes, //replaces "Switch" used till v5
|
||||||
Route,
|
Route,
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
|
|
||||||
import Header from "./Header"
|
import Header from "./Header"
|
||||||
|
import Leaderboard from "./Leaderboard";
|
||||||
|
import GameProposal from "./GameProposal";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const [games, setGames] = useState(null);
|
||||||
|
const [polling, setPolling] = useState(false);
|
||||||
|
|
||||||
|
const pollGames = useCallback(() => {
|
||||||
|
console.log('start polling..');
|
||||||
|
|
||||||
|
if (polling) {
|
||||||
|
console.log(' ..already in progress');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPolling(true);
|
||||||
|
fetch('/api/gamestate')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('poooled');
|
||||||
|
setGames(data);
|
||||||
|
setPolling(false);
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err.message));
|
||||||
|
}, [polling]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setInterval(pollGames(), 35 * 1000);
|
||||||
|
return clearInterval(timer);
|
||||||
|
}, [pollGames])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Header/>
|
<Header/>
|
||||||
|
|
||||||
<div className="Container">
|
<div className="Container">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/leaderboard" element={<Leaderboard/>} />
|
<Route path="/leaderboard" element={<Leaderboard/>} />
|
||||||
|
<Route path="/gameproposal" element={<GameProposal games={games}/>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
26
webapp/src/GameProposal.css
Normal file
26
webapp/src/GameProposal.css
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
.GameProposal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameProposal .li {
|
||||||
|
width: 50%;
|
||||||
|
border: 1px solid black;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameProposal .li p {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
width: 20%;
|
||||||
|
/* height: 20px; */
|
||||||
|
border-bottom: 1px dotted black;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 8px;
|
||||||
|
padding-left: 50%;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
52
webapp/src/GameProposal.js
Normal file
52
webapp/src/GameProposal.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './GameProposal.css';
|
||||||
|
|
||||||
|
const State = {
|
||||||
|
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
|
||||||
|
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
|
||||||
|
}
|
||||||
|
|
||||||
|
const GameProposal = ({games}) => {
|
||||||
|
|
||||||
|
if (games == null)
|
||||||
|
return <p>Loading..</p>
|
||||||
|
|
||||||
|
// for (const [key, value] of Object.entries(games))
|
||||||
|
// console.log(key, value);
|
||||||
|
|
||||||
|
const waitForYou = games
|
||||||
|
.filter(game => game.status === State.WaitForYou)
|
||||||
|
.map(game => { return (
|
||||||
|
<div class="li" key={game.uuid}>
|
||||||
|
<p>
|
||||||
|
from {game.opponentName}, opponentColor {game.opponentColor}<br/>
|
||||||
|
<q color="grey">{game.message}</q>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)});
|
||||||
|
|
||||||
|
const WaitForOpponent = games
|
||||||
|
.filter(game => game.status === State.WaitForOpponent)
|
||||||
|
.map(game => { return (
|
||||||
|
<div class="li" key={game.uuid}>
|
||||||
|
<p>
|
||||||
|
to {game.opponentName}, opponentColor ⛀ ⛂{game.opponentColor}<br/>
|
||||||
|
<q color="grey">{game.message}</q>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<p className="GameProposal">
|
||||||
|
{waitForYou}
|
||||||
|
{WaitForOpponent.length > 0 &&
|
||||||
|
<div class="separator">
|
||||||
|
waiting for opponent ({WaitForOpponent.length})
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{WaitForOpponent}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GameProposal;
|
3
webapp/src/Header.css
Normal file
3
webapp/src/Header.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
p {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
@ -1,15 +1,17 @@
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import './Header.css';
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<p>
|
||||||
<h1>CordaCheckers</h1>
|
<h1>CordaCheckers</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<Link to="/leaderboard">Leaderboard</Link> {"| "}
|
<Link to="/leaderboard">Leaderboard</Link> {"| "}
|
||||||
<Link to="/gameproposal">Game Proposal</Link> {"| "}
|
<Link to="/gameproposal">Game Proposal</Link> {"| "}
|
||||||
<Link to="/game">Games</Link> {"| "}
|
<Link to="/game">Active Games</Link> {"| "}
|
||||||
|
<Link to="/archive">Archive</Link> {"| "}
|
||||||
<Link to="about">About</Link>
|
<Link to="about">About</Link>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -2,5 +2,4 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 25px
|
}
|
||||||
}
|
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import './Leaderboard.css';
|
import './Leaderboard.css';
|
||||||
//const Leaderboard = ({hashmap}) => {
|
|
||||||
|
|
||||||
// var listItems = Object.keys(hashmap).map(playerName => {
|
|
||||||
// var rank = hashmap[playerName];
|
|
||||||
|
|
||||||
// return <li key={playerName}>
|
|
||||||
// {playerName}: played {rank.gamesPlayed}, won {rank.gamesWon}, draw {rank.gamesDraw}
|
|
||||||
// </li>
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return <ul>{listItems}</ul>;
|
|
||||||
|
|
||||||
const Leaderboard = () => {
|
const Leaderboard = () => {
|
||||||
|
|
||||||
@ -28,7 +17,16 @@ const Leaderboard = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return <span>Loading...</span>
|
return <p>Loading...</p>
|
||||||
|
|
||||||
|
// var listItems = Object.keys(data).map(playerName => {
|
||||||
|
// var rank = data[playerName];
|
||||||
|
//
|
||||||
|
// return <li key={playerName}>
|
||||||
|
// {playerName}: played {rank.gamesPlayed}, won {rank.gamesWon}, draw {rank.gamesDraw}
|
||||||
|
// </li>
|
||||||
|
// });
|
||||||
|
// return <ul>{listItems}</ul>;
|
||||||
|
|
||||||
const tableRows = Object.keys(data).map(playerName => {
|
const tableRows = Object.keys(data).map(playerName => {
|
||||||
var rank = data[playerName];
|
var rank = data[playerName];
|
||||||
@ -48,7 +46,7 @@ const Leaderboard = () => {
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th></th>
|
||||||
<th>Played</th>
|
<th>Played</th>
|
||||||
<th>Won</th>
|
<th>Won</th>
|
||||||
<th>Draw</th>
|
<th>Draw</th>
|
||||||
@ -62,5 +60,4 @@ const Leaderboard = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default Leaderboard;
|
export default Leaderboard;
|
||||||
|
Loading…
Reference in New Issue
Block a user