diff options
Diffstat (limited to 'sw-ui/src/components/game-browser')
-rw-r--r-- | sw-ui/src/components/game-browser/GameBrowser.tsx | 56 | ||||
-rw-r--r-- | sw-ui/src/components/game-browser/GameList.css | 3 | ||||
-rw-r--r-- | sw-ui/src/components/game-browser/GameList.tsx | 85 | ||||
-rw-r--r-- | sw-ui/src/components/game-browser/GameStatus.tsx | 17 | ||||
-rw-r--r-- | sw-ui/src/components/game-browser/PlayerCount.css | 3 | ||||
-rw-r--r-- | sw-ui/src/components/game-browser/PlayerCount.tsx | 12 | ||||
-rw-r--r-- | sw-ui/src/components/game-browser/PlayerInfo.tsx | 27 |
7 files changed, 203 insertions, 0 deletions
diff --git a/sw-ui/src/components/game-browser/GameBrowser.tsx b/sw-ui/src/components/game-browser/GameBrowser.tsx new file mode 100644 index 00000000..a6367d5e --- /dev/null +++ b/sw-ui/src/components/game-browser/GameBrowser.tsx @@ -0,0 +1,56 @@ +import { Button, Classes, InputGroup, Intent } from '@blueprintjs/core'; +import React, { ChangeEvent, Component, SyntheticEvent } from 'react'; +import { connect } from 'react-redux'; +import { Flex } from 'reflexbox'; +import { actions } from '../../redux/actions/lobby'; +import { GameList } from './GameList'; +import { PlayerInfo } from './PlayerInfo'; + +type GameBrowserProps = { + createGame: (gameName: string) => void, +} + +class GameBrowserPresenter extends Component<GameBrowserProps> { + + _gameName: string | void = undefined; + + createGame = (e: SyntheticEvent<any>): void => { + e.preventDefault(); + if (this._gameName !== undefined) { + this.props.createGame(this._gameName); + } + }; + + render() { + return ( + <div> + <Flex align="center" justify='space-between' p={1}> + <form onSubmit={this.createGame}> + <InputGroup + placeholder="Game name" + name="game_name" + onChange={(e: ChangeEvent<HTMLInputElement>) => (this._gameName = e.target.value)} + rightElement={<CreateGameButton createGame={this.createGame}/>} + /> + </form> + <PlayerInfo /> + </Flex> + <GameList /> + </div> + ); + } +} + +type CreateGameButtonProps = { + createGame: (e: SyntheticEvent<any>) => void +} + +const CreateGameButton = ({createGame}: CreateGameButtonProps) => ( + <Button className={Classes.MINIMAL} intent={Intent.PRIMARY} icon='add' onClick={createGame} /> +); + +const mapDispatchToProps = { + createGame: actions.requestCreateGame, +}; + +export const GameBrowser = connect(null, mapDispatchToProps)(GameBrowserPresenter); diff --git a/sw-ui/src/components/game-browser/GameList.css b/sw-ui/src/components/game-browser/GameList.css new file mode 100644 index 00000000..a04e126c --- /dev/null +++ b/sw-ui/src/components/game-browser/GameList.css @@ -0,0 +1,3 @@ +tr.gameListRow td { + vertical-align: middle; +} diff --git a/sw-ui/src/components/game-browser/GameList.tsx b/sw-ui/src/components/game-browser/GameList.tsx new file mode 100644 index 00000000..1b136940 --- /dev/null +++ b/sw-ui/src/components/game-browser/GameList.tsx @@ -0,0 +1,85 @@ +import { Button, Classes } from '@blueprintjs/core' +import { List } from 'immutable'; +import React from 'react'; +import { connect } from 'react-redux'; +import { ApiLobby } from '../../api/model'; +import { GlobalState } from '../../reducers'; +import { actions } from '../../redux/actions/lobby'; +import { getAllGames } from '../../redux/games'; +import './GameList.css'; +import { GameStatus } from './GameStatus'; +import { PlayerCount } from './PlayerCount'; + +type GameListStateProps = { + games: List<ApiLobby>, +}; + +type GameListDispatchProps = { + joinGame: (gameId: number) => void, +}; + +type GameListProps = GameListStateProps & GameListDispatchProps + +const GameListPresenter = ({ games, joinGame }: GameListProps) => ( + <table className={Classes.HTML_TABLE}> + <thead> + <GameListHeaderRow /> + </thead> + <tbody> + {games.map((game: ApiLobby) => <GameListItemRow key={game.id} game={game} joinGame={joinGame}/>)} + </tbody> + </table> +); + +const GameListHeaderRow = () => ( + <tr> + <th>Name</th> + <th>Status</th> + <th>Nb Players</th> + <th>Join</th> + </tr> +); + +type GameListItemRowProps = { + game: ApiLobby, + joinGame: (gameId: number) => void, +}; + +const GameListItemRow = ({game, joinGame}: GameListItemRowProps) => ( + <tr className="gameListRow"> + <td>{game.name}</td> + <td> + <GameStatus state={game.state} /> + </td> + <td> + <PlayerCount nbPlayers={game.players.length} /> + </td> + <td> + <JoinButton game={game} joinGame={joinGame}/> + </td> + </tr> +); + +type JoinButtonProps = { + game: ApiLobby, + joinGame: (gameId: number) => void, +}; + +const JoinButton = ({game, joinGame}: JoinButtonProps) => { + const disabled = game.state !== 'LOBBY'; + const onClick = () => joinGame(game.id); + return <Button minimal disabled={disabled} icon='arrow-right' title='Join Game' onClick={onClick}/>; +}; + +function mapStateToProps(state: GlobalState): GameListStateProps { + return { + games: getAllGames(state), + }; +} + +const mapDispatchToProps: GameListDispatchProps = { + joinGame: actions.requestJoinGame, +}; + +export const GameList = connect(mapStateToProps, mapDispatchToProps)(GameListPresenter); + diff --git a/sw-ui/src/components/game-browser/GameStatus.tsx b/sw-ui/src/components/game-browser/GameStatus.tsx new file mode 100644 index 00000000..5f237258 --- /dev/null +++ b/sw-ui/src/components/game-browser/GameStatus.tsx @@ -0,0 +1,17 @@ +import { Tag } from '@blueprintjs/core'; +import { Intent } from '@blueprintjs/core'; +import * as React from 'react'; +import { ApiGameState } from '../../api/model'; + +type GameStatusProps = { + state: ApiGameState, +} + +export const GameStatus = ({state}: GameStatusProps) => ( + <Tag minimal intent={statusIntents[state]}>{state}</Tag> +); + +const statusIntents = { + 'LOBBY': Intent.SUCCESS, + 'PLAYING': Intent.WARNING, +}; diff --git a/sw-ui/src/components/game-browser/PlayerCount.css b/sw-ui/src/components/game-browser/PlayerCount.css new file mode 100644 index 00000000..d2f18e50 --- /dev/null +++ b/sw-ui/src/components/game-browser/PlayerCount.css @@ -0,0 +1,3 @@ +.playerCountIcon, .playerCount { + vertical-align: middle; +} diff --git a/sw-ui/src/components/game-browser/PlayerCount.tsx b/sw-ui/src/components/game-browser/PlayerCount.tsx new file mode 100644 index 00000000..64028f68 --- /dev/null +++ b/sw-ui/src/components/game-browser/PlayerCount.tsx @@ -0,0 +1,12 @@ +import { Icon } from '@blueprintjs/core'; +import * as React from 'react'; +import './PlayerCount.css'; + +type PlayerCountProps = { + nbPlayers: number, +} + +export const PlayerCount = ({nbPlayers}: PlayerCountProps) => <div title='Number of players'> + <Icon className="playerCountIcon" icon="people" title={false} /> + <span className="playerCount"> {nbPlayers}</span> +</div>; diff --git a/sw-ui/src/components/game-browser/PlayerInfo.tsx b/sw-ui/src/components/game-browser/PlayerInfo.tsx new file mode 100644 index 00000000..4afed671 --- /dev/null +++ b/sw-ui/src/components/game-browser/PlayerInfo.tsx @@ -0,0 +1,27 @@ +import { Text } from '@blueprintjs/core'; +import React from 'react'; +import { connect } from 'react-redux'; +import { GlobalState } from '../../reducers'; +import { User } from '../../redux/user'; +import { getCurrentUser } from '../../redux/user'; + +type PlayerInfoProps = { + user: User | null, +} + +const PlayerInfoPresenter = ({user}: PlayerInfoProps) => ( + <Text> + <b>Username:</b> + {' '} + {user && user.displayName} + </Text> +); + +const mapStateToProps = (state: GlobalState): PlayerInfoProps => ({ + user: getCurrentUser(state), +}); + +const mapDispatchToProps = { +}; + +export const PlayerInfo = connect(mapStateToProps, mapDispatchToProps)(PlayerInfoPresenter); |