aboutsummaryrefslogtreecommitdiff
path: root/diplomacy/web/src/gui/pages/content_games.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'diplomacy/web/src/gui/pages/content_games.jsx')
-rw-r--r--diplomacy/web/src/gui/pages/content_games.jsx171
1 files changed, 171 insertions, 0 deletions
diff --git a/diplomacy/web/src/gui/pages/content_games.jsx b/diplomacy/web/src/gui/pages/content_games.jsx
new file mode 100644
index 0000000..31bd1af
--- /dev/null
+++ b/diplomacy/web/src/gui/pages/content_games.jsx
@@ -0,0 +1,171 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {Tabs} from "../components/tabs";
+import {Table} from "../components/table";
+import {FindForm} from "../forms/find_form";
+import {CreateForm} from "../forms/create_form";
+import {InlineGameView} from "../utils/inline_game_view";
+import {STRINGS} from "../../diplomacy/utils/strings";
+import {Helmet} from "react-helmet";
+import {Navigation} from "../components/navigation";
+import {PageContext} from "../components/page_context";
+import {ContentGame} from "./content_game";
+import PropTypes from 'prop-types';
+import {Tab} from "../components/tab";
+
+const TABLE_LOCAL_GAMES = {
+ game_id: ['Game ID', 0],
+ deadline: ['Deadline', 1],
+ rights: ['Rights', 2],
+ rules: ['Rules', 3],
+ players: ['Players/Expected', 4],
+ status: ['Status', 5],
+ phase: ['Phase', 6],
+ join: ['Join', 7],
+ actions: ['Actions', 8],
+};
+
+export class ContentGames extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {tab: null};
+ this.changeTab = this.changeTab.bind(this);
+ this.onFind = this.onFind.bind(this);
+ this.onCreate = this.onCreate.bind(this);
+ this.wrapGameData = this.wrapGameData.bind(this);
+ }
+
+ getPage() {
+ return this.context;
+ }
+
+ onFind(form) {
+ for (let field of ['game_id', 'status', 'include_protected', 'for_omniscience'])
+ if (!form[field])
+ form[field] = null;
+ this.getPage().channel.listGames(form)
+ .then((data) => {
+ this.getPage().success('Found ' + data.length + ' data.');
+ this.getPage().addGamesFound(data);
+ this.getPage().loadGames();
+ })
+ .catch((error) => {
+ this.getPage().error('Error when looking for distant games: ' + error);
+ });
+ }
+
+ onCreate(form) {
+ for (let key of Object.keys(form)) {
+ if (form[key] === '')
+ form[key] = null;
+ }
+ if (form.n_controls !== null)
+ form.n_controls = parseInt(form.n_controls, 10);
+ if (form.deadline !== null)
+ form.deadline = parseInt(form.deadline, 10);
+ form.rules = ['POWER_CHOICE'];
+ for (let rule of STRINGS.PUBLIC_RULES) {
+ const rule_id = `rule_${rule.toLowerCase()}`;
+ if (form.hasOwnProperty(rule_id)) {
+ if (form[rule_id])
+ form.rules.push(rule);
+ delete form[rule_id];
+ }
+ }
+ let networkGame = null;
+ this.getPage().channel.createGame(form)
+ .then((game) => {
+ this.getPage().addToMyGames(game.local);
+ networkGame = game;
+ return networkGame.getAllPossibleOrders();
+ })
+ .then(allPossibleOrders => {
+ networkGame.local.setPossibleOrders(allPossibleOrders);
+ this.getPage().load(
+ `game: ${networkGame.local.game_id}`,
+ <ContentGame data={networkGame.local}/>,
+ {success: 'Game created.'}
+ );
+ })
+ .catch((error) => {
+ this.getPage().error('Error when creating a game: ' + error);
+ });
+ }
+
+ changeTab(tabIndex) {
+ this.setState({tab: tabIndex});
+ }
+
+ wrapGameData(gameData) {
+ return new InlineGameView(this.getPage(), gameData);
+ }
+
+ render() {
+ const title = 'Games';
+ const page = this.getPage();
+ const navigation = [
+ ['load a game from disk', page.loadGameFromDisk],
+ ['logout', page.logout]
+ ];
+ const myGames = this.props.myGames;
+ const gamesFound = this.props.gamesFound;
+ myGames.sort((a, b) => b.timestamp_created - a.timestamp_created);
+ gamesFound.sort((a, b) => b.timestamp_created - a.timestamp_created);
+ const tab = this.state.tab ? this.state.tab : (myGames.length ? 'my-games' : 'find');
+ return (
+ <main>
+ <Helmet>
+ <title>{title} | Diplomacy</title>
+ </Helmet>
+ <Navigation title={title} username={page.channel.username} navigation={navigation}/>
+ <Tabs menu={['create', 'find', 'my-games']} titles={['Create', 'Find', 'My Games']}
+ onChange={this.changeTab} active={tab}>
+ {tab === 'create' ? (
+ <Tab id="tab-games-create" display={true}>
+ <CreateForm onSubmit={this.onCreate}/>
+ </Tab>
+ ) : ''}
+ {tab === 'find' ? (
+ <Tab id="tab-games-find" display={true}>
+ <FindForm onSubmit={this.onFind}/>
+ <Table className={"table table-striped"} caption={"Games"} columns={TABLE_LOCAL_GAMES}
+ data={gamesFound} wrapper={this.wrapGameData}/>
+ </Tab>
+ ) : ''}
+ {tab === 'my-games' ? (
+ <Tab id={'tab-my-games'} display={true}>
+ <Table className={"table table-striped"} caption={"My games"} columns={TABLE_LOCAL_GAMES}
+ data={myGames} wrapper={this.wrapGameData}/>
+ </Tab>
+ ) : ''}
+ </Tabs>
+ </main>
+ );
+ }
+
+ componentDidMount() {
+ window.scrollTo(0, 0);
+ }
+}
+
+ContentGames.contextType = PageContext;
+ContentGames.propTypes = {
+ gamesFound: PropTypes.array.isRequired,
+ myGames: PropTypes.array.isRequired
+};