diff --git a/src/botPage/view/Dialogs/Limits.js b/src/botPage/view/Dialogs/Limits.js index 33332b2b59..e0b87119c5 100644 --- a/src/botPage/view/Dialogs/Limits.js +++ b/src/botPage/view/Dialogs/Limits.js @@ -1,59 +1,122 @@ +import { LiveApi } from 'binary-live-api'; import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import { translate } from '../../../common/i18n'; -import * as style from '../style'; import Dialog from './Dialog'; import { restrictInputCharacter } from '../shared'; +import * as style from '../style'; +import { getToken } from '../../../common/utils/storageManager'; +import { showSpinnerInButton, removeSpinnerInButton, createUrl, translate } from '../../../common/utils/tools'; class LimitsContent extends PureComponent { constructor() { super(); this.state = { error : '', - maxLoss : '', - maxTrades: '', + maxTrades: 0, + maxLosses: null, }; } + submit() { - const maxLoss = parseFloat(this.state.maxLoss || 0); - const maxTrades = parseInt(this.state.maxTrades || 0); this.setState({ error: '' }); - if (maxTrades <= 0 || maxTrades > 100) { - this.setState({ error: 'Maximum number of trades should be between 1 and 100.' }); + + const onSave = () => { + this.props.onSave({ + maxTrades: this.state.maxTrades, + maxLoss : this.state.maxLosses, + }); + }; + + if (!this.state.maxLosses) { + this.updateMaxLosses() + .then(() => { + onSave(); + }) + .catch(() => { + this.setState({ + error: translate( + 'Please set your daily loss limit in the Self-Exclusion Facilities page to allow trading.' + ), + }); + }); return; } - if (!maxLoss) { - this.setState({ error: 'Please enter a Maximum Loss amount greater than zero.' }); + + if (this.state.maxTrades <= 0 || this.state.maxTrades > 100) { + this.setState({ error: translate('Maximum consecutive trades should be between 1 and 100') }); return; } - this.props.onSave({ - maxLoss, - maxTrades, + + onSave(); + } + + updateMaxLosses() { + return new Promise((resolve, reject) => { + const { api } = this.props; + const $startButton = $('#submit-trade-limits'); + const initialText = $startButton.text(); + + showSpinnerInButton($startButton); + + api.getSelfExclusion() + .then(response => { + const { max_losses: maxLosses } = response.get_self_exclusion; + let callback; + + if (maxLosses) { + this.setState({ maxLosses }); + callback = resolve; + } else { + callback = reject; + } + + removeSpinnerInButton($startButton, initialText); + callback(); + }) + .catch(() => { + removeSpinnerInButton($startButton, initialText); + reject(); + }); }); } + componentDidMount() { const cleanupLayout = () => { this.setState({ - maxTrades: '', - maxLoss : '', + maxTrades: 0, error : '', }); }; + + const onDialogOpen = () => { + this.updateMaxLosses().catch(() => {}); + }; + $('#limits-dialog-component').dialog({ + open : onDialogOpen, close : cleanupLayout, autoOpen: false, }); } + onMaxTradeChange(e) { if (restrictInputCharacter({ input: e.target.value, whitelistRegEx: '^[\\d]*$' })) { this.setState({ maxTrades: e.target.value }); } } - onMaxLossChange(e) { - if (restrictInputCharacter({ input: e.target.value, whitelistRegEx: '^\\d*\\.?\\d*$' })) { - this.setState({ maxLoss: e.target.value }); + + getDailyLossesLimit() { + if (this.state.maxLosses) { + const token = $('.account-id') + .first() + .attr('value'); + const tokenObj = getToken(token); + const currency = tokenObj && tokenObj.loginInfo.currency; + return currency ? `${this.state.maxLosses} ${currency}` : `${this.state.maxLosses}`; } + return translate('Not set'); } + render() { return (
-
-
- -
-
- -
- {this.state.error ?

{this.state.error}

: null} -

{translate( - 'Trade limitations are required by our regulators. Your bot will conclude trading when one or both of the conditions are met.' + 'We require you to set trade limitations in compliance with business regulations. Please note that your bot will only stop trading if any or both of the conditions below are met.' )}

-
- +
+ +
+ {translate([ + 'This is the threshold that limits your potential losses for the day in all Binary.com platforms. Once your total loss reaches or exceeds this amount, your bot will stop trading. Please set a value in the [_1]Self-Exclusion Facilities page[_2].', + ``, + '', + ])} +
+
+
+ +
+ {translate( + 'This is the maximum number of trades that you allow your bot to execute for this run.' + )} +
+
+
+ { + this.maxTradesDiv = el; + }} + type="text" + id="limitation-max-trades" + step="1" + maxLength="3" + value={this.state.maxTrades} + onChange={(...args) => this.onMaxTradeChange(...args)} + data-lpignore={true} + /> +
+ {this.state.error &&

{this.state.error}

} +
+
); } static props = { onSave: PropTypes.func, + api : PropTypes.instanceOf(LiveApi), }; } export default class Limits extends Dialog { - constructor() { + constructor(api) { const onSave = limits => { this.limitsPromise(limits); this.close(); }; - super('limits-dialog', translate('Trade Limitations'), , style.dialogLayout); + super( + 'limits-dialog', + translate('Trade Limitations'), + , + style.dialogLayout + ); + this.registerCloseOnOtherDialog(); } getLimits() { this.open(); diff --git a/src/botPage/view/View.js b/src/botPage/view/View.js index cb626fbd12..dbbcca6148 100644 --- a/src/botPage/view/View.js +++ b/src/botPage/view/View.js @@ -142,7 +142,6 @@ const clearRealityCheck = () => { stopRealityCheck(); }; -const limits = new Limits(); const integrationsDialog = new IntegrationsDialog(); const loadDialog = new LoadDialog(); const saveDialog = new SaveDialog(); @@ -518,8 +517,13 @@ export default class View { .attr('value'); const tokenObj = getToken(token); initRealityCheck(() => $('#stopButton').triggerHandler('click')); + if (tokenObj && tokenObj.hasTradeLimitation) { - limits.getLimits().then(startBot); + const limits = new Limits(api); + limits + .getLimits() + .then(startBot) + .catch(() => {}); } else { startBot(); } diff --git a/static/css/_panel.scss b/static/css/_panel.scss index 27cc5c61ca..56037bc5df 100644 --- a/static/css/_panel.scss +++ b/static/css/_panel.scss @@ -320,6 +320,24 @@ $disabled-color: #F2F2F2; .ui-dialog-content { padding: 0px !important; + + &.ui-widget-content { + input[type=text] { + height: 40px; + width: 100%; + } + .description { + font-size: 75%; + margin: 0.5em 0; + } + .input-row { + margin: 1em 0; + + &.last { + margin-bottom: 0; + } + } + } } #load-dialog, #save-dialog { @@ -328,23 +346,7 @@ $disabled-color: #F2F2F2; } } -#load-dialog, #save-dialog, #integrations-dialog { - .input-row { - margin: 1em 0; - } - .input-row.last { - margin-bottom: 0; - } - & .description { - font-size: 75%; - } -} - #save-dialog { - #save-filename { - width: 100%; - height: 40px; - } #collection { padding: 1.2em; border: 1px solid $brand-gray; @@ -367,9 +369,6 @@ $disabled-color: #F2F2F2; font-size: 20px; margin: 0 0 0.2em 0; } - .description { - margin: 0 0 0.2em 0; - } .left { width: 60%; display: table-cell;