]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front.git/commitdiff
Account page.
authorjloup <jeanloup.jamet@gmail.com>
Mon, 7 May 2018 15:39:58 +0000 (17:39 +0200)
committerjloup <jeanloup.jamet@gmail.com>
Mon, 7 May 2018 15:41:18 +0000 (17:41 +0200)
api/market_config.go
cmd/app/main.go
cmd/web/Makefile
cmd/web/js/account.jsx [new file with mode: 0644]
cmd/web/js/header_footer.jsx
cmd/web/js/main.jsx
cmd/web/js/poloniex.jsx
cmd/web/static/style.css

index 25e390d627811ad7c24136f195743e282f26d766..c2248b354e876403361f7a67169ae845ab7e2e90 100644 (file)
@@ -45,6 +45,14 @@ func (q MarketConfigQuery) Run() (interface{}, *Error) {
 
        }
 
+       if _, ok := config.Config["key"]; !ok {
+               config.Config["key"] = ""
+       }
+
+       if _, ok := config.Config["secret"]; !ok {
+               config.Config["secret"] = ""
+       }
+
        return config.Config, nil
 }
 
@@ -76,7 +84,7 @@ func (q MarketBalanceQuery) Run() (interface{}, *Error) {
        }
 
        if config.Config["key"] == "" || config.Config["secret"] == "" {
-               return nil, &Error{BadRequest, "your credentials for this market are not setup", fmt.Errorf("'%v' credentials are not setup", q.In.Market)}
+               return nil, &Error{InvalidMarketCredentials, "your credentials for this market are not setup", fmt.Errorf("'%v' credentials are not setup", q.In.Market)}
        }
 
        result := struct {
index a0463d260d0d839151ff18ee7f52ff57f622f249..28eb77522b0e2ff1c421b16292bae3290a58c514 100644 (file)
@@ -143,6 +143,7 @@ func main() {
                "/change-password",
                "/signout",
                "/me",
+               "/account",
                "/otp/enroll",
                "/otp/validate",
                "/not_confirmed",
index 02ff826d6eca77c7d7261edc59b9fe6e8af4e64f..3b100d16d8e43656bcaa610c5c203957a82fb7f2 100644 (file)
@@ -4,7 +4,7 @@ export PATH := $(PATH):./node_modules/.bin
 
 SRC_DIR=js
 BUILD_DIR=build/js
-JSX_SRC= header_footer.jsx main.jsx signup.jsx signin.jsx otp.jsx poloniex.jsx password_reset.jsx change_password.jsx
+JSX_SRC= header_footer.jsx main.jsx signup.jsx signin.jsx otp.jsx poloniex.jsx password_reset.jsx change_password.jsx account.jsx
 JS_SRC= cookies.js app.js api.js
 STATIC_FILES= index.html style.css fontello.css
 STATIC_FILES+=$(addprefix fonts/, fontello.eot fontello.svg fontello.ttf fontello.woff fontello.woff2)
diff --git a/cmd/web/js/account.jsx b/cmd/web/js/account.jsx
new file mode 100644 (file)
index 0000000..43e7083
--- /dev/null
@@ -0,0 +1,177 @@
+import Api from './api.js';
+import React from 'react';
+
+class PoloniexConfiguration extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {'apiKey': '', 'apiSecret': '', 'apiRequested': false, 'status': 'loading'};
+  }
+
+  checkCredentials = () => {
+    Api.Call('MARKET_BALANCE', {'name': 'poloniex', 'currency': 'BTC'}, function(err, status, data) {
+      if (err) {
+        console.error(err, data);
+        if (err.code === 'invalid_market_credentials') {
+          this.setState({'status': 'invalidCredentials'});
+        } else if (err.code === 'ip_restricted_api_key') {
+          this.setState({'status': 'ipRestricted'});
+        }
+        return;
+      }
+
+      this.setState({'status': 'ok'});
+    }.bind(this));
+  }
+
+  handleCredentialsChange = (key, secret) => {
+    this.setState({'apiKey': key, 'apiSecret': secret});
+  }
+
+  handleCredentialsSubmit = () => {
+
+    /*
+     *If (!this.state.apiKey || !this.state.apiSecret) {
+     *  return;
+     *}
+     */
+
+    Api.Call('UPDATE_MARKET', {'key': this.state.apiKey, 'secret': this.state.apiSecret, 'name': 'poloniex'}, function(err, status, data) {
+      if (err) {
+        console.error(err, data);
+        return;
+      }
+
+      this.setState({'status': 'loading'});
+      this.checkCredentials();
+    }.bind(this));
+  }
+
+  componentDidMount = () => {
+    Api.Call('MARKET', {'name': 'poloniex'}, function(err, status, data) {
+      this.setState({'apiRequested': true});
+      if (err) {
+        console.error(err, data);
+        return;
+      }
+
+      var newStatus = this.state.status;
+      if (!data.key || !data.secret) {
+        newStatus = 'emptyCredentials';
+      } else {
+        this.checkCredentials();
+      }
+
+      this.setState({'apiKey': data.key, 'apiSecret': data.secret, 'status': newStatus});
+    }.bind(this));
+  }
+
+  render = () => {
+    var displayText = null;
+    switch (this.state.status) {
+      case 'loading':
+        displayText = 'Checking Poloniex credentials...';
+        break;
+      case 'invalidCredentials':
+        displayText = 'Invalid poloniex credentials';
+        break;
+      case 'ipRestricted':
+        displayText = 'Your API key is IP restricted.';
+        break;
+      case 'emptyCredentials':
+        displayText = 'Please provide poloniex credentials';
+        break;
+      case 'ok':
+        displayText = 'You are all set !';
+        break;
+      default:
+        console.error('unknown status', this.state.status);
+        displayText = null;
+    }
+    if (this.state.apiRequested === false) {
+      return <div></div>;
+    }
+    return (
+      <div>
+        <PoloniexCredentialsForm onLoadCredentials={this.onLoadCredentials}
+                                 onCredentialsSubmit={this.handleCredentialsSubmit}
+                                 onCredentialsChange={this.handleCredentialsChange}
+                                 apiSecret={this.state.apiSecret}
+                                 apiKey={this.state.apiKey}
+                                 status={this.state.status}
+                                 statusMessage={displayText}/>
+      </div>
+    );
+  }
+}
+
+class PoloniexCredentialsForm extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {'editMode': false};
+  }
+
+  handleSubmit = (e) => {
+    this.props.onCredentialsSubmit();
+    this.setState({'editMode': false});
+    e.preventDefault();
+  }
+
+  handleApiKeyChange = (event) => {
+    this.props.onCredentialsChange(event.target.value, this.props.apiSecret);
+  }
+
+  handleApiSecretChange = (event) => {
+    this.props.onCredentialsChange(this.props.apiKey, event.target.value);
+  }
+
+  onEditClick = () => {
+    this.setState({'editMode': true});
+  }
+
+  render = () => {
+    var submitType      = this.state.editMode === true ? 'submit' : 'hidden';
+    var buttonDisplay   = this.state.editMode === true ? 'none' : 'inline';
+    var secretDisplayed = this.state.editMode === true ? this.props.apiSecret : 'XXXXXXX';
+    var keyDisplayed    = this.state.editMode === true ? this.props.apiKey : 'XXXXXXX';
+
+    var iconName = 'icon-cancel-circled';
+    switch (this.props.status) {
+      case 'loading':
+        iconName = 'icon-hourglass-2';
+        break;
+      case 'ok':
+        iconName = 'icon-ok-circled';
+        break;
+    }
+
+    return (
+        <div className="row api-credentials-form">
+          <div className="offset-2 col-8 box">
+            <span className="text-center">Poloniex credentials</span>
+            <hr/>
+            <div className="row config-status">
+              <div className="col-12">
+                <span><i className={iconName}></i>{this.props.statusMessage}</span>
+              </div>
+            </div>
+            <div className="row">
+              <div className="col-12">
+                <form role="form" onSubmit={this.handleSubmit}>
+                  <label className="w-100">Key:
+                    <input className="form-control" type="text" placeholder="key" value={keyDisplayed} onChange={this.handleApiKeyChange} disabled={!this.state.editMode}/>
+                  </label>
+                  <label className="w-100">Secret:
+                    <input className="form-control" type="text" placeholder="secret" value={secretDisplayed} onChange={this.handleApiSecretChange} disabled={!this.state.editMode}/>
+                  </label>
+                  <input className="form-control submit" type={submitType} value="Save" />
+                  <button className="form-control submit" style={{display: buttonDisplay}} onSubmit={null} onClick={this.onEditClick} type="button">Show/Edit</button>
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+       );
+  }
+}
+
+export default PoloniexConfiguration;
index 3cb9937a460af21a93056e011ccae724e6b1af37..f11ed06ea2d4589b7467b9d8a294dbbb39f10c49 100644 (file)
@@ -6,6 +6,12 @@ class Signout extends React.Component {
   }
 }
 
+class MyAccount extends React.Component {
+  render = () => {
+    return <a href="/account"><u>Account</u></a>;
+  }
+}
+
 class Logo extends React.Component {
   render() {
     return <div id="logo" className="w-100 h-100 align-self-center">
@@ -22,6 +28,7 @@ class Footer extends React.Component {
     }
 
     if (this.props.isLoggedIn === true) {
+      elements = elements.concat(<MyAccount />);
       elements = elements.concat(<Signout />);
     }
 
@@ -37,7 +44,7 @@ class Footer extends React.Component {
              </div>;
     });
     return <div id="footer" className="row">
-             <div className="offset-4 col-4 d-sm-none">
+             <div className="offset-4 col-4 d-md-none">
                {rows}
              </div>
            </div>;
@@ -52,11 +59,12 @@ class Header extends React.Component {
     }
 
     if (this.props.isLoggedIn === true) {
+      elements = elements.concat(<MyAccount />);
       elements = elements.concat(<Signout />);
     }
 
     elements = elements.map(function(element, i) {
-      return <div className="text-center"  key={'header-el-' + i}>
+      return <div className="text-center header-menu-section"  key={'header-el-' + i}>
                {element}
              </div>;
     });
@@ -65,7 +73,7 @@ class Header extends React.Component {
               <div className="offset-3 col-6 offset-md-4 col-md-4">
                 <Logo />
               </div>
-              <div className="col-3 col-md-4 align-self-center h-100 d-none d-sm-flex justify-content-end">
+              <div className="col-3 col-md-4 align-self-center h-100 d-none d-md-flex justify-content-end">
                 {elements}
               </div>
            </div>;
index 8a4fce81e35dba21ff6096b629e47f36c2454fb4..84b584895235ef7b426440d478e1f963784af344 100644 (file)
@@ -4,6 +4,7 @@ import PasswordResetForm from './password_reset.js';
 import ChangePasswordForm from './change_password.js';
 import OtpEnrollForm from './otp.js';
 import PoloniexController from './poloniex.js';
+import PoloniexConfiguration from './account.js';
 import App from './app.js';
 import Api from './api.js';
 import cookies from './cookies.js';
@@ -73,6 +74,12 @@ App.page('/me', true, function(context) {
     </div>);
 });
 
+App.page('/account', true, function(context) {
+  App.mount(<div>
+      <PoloniexConfiguration/>
+    </div>);
+});
+
 App.page('/not_confirmed', true, function(context) {
   App.mount(<div>
       <div className="row">
index db6b1c43da71f123ec830dc8d6a8f89bffbe8146..76b68d8913312ff7f3640b4f87c98804c3311284 100644 (file)
@@ -4,26 +4,7 @@ import React from 'react';
 class PoloniexController extends React.Component {
   constructor(props) {
     super(props);
-    this.state = {'apiKey': '', 'apiSecret': '', 'apiRequested': false, 'flag': 'loading', 'valueCurrency': null, 'balanceValue': null, 'balance': null};
-  }
-
-  handleCredentialsChange = (key, secret) => {
-    this.setState({'apiKey': key, 'apiSecret': secret});
-  }
-
-  handleCredentialsSubmit = () => {
-    if (!this.state.apiKey || !this.state.apiSecret) {
-      return;
-    }
-    Api.Call('UPDATE_MARKET', {'key': this.state.apiKey, 'secret': this.state.apiSecret, 'name': 'poloniex'}, function(err, status, data) {
-      if (err) {
-        console.error(err, data);
-        return;
-      }
-
-      this.setState({'flag': 'loading', 'valueCurrency': null, 'balanceValue': null, 'balance': null});
-      this.loadBalance();
-    }.bind(this));
+    this.state = {'apiRequested': false, 'flag': 'loading', 'valueCurrency': null, 'balanceValue': null, 'balance': null};
   }
 
   loadBalance = () => {
@@ -31,34 +12,19 @@ class PoloniexController extends React.Component {
       if (err) {
         console.error(err, data);
         if (err.code === 'invalid_market_credentials') {
-          this.setState({'flag': 'invalidCredentials', 'valueCurrency': null, 'balanceValue': null, 'balance': null});
+          this.setState({'flag': 'invalidCredentials', 'apiRequested': true, 'valueCurrency': null, 'balanceValue': null, 'balance': null});
         } else if (err.code === 'ip_restricted_api_key') {
-          this.setState({'flag': 'ipRestricted', 'valueCurrency': null, 'balanceValue': null, 'balance': null});
+          this.setState({'flag': 'ipRestricted', 'apiRequested': true, 'valueCurrency': null, 'balanceValue': null, 'balance': null});
         }
         return;
       }
 
-      this.setState({'flag': 'ok', 'valueCurrency': data.valueCurrency, 'balanceValue': data.value, 'balance': data.balance});
+      this.setState({'flag': 'ok', 'apiRequested': true, 'valueCurrency': data.valueCurrency, 'balanceValue': data.value, 'balance': data.balance});
     }.bind(this));
   }
 
   componentDidMount = () => {
-    Api.Call('MARKET', {'name': 'poloniex'}, function(err, status, data) {
-      this.setState({'apiRequested': true});
-      if (err) {
-        console.error(err, data);
-        return;
-      }
-
-      var flag = this.state.flag;
-      if (!data.key || !data.secret) {
-        flag = 'emptyCredentials';
-      } else {
-        this.loadBalance();
-      }
-
-      this.setState({'apiKey': data.key, 'apiSecret': data.secret, 'flag': flag});
-    }.bind(this));
+    this.loadBalance();
   }
 
   render = () => {
@@ -68,13 +34,9 @@ class PoloniexController extends React.Component {
         displayText = 'Loading data from poloniex...';
         break;
       case 'invalidCredentials':
-        displayText = 'Invalid poloniex credentials';
-        break;
       case 'ipRestricted':
-        displayText = 'Your API key is IP restricted. Please whitelist us.';
-        break;
       case 'emptyCredentials':
-        displayText = 'Please provide poloniex credentials';
+        displayText = <div>Please provide poloniex credentials in <a href="/account">Account</a> page.</div>;
         break;
       default:
         displayText = null;
@@ -88,11 +50,6 @@ class PoloniexController extends React.Component {
                           balanceValue={this.state.balanceValue}
                           balance={this.state.balance}
                           displayText={displayText}/>
-        <PoloniexCredentialsForm onLoadCredentials={this.onLoadCredentials}
-                                 onCredentialsSubmit={this.handleCredentialsSubmit}
-                                 onCredentialsChange={this.handleCredentialsChange}
-                                 apiSecret={this.state.apiSecret}
-                                 apiKey={this.state.apiKey}/>
       </div>
     );
   }
@@ -141,14 +98,14 @@ class PoloniexBalance extends React.Component {
             </div>
           </div>
         </div>;
-} else {
+    } else {
       dashboard =
         <div className="row">
           <div className="col-12 text-center">
            <span>{this.props.displayText}</span>
           </div>
         </div>;
-}
+    }
 
     return (
       <div className="row">
@@ -164,55 +121,4 @@ class PoloniexBalance extends React.Component {
   }
 }
 
-class PoloniexCredentialsForm extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {'hideMsg': true, 'msg': '', 'editMode': false, 'msgOk': false};
-  }
-
-  handleSubmit = (e) => {
-    this.props.onCredentialsSubmit();
-    this.setState({'editMode': false});
-    e.preventDefault();
-  }
-
-  handleApiKeyChange = (event) => {
-    this.props.onCredentialsChange(event.target.value, this.props.apiSecret);
-  }
-
-  handleApiSecretChange = (event) => {
-    this.props.onCredentialsChange(this.props.apiKey, event.target.value);
-  }
-
-  onEditClick = () => {
-    this.setState({'editMode': true});
-  }
-
-  render = () => {
-    var submitType      = this.state.editMode === true ? 'submit' : 'hidden';
-    var buttonDisplay   = this.state.editMode === true ? 'none' : 'inline';
-    var secretDisplayed = this.state.editMode === true ? this.props.apiSecret : 'XXXXXXX';
-    var keyDisplayed    = this.state.editMode === true ? this.props.apiKey : 'XXXXXXX';
-
-    return (
-        <div className="row api-credentials-form">
-          <div className="offset-2 col-8 box">
-            <span className="text-center">Poloniex credentials</span>
-            <hr/>
-            <form role="form" onSubmit={this.handleSubmit}>
-              <label className="w-100">Key:
-                <input className="form-control" type="text" placeholder="key" value={keyDisplayed} onChange={this.handleApiKeyChange} disabled={!this.state.editMode}/>
-              </label>
-              <label className="w-100">Secret:
-                <input className="form-control" type="text" placeholder="secret" value={secretDisplayed} onChange={this.handleApiSecretChange} disabled={!this.state.editMode}/>
-              </label>
-              <input className="form-control submit" type={submitType} value="Save" />
-              <button className="form-control submit" style={{display: buttonDisplay}} onSubmit={null} onClick={this.onEditClick} type="button">Show/Edit</button>
-            </form>
-          </div>
-        </div>
-       );
-  }
-}
-
 export default PoloniexController;
index 5e49c55d8378385cbdc8716fd1332d6419e5ceff..2212168befe603a5528f2d62775d723f2f0d0dc3 100644 (file)
@@ -44,6 +44,10 @@ i.cc {
   margin-bottom: 30px;
 }
 
+.header-menu-section {
+  margin-right: 10px;
+}
+
 h1 {
   font-size: 1.5em;
   margin-bottom: 5px;
@@ -57,6 +61,22 @@ h1 {
   background-color: white;
 }
 
+.config-status {
+  margin-bottom: 10px;
+  font-size: 0.9em;
+}
+
+.config-status .icon-cancel-circled {
+  color: red;
+}
+
+.config-status .icon-ok-circled {
+  color: green;
+}
+.config-status i {
+  font-size: 1.2em;
+}
+
 .sign-in .submit {
   background-color: rgb(20, 20, 20);
   color: white;