Skip to content
This repository has been archived by the owner on Oct 26, 2021. It is now read-only.

Merge balance common #489

Open
wants to merge 4 commits into
base: latest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"@walletconnect/browser": "^1.0.0-beta.18",
"@walletconnect/qrcode-modal": "^1.0.0-beta.18",
"axios": "^0.18.0",
"balance-common": "^0.6.1",
"bignumber.js": "^7.0.1",
"bowser": "^2.0.0-alpha.4",
"ethereumjs-tx": "^1.3.4",
Expand Down
4 changes: 2 additions & 2 deletions src/components/CopyToClipboard/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { lang } from 'balance-common';
import lang from '../../languages';
import clipboardIcon from '../../assets/clipboard.png';
import { toChecksumAddress } from 'balance-common';
import { toChecksumAddress } from '../../handlers/web3';
import { notificationShow } from '../../reducers/_notification';
import {
StyledCopyToClipboard,
Expand Down
2 changes: 1 addition & 1 deletion src/components/DropdownAsset.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import selector from '../assets/selector-grey.svg';
import { ellipseText } from 'balance-common';
import { ellipseText } from '../helpers/utilities';
import { fonts, colors, shadows, responsive, transitions } from '../styles';
import AssetIcon from './AssetIcon';
import ClickOutside from './ClickOutside';
Expand Down
2 changes: 1 addition & 1 deletion src/components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import styled from 'styled-components';
import { lang } from 'balance-common';
import lang from '../languages';
import OpenSeaLogo from '../assets/opensea-logo.svg';
import { fonts, responsive } from '../styles';

Expand Down
2 changes: 1 addition & 1 deletion src/components/GasButton/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import { lang } from 'balance-common';
import lang from '../../languages';

import { StyledGasButton } from './styles';

Expand Down
2 changes: 1 addition & 1 deletion src/components/Input.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled, { keyframes } from 'styled-components';
import { lang } from 'balance-common';
import lang from '../languages';
import { colors, fonts, shadows, responsive } from '../styles';

const shimmer = keyframes`
Expand Down
322 changes: 322 additions & 0 deletions src/components/SendComponentWithData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { get } from 'lodash';
import lang from '../languages';
import {
sendModalInit,
sendUpdateGasPrice,
sendTransaction,
sendClearFields,
sendUpdateRecipient,
sendUpdateNativeAmount,
sendUpdateAssetAmount,
sendUpdateSelected,
sendMaxBalance,
sendToggleConfirmationView,
} from '../reducers/_send';
import { notificationShow } from '../reducers/_notification';

import { isValidAddress } from '../helpers/validators';
import { convertAmountFromBigNumber, greaterThan } from '../helpers/bignumber';

import { transactionData } from '../helpers/utilities';

const reduxProps = ({ send, account }) => ({
fetching: send.fetching,
recipient: send.recipient,
nativeAmount: send.nativeAmount,
assetAmount: send.assetAmount,
isSufficientGas: send.isSufficientGas,
isSufficientBalance: send.isSufficientBalance,
txHash: send.txHash,
address: send.address,
selected: send.selected,
gasPrices: send.gasPrices,
gasPrice: send.gasPrice,
gasLimit: send.gasLimit,
gasPriceOption: send.gasPriceOption,
confirm: send.confirm,
accountInfo: account.accountInfo,
accountType: account.accountType,
network: account.network,
nativeCurrency: account.nativeCurrency,
prices: account.prices,
});

/**
* Create SendComponent connected to redux with actions for sending assets.
* @param {Component} SendComponent React component for sending.
* @param {Object} options
* {Function} options.sendTransactionCallback Function to be run after sendTransaction redux action.
* {String} options.defaultAsset Symbol for default asset to send.
* @return {Component} SendComponent connected to redux.
*/
export const withSendComponentWithData = (SendComponent, options) => {
class SendComponentWithData extends Component {
static propTypes = {
sendModalInit: PropTypes.func.isRequired,
sendUpdateGasPrice: PropTypes.func.isRequired,
sendTransaction: PropTypes.func.isRequired,
sendClearFields: PropTypes.func.isRequired,
sendUpdateRecipient: PropTypes.func.isRequired,
sendUpdateNativeAmount: PropTypes.func.isRequired,
sendUpdateAssetAmount: PropTypes.func.isRequired,
sendUpdateSelected: PropTypes.func.isRequired,
sendMaxBalance: PropTypes.func.isRequired,
sendToggleConfirmationView: PropTypes.func.isRequired,
notificationShow: PropTypes.func.isRequired,
fetching: PropTypes.bool.isRequired,
recipient: PropTypes.string.isRequired,
nativeAmount: PropTypes.string.isRequired,
assetAmount: PropTypes.string.isRequired,
isSufficientGas: PropTypes.func.isRequired,
isSufficientBalance: PropTypes.func.isRequired,
txHash: PropTypes.string.isRequired,
selected: PropTypes.object.isRequired,
gasPrice: PropTypes.object.isRequired,
gasPrices: PropTypes.object.isRequired,
gasLimit: PropTypes.number.isRequired,
gasPriceOption: PropTypes.string.isRequired,
confirm: PropTypes.bool.isRequired,
accountInfo: PropTypes.object.isRequired,
accountType: PropTypes.string.isRequired,
network: PropTypes.string.isRequired,
nativeCurrency: PropTypes.string.isRequired,
prices: PropTypes.object.isRequired,
};

constructor(props) {
super(props);

this.state = {
isValidAddress: false,
showQRCodeReader: false,
};

this.defaultAsset = options.defaultAsset || 'ETH';
this.gasFormat = options.gasFormat || 'long';
this.sendTransactionCallback =
options.sendTransactionCallback || function noop() {};
}

componentDidMount() {
this.props.sendModalInit({
defaultAsset: this.defaultAsset,
gasFormat: this.gasFormat,
});
}

componentDidUpdate(prevProps) {
const {
assetAmount,
recipient,
selected,
sendUpdateGasPrice,
} = this.props;

if (recipient.length >= 42) {
if (selected.symbol !== prevProps.selected.symbol) {
sendUpdateGasPrice();
} else if (recipient !== prevProps.recipient) {
sendUpdateGasPrice();
} else if (assetAmount !== prevProps.assetAmount) {
sendUpdateGasPrice();
}
}

if (recipient !== prevProps.recipient) {
this.setState({ isValidAddress: isValidAddress(recipient) });
}
}

onAddressInputFocus = () => {
const { recipient } = this.props;

this.setState({ isValidAddress: isValidAddress(recipient) });
};

onAddressInputBlur = () => {
const { recipient } = this.props;

this.setState({ isValidAddress: isValidAddress(recipient) });
};

onGoBack = () => this.props.sendToggleConfirmationView(false);

onSendMaxBalance = () => this.props.sendMaxBalance();

onSendAnother = () => {
this.props.sendToggleConfirmationView(false);
this.props.sendClearFields();
this.props.sendModalInit({ defaultAsset: this.defaultAsset });
};

onSubmit = event => {
if (event && typeof event.preventDefault === 'function') {
event.preventDefault();
}

if (!this.props.gasPrice.txFee) {
this.props.notificationShow(
lang.t('notification.error.generic_error'),
true,
);

return;
}

if (!this.props.confirm) {
if (!isValidAddress(this.props.recipient)) {
this.props.notificationShow(
lang.t('notification.error.invalid_address'),
true,
);

return;
} else if (this.props.selected.symbol === 'ETH') {
const { requestedAmount, balance, amountWithFees } = transactionData(
this.props.accountInfo,
this.props.assetAmount,
this.props.gasPrice,
);

if (greaterThan(requestedAmount, balance)) {
this.props.notificationShow(
lang.t('notification.error.insufficient_balance'),
true,
);

return;
} else if (greaterThan(amountWithFees, balance)) {
this.props.notificationShow(
lang.t('notification.error.insufficient_for_fees'),
true,
);

return;
}
} else {
const { requestedAmount, balance, txFee } = transactionData(
this.props.accountInfo,
this.props.assetAmount,
this.props.gasPrice,
);

const tokenBalanceAmount = get(this.props, 'selected.balance.amount');
const tokenBalance = convertAmountFromBigNumber(tokenBalanceAmount);

if (greaterThan(requestedAmount, tokenBalance)) {
this.props.notificationShow(
lang.t('notification.error.insufficient_balance'),
true,
);

return;
} else if (greaterThan(txFee, balance)) {
this.props.notificationShow(
lang.t('notification.error.insufficient_for_fees'),
true,
);

return;
}
}

this.props.sendToggleConfirmationView(true);

return this.props.sendTransaction(
{
address: this.props.accountInfo.address,
recipient: this.props.recipient,
amount: this.props.assetAmount,
asset: this.props.selected,
gasPrice: this.props.gasPrice,
gasLimit: this.props.gasLimit,
},
this.sendTransactionCallback,
);
}
};

updateGasPrice = gasPrice => {
this.props.sendUpdateGasPrice(gasPrice);
};

onClose = () => {
this.props.sendClearFields();
// TODO: close function ?? (previously was to hit modal reducer)
};

updateGasPrice = gasPrice => {
this.props.sendUpdateGasPrice(gasPrice);
};

// QR Code Reader Handlers
toggleQRCodeReader = () =>
this.setState({ showQRCodeReader: !this.state.showQRCodeReader });

onQRCodeValidate = rawData => {
const data = rawData.match(/0x\w{40}/g)
? rawData.match(/0x\w{40}/g)[0]
: null;
const result = data ? isValidAddress(data) : false;
const onError = () =>
this.props.notificationShow(
lang.t('notification.error.invalid_address_scanned'),
true,
);

return { data, result, onError };
};

onQRCodeScan = data => {
this.props.sendUpdateRecipient(data);
this.setState({ showQRCodeReader: false });
};

onQRCodeError = () => {
this.props.notificationShow(
lang.t('notification.error.failed_scanning_qr_code'),
true,
);
};

render() {
return (
<SendComponent
isValidAddress={this.state.isValidAddress}
onSendMaxBalance={this.onSendMaxBalance}
onAddressInputFocus={this.onAddressInputFocus}
onAddressInputBlur={this.onAddressInputBlur}
onClose={this.onClose}
onQRCodeValidate={this.onQRCodeValidate}
onQRCodeScan={this.onQRCodeScan}
onQRCodeError={this.onQRCodeError}
onSubmit={this.onSubmit}
showQRCodeReader={this.state.showQRCodeReader}
toggleQRCodeReader={this.toggleQRCodeReader}
updateGasPrice={this.updateGasPrice}
{...this.props}
/>
);
}
}

return connect(
reduxProps,
{
sendModalInit,
sendUpdateGasPrice,
sendTransaction,
sendClearFields,
sendUpdateRecipient,
sendUpdateNativeAmount,
sendUpdateAssetAmount,
sendUpdateSelected,
sendMaxBalance,
sendToggleConfirmationView,
notificationShow,
},
)(SendComponentWithData);
};
3 changes: 2 additions & 1 deletion src/components/SubscribeForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import styled from 'styled-components';
import PropTypes from 'prop-types';
import jsonp from 'jsonp';
import Button from './Button';
import { isValidEmail, lang } from 'balance-common';
import { isValidEmail } from '../helpers/validators';
import lang from '../languages';
import { fonts, colors, transitions } from '../styles';

const SForm = styled.form`
Expand Down
2 changes: 1 addition & 1 deletion src/components/TabMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { lang } from 'balance-common';
import lang from '../languages';
import i18next from 'i18next';
import Link from './Link';
import Button from './Button';
Expand Down
Loading