Compare commits

...

2 Commits

Author SHA1 Message Date
b632aa7dc3 GameSelector
- single component for GameProposals, ActiveGames and Archive

- clickabple and scrollable
2023-11-09 18:19:31 +01:00
6b8b75ba7f component params grouping 2023-11-09 15:59:38 +01:00
9 changed files with 122 additions and 45 deletions

View File

@ -26,14 +26,19 @@ export default function App() {
const gamesApi = useGamesApi(dispatchGames);
gamesApi.list(pollingReducer);
const players = {
leaderboard,
isCurrentUser: (playerName) => user?.isCurrentUser(playerName) === true ? true : null
};
return (
<BrowserRouter>
<Header pollingReducer={pollingReducer} />
<Routes>
<Route path='/' element={<About />} />
<Route path='/about' element={<About />} />
<Route path='/games/*' element={<Games games={games} dispatchGames={dispatchGames} gamesApi={gamesApi} />} />
<Route path='/leaderboard' element={<Leaderboard leaderboard={leaderboard} user={user} />} />
<Route path='/games/*' element={<Games context={{ games, dispatchGames, gamesApi }} players={players} />} />
<Route path='/leaderboard' element={<Leaderboard players={players} />} />
</Routes>
</BrowserRouter>
)

View File

@ -110,11 +110,9 @@ export function Board() {
}
function WhiteTile({ id, stone }) {
return (
<div
className='Tile white'
onClick={() => handleClick(id)}
<div className='Tile white'
onClick={() => console.log('click', id)}
>
{stone}
</div>
@ -123,8 +121,4 @@ function WhiteTile({ id, stone }) {
function BlackTile() {
return <div className='Tile black' />
}
function handleClick(i) {
console.log("click", i)
}

View File

@ -21,13 +21,13 @@ import GameBoard from './games/GameBoard';
import { GamesContext, GamesDispatchContext, GamesApiContext } from '../context/games';
export default function Games({ games, dispatchGames, gamesApi }) {
export default function Games({ context }) {
return (
<div className="Games">
<GamesContext.Provider value={games} >
<GamesDispatchContext.Provider value={dispatchGames} >
<GamesApiContext.Provider value={gamesApi} >
<GamesContext.Provider value={context.games} >
<GamesDispatchContext.Provider value={context.dispatchGames} >
<GamesApiContext.Provider value={context.gamesApi} >
<div className="Games">
<div className='left-side'>
<ViewSelector />
<ViewProvider />
@ -39,10 +39,10 @@ export default function Games({ games, dispatchGames, gamesApi }) {
<GameMessage />
<Message2Opponent /> */}
</div>
</GamesApiContext.Provider>
</GamesDispatchContext.Provider>
</GamesContext.Provider>
</div >
</div >
</GamesApiContext.Provider>
</GamesDispatchContext.Provider>
</GamesContext.Provider>
)
};

View File

@ -2,18 +2,17 @@ import './Leaderboard.css';
import React from "react"
import Loading from '../components/Loading';
export default function Leaderboard({ leaderboard, user }) {
export default function Leaderboard({ players }) {
const leaderboard = players.leaderboard;
if (leaderboard == null)
return <Loading />
const isCurrentUser = (playerName) =>
user?.isCurrentUser(playerName) === true ? true : null;
const tableRows = Object.keys(leaderboard).map(playerName => {
var rank = leaderboard[playerName];
return <tr key={playerName} className={isCurrentUser(playerName) && 'currentuser'}>
return <tr key={playerName} className={players.isCurrentUser(playerName) && 'currentuser'}>
<td>{playerName}</td>
<td>{rank.gamesPlayed}</td>
<td>{rank.gamesWon}</td>

View File

@ -1,7 +0,0 @@
import React from 'react';
export default function ActiveGames() {
return (
<div>View: ActiveGame</div>
)
}

View File

@ -1,7 +0,0 @@
import React from 'react';
export default function GameProposals() {
return (
<div>View: GameProposals</div>
)
}

View File

@ -0,0 +1,48 @@
.GameSelector {
flex: 1 1 auto;
overflow-y: scroll;
}
.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;
}

View File

@ -0,0 +1,52 @@
import './GameSelector.css';
import React, { useContext } from 'react';
import { GamesContext } from '../../../context/games';
import { Color, Player } from '../../../components/Checkers';
import Loading from '../../../components/Loading';
export default function GameSelector({ yours, opponents, onClick }) {
const games = useContext(GamesContext);
if (games.list === null)
return <Loading />
const yoursList = games.list.filter(game => game.status === yours)
.map(game => <Selectable game={game} key={game.uuid} onClick={onClick} />)
const opponentsList = games.list.filter(game => game.status === opponents)
.map(game => <Selectable game={game} key={game.uuid} onClick={onClick} />)
return (
<div className="GameSelector">
{yoursList}
{opponentsList.length > 0 && <Separator counter={opponentsList.length} />}
{opponentsList}
</div>
)
}
function Selectable({ game, onClick }) {
const myColor = game.myColor;
const opponentColor = Color.opposite(myColor);
const opponentName = game.opponentName;
return (
<div className='Selectable' onClick={() => onClick(game.uuid)}>
<div className='Title'>
<Player color={myColor} />
<i>vs</i>
<Player color={opponentColor} name={opponentName} />
</div>
<q>{game.message}</q>
</div>
)
};
function Separator({ counter }) {
return (
<div className="Separator">
waiting for opponent ({counter})
</div>
)
}

View File

@ -1,7 +0,0 @@
import React from 'react';
export default function GamesArchive() {
return (
<div>View: GameArchive</div>
)
}