NewGame to use dispatchGames
- remove DispatchGames and GamesAPI Context transfer it as props instead - DropdownList component - delete obsoleete files
This commit is contained in:
parent
3171a97827
commit
76eb556d09
15
webapp/src/components/DropdownList.jsx
Normal file
15
webapp/src/components/DropdownList.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function DropdownList({ selected, onSelect, optionsList }) {
|
||||
const handleSelect = (event) => {
|
||||
onSelect(event.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<form className='SelectPlayer'>
|
||||
<select value={selected} onChange={handleSelect}>
|
||||
{optionsList}
|
||||
</select>
|
||||
</form>
|
||||
)
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
.game-message {
|
||||
border-radius: 3px;
|
||||
border-color: lightgray;
|
||||
background-color:violet;
|
||||
width: 70%;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import './GameMessage.css'
|
||||
import React from 'react'
|
||||
|
||||
// import { AppContext } from '../../context/app'
|
||||
|
||||
export default function GameMessage() {
|
||||
|
||||
// const [ctx] = React.useContext(AppContext)
|
||||
|
||||
return (
|
||||
<div className='game-message'>
|
||||
TBD: Game Message
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
.Games {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.Games .li {
|
||||
border: 1px solid black;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.Games .li p {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.Games .li p q {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.Games .li p i {
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
.Games .li button.action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Games .li:hover button.action {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.separator {
|
||||
/* width: 20%; */
|
||||
/* height: 20px; */
|
||||
border-bottom: 1px dotted black;
|
||||
text-align: center;
|
||||
font-size: 50%;
|
||||
padding-left: 50%;
|
||||
margin-bottom: 7px;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import './GameSelector.css';
|
||||
import React from 'react';
|
||||
import { useLocation, matchPath } from "react-router";
|
||||
|
||||
import { AppData } from "../../context/data"
|
||||
import { AppContext } from "../../context/app"
|
||||
import Proposal from './GameSelector/GameProposal';
|
||||
|
||||
export default function GameSelector() {
|
||||
const [data] = React.useContext(AppData)
|
||||
const [/*ctx*/, dispatchCtx] = React.useContext(AppContext)
|
||||
|
||||
const { pathname } = useLocation();
|
||||
const isProposalPath = matchPath("/game/proposal/*", pathname);
|
||||
const isActivelPath = matchPath("/game/active/*", pathname);
|
||||
const isArchivePath = matchPath("/game/archive/*", pathname);
|
||||
|
||||
// console.log("GameSelector appCtx", ctx)
|
||||
|
||||
const onClick_proposal = (selectedGame) => {
|
||||
dispatchCtx({ component: "game-selector", selectedGameProposal: selectedGame })
|
||||
}
|
||||
|
||||
// const onClick_active = (selectedGame) => {
|
||||
// dispatchCtx({ component: "game-selector", selectedActiveGame: selectedGame })
|
||||
// }
|
||||
|
||||
// const onClick_archive = (selectedGame) => {
|
||||
// dispatchCtx({ component: "game-selector", selectedArchiveGame: selectedGame })
|
||||
// }
|
||||
|
||||
if (!data.games)
|
||||
return <div>Loading..</div>
|
||||
|
||||
console.log("Games", data.games)
|
||||
|
||||
return (
|
||||
<div className='game-selector'>
|
||||
{isProposalPath && <Proposal games={data.games} onClick={onClick_proposal} />}
|
||||
{isActivelPath && <div>TBD #1</div>}
|
||||
{isArchivePath && <div>TBD #2</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import './ProposalSelector.css'
|
||||
import React from 'react';
|
||||
import Selectable from './Selectable';
|
||||
|
||||
export default function ProposalSelector({ games }) {
|
||||
|
||||
const waitForYou = games
|
||||
.filter(game => game.status === Status.WaitForYou)
|
||||
.map(game => <Selectable game={game} />)
|
||||
|
||||
const WaitForOpponent = games
|
||||
.filter(game => game.status === Status.WaitForOpponent)
|
||||
.map(game => <Selectable game={game} />)
|
||||
|
||||
return <div className="Container">
|
||||
<div className="Games">
|
||||
{waitForYou}
|
||||
{WaitForOpponent.length > 0 &&
|
||||
<div className="separator">
|
||||
waiting for opponent ({WaitForOpponent.length})
|
||||
</div>
|
||||
}
|
||||
{WaitForOpponent}
|
||||
</div>
|
||||
</div>
|
||||
};
|
||||
|
||||
|
||||
const Status = {
|
||||
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
|
||||
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import './ProposalSelector.css'
|
||||
import React from 'react';
|
||||
import Selectable from './Selectable';
|
||||
|
||||
export default function ProposalSelector({ games }) {
|
||||
|
||||
const waitForYou = games
|
||||
.filter(game => game.status === Status.WaitForYou)
|
||||
.map(game => <Selectable game={game} />)
|
||||
|
||||
const WaitForOpponent = games
|
||||
.filter(game => game.status === Status.WaitForOpponent)
|
||||
.map(game => <Selectable game={game} />)
|
||||
|
||||
return <div className="Container">
|
||||
<div className="Games">
|
||||
{waitForYou}
|
||||
{WaitForOpponent.length > 0 &&
|
||||
<div className="separator">
|
||||
waiting for opponent ({WaitForOpponent.length})
|
||||
</div>
|
||||
}
|
||||
{WaitForOpponent}
|
||||
</div>
|
||||
</div>
|
||||
};
|
||||
|
||||
|
||||
const Status = {
|
||||
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
|
||||
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import React from 'react';
|
||||
import Selectable from './Selectable';
|
||||
|
||||
export default function ProposalSelector({ games, onClick }) {
|
||||
|
||||
const waitForYou = games
|
||||
.filter(game => game.status === Status.WaitForYou)
|
||||
.map(game => <Selectable game={game} key={game.uuid} onClick={onClick} />)
|
||||
|
||||
const WaitForOpponent = games
|
||||
.filter(game => game.status === Status.WaitForOpponent)
|
||||
.map(game => <Selectable game={game} key={game.uuid} onClick={onClick} />)
|
||||
|
||||
return (
|
||||
<div className="Games">
|
||||
{waitForYou}
|
||||
{WaitForOpponent.length > 0 &&
|
||||
<div className="separator">
|
||||
waiting for opponent ({WaitForOpponent.length})
|
||||
</div>
|
||||
}
|
||||
{WaitForOpponent}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Status = {
|
||||
WaitForOpponent: "GAME_PROPOSAL_WAIT_FOR_OPPONENT",
|
||||
WaitForYou: "GAME_PROPOSAL_WAIT_FOR_YOU",
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
.selectable {
|
||||
border: 1px solid black;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.selectable q {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.selectable i {
|
||||
font-size: 70%;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.selectable:hover {
|
||||
background-color: #d3d3d360;
|
||||
}
|
||||
|
||||
/* .Games .li button.action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Games .li:hover button.action {
|
||||
display: initial;
|
||||
} */
|
||||
|
||||
.separator {
|
||||
/* width: 20%; */
|
||||
/* height: 20px; */
|
||||
border-bottom: 1px dotted black;
|
||||
text-align: center;
|
||||
font-size: 50%;
|
||||
padding-left: 50%;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.selectable .title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import './Selectable.css'
|
||||
import React from 'react';
|
||||
import { oppositeColor } from '../Stone';
|
||||
import { Player } from '../../Player';
|
||||
|
||||
export default function Selectable({ game, onClick }) {
|
||||
|
||||
const myColor = game.myColor
|
||||
|
||||
const opponentColor = oppositeColor(myColor)
|
||||
const opponentName = game.opponentName
|
||||
|
||||
return (
|
||||
<div className='selectable'>
|
||||
<div className='title' onClick={() => onClick(game)}>
|
||||
<Player color={myColor} />
|
||||
<i>vs</i>
|
||||
<Player color={opponentColor} name={opponentName} />
|
||||
</div>
|
||||
<q>{game.message}</q>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
@ -1,30 +0,0 @@
|
||||
.game-view {
|
||||
margin-bottom: 10px;
|
||||
background-color: lightgrey;
|
||||
width: 100%;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.game-view a {
|
||||
color:darkgrey;
|
||||
text-decoration: none;
|
||||
transition: .25s ease;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.game-view .active {
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
background-color: cadetblue;
|
||||
opacity: 80%;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.game-view a:hover:not(.active) {
|
||||
color: cadetblue;
|
||||
box-shadow: 0 1.5px 0 0 currentColor;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import './GameView.css';
|
||||
import React from 'react';
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
export default function GameView() {
|
||||
|
||||
return (
|
||||
<nav className='game-view'>
|
||||
<NavLink to="/game/new">New</NavLink>
|
||||
<NavLink to="/game/proposal">Proposal</NavLink>
|
||||
<NavLink to="/game/active">Active</NavLink>
|
||||
<NavLink to="/game/archive">Archive</NavLink>
|
||||
</nav>
|
||||
)
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
.new-game {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.new-game * {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.new-game>div { /* first level childs only*/
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.new-game .stone {
|
||||
font-size: 150%;
|
||||
vertical-align: -3px;
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
import './NewGame.css';
|
||||
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 { WhiteStone, BlackStone } from './Stone';
|
||||
|
||||
|
||||
export default function NewGame() {
|
||||
const [ctx, dispatchCtx] = React.useContext(AppContext)
|
||||
const [data] = React.useContext(AppData)
|
||||
const { pathname } = useLocation();
|
||||
const isMyPath = matchPath("/game/new", pathname);
|
||||
|
||||
if (!isMyPath)
|
||||
return
|
||||
|
||||
/*
|
||||
* Name options
|
||||
*/
|
||||
const nameOptions = data.leaderboard ? Object.keys(data.leaderboard).map(playerName =>
|
||||
<option key={playerName} value={playerName}>
|
||||
{data.isCurrentUser(playerName) ? 'You' : playerName}
|
||||
</option>)
|
||||
: [<option key='loading' value='…'>…loading</option>]
|
||||
|
||||
const whiteOptions = Array(nameOptions)
|
||||
whiteOptions.push(<option key='default' value=''>{'white player …'}</option>)
|
||||
|
||||
const blackOptions = Array(nameOptions)
|
||||
blackOptions.push(<option key='default' value=''>{'black player …'}</option>)
|
||||
|
||||
/*
|
||||
* Radiobutton
|
||||
*/
|
||||
const radioButton = (whitePlayer, blackPlayer) => {
|
||||
if (whitePlayer !== '' && whitePlayer === ctx.newGame.blackPlayer) {
|
||||
blackPlayer = ''
|
||||
}
|
||||
if (blackPlayer !== '' && blackPlayer === ctx.newGame.whitePlayer) {
|
||||
whitePlayer = ''
|
||||
}
|
||||
|
||||
dispatchCtx({ update: "newGame", whitePlayer, blackPlayer })
|
||||
}
|
||||
|
||||
const setWhitePlayer = (name) => {
|
||||
radioButton(name, ctx.newGame.blackPlayer)
|
||||
}
|
||||
|
||||
const setBlackPlayer = (name) => {
|
||||
radioButton(ctx.newGame.whitePlayer, name)
|
||||
}
|
||||
|
||||
/*
|
||||
* Component
|
||||
*/
|
||||
return (
|
||||
<div className='new-game'>
|
||||
<div>
|
||||
<WhiteStone />
|
||||
<SelectPlayer name={ctx.newGame.whitePlayer} setName={setWhitePlayer} nameOptions={whiteOptions} />
|
||||
</div>
|
||||
<div>- vs -</div>
|
||||
<div>
|
||||
<SelectPlayer name={ctx.newGame.blackPlayer} setName={setBlackPlayer} nameOptions={blackOptions} />
|
||||
<BlackStone />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -17,18 +17,16 @@ import Forward from './games/action/Forward';
|
||||
|
||||
import GameBoard from './games/GameBoard';
|
||||
|
||||
import { GamesContext, GamesDispatchContext, GamesApiContext } from '../context/games';
|
||||
import { GamesContext } from '../context/games';
|
||||
|
||||
export default function Games({ context }) {
|
||||
export default function Games({ context, players }) {
|
||||
|
||||
return (
|
||||
<GamesContext.Provider value={context.games} >
|
||||
<GamesDispatchContext.Provider value={context.dispatchGames} >
|
||||
<GamesApiContext.Provider value={context.gamesApi} >
|
||||
<div className='Games'>
|
||||
<div className='left-side'>
|
||||
<ViewSelector />
|
||||
<ViewProvider />
|
||||
<ViewProvider players={players} dispatchGames={context.dispatchGames} />
|
||||
</div>
|
||||
<div className='right-side'>
|
||||
<ActionPanel />
|
||||
@ -38,8 +36,6 @@ export default function Games({ context }) {
|
||||
<Message2Opponent /> */}
|
||||
</div>
|
||||
</div >
|
||||
</GamesApiContext.Provider>
|
||||
</GamesDispatchContext.Provider>
|
||||
</GamesContext.Provider>
|
||||
)
|
||||
};
|
||||
@ -57,11 +53,17 @@ function ViewSelector() {
|
||||
)
|
||||
}
|
||||
|
||||
function ViewProvider(/*todo: dispatchGame*/) {
|
||||
function ViewProvider({ players, dispatchGames }) {
|
||||
return (
|
||||
<div className='ViewProvider'>
|
||||
<Routes>
|
||||
<Route path='new' element={<NewGame />} />
|
||||
|
||||
<Route path='new' element={
|
||||
<NewGame
|
||||
players={players}
|
||||
onSelectPlayer={(whitePlayer, blackPlayer) => dispatchGames({ type: "next", newGame: { whitePlayer, blackPlayer } })}
|
||||
/>
|
||||
} />
|
||||
|
||||
<Route path='proposal' element={
|
||||
<GameSelector
|
||||
|
@ -1,8 +1,13 @@
|
||||
.SelectPlayer {
|
||||
border-radius: 5px;
|
||||
border: 0.5px solid darkgrey;
|
||||
.NewGame * {
|
||||
/* all childs */
|
||||
width: 200px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.SelectPlayer select:hover {
|
||||
background: lightgray;
|
||||
.NewGame>i {
|
||||
/* first level childs only*/
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
@ -1,30 +1,62 @@
|
||||
import './NewGame.css'
|
||||
import React, { useContext } from 'react';
|
||||
import { GamesContext } from '../../../context/games';
|
||||
|
||||
export default function NewGame() {
|
||||
import DropdownList from '../../../components/DropdownList';
|
||||
import { WhiteStone, BlackStone } from '../../../components/Checkers';
|
||||
|
||||
export default function NewGame({ players, onSelectPlayer }) {
|
||||
const games = useContext(GamesContext);
|
||||
|
||||
console.log("NewGame", games);
|
||||
/*
|
||||
* Name options
|
||||
*/
|
||||
const nameOptions = !players.leaderboard
|
||||
? [<option key='loading' value='…'>…loading</option>]
|
||||
: Object.keys(players.leaderboard).map(playerName =>
|
||||
<option key={playerName} value={playerName}>
|
||||
{players.isCurrentUser(playerName) ? 'You' : playerName}
|
||||
</option>)
|
||||
|
||||
return (
|
||||
<div>View: NewGame</div>
|
||||
)
|
||||
const whiteOptions = Array(nameOptions)
|
||||
whiteOptions.push(<option key='default' value=''>{'white player …'}</option>)
|
||||
|
||||
const blackOptions = Array(nameOptions)
|
||||
blackOptions.push(<option key='default' value=''>{'black player …'}</option>)
|
||||
|
||||
/*
|
||||
* Radiobutton
|
||||
*/
|
||||
const radioButton = (whitePlayer, blackPlayer) => {
|
||||
if (whitePlayer !== '' && whitePlayer === games.newGame.blackPlayer) {
|
||||
blackPlayer = '';
|
||||
}
|
||||
if (blackPlayer !== '' && blackPlayer === games.newGame.whitePlayer) {
|
||||
whitePlayer = '';
|
||||
}
|
||||
|
||||
|
||||
// Move to components as DropSelector
|
||||
function SelectPlayer({ name, setName, nameOptions }) {
|
||||
const handleSelectChange = (event) => {
|
||||
setName(event.target.value)
|
||||
console.log("WhitePlayer", whitePlayer, "BlackPlayer", blackPlayer);
|
||||
onSelectPlayer(whitePlayer, blackPlayer);
|
||||
}
|
||||
|
||||
const setWhitePlayer = (name) => {
|
||||
radioButton(name, games.newGame.blackPlayer);
|
||||
}
|
||||
|
||||
const setBlackPlayer = (name) => {
|
||||
radioButton(games.newGame.whitePlayer, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Component
|
||||
*/
|
||||
return (
|
||||
<div className='SelectPlayer'>
|
||||
<form>
|
||||
<select value={name} onChange={handleSelectChange}>
|
||||
{nameOptions}
|
||||
</select>
|
||||
</form>
|
||||
<div className='NewGame'>
|
||||
<WhiteStone />
|
||||
<DropdownList selected={games.newGame.whitePlayer} onSelect={setWhitePlayer} optionsList={whiteOptions} />
|
||||
<i>- vs -</i>
|
||||
<DropdownList selected={games.newGame.blackPlayer} onSelect={setBlackPlayer} optionsList={blackOptions} />
|
||||
<BlackStone />
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const GamesContext = createContext(null);
|
||||
export const GamesDispatchContext = createContext(null);
|
||||
export const GamesApiContext = createContext(null);
|
||||
|
||||
// export const Games = React.createContext({
|
||||
// state: initialState,
|
||||
|
@ -3,6 +3,11 @@ import { nextState } from '../util/StateHelper';
|
||||
|
||||
export const gamesInitialState = {
|
||||
list: null,
|
||||
|
||||
newGame: {
|
||||
whitePlayer: '',
|
||||
blackPlayer: ''
|
||||
}
|
||||
};
|
||||
|
||||
export function gamesReducer(state, action) {
|
||||
|
Loading…
Reference in New Issue
Block a user