#24-directory-structure #26
@ -16,7 +16,7 @@ import djmil.cordacheckers.user.User;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("api/gamestate")
 | 
			
		||||
@RequestMapping("api/games")
 | 
			
		||||
public class GameStateController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,8 @@
 | 
			
		||||
.App {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
[data-darkreader-scheme="dark"] .Header a {
 | 
			
		||||
  color: darkslategrey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[data-darkreader-scheme="dark"] .Header .active {
 | 
			
		||||
  color: white;
 | 
			
		||||
  box-shadow: 0 1.5px 0 0 currentcolor;
 | 
			
		||||
}
 | 
			
		||||
@ -1,46 +1,41 @@
 | 
			
		||||
import './App.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
 | 
			
		||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import Header from "./container/Header"
 | 
			
		||||
import Leaderboard from "./container/Leaderboard"
 | 
			
		||||
import Game from "./components/Game"
 | 
			
		||||
import Header from './container/Header';
 | 
			
		||||
import About from "./components/About"
 | 
			
		||||
import Games from './container/Games';
 | 
			
		||||
import Leaderboard from './container/Leaderboard';
 | 
			
		||||
 | 
			
		||||
import usePollingReducer from './reducer/polling';
 | 
			
		||||
import useUserReducer from './reducer/user';
 | 
			
		||||
import usePollingReducer from './reducer/polling';
 | 
			
		||||
import useLeaderboardReducer from './reducer/leaderboard';
 | 
			
		||||
import useGamesReducer from './reducer/games';
 | 
			
		||||
 | 
			
		||||
import useLeaderboardApi from './api/leaderboard';
 | 
			
		||||
import useUserApi from './api/user';
 | 
			
		||||
import useLeaderboardApi from './api/leaderboard';
 | 
			
		||||
import useGamesApi from './api/games';
 | 
			
		||||
 | 
			
		||||
function App() {
 | 
			
		||||
  const pollingReducer = usePollingReducer();
 | 
			
		||||
  const userReducer = useUserReducer();
 | 
			
		||||
  const pollingReducer = usePollingReducer();
 | 
			
		||||
  const leaderboardReducer = useLeaderboardReducer();
 | 
			
		||||
  
 | 
			
		||||
  const leaderboardApi = useLeaderboardApi(leaderboardReducer);
 | 
			
		||||
  const userApi = useUserApi(userReducer);
 | 
			
		||||
  
 | 
			
		||||
  const leaderboard = leaderboardApi.get(pollingReducer);
 | 
			
		||||
  const user = userApi.get();
 | 
			
		||||
  const gamesReducer = useGamesReducer();
 | 
			
		||||
 | 
			
		||||
  const user = useUserApi(userReducer).get();
 | 
			
		||||
  const leaderboard = useLeaderboardApi(leaderboardReducer).poll(pollingReducer);
 | 
			
		||||
  /*const gamesApi = */ useGamesApi(gamesReducer).list(pollingReducer);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="App" >
 | 
			
		||||
      <BrowserRouter>
 | 
			
		||||
        <Header pollingReducer={pollingReducer} />
 | 
			
		||||
        <Routes>
 | 
			
		||||
          {/* https://stackoverflow.com/questions/40541994/multiple-path-names-for-a-same-component-in-react-router */}
 | 
			
		||||
          <Route path="/game" element={<Game />} />
 | 
			
		||||
          <Route path="/game/new" element={<Game />} />
 | 
			
		||||
          <Route path="/game/proposal" element={<Game />} />
 | 
			
		||||
          <Route path="/game/active" element={<Game />} />
 | 
			
		||||
          <Route path="/game/archive" element={<Game />} />
 | 
			
		||||
          <Route path="/leaderboard" element={<Leaderboard leaderboard={leaderboard} user={user} />} />
 | 
			
		||||
          <Route path="/about" element={<About />} />
 | 
			
		||||
        </Routes>
 | 
			
		||||
      </BrowserRouter>
 | 
			
		||||
    </div>
 | 
			
		||||
    <BrowserRouter>
 | 
			
		||||
      <Header pollingReducer={pollingReducer} />
 | 
			
		||||
      <Routes>
 | 
			
		||||
        <Route path="/" element={<About />} />
 | 
			
		||||
        <Route path="/about" element={<About />} />
 | 
			
		||||
        <Route path="/games/*" element={<Games />} />
 | 
			
		||||
        <Route path="/leaderboard" element={<Leaderboard leaderboard={leaderboard} user={user} />} />
 | 
			
		||||
      </Routes>
 | 
			
		||||
    </BrowserRouter>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								webapp/src/api/games.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								webapp/src/api/games.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
import usePolling from "../util/Polling"
 | 
			
		||||
 | 
			
		||||
const uri = '/api/games';
 | 
			
		||||
 | 
			
		||||
export default function useGamesApi(gamesReducer) {
 | 
			
		||||
    const [games, dispatchGames] = gamesReducer;
 | 
			
		||||
 | 
			
		||||
    const useList = (pollingReducer) => {
 | 
			
		||||
        const [polling, dispatchPolling] = pollingReducer;
 | 
			
		||||
 | 
			
		||||
        const mode = (polling.enabled === true)
 | 
			
		||||
            ? { interval_sec: 30 }      // update games list half a minue
 | 
			
		||||
            : { interval_stop: true }   // user has fliped OfflineToggel
 | 
			
		||||
 | 
			
		||||
        const [list, isFetching] = usePolling(uri, mode);
 | 
			
		||||
 | 
			
		||||
        if (polling.games !== isFetching) {
 | 
			
		||||
            dispatchPolling({ type: 'next', games: isFetching });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (games.list !== list) {
 | 
			
		||||
            dispatchGames({ type: 'next', list });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return games;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        list: useList
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,7 +5,7 @@ const uri = '/api/leaderboard';
 | 
			
		||||
export default function useLeaderboardApi(leaderboardReducer) {
 | 
			
		||||
    const [leaderboard, dispatchLeaderboaed] = leaderboardReducer;
 | 
			
		||||
 | 
			
		||||
    const useGet = (pollingReducer) => {
 | 
			
		||||
    const usePoll = (pollingReducer) => {
 | 
			
		||||
        const [polling, dispatchPolling] = pollingReducer;
 | 
			
		||||
 | 
			
		||||
        const mode = (polling.enabled === true)
 | 
			
		||||
@ -26,6 +26,6 @@ export default function useLeaderboardApi(leaderboardReducer) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        get: useGet
 | 
			
		||||
        poll: usePoll
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,15 @@
 | 
			
		||||
.board {
 | 
			
		||||
.Stone {
 | 
			
		||||
    cursor: default; /* disable 'I beam' cursor change */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Player {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Board {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
@ -6,7 +17,7 @@
 | 
			
		||||
    /* scale: 15%; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tile {
 | 
			
		||||
.Tile {
 | 
			
		||||
    border: 1px solid #e4e4e4;
 | 
			
		||||
    float: left;
 | 
			
		||||
    font-size: 200%;
 | 
			
		||||
@ -20,14 +31,14 @@
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tile.black {
 | 
			
		||||
.Tile.black {
 | 
			
		||||
    background: lightgray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tile.white:hover {
 | 
			
		||||
.Tile.white:hover {
 | 
			
		||||
    background-color:azure;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.stone {
 | 
			
		||||
.Tile .Stone {
 | 
			
		||||
    font-size: 120%;
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										130
									
								
								webapp/src/components/Checkers.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								webapp/src/components/Checkers.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
			
		||||
import './Checkers.css'
 | 
			
		||||
import React from 'react'
 | 
			
		||||
 | 
			
		||||
export const Color = {
 | 
			
		||||
    white: "WHITE",
 | 
			
		||||
    black: "BLACK",
 | 
			
		||||
 | 
			
		||||
    opposite: (color) => {
 | 
			
		||||
        if (color === Color.white)
 | 
			
		||||
            return Color.black;
 | 
			
		||||
        if (color === Color.black)
 | 
			
		||||
            return Color.white;
 | 
			
		||||
 | 
			
		||||
        return color;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Stone
 | 
			
		||||
 */
 | 
			
		||||
export function Stone({ color }) {
 | 
			
		||||
    switch (color) {
 | 
			
		||||
        case Color.white:
 | 
			
		||||
            return WhiteStone();
 | 
			
		||||
 | 
			
		||||
        case Color.black:
 | 
			
		||||
            return BlackStone();
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            console.warn("Unknown color: ", color)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function WhiteStone() {
 | 
			
		||||
    return <span className="Stone white">⛀</span>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BlackStone() {
 | 
			
		||||
    return <span className="Stone black">⛂</span>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Player
 | 
			
		||||
 */
 | 
			
		||||
export function Player({ color, name }) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div className='Player'>
 | 
			
		||||
            <Stone color={color} />
 | 
			
		||||
            {name}
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Board
 | 
			
		||||
 */
 | 
			
		||||
export function Board() {
 | 
			
		||||
 | 
			
		||||
    return <div className='Board'>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <BlackTile /> <WhiteTile id={0} stone={WhiteStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={1} stone={WhiteStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={2} stone={WhiteStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={4} stone={WhiteStone()} />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <WhiteTile id={5} stone={WhiteStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={6} stone={WhiteStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={7} stone={WhiteStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={8} stone={WhiteStone()} /> <BlackTile />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <BlackTile /> <WhiteTile id={9} stone={WhiteStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={10} stone={WhiteStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={11} stone={WhiteStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={12} stone={WhiteStone()} />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <WhiteTile id={13} stone={null} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={14} stone={null} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={15} stone={null} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={16} stone={null} /> <BlackTile />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <BlackTile /> <WhiteTile id={17} stone={null} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={18} stone={null} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={19} stone={null} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={20} stone={null} />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <WhiteTile id={21} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={22} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={23} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={24} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <BlackTile /> <WhiteTile id={25} stone={BlackStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={26} stone={BlackStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={27} stone={BlackStone()} />
 | 
			
		||||
            <BlackTile /> <WhiteTile id={28} stone={BlackStone()} />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className='row'>
 | 
			
		||||
            <WhiteTile id={29} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={30} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={31} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
            <WhiteTile id={32} stone={BlackStone()} /> <BlackTile />
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function WhiteTile({ id, stone }) {
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            className='Tile white'
 | 
			
		||||
            onClick={() => handleClick(id)}
 | 
			
		||||
        >
 | 
			
		||||
            {stone}
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function BlackTile() {
 | 
			
		||||
    return <div className='Tile black' />
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleClick(i) {
 | 
			
		||||
    console.log("click", i)
 | 
			
		||||
}
 | 
			
		||||
@ -1,26 +0,0 @@
 | 
			
		||||
.game {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game .left-side {
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 45%;
 | 
			
		||||
    /* max-width: 400px; */
 | 
			
		||||
 | 
			
		||||
  /* height: 100px; */
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game .right-side {
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 55%;
 | 
			
		||||
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
import './Game.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import GameView from './Game/GameView'
 | 
			
		||||
import GameSelector from './Game/GameSelector'
 | 
			
		||||
import GameAction from './Game/GameAction'
 | 
			
		||||
import GameBoard from './Game/GameBoard'
 | 
			
		||||
import NewGame from './Game/NewGame'
 | 
			
		||||
import GameMessage from './Game/GameMessage'
 | 
			
		||||
import Message2Opponent from './Game/Message2Opponent'
 | 
			
		||||
 | 
			
		||||
export default function Game() {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="game">
 | 
			
		||||
      <div className='left-side'>
 | 
			
		||||
        <GameView />
 | 
			
		||||
        <GameSelector />
 | 
			
		||||
        <NewGame />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className='right-side'>
 | 
			
		||||
        <GameAction />
 | 
			
		||||
        <GameMessage />
 | 
			
		||||
        <GameBoard />
 | 
			
		||||
        <Message2Opponent />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,55 +0,0 @@
 | 
			
		||||
.action-panel {
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
    /* background-color: lightgrey; */
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    /* padding-top: 8px;
 | 
			
		||||
    padding-bottom: 8px; */
 | 
			
		||||
    color: black;
 | 
			
		||||
    padding-left: -10px;
 | 
			
		||||
    /* */
 | 
			
		||||
 | 
			
		||||
    margin-left: 10px;
 | 
			
		||||
    border: 0.5px dotted lightslategray; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action {
 | 
			
		||||
    width:fit-content;
 | 
			
		||||
    padding: 8px;
 | 
			
		||||
    padding-left: 15px;
 | 
			
		||||
    padding-right: 15px;
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    border: 0.5px solid darkgrey; 
 | 
			
		||||
    margin: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.create:hover,  /* OR */
 | 
			
		||||
.game-action.busy 
 | 
			
		||||
{
 | 
			
		||||
    background-color:#00b0ff60;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.create.enabled:active {
 | 
			
		||||
    background-color:#00b0ffa0;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.cancel:hover,
 | 
			
		||||
.game-action.reject:hover {
 | 
			
		||||
    background-color:#ff000030
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.cancel:active,
 | 
			
		||||
.game-action.reject:active {
 | 
			
		||||
    background-color:#ff000080
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.accept:hover {
 | 
			
		||||
    background-color: #00af0030;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.accept:active {
 | 
			
		||||
    background-color:#00af0080;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.game-action.disabled {
 | 
			
		||||
    color: gray;
 | 
			
		||||
}
 | 
			
		||||
@ -1,45 +0,0 @@
 | 
			
		||||
import './GameAction.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useLocation, matchPath } from "react-router";
 | 
			
		||||
 | 
			
		||||
import Create from './GameAction/Create';
 | 
			
		||||
 | 
			
		||||
import Reject from './GameAction/Reject';
 | 
			
		||||
import Cancel from './GameAction/Cancel';
 | 
			
		||||
import Accept from './GameAction/Accept';
 | 
			
		||||
 | 
			
		||||
import DrawReq from './GameAction/DrawReq';
 | 
			
		||||
import DrawAcq from './GameAction/DrawAcq';
 | 
			
		||||
import Surrender from './GameAction/Surrender';
 | 
			
		||||
 | 
			
		||||
import Backward from './GameAction/Backward';
 | 
			
		||||
import Forward from './GameAction/Forward';
 | 
			
		||||
 | 
			
		||||
// import { AppContext } from '../../context/app'
 | 
			
		||||
 | 
			
		||||
export default function GameAction() {
 | 
			
		||||
  // const [ctx, dispatchCtx] = React.useContext(AppContext)
 | 
			
		||||
 | 
			
		||||
  const { pathname } = useLocation();
 | 
			
		||||
  const isNewGamePath = matchPath("/game/new", pathname);
 | 
			
		||||
  const isProposalPath = matchPath("/game/proposal/*", pathname);
 | 
			
		||||
  const isActivelPath = matchPath("/game/active/*", pathname);
 | 
			
		||||
  const isArchivePath = matchPath("/game/archive/*", pathname);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className='action-panel'>
 | 
			
		||||
      {isNewGamePath && <Create />}
 | 
			
		||||
 | 
			
		||||
      {isProposalPath && <Reject />}
 | 
			
		||||
      {isProposalPath && <Cancel />}
 | 
			
		||||
      {isProposalPath && <Accept />}
 | 
			
		||||
 | 
			
		||||
      {isActivelPath && <DrawReq />}      
 | 
			
		||||
      {isActivelPath && <DrawAcq />}      
 | 
			
		||||
      {isActivelPath && <Surrender />}
 | 
			
		||||
 | 
			
		||||
      {isArchivePath && <Backward />}      
 | 
			
		||||
      {isArchivePath && <Forward />}      
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Backward() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action backward'>Backward</button>
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function DrawAcq() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action draw-acq'>Draw acquire</button>
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function DrawReq() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action drawreq'>Draw request</button>
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Forward() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action forward'>Forward</button>
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Surrender() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action surrender'>Surrender</button>
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
.game-board .board {
 | 
			
		||||
    padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
import './GameBoard.css'
 | 
			
		||||
import React from 'react'
 | 
			
		||||
import Board from './GameBoard/Board'
 | 
			
		||||
import { WHITE, BLACK } from './Stone'
 | 
			
		||||
import { Player } from './Player'
 | 
			
		||||
 | 
			
		||||
import { AppContext } from '../../context/app'
 | 
			
		||||
 | 
			
		||||
export default function GameBoard() {
 | 
			
		||||
 | 
			
		||||
  const [ctx] = React.useContext(AppContext)
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className='game-board'>
 | 
			
		||||
      <Player color={WHITE()} name={ctx.newGame.whitePlayer} />
 | 
			
		||||
      <Board />
 | 
			
		||||
      <Player color={BLACK()} name={ctx.newGame.blackPlayer} />
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@ -1,79 +0,0 @@
 | 
			
		||||
import './Board.css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { WhiteStone, BlackStone } from '../Stone' 
 | 
			
		||||
 | 
			
		||||
export default function Board() {
 | 
			
		||||
 | 
			
		||||
  return <div className='board'>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={0} stone={WhiteStone()} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={1} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={2} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={4} stone={WhiteStone()} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={5} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={6} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={7} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={8} stone={WhiteStone()} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={ 9} stone={WhiteStone()} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={10} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={11} stone={WhiteStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={12} stone={WhiteStone()} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={13} stone={null} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={14} stone={null} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={15} stone={null} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={16} stone={null} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={17} stone={null} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={18} stone={null} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={19} stone={null} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={20} stone={null} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={21} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={22} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={23} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={24} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <BlackTile/> <WhiteTile id={25} stone={BlackStone()} /> 
 | 
			
		||||
      <BlackTile/> <WhiteTile id={26} stone={BlackStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={27} stone={BlackStone()} />
 | 
			
		||||
      <BlackTile/> <WhiteTile id={28} stone={BlackStone()} />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div className='row'>
 | 
			
		||||
      <WhiteTile id={29} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={30} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={31} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
      <WhiteTile id={32} stone={BlackStone()} /> <BlackTile/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function WhiteTile({ id, stone }) {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div 
 | 
			
		||||
      className='tile white'
 | 
			
		||||
      onClick={() => handleClick(id)}
 | 
			
		||||
    >
 | 
			
		||||
      {stone}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function BlackTile() {
 | 
			
		||||
  return <div className='tile black'/>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleClick(i) {
 | 
			
		||||
  console.log("click", i)
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import './Selectable.css'
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { oppositeColor } from '../Stone';
 | 
			
		||||
import { Player } from '../Player';
 | 
			
		||||
import { Player } from '../../Player';
 | 
			
		||||
 | 
			
		||||
export default function Selectable({ game, onClick }) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ import React from 'react';
 | 
			
		||||
import { AppData } from '../../context/data'
 | 
			
		||||
import { AppContext } from '../../context/app'
 | 
			
		||||
import { useLocation, matchPath } from "react-router";
 | 
			
		||||
import { SelectPlayer } from './Player';
 | 
			
		||||
import { SelectPlayer } from '../Player';
 | 
			
		||||
import { WhiteStone, BlackStone } from './Stone';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
.player {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player select {
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    border: 0.5px solid darkgrey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player select:hover {
 | 
			
		||||
    background: lightgray;
 | 
			
		||||
}
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
import './Player.css'
 | 
			
		||||
import React from 'react'
 | 
			
		||||
import { Stone } from './Stone'
 | 
			
		||||
 | 
			
		||||
export function Player({ color, name }) {
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className='player'>
 | 
			
		||||
            <Stone color={color} />
 | 
			
		||||
            {name}
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function SelectPlayer({ name, setName, nameOptions }) {
 | 
			
		||||
    const handleSelectChange = (event) => {
 | 
			
		||||
        setName(event.target.value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className='select player'>
 | 
			
		||||
            <form>
 | 
			
		||||
                <select value={name} onChange={handleSelectChange}>
 | 
			
		||||
                    {nameOptions}
 | 
			
		||||
                </select>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
.stone {
 | 
			
		||||
    cursor: default; /* disable 'I beam' cursor change */
 | 
			
		||||
}
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
import './Stone.css'
 | 
			
		||||
import React from 'react'
 | 
			
		||||
 | 
			
		||||
export function Stone({ color }) {
 | 
			
		||||
    switch (color) {
 | 
			
		||||
        case WHITE():
 | 
			
		||||
            return WhiteStone()
 | 
			
		||||
 | 
			
		||||
        case BLACK():
 | 
			
		||||
            return BlackStone()
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            console.warn("Unknown color: ", color)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function WhiteStone() {
 | 
			
		||||
    return <span className="stone white">⛀</span>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BlackStone() {
 | 
			
		||||
    return <span className="stone black">⛂</span>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function oppositeColor(color) {
 | 
			
		||||
    if (color === WHITE())
 | 
			
		||||
        return BLACK()
 | 
			
		||||
 | 
			
		||||
    if (color === BLACK())
 | 
			
		||||
        return WHITE()
 | 
			
		||||
 | 
			
		||||
    return color
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function WHITE() {
 | 
			
		||||
    return "WHITE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BLACK() {
 | 
			
		||||
    return "BLACK"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										125
									
								
								webapp/src/container/Games.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								webapp/src/container/Games.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
.Games {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Games .left-side {
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 45%;
 | 
			
		||||
    /* max-width: 400px; */
 | 
			
		||||
 | 
			
		||||
  /* height: 100px; */
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Games .right-side {
 | 
			
		||||
    float: left;
 | 
			
		||||
    width: 55%;
 | 
			
		||||
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.ViewSelector {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
    background-color: lightgrey;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
    padding-bottom: 8px;
 | 
			
		||||
    color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ViewSelector a {
 | 
			
		||||
    color: black;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    transition: .25s ease;
 | 
			
		||||
    margin-left: 5px;
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ViewSelector .active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    background-color: cadetblue;
 | 
			
		||||
    opacity: 80%;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
    padding-bottom: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ViewSelector a:hover:not(.active) {
 | 
			
		||||
    color: cadetblue; 
 | 
			
		||||
    box-shadow: 0 1.5px 0 0 currentColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.ViewProvider {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center; 
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.ActionPanel {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
    height: 34.5px;
 | 
			
		||||
 | 
			
		||||
    /* background-color: lightgrey; */
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    /* padding-top: 8px;
 | 
			
		||||
    padding-bottom: 8px; */
 | 
			
		||||
    color: black;
 | 
			
		||||
    padding-left: -10px;
 | 
			
		||||
    /* */
 | 
			
		||||
 | 
			
		||||
    margin-left: 10px;
 | 
			
		||||
    border: 0.5px dotted lightslategray; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel button {
 | 
			
		||||
    width:fit-content;
 | 
			
		||||
    padding: 6px;
 | 
			
		||||
    padding-left: 15px;
 | 
			
		||||
    padding-right: 15px;
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    border: 0.5px solid darkgrey; 
 | 
			
		||||
    margin: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel .Create:hover,  /* OR */
 | 
			
		||||
.game-action.busy 
 | 
			
		||||
{
 | 
			
		||||
    background-color:#00b0ff60;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel .Create.enabled:active {
 | 
			
		||||
    background-color:#00b0ffa0;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel .Cancel:hover,
 | 
			
		||||
.ActionPanel .Reject:hover {
 | 
			
		||||
    background-color:#ff000030
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel .Cancel:active,
 | 
			
		||||
.ActionPanel .Reject:active {
 | 
			
		||||
    background-color:#ff000080
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel .Accept:hover {
 | 
			
		||||
    background-color: #00af0030;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ActionPanel .Accept:active {
 | 
			
		||||
    background-color:#00af0080;  
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								webapp/src/container/Games.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								webapp/src/container/Games.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
			
		||||
import './Games.css';
 | 
			
		||||
import React from "react"
 | 
			
		||||
import { NavLink, Routes, Route } from "react-router-dom";
 | 
			
		||||
 | 
			
		||||
import NewGame from './games/view/NewGame';
 | 
			
		||||
import GameProposals from './games/view/GameProposals';
 | 
			
		||||
import ActiveGames from './games/view/ActiveGames';
 | 
			
		||||
import GamesArchive from './games/view/GamesArchive';
 | 
			
		||||
 | 
			
		||||
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 Backward from './games/action/Backward';
 | 
			
		||||
import Forward from './games/action/Forward';
 | 
			
		||||
 | 
			
		||||
import GameBoard from './games/GameBoard';
 | 
			
		||||
 | 
			
		||||
export default function Games({ gamesReducer, user }) {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="Games">
 | 
			
		||||
      <div className='left-side'>
 | 
			
		||||
        <ViewSelector />
 | 
			
		||||
        <ViewProvider />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className='right-side'>
 | 
			
		||||
        <ActionPanel />
 | 
			
		||||
        <GameBoard />
 | 
			
		||||
        {/*
 | 
			
		||||
        <GameMessage />
 | 
			
		||||
        <GameBoard />
 | 
			
		||||
        <Message2Opponent /> */}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ViewSelector() {
 | 
			
		||||
  return (
 | 
			
		||||
    <nav className='ViewSelector'>
 | 
			
		||||
      <NavLink to="new">New</NavLink>
 | 
			
		||||
      <NavLink to="proposal">Proposal</NavLink>
 | 
			
		||||
      <NavLink to="active">Active</NavLink>
 | 
			
		||||
      <NavLink to="archive">Archive</NavLink>
 | 
			
		||||
    </nav>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ViewProvider() {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className='ViewProvider'>
 | 
			
		||||
      <Routes>
 | 
			
		||||
        <Route path="new" element={<NewGame />} />
 | 
			
		||||
        <Route path="proposal" element={<GameProposals />} />
 | 
			
		||||
        <Route path="active" element={<ActiveGames />} />
 | 
			
		||||
        <Route path="archive" element={<GamesArchive />} />
 | 
			
		||||
      </Routes>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ActionPanel() {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className='ActionPanel'>
 | 
			
		||||
      <Routes>
 | 
			
		||||
        <Route path="new" element={<Create />} />
 | 
			
		||||
        <Route path="proposal" element={[<Accept key={1} />, <Reject key={2} />, <Cancel key={3} />]} />
 | 
			
		||||
        <Route path="active" element={[<DrawReq key={1} />, <DrawAcq key={2} />, <Surrender key={3} />]} />
 | 
			
		||||
        <Route path="archive" element={[<Backward key={1} />, <Forward key={2} />]} />
 | 
			
		||||
      </Routes>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Header a {
 | 
			
		||||
    color: lightgray;
 | 
			
		||||
    color: black; 
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    transition: .25s ease;
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
@ -38,14 +38,5 @@
 | 
			
		||||
.Header a:hover:not(.active) {
 | 
			
		||||
    color: cadetblue;
 | 
			
		||||
 | 
			
		||||
    box-shadow: 0 1.5px 0 0 currentcolor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[data-darkreader-scheme="dark"] .Header a {
 | 
			
		||||
    color: darkslategrey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[data-darkreader-scheme="dark"] .Header .active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    box-shadow: 0 1.5px 0 0 currentcolor;
 | 
			
		||||
}
 | 
			
		||||
@ -23,8 +23,8 @@ export default function Header({ pollingReducer }) {
 | 
			
		||||
          About
 | 
			
		||||
        </NavLink>
 | 
			
		||||
 | 
			
		||||
        <NavLink to="/game">
 | 
			
		||||
          <Wobler text="Game" dance={polling.games} />
 | 
			
		||||
        <NavLink to="/games">
 | 
			
		||||
          <Wobler text="Games" dance={polling.games} />
 | 
			
		||||
        </NavLink>
 | 
			
		||||
 | 
			
		||||
        <NavLink to="/leaderboard">
 | 
			
		||||
 | 
			
		||||
@ -22,19 +22,21 @@ export default function Leaderboard({ leaderboard, user }) {
 | 
			
		||||
    </tr>
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return <div className="Leaderboard">
 | 
			
		||||
    <table>
 | 
			
		||||
      <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <th></th>
 | 
			
		||||
          <th>Played</th>
 | 
			
		||||
          <th>Won</th>
 | 
			
		||||
          <th>Draw</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </thead>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        {tableRows}
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
  </div>
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="Leaderboard">
 | 
			
		||||
      <table>
 | 
			
		||||
        <thead>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th></th>
 | 
			
		||||
            <th>Played</th>
 | 
			
		||||
            <th>Won</th>
 | 
			
		||||
            <th>Draw</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
          {tableRows}
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										3
									
								
								webapp/src/container/games/GameBoard.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								webapp/src/container/games/GameBoard.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
.GameBoard .Board {
 | 
			
		||||
    padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								webapp/src/container/games/GameBoard.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								webapp/src/container/games/GameBoard.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
import './GameBoard.css'
 | 
			
		||||
import React from 'react'
 | 
			
		||||
 | 
			
		||||
import { Color, Player, Board } from '../../components/Checkers';
 | 
			
		||||
 | 
			
		||||
//import { AppContext } from '../../context/app'
 | 
			
		||||
 | 
			
		||||
export default function GameBoard() {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  //const [ctx] = React.useContext(AppContext)
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className='GameBoard'>
 | 
			
		||||
      <Player color={Color.white} name={/*ctx.newGame.whitePlayer*/"White player name"} />
 | 
			
		||||
      <Board />
 | 
			
		||||
      <Player color={Color.black} name={/*ctx.newGame.blackPlayer*/"Black player name"} />
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@ -2,5 +2,5 @@ import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Accept() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action accept'>Accept</button>
 | 
			
		||||
    return <button className='Accept'>Accept</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								webapp/src/container/games/action/Backward.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								webapp/src/container/games/action/Backward.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Backward() {
 | 
			
		||||
 | 
			
		||||
    return <button className='Backward' disabled>Backward</button>
 | 
			
		||||
}
 | 
			
		||||
@ -2,5 +2,5 @@ import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Cancel() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action cancel'>Cancel</button>
 | 
			
		||||
    return <button className='Cancel'>Cancel</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								webapp/src/container/games/action/Create.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								webapp/src/container/games/action/Create.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Create() {
 | 
			
		||||
 | 
			
		||||
    return <button className='Create'>Create</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								webapp/src/container/games/action/DrawAcq.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								webapp/src/container/games/action/DrawAcq.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function DrawAcq() {
 | 
			
		||||
 | 
			
		||||
    return <button className='DrawAcq'>Draw accept</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								webapp/src/container/games/action/DrawReq.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								webapp/src/container/games/action/DrawReq.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function DrawReq() {
 | 
			
		||||
 | 
			
		||||
    return <button className='DrawReq'>Draw request</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								webapp/src/container/games/action/Forward.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								webapp/src/container/games/action/Forward.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Forward() {
 | 
			
		||||
 | 
			
		||||
    return <button className='Forward' disabled>Forward</button>
 | 
			
		||||
}
 | 
			
		||||
@ -2,5 +2,5 @@ import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Reject() {
 | 
			
		||||
 | 
			
		||||
    return <button className='game-action reject'>Reject</button>
 | 
			
		||||
    return <button className='Reject'>Reject</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								webapp/src/container/games/action/Surrender.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								webapp/src/container/games/action/Surrender.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function Surrender() {
 | 
			
		||||
 | 
			
		||||
    return <button className='Surrender'>Surrender</button>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								webapp/src/container/games/view/ActiveGames.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								webapp/src/container/games/view/ActiveGames.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function ActiveGames() {
 | 
			
		||||
    return (
 | 
			
		||||
        <div>View: ActiveGame</div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								webapp/src/container/games/view/GameProposals.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								webapp/src/container/games/view/GameProposals.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function GameProposals() {
 | 
			
		||||
    return (
 | 
			
		||||
        <div>View: GameProposals</div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								webapp/src/container/games/view/GamesArchive.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								webapp/src/container/games/view/GamesArchive.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function GamesArchive() {
 | 
			
		||||
    return (
 | 
			
		||||
        <div>View: GameArchive</div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								webapp/src/container/games/view/NewGame.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								webapp/src/container/games/view/NewGame.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
.SelectPlayer {
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    border: 0.5px solid darkgrey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.SelectPlayer select:hover {
 | 
			
		||||
    background: lightgray;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								webapp/src/container/games/view/NewGame.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								webapp/src/container/games/view/NewGame.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default function NewGame() {
 | 
			
		||||
    return (
 | 
			
		||||
        <div>View: NewGame</div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Move to components as DropSelector
 | 
			
		||||
function SelectPlayer({ name, setName, nameOptions }) {
 | 
			
		||||
    const handleSelectChange = (event) => {
 | 
			
		||||
        setName(event.target.value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className='SelectPlayer'>
 | 
			
		||||
            <form>
 | 
			
		||||
                <select value={name} onChange={handleSelectChange}>
 | 
			
		||||
                    {nameOptions}
 | 
			
		||||
                </select>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								webapp/src/reducer/games.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								webapp/src/reducer/games.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
import { useReducer } from 'react';
 | 
			
		||||
import { nextState } from '../util/StateHelper';
 | 
			
		||||
 | 
			
		||||
export const gamesInitialState = {
 | 
			
		||||
  list: null,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function gamesReducer(state, action) {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
 | 
			
		||||
    case 'next': 
 | 
			
		||||
      return nextState(state, action);
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      throw Error('GameReducer: unknown action.type', action.type);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function useGamesReducer() {
 | 
			
		||||
  return useReducer(gamesReducer, gamesInitialState);
 | 
			
		||||
}
 | 
			
		||||
@ -17,7 +17,7 @@ export function userReducer(state, action) {
 | 
			
		||||
      return nextState(state, action);
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      throw Error('Unknown action.type', action.type);
 | 
			
		||||
      throw Error('UserReducer: unknown action.type', action.type);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user