From 09be214dfa0741df2399c3e0c928929138de226b Mon Sep 17 00:00:00 2001
From: notoraptor <notoraptor@users.noreply.github.com>
Date: Tue, 16 Jul 2019 10:39:16 -0400
Subject: [web] Add a button to delete game. (#39)

- [server] Also delete game from RAM.
---
 diplomacy/web/src/gui/core/delete_button.jsx | 43 +++++++++++++++
 diplomacy/web/src/gui/core/page.jsx          | 79 +++++++++++++++++++++++++---
 2 files changed, 114 insertions(+), 8 deletions(-)
 create mode 100644 diplomacy/web/src/gui/core/delete_button.jsx

(limited to 'diplomacy/web/src/gui/core')

diff --git a/diplomacy/web/src/gui/core/delete_button.jsx b/diplomacy/web/src/gui/core/delete_button.jsx
new file mode 100644
index 0000000..59141fd
--- /dev/null
+++ b/diplomacy/web/src/gui/core/delete_button.jsx
@@ -0,0 +1,43 @@
+import React from "react";
+import {Button} from "./button";
+import PropTypes from "prop-types";
+
+export class DeleteButton extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {step: 0};
+        this.onClick = this.onClick.bind(this);
+    }
+
+    onClick() {
+        this.setState({step: this.state.step + 1}, () => {
+            if (this.state.step === 2)
+                this.props.onClick();
+        });
+    }
+
+    render() {
+        let title = '';
+        let color = '';
+        if (this.state.step === 0) {
+            title = this.props.title;
+            color = 'secondary';
+        } else if (this.state.step === 1) {
+            title = this.props.confirmTitle;
+            color = 'danger';
+        } else if (this.state.step === 2) {
+            title = this.props.waitingTitle;
+            color = 'danger';
+        }
+        return (
+            <Button title={title} color={color} onClick={this.onClick} small={true} large={true}/>
+        );
+    }
+}
+
+DeleteButton.propTypes = {
+    title: PropTypes.string.isRequired,
+    confirmTitle: PropTypes.string.isRequired,
+    waitingTitle: PropTypes.string.isRequired,
+    onClick: PropTypes.func.isRequired
+};
diff --git a/diplomacy/web/src/gui/core/page.jsx b/diplomacy/web/src/gui/core/page.jsx
index ad830f1..560252c 100644
--- a/diplomacy/web/src/gui/core/page.jsx
+++ b/diplomacy/web/src/gui/core/page.jsx
@@ -55,6 +55,10 @@ export class Page extends React.Component {
         this.logout = this.logout.bind(this);
         this.loadGameFromDisk = this.loadGameFromDisk.bind(this);
         this.unloadFancyBox = this.unloadFancyBox.bind(this);
+        this._post_remove = this._post_remove.bind(this);
+        this._add_to_my_games = this._add_to_my_games.bind(this);
+        this._remove_from_my_games = this._remove_from_my_games.bind(this);
+        this._remove_from_games = this._remove_from_games.bind(this);
     }
 
     static wrapMessage(message) {
@@ -194,6 +198,12 @@ export class Page extends React.Component {
         this.setState({myGames: myGames, games: gamesFound});
     }
 
+    getGame(gameID) {
+        if (this.state.myGames.hasOwnProperty(gameID))
+            return this.state.myGames[gameID];
+        return this.state.games[gameID];
+    }
+
     getMyGames() {
         return Page.__sort_games(Object.values(this.state.myGames));
     }
@@ -230,9 +240,40 @@ export class Page extends React.Component {
         }
     }
 
+    _post_remove(gameID) {
+        this.disconnectGame(gameID)
+            .then(() => {
+                const myGames = this._remove_from_my_games(gameID);
+                const games = this._remove_from_games(gameID);
+                this.setState(
+                    {games, myGames},
+                    () => this.loadGames({info: `Game ${gameID} deleted.`}));
+            });
+    }
+
+    removeGame(gameID) {
+        const game = this.getGame(gameID);
+        if (game) {
+            if (game.client) {
+                game.client.remove()
+                    .then(() => this._post_remove(gameID))
+                    .catch(error => this.error(`Error when deleting game ${gameID}: ${error.toString()}`));
+            } else {
+                this.channel.joinGame({game_id: gameID})
+                    .then(networkGame => {
+                        networkGame.remove()
+                            .then(() => this._post_remove(gameID))
+                            .catch(error => this.error(`Error when deleting game ${gameID}: ${error.toString()}`));
+                    })
+                    .catch(error => this.error(`Error when connecting to game to delete (${gameID}): ${error.toString()}`));
+            }
+        }
+    }
+
+
     disconnectGame(gameID) {
-        if (this.state.myGames.hasOwnProperty(gameID)) {
-            const game = this.state.myGames[gameID];
+        const game = this.getGame(gameID);
+        if (game) {
             if (game.client)
                 game.client.clearAllCallbacks();
             return this.channel.getGamesInfo({games: [gameID]})
@@ -244,26 +285,48 @@ export class Page extends React.Component {
         return null;
     }
 
-    addToMyGames(game) {
-        // Update state myGames with given game **and** update local storage.
+    _add_to_my_games(game) {
         const myGames = Object.assign({}, this.state.myGames);
         const gamesFound = this.state.games.hasOwnProperty(game.game_id) ? Object.assign({}, this.state.games) : this.state.games;
         myGames[game.game_id] = game;
         if (gamesFound.hasOwnProperty(game.game_id))
             gamesFound[game.game_id] = game;
-        DipStorage.addUserGame(this.channel.username, game.game_id);
-        this.setState({myGames: myGames, games: gamesFound}, () => this.loadGames());
+        return {myGames: myGames, games: gamesFound};
     }
 
-    removeFromMyGames(gameID) {
+    _remove_from_my_games(gameID) {
         if (this.state.myGames.hasOwnProperty(gameID)) {
             const games = Object.assign({}, this.state.myGames);
             delete games[gameID];
             DipStorage.removeUserGame(this.channel.username, gameID);
-            this.setState({myGames: games}, () => this.loadGames());
+            return games;
+        } else {
+            return this.state.myGames;
+        }
+    }
+
+    _remove_from_games(gameID) {
+        if (this.state.games.hasOwnProperty(gameID)) {
+            const games = Object.assign({}, this.state.games);
+            delete games[gameID];
+            return games;
+        } else {
+            return this.state.games;
         }
     }
 
+    addToMyGames(game) {
+        // Update state myGames with given game **and** update local storage.
+        DipStorage.addUserGame(this.channel.username, game.game_id);
+        this.setState(this._add_to_my_games(game), () => this.loadGames());
+    }
+
+    removeFromMyGames(gameID) {
+        const myGames = this._remove_from_my_games(gameID);
+        if (myGames !== this.state.myGames)
+            this.setState({myGames}, () => this.loadGames());
+    }
+
     hasMyGame(gameID) {
         return this.state.myGames.hasOwnProperty(gameID);
     }
-- 
cgit v1.2.3