From 72435ac7623c14f7fae4b65e3d648db0103b95f4 Mon Sep 17 00:00:00 2001 From: Abdulov Ivan Date: Wed, 13 Dec 2017 13:18:21 +0300 Subject: [PATCH] Mint 874 add preloader to exchange search (#429) --- packages/login/network/ExchangeProvider.js | 2 + .../BuyTokensDialog/BuyTokensDialog.jsx | 7 +- .../BuyTokensDialog/BuyTokensDialog.scss | 6 + .../BuyTokensDialog/BuyTokensForm.jsx | 21 +++- .../exchange/BuyTokensDialog/lang.js | 2 + .../exchange/BuyTokensDialog/validate.js | 8 +- .../ExchangeTransferDialog.jsx | 28 ++++- .../ExchangeTransferDialog.scss | 6 + .../exchange/ExchangeTransferDialog/lang.js | 2 + .../ExchangeWidget/ExchangeWidget.jsx | 115 ++++++++++-------- .../ExchangeWidget/ExchangeWidget.scss | 7 ++ .../exchange/ExchangeWidget/lang.js | 6 +- src/dao/ExchangeManagerDAO.js | 42 +++---- src/layouts/partials/styles.js | 3 + src/redux/exchange/actions.js | 16 +-- 15 files changed, 179 insertions(+), 92 deletions(-) diff --git a/packages/login/network/ExchangeProvider.js b/packages/login/network/ExchangeProvider.js index 90a1c04f3..e47586561 100644 --- a/packages/login/network/ExchangeProvider.js +++ b/packages/login/network/ExchangeProvider.js @@ -5,6 +5,8 @@ import { NETWORK_MAIN_ID, MIDDLEWARE_MAP } from './settings' class ExchangeProvider { url () { + // TODO @abdulov remove it + throw new Error() // make an Error const { network } = networkService.getProviderSettings() if (!network.id) { diff --git a/src/components/exchange/BuyTokensDialog/BuyTokensDialog.jsx b/src/components/exchange/BuyTokensDialog/BuyTokensDialog.jsx index 6dc7dd0e1..2ae37c025 100644 --- a/src/components/exchange/BuyTokensDialog/BuyTokensDialog.jsx +++ b/src/components/exchange/BuyTokensDialog/BuyTokensDialog.jsx @@ -12,6 +12,7 @@ import { connect } from 'react-redux' import { Translate } from 'react-redux-i18n' import { DUCK_EXCHANGE, exchange, getTokensAllowance } from 'redux/exchange/actions' import { modalsClose } from 'redux/modals/actions' +import TokenModel from 'models/TokenModel' import './BuyTokensDialog.scss' import BuyTokensForm from './BuyTokensForm' @@ -48,6 +49,10 @@ export default class BuyTokensDialog extends React.PureComponent { render () { const exchangeToken = this.props.tokens.getBySymbol(this.props.exchange.symbol()) + let userExchangeToken = this.props.usersTokens.get(this.props.exchange.symbol()) + if (!userExchangeToken) { + userExchangeToken = new TokenModel({}) + } const ethToken = this.props.usersTokens.get('ETH') return ( @@ -67,7 +72,7 @@ export default class BuyTokensDialog extends React.PureComponent {
diff --git a/src/components/exchange/BuyTokensDialog/BuyTokensDialog.scss b/src/components/exchange/BuyTokensDialog/BuyTokensDialog.scss index e9e0d9a9d..819f9d232 100644 --- a/src/components/exchange/BuyTokensDialog/BuyTokensDialog.scss +++ b/src/components/exchange/BuyTokensDialog/BuyTokensDialog.scss @@ -210,3 +210,9 @@ padding-top: 8px; padding-bottom: 8px; } + +.warningMessage { + display: flex; + padding-bottom: 16px; + color: $color-warning; +} diff --git a/src/components/exchange/BuyTokensDialog/BuyTokensForm.jsx b/src/components/exchange/BuyTokensDialog/BuyTokensForm.jsx index 661c62675..a25be8c1f 100644 --- a/src/components/exchange/BuyTokensDialog/BuyTokensForm.jsx +++ b/src/components/exchange/BuyTokensDialog/BuyTokensForm.jsx @@ -55,7 +55,9 @@ export default class BuyTokensForm extends React.PureComponent { } componentDidMount () { - !this.props.isBuy && this.props.dispatch(getTokensAllowance(this.props.exchange)) + this.props.usersTokens.get(this.props.exchange.symbol()) && + !this.props.isBuy && + this.props.dispatch(getTokensAllowance(this.props.exchange)) } handleSetPrice = (e) => { @@ -82,6 +84,10 @@ export default class BuyTokensForm extends React.PureComponent { } render () { + let showWarningMessage = false + if (!this.props.usersTokens.get(this.props.exchange.symbol())) { + showWarningMessage = true + } const exchangeToken = this.props.tokens.getBySymbol(this.props.exchange.symbol()) const ethToken = this.props.usersTokens.get('ETH') @@ -92,6 +98,13 @@ export default class BuyTokensForm extends React.PureComponent {
+ { + showWarningMessage && +
+ warning + +
+ }
:
@@ -191,7 +204,7 @@ export default class BuyTokensForm extends React.PureComponent { {...globalStyles.buttonRaisedMultyLine} /> : @@ -199,14 +212,14 @@ export default class BuyTokensForm extends React.PureComponent { )} primary - onTouchTap={this.handleApprove} + onClick={this.handleApprove} {...globalStyles.buttonRaisedMultyLine} /> }
} } {...globalStyles.buttonRaisedMultyLine} diff --git a/src/components/exchange/BuyTokensDialog/lang.js b/src/components/exchange/BuyTokensDialog/lang.js index 20cc046a3..bf1756bbd 100644 --- a/src/components/exchange/BuyTokensDialog/lang.js +++ b/src/components/exchange/BuyTokensDialog/lang.js @@ -13,6 +13,7 @@ export default { allowance: 'Your allowance', approve: 'Approve tokens', revoke: 'Revoke tokens', + needToCreateWallet: 'You need to create %{symbol} wallet', }, ru: { orderBook: 'Книга Ордеров', @@ -28,5 +29,6 @@ export default { allowance: 'Подтвержденная сумма', approve: 'Подтвердить перевод токенов', revoke: 'Отменить перевод токенов', + needToCreateWallet: 'Вам нужно создать кошелек для %{symbol}', }, } diff --git a/src/components/exchange/BuyTokensDialog/validate.js b/src/components/exchange/BuyTokensDialog/validate.js index b619eefbe..d53685aac 100644 --- a/src/components/exchange/BuyTokensDialog/validate.js +++ b/src/components/exchange/BuyTokensDialog/validate.js @@ -1,5 +1,6 @@ import * as validator from 'components/forms/validator' import ErrorList from 'components/forms/ErrorList' +import TokenModel from 'models/TokenModel' export default function validate (values, props) { let buyErrors = new ErrorList() @@ -9,7 +10,10 @@ export default function validate (values, props) { sellErrors.add(validator.positiveNumber(values.get('sell'), true)) const userEthBalance = props.usersTokens.get('ETH').balance() - const exchangeTokenBalance = props.tokens.getBySymbol(props.exchange.symbol()).balance() + let userExchangeTokenBalance = props.usersTokens.get(props.exchange.symbol()) + if (!userExchangeTokenBalance) { + userExchangeTokenBalance = new TokenModel({}) + } const assetBalance = props.exchange.assetBalance() const ethBalance = props.exchange.ethBalance() @@ -17,7 +21,7 @@ export default function validate (values, props) { buyErrors.add(validator.lowerThan(values.get('buy'), assetBalance.toNumber())) sellErrors.add(validator.lowerThan(values.get('sell'), userEthBalance.toNumber())) } else { - buyErrors.add(validator.lowerThan(values.get('buy'), exchangeTokenBalance.toNumber())) + buyErrors.add(validator.lowerThan(values.get('buy'), userExchangeTokenBalance.balance().toNumber())) sellErrors.add(validator.lowerThan(values.get('sell'), ethBalance.toNumber())) } diff --git a/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.jsx b/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.jsx index ff72e2df5..f1b7655b7 100644 --- a/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.jsx +++ b/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.jsx @@ -6,8 +6,9 @@ import PropTypes from 'prop-types' import React from 'react' import { connect } from 'react-redux' import { Translate } from 'react-redux-i18n' -import { withdrawFromExchange } from 'redux/exchange/actions' +import { DUCK_EXCHANGE, withdrawFromExchange } from 'redux/exchange/actions' import { DUCK_MAIN_WALLET, mainTransfer } from 'redux/mainWallet/actions' +import TokensCollection from 'models/exchange/TokensCollection' import { modalsClose } from 'redux/modals/actions' import ExchangeDepositForm from './ExchangeDepositForm' import './ExchangeTransferDialog.scss' @@ -30,8 +31,10 @@ function mapDispatchToProps (dispatch) { } function mapStateToProps (state) { + const exchange = state.get(DUCK_EXCHANGE) return { userWallet: state.get(DUCK_MAIN_WALLET), + tokens: exchange.tokens(), } } @@ -45,6 +48,7 @@ export default class ExchangeTransferDialog extends React.PureComponent { dispatch: PropTypes.func, depositToExchange: PropTypes.func, withdrawFromExchange: PropTypes.func, + tokens: PropTypes.instanceOf(TokensCollection), } handleDeposit = (values, dispatch, props) => { @@ -67,7 +71,14 @@ export default class ExchangeTransferDialog extends React.PureComponent { } render () { - const token = this.props.userWallet.tokens().get(this.props.tokenSymbol) + let token = this.props.userWallet.tokens().get(this.props.tokenSymbol) + let showMessage = false + + if (!token) { + token = this.props.tokens.getBySymbol(this.props.tokenSymbol) + showMessage = true + } + return (
@@ -81,15 +92,22 @@ export default class ExchangeTransferDialog extends React.PureComponent {
+ { + showMessage && +
+ warning + +
+ } {this.props.tokenSymbol}} + title={ {this.props.tokenSymbol}} form={FORM_EXCHANGE_DEPOSIT_FORM} onSubmit={this.handleDeposit} - maxAmount={token.balance()} + maxAmount={token ? token.balance() : 0} symbol={token.symbol()} /> {this.props.tokenSymbol}} + title={ {this.props.tokenSymbol}} form={FORM_EXCHANGE_WITHDRAWAL_FORM} onSubmit={this.handleWithdrawal} maxAmount={this.props.tokenSymbol === 'ETH' ? this.props.exchange.ethBalance() : this.props.exchange.assetBalance()} diff --git a/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.scss b/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.scss index d37fec265..e5f8f1000 100644 --- a/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.scss +++ b/src/components/exchange/ExchangeTransferDialog/ExchangeTransferDialog.scss @@ -77,3 +77,9 @@ margin-bottom: 12px; margin-top: 16px; } + +.warningMessage { + display: flex; + padding: 0 16px; + color: $color-warning; +} diff --git a/src/components/exchange/ExchangeTransferDialog/lang.js b/src/components/exchange/ExchangeTransferDialog/lang.js index aaa8ed1fc..b12fee1dd 100644 --- a/src/components/exchange/ExchangeTransferDialog/lang.js +++ b/src/components/exchange/ExchangeTransferDialog/lang.js @@ -6,6 +6,7 @@ export default { maxAmount: 'Maximum amount: ', amountIn: 'Amount in ', sendRequest: 'send request', + needToCreateWallet: 'You need to create %{symbol} wallet', }, ru: { title: 'Внести/вывести ', @@ -14,5 +15,6 @@ export default { maxAmount: 'Максимальное значение: ', amountIn: 'Сумма в ', sendRequest: 'отправить запрос', + needToCreateWallet: 'Вам нужно создать кошелек для %{symbol}', }, } diff --git a/src/components/exchange/ExchangeWidget/ExchangeWidget.jsx b/src/components/exchange/ExchangeWidget/ExchangeWidget.jsx index 62ab8e502..f50c2d61d 100644 --- a/src/components/exchange/ExchangeWidget/ExchangeWidget.jsx +++ b/src/components/exchange/ExchangeWidget/ExchangeWidget.jsx @@ -1,4 +1,5 @@ import { change, Field, formValueSelector, reduxForm } from 'redux-form/immutable' +import Preloader from 'components/common/Preloader/Preloader' import { MenuItem, RaisedButton } from 'material-ui' import PropTypes from 'prop-types' import React from 'react' @@ -10,6 +11,7 @@ import { connect } from 'react-redux' import { modalsOpen } from 'redux/modals/actions' import { DUCK_EXCHANGE, search } from 'redux/exchange/actions' import AddExchangeDialog from 'components/exchange/AddExchangeDialog/AddExchangeDialog' +import globalStyles from 'layouts/partials/styles' import validate from './validate' import './ExchangeWidget.scss' @@ -26,9 +28,10 @@ const mapStateToProps = (state) => { const selector = formValueSelector(FORM_EXCHANGE) return { isFetching: exchange.isFetching(), + isFetched: exchange.isFetched(), assetSymbols: exchange.assetSymbols(), filterMode: selector(state, 'filterMode'), - initialValues: new Immutable.Map({ filterMode: MODES[ 0 ] }), + initialValues: new Immutable.Map({ filterMode: MODES[0] }), showFilter: exchange.showFilter(), } } @@ -51,6 +54,8 @@ const onSubmit = (values, dispatch) => { @reduxForm({ form: FORM_EXCHANGE, validate, onSubmit }) export default class ExchangeWidget extends React.Component { static propTypes = { + isFetched: PropTypes.bool, + isFetching: PropTypes.bool, search: PropTypes.func, assetSymbols: PropTypes.arrayOf(PropTypes.string), handleSubmit: PropTypes.func, @@ -65,7 +70,7 @@ export default class ExchangeWidget extends React.Component { } handleChangeMode (value) { - this.props.dispatch(change(FORM_EXCHANGE, 'filterMode', MODES[ value ])) + this.props.dispatch(change(FORM_EXCHANGE, 'filterMode', MODES[value])) } render () { @@ -98,55 +103,69 @@ export default class ExchangeWidget extends React.Component { }
- { - this.props.showFilter ? - - this.handleChangeMode(index)} - > - {MODES.map((el) => ( -
-
-
- } - /> -
-
- } - > - { - this.props.assetSymbols - .map((symbol) => ) - } - -
-
-
- } - primary + + this.handleChangeMode(index)} + > + {MODES.map((el) => ( +
+
+
+ } + /> +
+
+ } + > + { + this.props.assetSymbols.length > 0 + ? this.props.assetSymbols + .map((symbol) => ) + : } /> -
-
+ } + +
+
+
+ + {this.props.isFetching ? : } + + } + primary + />
- ))} -
- - : -
- -
+
+
+ ))} + + + { + !this.props.showFilter && +
+ +
}
diff --git a/src/components/exchange/ExchangeWidget/ExchangeWidget.scss b/src/components/exchange/ExchangeWidget/ExchangeWidget.scss index b13e07163..d258f2a1e 100644 --- a/src/components/exchange/ExchangeWidget/ExchangeWidget.scss +++ b/src/components/exchange/ExchangeWidget/ExchangeWidget.scss @@ -152,3 +152,10 @@ padding: 16px; text-align: center; } + +.buttonLabel { + display: flex; + align-items: center; + padding-top: 8px; + padding-bottom: 8px; +} diff --git a/src/components/exchange/ExchangeWidget/lang.js b/src/components/exchange/ExchangeWidget/lang.js index e16b48535..e901123e4 100644 --- a/src/components/exchange/ExchangeWidget/lang.js +++ b/src/components/exchange/ExchangeWidget/lang.js @@ -8,7 +8,8 @@ export default { sell: 'Sell', amount: 'Amount', createExchange: 'Create an exchange', - middlewareDisconnected: 'The search is not available because MiddleWare is disconnected', + middlewareDisconnected: 'The search is not available because Middleware is disconnected', + emptyList: 'List is empty', }, ru: { exchange: 'Обмен', @@ -19,6 +20,7 @@ export default { sell: 'Продать', amount: 'Сумма', createExchange: 'Создать обменник', - middlewareDisconnected: 'Поиск недоступен, так как MiddleWare отключен', + middlewareDisconnected: 'Поиск недоступен, так как Middleware отключен', + emptyList: 'Список пуст', }, } diff --git a/src/dao/ExchangeManagerDAO.js b/src/dao/ExchangeManagerDAO.js index b6c2b70ab..c2abc5660 100644 --- a/src/dao/ExchangeManagerDAO.js +++ b/src/dao/ExchangeManagerDAO.js @@ -80,30 +80,28 @@ export default class ExchangeManagerDAO extends AbstractContractDAO { exchangesAddresses.forEach((address, i) => { const symbol = this._c.bytesToString(symbols[i]) // symbol may be empty, but exchange not be without token symbol - if (symbol) { - const buyPrice = new BigNumber(buyPrices[i]) - const sellPrice = new BigNumber(sellPrices[i]) - const assetBalance = assetBalances[i] - const ethBalance = ethBalances[i] - const token = tokens.getBySymbol(symbol) + const buyPrice = new BigNumber(buyPrices[i]) + const sellPrice = new BigNumber(sellPrices[i]) + const assetBalance = assetBalances[i] + const ethBalance = ethBalances[i] + const token = tokens.getBySymbol(symbol) - try { - exchangeService.subscribeToExchange(address) - exchangeService.subscribeToToken(token, address) - } catch (e) { - // eslint-disable-next-line - console.error('watch error', e.message) - } - - exchangesCollection = exchangesCollection.add(new ExchangeOrderModel({ - address: address, - symbol, - buyPrice: this._c.fromWei(buyPrice).mul(Math.pow(10, token.decimals())), - sellPrice: this._c.fromWei(sellPrice).mul(Math.pow(10, token.decimals())), - assetBalance: token.dao().removeDecimals(assetBalance), - ethBalance: this._c.fromWei(ethBalance), - })) + try { + exchangeService.subscribeToExchange(address) + exchangeService.subscribeToToken(token, address) + } catch (e) { + // eslint-disable-next-line + console.error('watch error', e.message) } + + exchangesCollection = exchangesCollection.add(new ExchangeOrderModel({ + address: address, + symbol: symbol || address, + buyPrice: this._c.fromWei(buyPrice).mul(Math.pow(10, token.decimals())), + sellPrice: this._c.fromWei(sellPrice).mul(Math.pow(10, token.decimals())), + assetBalance: token.dao().removeDecimals(assetBalance), + ethBalance: this._c.fromWei(ethBalance), + })) }) return exchangesCollection } diff --git a/src/layouts/partials/styles.js b/src/layouts/partials/styles.js index abc6128d0..d20ccf65e 100644 --- a/src/layouts/partials/styles.js +++ b/src/layouts/partials/styles.js @@ -122,6 +122,9 @@ export default { overflow: 'visible', textAlign: 'left', }, + buttonStyle: { + lineHeight: 'normal', + }, labelStyle: { display: 'block', }, diff --git a/src/redux/exchange/actions.js b/src/redux/exchange/actions.js index 44617eaa1..f630f549e 100644 --- a/src/redux/exchange/actions.js +++ b/src/redux/exchange/actions.js @@ -162,24 +162,24 @@ export const watchExchanges = () => async (dispatch, getState) => { } dispatch(getExchangesCount()) }) - exchangeService.on('Error', async (tx) => { + exchangeService.on('Error', async (/*tx*/) => { // eslint-disable-next-line - console.error(tx) + // console.error('event error', tx) }) - exchangeService.on('FeeUpdated', async (tx) => { + exchangeService.on('FeeUpdated', async (/*tx*/) => { // eslint-disable-next-line - console.log('--actions#FeeUpdated', tx) + // console.log('--actions#FeeUpdated', tx) }) - exchangeService.on('PricesUpdated', async (tx) => { + exchangeService.on('PricesUpdated', async (/*tx*/) => { // eslint-disable-next-line - console.log('--actions#PricesUpdated', tx) + // console.log('--actions#PricesUpdated', tx) }) - exchangeService.on('ActiveChanged', async (tx) => { + exchangeService.on('ActiveChanged', async (/*tx*/) => { // eslint-disable-next-line - console.log('--actions#ActiveChanged', tx) + // console.log('--actions#ActiveChanged', tx) }) exchangeService.on('Buy', async (tx) => {