diff --git a/app/actions/modals/index.js b/app/actions/modals/index.js
index 4c1f43b5ac3..0bda0082634 100644
--- a/app/actions/modals/index.js
+++ b/app/actions/modals/index.js
@@ -23,3 +23,9 @@ export function toggleReceiveModal(asset) {
asset
};
}
+
+export function toggleDappTransactionModal() {
+ return {
+ type: 'TOGGLE_DAPP_TRANSACTION_MODAL'
+ };
+}
diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js
index 8698ddc523e..8b68c2ac1ce 100644
--- a/app/components/Nav/Main/index.js
+++ b/app/components/Nav/Main/index.js
@@ -102,6 +102,7 @@ import {
hideTransactionNotification,
showSimpleNotification
} from '../../../actions/notification';
+import { toggleDappTransactionModal } from '../../../actions/modals';
import AccountApproval from '../../UI/AccountApproval';
const styles = StyleSheet.create({
@@ -439,9 +440,16 @@ class Main extends PureComponent {
/**
* Indicates whether third party API mode is enabled
*/
- thirdPartyApiMode: PropTypes.bool
+ thirdPartyApiMode: PropTypes.bool,
+ /**
+ /* Hides or shows dApp transaction modal
+ */
+ toggleDappTransactionModal: PropTypes.func,
+ /**
+ /* dApp transaction modal visible or not
+ */
+ dappTransactionModalVisible: PropTypes.bool
};
-
state = {
connected: true,
forceReload: false,
@@ -816,7 +824,7 @@ class Main extends PureComponent {
if (data && data.substr(0, 10) === APPROVE_FUNCTION_SIGNATURE) {
this.props.navigation.push('ApproveView');
} else {
- this.props.navigation.push('ApprovalView');
+ this.props.toggleDappTransactionModal();
}
}
};
@@ -1050,6 +1058,12 @@ class Main extends PureComponent {
backupAlertPress = () => {
this.props.navigation.navigate('AccountBackupStep1');
};
+ renderDappTransactionModal = () => (
+
+ );
render() {
const { isPaymentChannelTransaction, isPaymentRequest } = this.props;
@@ -1072,6 +1086,7 @@ class Main extends PureComponent {
{this.renderSigningModal()}
{this.renderWalletConnectSessionRequestModal()}
+ {this.props.dappTransactionModalVisible && this.renderDappTransactionModal()}
);
}
@@ -1087,7 +1102,8 @@ const mapStateToProps = state => ({
providerType: state.engine.backgroundState.NetworkController.provider.type,
isPaymentChannelTransaction: state.transaction.paymentChannelTransaction,
isPaymentRequest: state.transaction.paymentRequest,
- identities: state.engine.backgroundState.PreferencesController.identities
+ identities: state.engine.backgroundState.PreferencesController.identities,
+ dappTransactionModalVisible: state.modals.dappTransactionModalVisible
});
const mapDispatchToProps = dispatch => ({
@@ -1095,7 +1111,8 @@ const mapDispatchToProps = dispatch => ({
setTransactionObject: transaction => dispatch(setTransactionObject(transaction)),
showTransactionNotification: args => dispatch(showTransactionNotification(args)),
showSimpleNotification: args => dispatch(showSimpleNotification(args)),
- hideTransactionNotification: () => dispatch(hideTransactionNotification())
+ hideTransactionNotification: () => dispatch(hideTransactionNotification()),
+ toggleDappTransactionModal: () => dispatch(toggleDappTransactionModal())
});
export default connect(
diff --git a/app/components/UI/CustomGas/__snapshots__/index.test.js.snap b/app/components/UI/CustomGas/__snapshots__/index.test.js.snap
index 42bb83fa9f9..2763d6cb592 100644
--- a/app/components/UI/CustomGas/__snapshots__/index.test.js.snap
+++ b/app/components/UI/CustomGas/__snapshots__/index.test.js.snap
@@ -4,12 +4,18 @@ exports[`CustomGas should render correctly 1`] = `
-
- Loading...
-
+
`;
diff --git a/app/components/UI/CustomGas/index.js b/app/components/UI/CustomGas/index.js
index 71d3ba81bd8..cf3d6042187 100644
--- a/app/components/UI/CustomGas/index.js
+++ b/app/components/UI/CustomGas/index.js
@@ -1,8 +1,8 @@
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import { StyleSheet, View, Text, TextInput, TouchableOpacity } from 'react-native';
-import { colors, fontStyles, baseStyles } from '../../../styles/common';
+import { StyleSheet, View, Text, TextInput, TouchableOpacity, ActivityIndicator } from 'react-native';
+import { colors, fontStyles } from '../../../styles/common';
import { strings } from '../../../../locales/i18n';
import {
getRenderableEthGasFee,
@@ -10,35 +10,99 @@ import {
apiEstimateModifiedToWEI,
getBasicGasEstimates
} from '../../../util/custom-gas';
+import IonicIcon from 'react-native-vector-icons/Ionicons';
import { BN } from 'ethereumjs-util';
-import { fromWei, renderWei, hexToBN } from '../../../util/number';
-import { getTicker } from '../../../util/transactions';
+import { fromWei, renderWei, hexToBN, isDecimal, isBN } from '../../../util/number';
+import { getTicker, getNormalizedTxState } from '../../../util/transactions';
+import { safeToChecksumAddress } from '../../../util/address';
import Radio from '../Radio';
+import StyledButton from '../../UI/StyledButton';
const styles = StyleSheet.create({
- labelText: {
+ root: {
+ paddingHorizontal: 24
+ },
+ customGasHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ width: '100%',
+ paddingBottom: 20
+ },
+ customGasModalTitleText: {
...fontStyles.bold,
- color: colors.grey400,
- fontSize: 16
+ color: colors.black,
+ fontSize: 14,
+ alignSelf: 'center'
+ },
+ optionsContainer: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingBottom: 20
+ },
+ basicButton: {
+ width: 116,
+ height: 36,
+ padding: 8,
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ optionSelected: {
+ backgroundColor: colors.grey000,
+ borderWidth: 1,
+ borderRadius: 20,
+ borderColor: colors.grey100
+ },
+ textOptions: {
+ ...fontStyles.normal,
+ fontSize: 14,
+ color: colors.black
+ },
+ message: {
+ ...fontStyles.normal,
+ color: colors.black,
+ fontSize: 12,
+ paddingBottom: 20
+ },
+ warningWrapper: {
+ marginBottom: 20,
+ height: 50,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ warningTextWrapper: {
+ width: '100%',
+ paddingHorizontal: 10,
+ paddingVertical: 8,
+ backgroundColor: colors.red000,
+ borderColor: colors.red,
+ borderRadius: 8,
+ borderWidth: 1,
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ warningText: {
+ color: colors.red,
+ fontSize: 12,
+ ...fontStyles.normal
+ },
+ invisible: {
+ opacity: 0
},
titleContainer: {
- flex: 1,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between'
},
- titleMargin: {
- marginBottom: 10,
- alignItems: 'flex-end'
- },
radio: {
marginLeft: 'auto'
},
selectors: {
- flex: 1,
position: 'relative',
flexDirection: 'row',
- justifyContent: 'space-evenly'
+ justifyContent: 'space-evenly',
+ marginBottom: 8
},
selector: {
alignSelf: 'stretch',
@@ -56,10 +120,6 @@ const styles = StyleSheet.create({
borderColor: colors.blue,
zIndex: 1
},
- advancedOptions: {
- textAlign: 'right',
- alignItems: 'flex-end'
- },
slow: {
borderBottomStartRadius: 6,
borderTopStartRadius: 6
@@ -78,9 +138,6 @@ const styles = StyleSheet.create({
fontSize: 10,
color: colors.black
},
- textTotalGas: {
- ...fontStyles.bold
- },
textTime: {
...fontStyles.bold,
color: colors.black,
@@ -88,27 +145,53 @@ const styles = StyleSheet.create({
fontSize: 18,
textTransform: 'none'
},
- textAdvancedOptions: {
- color: colors.blue,
+ loaderContainer: {
+ height: 200,
+ backgroundColor: colors.white,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ advancedOptionsContainer: {
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ valueRow: {
+ width: '100%',
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginBottom: 20
+ },
+ advancedOptionsText: {
+ flex: 1,
+ textAlign: 'left',
+ ...fontStyles.light,
+ color: colors.black,
+ fontSize: 16
+ },
+ totalGasWrapper: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'flex-start',
+ paddingVertical: 8,
+ paddingRight: 20
+ },
+ textTotalGas: {
+ ...fontStyles.bold,
+ color: colors.black,
fontSize: 14
},
gasInput: {
+ flex: 1,
...fontStyles.bold,
backgroundColor: colors.white,
borderColor: colors.grey100,
- borderRadius: 4,
+ borderRadius: 8,
borderWidth: 1,
- fontSize: 16,
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 52,
- paddingTop: 8,
- position: 'relative',
- marginTop: 5
- },
- warningText: {
- color: colors.red,
- ...fontStyles.normal
+ fontSize: 14,
+ paddingHorizontal: 10,
+ paddingVertical: 8,
+ position: 'relative'
}
});
@@ -117,6 +200,10 @@ const styles = StyleSheet.create({
*/
class CustomGas extends PureComponent {
static propTypes = {
+ /**
+ * List of accounts from the AccountTrackerController
+ */
+ accounts: PropTypes.object,
/**
/* conversion rate of ETH - FIAT
*/
@@ -129,14 +216,14 @@ class CustomGas extends PureComponent {
* Callback triggered when gas fee is selected
*/
handleGasFeeSelection: PropTypes.func,
- /**
- * Object BN containing total gas fee
- */
- totalGas: PropTypes.object,
/**
* Object BN containing estimated gas limit
*/
gas: PropTypes.object,
+ /**
+ * Object BN containing gas price
+ */
+ gasPrice: PropTypes.object,
/**
* Callback to modify state in parent state
*/
@@ -148,7 +235,15 @@ class CustomGas extends PureComponent {
/**
* Displayed when there is a gas station error
*/
- gasError: PropTypes.string
+ gasError: PropTypes.string,
+ /**
+ * Changes the mode to 'review'
+ */
+ review: PropTypes.func,
+ /**
+ * Transaction object associated with this transaction
+ */
+ transaction: PropTypes.object
};
state = {
@@ -167,13 +262,16 @@ class CustomGas extends PureComponent {
advancedCustomGas: false,
customGasPrice: '10',
customGasLimit: fromWei(this.props.gas, 'wei'),
+ customGasPriceBN: this.props.gasPrice,
+ customGasLimitBN: this.props.gas,
warningGasLimit: '',
- warningGasPrice: ''
+ warningGasPrice: '',
+ warningSufficientFunds: ''
};
onPressGasFast = () => {
const { fastGwei } = this.state;
- const { gas, onPress } = this.props;
+ const { onPress } = this.props;
onPress && onPress();
this.setState({
gasFastSelected: true,
@@ -182,12 +280,11 @@ class CustomGas extends PureComponent {
selected: 'fast',
customGasPrice: fastGwei
});
- this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(fastGwei));
};
onPressGasAverage = () => {
const { averageGwei } = this.state;
- const { gas, onPress } = this.props;
+ const { onPress } = this.props;
onPress && onPress();
this.setState({
gasFastSelected: false,
@@ -196,12 +293,11 @@ class CustomGas extends PureComponent {
selected: 'average',
customGasPrice: averageGwei
});
- this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(averageGwei));
};
onPressGasSlow = () => {
const { safeLowGwei } = this.state;
- const { gas, onPress } = this.props;
+ const { onPress } = this.props;
onPress && onPress();
this.setState({
gasFastSelected: false,
@@ -210,38 +306,26 @@ class CustomGas extends PureComponent {
selected: 'slow',
customGasPrice: safeLowGwei
});
- this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(safeLowGwei));
};
- onAdvancedOptions = () => {
- const { advancedCustomGas, selected, fastGwei, averageGwei, safeLowGwei, customGasPrice } = this.state;
- const { gas, onPress } = this.props;
- onPress && onPress();
- if (advancedCustomGas) {
- switch (selected) {
- case 'slow':
- this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(safeLowGwei));
- break;
- case 'average':
- this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(averageGwei));
- break;
- case 'fast':
- this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(fastGwei));
- break;
- }
- } else {
- this.setState({ customGasLimit: fromWei(gas, 'wei') });
+ toggleAdvancedOptions = () => {
+ const { advancedCustomGas, customGasPrice } = this.state;
+ const { gas } = this.props;
+ if (!advancedCustomGas) {
+ this.setState({ customGasLimit: fromWei(gas, 'wei'), advancedCustomGas: !advancedCustomGas });
this.props.handleGasFeeSelection(gas, apiEstimateModifiedToWEI(customGasPrice));
+ } else {
+ this.setState({ advancedCustomGas: !advancedCustomGas });
}
- this.setState({ advancedCustomGas: !advancedCustomGas });
};
componentDidMount = async () => {
+ const { gas, gasPrice } = this.props;
await this.handleFetchBasicEstimates();
+ const warningSufficientFunds = this.hasSufficientFunds(gas, gasPrice);
const { ticker } = this.props;
- if (ticker && ticker !== 'ETH') {
- this.setState({ advancedCustomGas: true });
- }
+ //Applies ISF error if present before any gas modifications
+ this.setState({ warningSufficientFunds, advancedCustomGas: ticker && ticker !== 'ETH' });
};
componentDidUpdate = prevProps => {
@@ -252,9 +336,8 @@ class CustomGas extends PureComponent {
handleGasRecalculationForCustomGasInput = prevProps => {
const actualGasLimitWei = renderWei(hexToBN(this.props.gas));
- if (renderWei(hexToBN(prevProps.gas)) !== actualGasLimitWei) {
+ if (renderWei(hexToBN(prevProps.gas)) !== actualGasLimitWei)
this.setState({ customGasLimit: actualGasLimitWei });
- }
};
handleFetchBasicEstimates = async () => {
@@ -263,17 +346,73 @@ class CustomGas extends PureComponent {
this.setState({ ...basicGasEstimates, ready: true });
};
+ //Validate locally instead of in TransactionEditor, otherwise cannot change back to review mode if insufficient funds
+ hasSufficientFunds = (gas, gasPrice) => {
+ const {
+ transaction: { from, value }
+ } = this.props;
+ const checksummedFrom = safeToChecksumAddress(from) || '';
+ const fromAccount = this.props.accounts[checksummedFrom];
+ if (hexToBN(fromAccount.balance).lt(gas.mul(gasPrice).add(value))) return strings('transaction.insufficient');
+ return '';
+ };
+
onGasLimitChange = value => {
- const { customGasPrice } = this.state;
+ const { customGasPriceBN } = this.state;
const bnValue = new BN(value);
- this.setState({ customGasLimit: value });
- this.props.handleGasFeeSelection(bnValue, apiEstimateModifiedToWEI(customGasPrice));
+ const warningSufficientFunds = this.hasSufficientFunds(bnValue, customGasPriceBN);
+ let warningGasLimit;
+ if (!value || value === '' || !isDecimal(value)) warningGasLimit = strings('transaction.invalid_gas');
+ else if (bnValue && !isBN(bnValue)) warningGasLimit = strings('transaction.invalid_gas');
+ else if (bnValue.lt(new BN(21000)) || bnValue.gt(new BN(7920028)))
+ warningGasLimit = strings('custom_gas.warning_gas_limit');
+
+ this.setState({
+ customGasLimit: value,
+ customGasLimitBN: bnValue,
+ warningGasLimit,
+ warningSufficientFunds
+ });
};
onGasPriceChange = value => {
- const { customGasLimit } = this.state;
- this.setState({ customGasPrice: value });
- this.props.handleGasFeeSelection(new BN(customGasLimit, 10), apiEstimateModifiedToWEI(value));
+ const { customGasLimitBN } = this.state;
+ //Added because apiEstimateModifiedToWEI doesn't like empty strings
+ const gasPrice = value === '' ? '0' : value;
+ const gasPriceBN = apiEstimateModifiedToWEI(gasPrice);
+ const warningSufficientFunds = this.hasSufficientFunds(customGasLimitBN, gasPriceBN);
+ let warningGasPrice;
+ if (!value || value === '' || !isDecimal(value) || value <= 0)
+ warningGasPrice = strings('transaction.invalid_gas_price');
+ if (gasPriceBN && !isBN(gasPriceBN)) warningGasPrice = strings('transaction.invalid_gas_price');
+ this.setState({
+ customGasPrice: value,
+ customGasPriceBN: gasPriceBN,
+ warningGasPrice,
+ warningSufficientFunds
+ });
+ };
+
+ //Handle gas fee selection when save button is pressed instead of everytime a change is made, otherwise cannot switch back to review mode if there is an error
+ saveCustomGasSelection = () => {
+ const {
+ selected,
+ fastGwei,
+ averageGwei,
+ safeLowGwei,
+ customGasLimit,
+ customGasPrice,
+ advancedCustomGas
+ } = this.state;
+ const { review, gas, handleGasFeeSelection } = this.props;
+ if (advancedCustomGas) {
+ handleGasFeeSelection(new BN(customGasLimit), apiEstimateModifiedToWEI(customGasPrice));
+ } else {
+ if (selected === 'slow') handleGasFeeSelection(gas, apiEstimateModifiedToWEI(safeLowGwei));
+ if (selected === 'average') handleGasFeeSelection(gas, apiEstimateModifiedToWEI(averageGwei));
+ if (selected === 'fast') handleGasFeeSelection(gas, apiEstimateModifiedToWEI(fastGwei));
+ }
+ review();
};
renderCustomGasSelector = () => {
@@ -354,71 +493,119 @@ class CustomGas extends PureComponent {
};
renderCustomGasInput = () => {
- const { customGasLimit, customGasPrice, warningGasLimit, warningGasPrice } = this.state;
- const { totalGas } = this.props;
+ const { customGasPrice, customGasLimitBN, customGasPriceBN } = this.state;
+ const totalGas = customGasLimitBN.mul(customGasPriceBN);
const ticker = getTicker(this.props.ticker);
return (
-
-
- {fromWei(totalGas)} {ticker}
-
- {strings('custom_gas.gas_limit')}
-
- {warningGasLimit}
- {strings('custom_gas.gas_price')}
-
- {warningGasPrice}
+
+
+ {strings('custom_gas.total')}
+
+
+ {fromWei(totalGas)} {ticker}
+
+
+
+
+ {strings('custom_gas.gas_limit')}
+
+
+
+ {strings('custom_gas.gas_price')}
+
+
+
+ );
+ };
+
+ renderGasError = () => {
+ const { warningGasLimit, warningGasPrice, warningSufficientFunds } = this.state;
+ const { gasError } = this.props;
+ const gasErrorMessage = warningGasPrice || warningGasLimit || warningSufficientFunds || gasError;
+ return (
+
+
+ {gasErrorMessage}
+
);
};
render = () => {
if (this.state.ready) {
- const { advancedCustomGas } = this.state;
- const { gasError } = this.props;
+ const { advancedCustomGas, warningGasLimit, warningGasPrice, warningSufficientFunds } = this.state;
+ const { review, gasError } = this.props;
+ const disableButton = advancedCustomGas
+ ? !!warningGasLimit || !!warningGasPrice || !!warningSufficientFunds || !!gasError
+ : false;
return (
-
-
-
- {strings('transaction.gas_fee')}:
- {gasError ? {gasError} : null}
-
-
-
-
- {advancedCustomGas
- ? strings('custom_gas.hide_advanced_options')
- : strings('custom_gas.advanced_options')}
-
-
-
+
+
+
+
+
+ {strings('transaction.edit_network_fee')}
+
+
+
+ {strings('custom_gas.basic_options')}
+
+
+ {strings('custom_gas.advanced_options')}
+
+
+
{advancedCustomGas ? this.renderCustomGasInput() : this.renderCustomGasSelector()}
+ {!advancedCustomGas ? (
+ {strings('custom_gas.cost_explanation')}
+ ) : null}
+ {advancedCustomGas ? this.renderGasError() : null}
+
+
+ {strings('custom_gas.save')}
+
+
);
}
return (
-
- {strings('transaction.loading')}
+
+
);
};
}
const mapStateToProps = state => ({
+ accounts: state.engine.backgroundState.AccountTrackerController.accounts,
conversionRate: state.engine.backgroundState.CurrencyRateController.conversionRate,
currentCurrency: state.engine.backgroundState.CurrencyRateController.currentCurrency,
- ticker: state.engine.backgroundState.NetworkController.provider.ticker
+ ticker: state.engine.backgroundState.NetworkController.provider.ticker,
+ transaction: getNormalizedTxState(state)
});
export default connect(mapStateToProps)(CustomGas);
diff --git a/app/components/UI/CustomGas/index.test.js b/app/components/UI/CustomGas/index.test.js
index 32615ed9f5b..682acdef87f 100644
--- a/app/components/UI/CustomGas/index.test.js
+++ b/app/components/UI/CustomGas/index.test.js
@@ -17,12 +17,21 @@ describe('CustomGas', () => {
currentCurrency: 'usd',
conversionRate: 0.1
},
+ AccountTrackerController: {
+ accounts: {
+ '0x': '0x'
+ }
+ },
NetworkController: {
provider: {
ticker: 'ETH'
}
}
}
+ },
+ transaction: {
+ from: '0x',
+ value: 100
}
};
diff --git a/app/components/UI/TransactionEdit/__snapshots__/index.test.js.snap b/app/components/UI/TransactionEdit/__snapshots__/index.test.js.snap
index 27053dee41c..92839aca650 100644
--- a/app/components/UI/TransactionEdit/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionEdit/__snapshots__/index.test.js.snap
@@ -1,297 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TransactionEdit should render correctly 1`] = `
-
-
-
-
-
-
- From
- :
-
-
-
-
-
-
-
- Amount
- :
-
-
-
- Max
-
-
-
-
-
-
-
-
- To
- :
-
-
-
-
-
-
-
-
-
-
- Hex Data
- :
-
-
-
-
-
-
-
+
`;
diff --git a/app/components/UI/TransactionEdit/index.js b/app/components/UI/TransactionEdit/index.js
index bba68f392f2..5360ff9f979 100644
--- a/app/components/UI/TransactionEdit/index.js
+++ b/app/components/UI/TransactionEdit/index.js
@@ -1,135 +1,16 @@
import React, { PureComponent } from 'react';
-import AccountInput from '../AccountInput';
-import AccountSelect from '../AccountSelect';
-import ActionView from '../ActionView';
-import EthInput from '../EthInput';
import PropTypes from 'prop-types';
-import { StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
-import { colors, fontStyles } from '../../../styles/common';
import { connect } from 'react-redux';
-import { toBN, isBN, hexToBN, fromWei, fromTokenMinimalUnit, toTokenMinimalUnit } from '../../../util/number';
-import { strings } from '../../../../locales/i18n';
+import { toBN, isBN, fromWei } from '../../../util/number';
import CustomGas from '../CustomGas';
import { addHexPrefix } from 'ethereumjs-util';
-import { getTransactionOptionsTitle } from '../../UI/Navbar';
-import PaymentChannelsClient from '../../../core/PaymentChannelsClient';
-import Device from '../../../util/Device';
import { getNormalizedTxState } from '../../../util/transactions';
-const styles = StyleSheet.create({
- root: {
- backgroundColor: colors.white,
- flex: 1
- },
- formRow: {
- flexDirection: 'row'
- },
- fromRow: {
- marginRight: 0,
- position: 'absolute',
- zIndex: 5,
- right: 24,
- left: 24,
- marginTop: 30
- },
- toRow: {
- right: 24,
- left: 24,
- marginTop: Device.isAndroid() ? 125 : 120,
- position: 'absolute',
- zIndex: 4
- },
- row: {
- marginTop: 18,
- zIndex: 3
- },
- amountRow: {
- right: 24,
- left: 24,
- marginTop: Device.isAndroid() ? 200 : 190,
- position: 'absolute',
- zIndex: 4
- },
- notAbsolute: {
- marginTop: Device.isAndroid() ? 270 : 240
- },
- label: {
- flex: 0,
- paddingRight: 18,
- width: 106
- },
- labelText: {
- ...fontStyles.bold,
- color: colors.grey400,
- fontSize: 16
- },
- max: {
- ...fontStyles.bold,
- color: colors.blue,
- fontSize: 12,
- paddingTop: 6
- },
- error: {
- ...fontStyles.bold,
- color: colors.red,
- fontSize: 12,
- lineHeight: 12,
- paddingTop: 6
- },
- warning: {
- ...fontStyles.bold,
- color: colors.orange300,
- fontSize: 12,
- lineHeight: 12,
- paddingTop: 6
- },
- form: {
- flex: 1,
- paddingVertical: 16,
- paddingHorizontal: 24,
- flexDirection: 'column'
- },
- androidForm: {
- paddingBottom: 100,
- minHeight: 500
- },
- hexData: {
- ...fontStyles.bold,
- backgroundColor: colors.white,
- borderColor: colors.grey100,
- borderRadius: 4,
- borderWidth: 1,
- flex: 1,
- fontSize: 16,
- minHeight: 64,
- paddingLeft: 10,
- paddingVertical: 6
- }
-});
-
/**
* PureComponent that supports editing and reviewing a transaction
*/
class TransactionEdit extends PureComponent {
- static navigationOptions = ({ navigation }) => getTransactionOptionsTitle('send.title', 'Cancel', navigation);
-
static propTypes = {
- /**
- * List of accounts from the AccountTrackerController
- */
- accounts: PropTypes.object,
- /**
- * Callback to warn if transaction to is a known contract address
- */
- checkForAssetAddress: PropTypes.func,
- /**
- * react-navigation object used for switching between screens
- */
- navigation: PropTypes.object,
- /**
- * Callback triggered when this transaction is cancelled
- */
- onCancel: PropTypes.func,
/**
* Called when a user changes modes
*/
@@ -150,22 +31,10 @@ class TransactionEdit extends PureComponent {
* Callback to update data in transaction in parent state
*/
handleUpdateData: PropTypes.func,
- /**
- * Callback to update from address in transaction in parent state
- */
- handleUpdateFromAddress: PropTypes.func,
/**
* Callback to update readable value in transaction in parent state
*/
handleUpdateReadableValue: PropTypes.func,
- /**
- * Callback to update to address in transaction in parent state
- */
- handleUpdateToAddress: PropTypes.func,
- /**
- * Callback to update selected asset in transaction in parent state
- */
- handleUpdateAsset: PropTypes.func,
/**
* Callback to validate amount in transaction in parent state
*/
@@ -177,41 +46,15 @@ class TransactionEdit extends PureComponent {
/**
* Callback to validate to address in transaction in parent state
*/
- validateToAddress: PropTypes.func,
- /**
- * Object containing accounts balances
- */
- contractBalances: PropTypes.object,
- /**
- * Indicates whether hex data should be shown in transaction editor
- */
- showHexData: PropTypes.bool
+ validateToAddress: PropTypes.func
};
state = {
toFocused: false,
amountError: '',
- addressError: '',
toAddressError: '',
- toAddressWarning: '',
gasError: '',
- fillMax: false,
- ensRecipient: undefined,
- data: undefined,
- accountSelectIsOpen: false,
- ethInputIsOpen: false
- };
-
- openAccountSelect = isOpen => {
- this.setState({ accountSelectIsOpen: isOpen, ethInputIsOpen: false });
- };
-
- openEthInputIsOpen = isOpen => {
- this.setState({ ethInputIsOpen: isOpen, accountSelectIsOpen: false });
- };
-
- closeDropdowns = () => {
- this.setState({ accountSelectIsOpen: false, ethInputIsOpen: false });
+ data: undefined
};
componentDidMount = () => {
@@ -233,44 +76,6 @@ class TransactionEdit extends PureComponent {
}
};
- fillMax = () => {
- const { gas, gasPrice, from, selectedAsset, assetType, paymentChannelTransaction } = this.props.transaction;
- const { balance } = this.props.accounts[from];
- const { contractBalances } = this.props;
- let value, readableValue;
- if (assetType === 'ETH') {
- const totalGas = isBN(gas) && isBN(gasPrice) ? gas.mul(gasPrice) : fromWei(0);
- value = hexToBN(balance)
- .sub(totalGas)
- .gt(fromWei(0))
- ? hexToBN(balance).sub(totalGas)
- : fromWei(0);
- readableValue = fromWei(value);
- } else if (paymentChannelTransaction) {
- const state = PaymentChannelsClient.getState();
- value = toTokenMinimalUnit(state.balance, selectedAsset.decimals);
- readableValue = state.balance;
- } else if (assetType === 'ERC20') {
- value = hexToBN(contractBalances[selectedAsset.address].toString(16));
- readableValue = fromTokenMinimalUnit(value, selectedAsset.decimals);
- }
- this.props.handleUpdateAmount(value);
- this.props.handleUpdateReadableValue(readableValue);
- this.setState({ fillMax: true });
- };
-
- updateFillMax = fillMax => {
- this.setState({ fillMax });
- };
-
- updateToAddressError = error => {
- this.setState({ toAddressError: error });
- };
-
- onFocusToAddress = () => {
- this.setState({ toFocused: true });
- };
-
review = async () => {
const { onModeChange } = this.props;
const { data } = this.state;
@@ -280,8 +85,8 @@ class TransactionEdit extends PureComponent {
if (data && data.substr(0, 2) !== '0x') {
this.updateData(addHexPrefix(data));
}
- onModeChange && onModeChange('review');
}
+ onModeChange && onModeChange('review');
};
validate = async () => {
@@ -292,13 +97,6 @@ class TransactionEdit extends PureComponent {
return amountError || gasError || toAddressError;
};
- updateAmount = async (amount, renderValue) => {
- await this.props.handleUpdateAmount(amount);
- this.props.handleUpdateReadableValue(renderValue);
- const amountError = await this.props.validateAmount(true);
- this.setState({ amountError });
- };
-
updateGas = async (gas, gasLimit) => {
await this.props.handleGasFeeSelection(gas, gasLimit);
const gasError = this.props.validateGas();
@@ -310,165 +108,26 @@ class TransactionEdit extends PureComponent {
this.props.handleUpdateData(data);
};
- updateFromAddress = from => {
- this.props.handleUpdateFromAddress(from);
- };
-
- updateToAddress = async to => {
- await this.props.handleUpdateToAddress(to);
- this.setState({ toAddressError: undefined });
- };
-
- updateAndValidateToAddress = async (to, ensRecipient) => {
- await this.props.handleUpdateToAddress(to, ensRecipient);
- let { toAddressError, toAddressWarning } = this.state;
- toAddressError = toAddressError || this.props.validateToAddress();
- toAddressWarning = toAddressWarning || this.props.checkForAssetAddress();
- this.setState({ toAddressError, toAddressWarning, ensRecipient });
- };
-
- renderAmountLabel = () => {
- const { amountError } = this.state;
- const { assetType } = this.props.transaction;
- if (assetType !== 'ERC721') {
- return (
-
- {strings('transaction.amount')}:
- {amountError ? (
- {amountError}
- ) : (
-
- {strings('transaction.max')}
-
- )}
-
- );
- }
- return (
-
- Collectible:
- {amountError ? {amountError} : undefined}
-
- );
- };
-
render() {
const {
- navigation,
- transaction: {
- value,
- gas,
- gasPrice,
- from,
- to,
- selectedAsset,
- readableValue,
- ensRecipient,
- paymentChannelTransaction
- },
- showHexData
+ transaction: { gas, gasPrice }
} = this.props;
- const { gasError, toAddressError, toAddressWarning, data, accountSelectIsOpen, ethInputIsOpen } = this.state;
+ const { gasError } = this.state;
const totalGas = isBN(gas) && isBN(gasPrice) ? gas.mul(gasPrice) : toBN('0x0');
return (
-
-
-
-
-
- {strings('transaction.from')}:
-
-
-
-
- {this.renderAmountLabel()}
-
-
-
-
- {strings('transaction.to')}:
- {toAddressError ? {toAddressError} : null}
- {!toAddressError && toAddressWarning ? (
- {toAddressWarning}
- ) : null}
-
-
-
- {!paymentChannelTransaction && (
- <>
-
-
-
-
- {showHexData && (
-
- {strings('transaction.hex_data')}:
-
- )}
- {showHexData && (
-
- )}
-
- >
- )}
-
-
-
+
);
}
}
const mapStateToProps = state => ({
- accounts: state.engine.backgroundState.AccountTrackerController.accounts,
- contractBalances: state.engine.backgroundState.TokenBalancesController.contractBalances,
- showHexData: state.settings.showHexData,
transaction: getNormalizedTxState(state)
});
diff --git a/app/components/UI/TransactionEditor/__snapshots__/index.test.js.snap b/app/components/UI/TransactionEditor/__snapshots__/index.test.js.snap
index 9436176b551..3523637f1c9 100644
--- a/app/components/UI/TransactionEditor/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionEditor/__snapshots__/index.test.js.snap
@@ -1,12 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`TransactionEditor should render correctly 1`] = `
-
-`;
+exports[`TransactionEditor should render correctly 1`] = ``;
diff --git a/app/components/UI/TransactionEditor/index.js b/app/components/UI/TransactionEditor/index.js
index 41130974e26..0c36516c8f7 100644
--- a/app/components/UI/TransactionEditor/index.js
+++ b/app/components/UI/TransactionEditor/index.js
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
+import { View, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
-import { StyleSheet, View } from 'react-native';
import { colors } from '../../../styles/common';
import ConfirmSend from '../../Views/SendFlow/Confirm';
import TransactionReview from '../TransactionReview';
@@ -17,14 +17,29 @@ import contractMap from 'eth-contract-metadata';
import PaymentChannelsClient from '../../../core/PaymentChannelsClient';
import { safeToChecksumAddress } from '../../../util/address';
import TransactionTypes from '../../../core/TransactionTypes';
+import Device from '../../../util/Device';
const EDIT = 'edit';
const REVIEW = 'review';
const styles = StyleSheet.create({
- root: {
+ reviewRoot: {
backgroundColor: colors.white,
- flex: 1
+ minHeight: 200,
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ paddingTop: 24,
+ paddingBottom: Device.isIphoneX() ? 24 : 0,
+ justifyContent: 'flex-end'
+ },
+ editRoot: {
+ backgroundColor: colors.white,
+ minHeight: 200,
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ paddingTop: 24,
+ paddingBottom: Device.isIphoneX() ? 44 : 24,
+ justifyContent: 'flex-end'
}
});
@@ -573,36 +588,40 @@ class TransactionEditor extends PureComponent {
const { mode, transactionConfirmed, transaction } = this.props;
return (
-
+
{mode === EDIT && transaction.paymentChannelTransaction && }
{mode === EDIT && !transaction.paymentChannelTransaction && (
-
+
+
+
)}
{mode === REVIEW && (
-
+
+
+
)}
-
+
);
};
}
diff --git a/app/components/UI/TransactionReview/TransactionReviewData/__snapshots__/index.test.js.snap b/app/components/UI/TransactionReview/TransactionReviewData/__snapshots__/index.test.js.snap
index 7820fefeda6..74b841eee08 100644
--- a/app/components/UI/TransactionReview/TransactionReviewData/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionReview/TransactionReviewData/__snapshots__/index.test.js.snap
@@ -4,104 +4,150 @@ exports[`TransactionReviewData should render correctly 1`] = `
+
+
+
+
+ Data
+
+
+
+
+ Data associated with this transaction
+
+
- FUNCTION TYPE
+ Function
+ :
+
-
-
- HEX DATA
+ Hex data
:
+
-
-
+ />
+
`;
diff --git a/app/components/UI/TransactionReview/TransactionReviewData/index.js b/app/components/UI/TransactionReview/TransactionReviewData/index.js
index fef3d57ab05..08b50acb187 100644
--- a/app/components/UI/TransactionReview/TransactionReviewData/index.js
+++ b/app/components/UI/TransactionReview/TransactionReviewData/index.js
@@ -1,44 +1,62 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
-import { StyleSheet, Text, View, TextInput } from 'react-native';
+import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
+import IonicIcon from 'react-native-vector-icons/Ionicons';
import { colors, fontStyles } from '../../../../styles/common';
import { strings } from '../../../../../locales/i18n';
import { connect } from 'react-redux';
const styles = StyleSheet.create({
overview: {
- paddingHorizontal: 24
+ paddingHorizontal: 24,
+ marginBottom: 24
},
- label: {
- flex: 0,
- paddingRight: 18
+ dataHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ width: '100%',
+ marginBottom: 28
},
- labelText: {
+ dataTitleText: {
...fontStyles.bold,
- color: colors.grey400,
- fontSize: 12
+ color: colors.black,
+ fontSize: 14,
+ alignSelf: 'center'
},
- functionType: {
+ dataDescription: {
+ textAlign: 'center',
...fontStyles.normal,
color: colors.black,
- fontSize: 12,
- padding: 16
+ fontSize: 14,
+ marginBottom: 28
+ },
+ dataBox: {
+ padding: 12,
+ borderWidth: 1,
+ borderColor: colors.grey200,
+ borderRadius: 8
+ },
+ hexDataContainer: {},
+ label: {
+ flexDirection: 'row',
+ justifyContent: 'flex-start',
+ marginBottom: 12
+ },
+ boldLabel: {
+ ...fontStyles.bold
+ },
+ labelText: {
+ ...fontStyles.normal,
+ color: colors.black,
+ fontSize: 14
},
hexData: {
...fontStyles.normal,
backgroundColor: colors.white,
color: colors.black,
- flex: 1,
- fontSize: 12,
- minHeight: 64,
- padding: 16
- },
- topOverviewRow: {
- borderBottomWidth: 1,
- borderColor: colors.grey200
- },
- overviewRow: {
- paddingVertical: 15
+ fontSize: 14,
+ paddingTop: 0
}
});
@@ -54,36 +72,44 @@ class TransactionReviewData extends PureComponent {
/**
* Transaction corresponding action key
*/
- actionKey: PropTypes.string
+ actionKey: PropTypes.string,
+ /**
+ * Hides or shows transaction data
+ */
+ toggleDataView: PropTypes.func
};
render = () => {
const {
transaction: { data },
- actionKey
+ actionKey,
+ toggleDataView
} = this.props;
return (
- {actionKey !== strings('transactions.tx_review_confirm') && (
-
+
+
+
+
+ {strings('transaction.data')}
+
+
+ {strings('transaction.data_description')}
+
+ {actionKey !== strings('transactions.tx_review_confirm') && (
- {strings('transaction.review_function_type')}
- {actionKey}
+
+ {strings('transaction.review_function')}:{' '}
+
+ {actionKey}
+ )}
+
+
+ {strings('transaction.review_hex_data')}:{' '}
+
+ {data}
- )}
-
-
- {strings('transaction.review_hex_data')}:
-
-
);
diff --git a/app/components/UI/TransactionReview/TransactionReviewFeeCard/__snapshots__/index.test.js.snap b/app/components/UI/TransactionReview/TransactionReviewFeeCard/__snapshots__/index.test.js.snap
index 9fb0bd45533..5d11a7f3627 100644
--- a/app/components/UI/TransactionReview/TransactionReviewFeeCard/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionReview/TransactionReviewFeeCard/__snapshots__/index.test.js.snap
@@ -4,20 +4,28 @@ exports[`TransactionReviewFeeCard should render correctly 1`] = `
-
-
- Amount
-
-
+
-
+ }
+ />
+
+
-
+ Network fee
+
+
- Network fee
+ Edit
-
-
- Edit
-
-
-
-
+
+
-
-
+ }
+ >
+
+
+
-
-
- Total
-
- Amount
-
-
+ Total
+
+ Amount
+
+
+
-
-
-
+
diff --git a/app/components/UI/TransactionReview/TransactionReviewFeeCard/index.js b/app/components/UI/TransactionReview/TransactionReviewFeeCard/index.js
index d23335ffa8f..e7b1be6abe7 100644
--- a/app/components/UI/TransactionReview/TransactionReviewFeeCard/index.js
+++ b/app/components/UI/TransactionReview/TransactionReviewFeeCard/index.js
@@ -5,16 +5,12 @@ import { colors, fontStyles } from '../../../../styles/common';
import { strings } from '../../../../../locales/i18n';
const styles = StyleSheet.create({
- overviewWrapper: {
- flexDirection: 'row',
- justifyContent: 'center'
- },
overview: {
- width: '90%',
borderWidth: 1,
borderColor: colors.grey200,
borderRadius: 10,
- padding: 16
+ padding: 16,
+ marginHorizontal: 24
},
overviewAccent: {
color: colors.blue
@@ -27,10 +23,10 @@ const styles = StyleSheet.create({
topOverviewCol: {
borderBottomWidth: 1,
borderColor: colors.grey200,
- paddingBottom: 10
+ paddingBottom: 12
},
bottomOverviewCol: {
- paddingTop: 10
+ paddingTop: 12
},
amountRow: {
width: '100%',
@@ -39,7 +35,7 @@ const styles = StyleSheet.create({
alignItems: 'center'
},
amountRowBottomSpace: {
- paddingBottom: 10
+ paddingBottom: 12
},
totalValueRow: {
justifyContent: 'flex-end'
@@ -58,7 +54,8 @@ const styles = StyleSheet.create({
paddingRight: 5
},
totalValueText: {
- color: colors.fontSecondary
+ color: colors.fontSecondary,
+ textTransform: 'uppercase'
},
loader: {
backgroundColor: colors.white,
@@ -94,7 +91,7 @@ class TransactionReviewFeeCard extends PureComponent {
/**
* Total transaction value in ETH
*/
- totalValue: PropTypes.string,
+ totalValue: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
/**
* Transaction value in ETH before gas fee
*/
@@ -148,42 +145,37 @@ class TransactionReviewFeeCard extends PureComponent {
equivalentTotalAmount = totalValue;
}
return (
-
-
-
-
- {strings('transaction.amount')}
- {amount}
-
-
-
-
- {strings('transaction.gas_fee')}
-
-
-
- {strings('transaction.edit')}
-
-
-
- {this.renderIfGasEstimationReady({networkFee})}
-
+
+
+
+ {strings('transaction.amount')}
+ {amount}
-
-
-
- {strings('transaction.total')} {strings('transaction.amount')}
+
+
+
+ {strings('transaction.gas_fee')}
- {!!totalFiat &&
- this.renderIfGasEstimationReady({totalAmount})}
-
-
- {this.renderIfGasEstimationReady(
-
- {equivalentTotalAmount}
+
+
+ {strings('transaction.edit')}
- )}
+
+ {this.renderIfGasEstimationReady({networkFee})}
+
+
+
+
+
+ {strings('transaction.total')} {strings('transaction.amount')}
+
+ {!!totalFiat && this.renderIfGasEstimationReady(totalAmount)}
+
+
+ {this.renderIfGasEstimationReady(
+ {equivalentTotalAmount}
+ )}
diff --git a/app/components/UI/TransactionReview/TransactionReviewInformation/__snapshots__/index.test.js.snap b/app/components/UI/TransactionReview/TransactionReviewInformation/__snapshots__/index.test.js.snap
index 1a0592ad43a..5b8f396ad55 100644
--- a/app/components/UI/TransactionReview/TransactionReviewInformation/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionReview/TransactionReviewInformation/__snapshots__/index.test.js.snap
@@ -1,117 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TransactionReviewInformation should render correctly 1`] = `
-
-
-
- Network fee
-
-
-
- $0
-
-
- < 0.00001 ETH
-
-
-
+
+
-
- Total
-
-
- Amount + Network fee
+ View Data
-
+
-
+
`;
diff --git a/app/components/UI/TransactionReview/TransactionReviewInformation/index.js b/app/components/UI/TransactionReview/TransactionReviewInformation/index.js
index 0255076348b..d97087dffff 100644
--- a/app/components/UI/TransactionReview/TransactionReviewInformation/index.js
+++ b/app/components/UI/TransactionReview/TransactionReviewInformation/index.js
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import PropTypes from 'prop-types';
-import { StyleSheet, Text, View } from 'react-native';
+import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { colors, fontStyles } from '../../../../styles/common';
import { connect } from 'react-redux';
import {
@@ -15,18 +15,9 @@ import {
} from '../../../../util/number';
import { strings } from '../../../../../locales/i18n';
import { getTicker, getNormalizedTxState } from '../../../../util/transactions';
+import TransactionReviewFeeCard from '../TransactionReviewFeeCard';
const styles = StyleSheet.create({
- overview: {
- paddingHorizontal: 24,
- borderTopWidth: 1,
- borderColor: colors.grey200
- },
- overviewRow: {
- alignItems: 'center',
- flexDirection: 'row',
- paddingVertical: 15
- },
overviewAlert: {
alignItems: 'center',
backgroundColor: colors.red000,
@@ -35,7 +26,9 @@ const styles = StyleSheet.create({
borderWidth: 1,
flexDirection: 'row',
height: 32,
- paddingHorizontal: 16
+ paddingHorizontal: 16,
+ marginHorizontal: 24,
+ marginTop: 12
},
overviewAlertText: {
...fontStyles.normal,
@@ -48,18 +41,6 @@ const styles = StyleSheet.create({
color: colors.red,
flex: 0
},
- topOverviewRow: {
- borderBottomWidth: 1,
- borderColor: colors.grey200
- },
- overviewLabel: {
- ...fontStyles.bold,
- color: colors.grey500,
- flex: 1,
- fontSize: 12,
- minWidth: 30,
- textTransform: 'uppercase'
- },
overviewPrimary: {
...fontStyles.bold,
color: colors.fontPrimary,
@@ -72,16 +53,8 @@ const styles = StyleSheet.create({
},
overviewEth: {
...fontStyles.normal,
- color: colors.grey500,
- fontSize: 16,
- textAlign: 'right',
- textTransform: 'uppercase'
- },
- overviewInfo: {
- ...fontStyles.normal,
- color: colors.grey500,
- fontSize: 12,
- marginBottom: 6,
+ color: colors.fontPrimary,
+ fontSize: 14,
textAlign: 'right',
textTransform: 'uppercase'
},
@@ -95,6 +68,20 @@ const styles = StyleSheet.create({
},
collectibleName: {
maxWidth: '30%'
+ },
+ viewDataWrapper: {
+ marginTop: 32,
+ marginBottom: 16
+ },
+ viewDataButton: {
+ alignSelf: 'center'
+ },
+ viewDataText: {
+ color: colors.blue,
+ textAlign: 'center',
+ fontSize: 12,
+ ...fontStyles.bold,
+ alignSelf: 'center'
}
});
@@ -126,7 +113,23 @@ class TransactionReviewInformation extends PureComponent {
/**
* Current provider ticker
*/
- ticker: PropTypes.string
+ ticker: PropTypes.string,
+ /**
+ * Transaction amount in selected asset before gas
+ */
+ assetAmount: PropTypes.string,
+ /**
+ * Transaction amount in fiat before gas
+ */
+ fiatValue: PropTypes.string,
+ /**
+ * ETH or fiat, depending on user setting
+ */
+ primaryCurrency: PropTypes.string,
+ /**
+ * Hides or shows transaction data
+ */
+ toggleDataView: PropTypes.func
};
state = {
@@ -234,32 +237,20 @@ class TransactionReviewInformation extends PureComponent {
render() {
const { amountError, totalGasFiat, totalGasEth, totalFiat, totalValue } = this.state;
- const gasPrimary = totalGasFiat || totalGasEth;
- const gasSeconday = totalGasFiat ? totalGasEth : null;
-
+ const { fiatValue, assetAmount, primaryCurrency, toggleDataView } = this.props;
return (
-
-
- {strings('transaction.gas_fee')}
-
- {gasPrimary}
- {!!gasSeconday && {totalGasEth}}
-
-
-
-
- {strings('transaction.total')}
-
-
- {`${strings('transaction.amount')} + ${strings('transaction.gas_fee')}`}
-
- {!!totalFiat && (
- {totalFiat}
- )}
- {totalValue}
-
-
-
+
+
{!!amountError && (
@@ -268,7 +259,12 @@ class TransactionReviewInformation extends PureComponent {
)}
-
+
+
+ {strings('transaction.view_data')}
+
+
+
);
}
}
@@ -278,7 +274,8 @@ const mapStateToProps = state => ({
currentCurrency: state.engine.backgroundState.CurrencyRateController.currentCurrency,
contractExchangeRates: state.engine.backgroundState.TokenRatesController.contractExchangeRates,
transaction: getNormalizedTxState(state),
- ticker: state.engine.backgroundState.NetworkController.provider.ticker
+ ticker: state.engine.backgroundState.NetworkController.provider.ticker,
+ primaryCurrency: state.settings.primaryCurrency
});
export default connect(mapStateToProps)(TransactionReviewInformation);
diff --git a/app/components/UI/TransactionReview/TransactionReviewInformation/index.test.js b/app/components/UI/TransactionReview/TransactionReviewInformation/index.test.js
index 3f9fcff93a4..0e6a69326a0 100644
--- a/app/components/UI/TransactionReview/TransactionReviewInformation/index.test.js
+++ b/app/components/UI/TransactionReview/TransactionReviewInformation/index.test.js
@@ -36,6 +36,9 @@ describe('TransactionReviewInformation', () => {
to: '0x2',
selectedAsset: undefined,
assetType: undefined
+ },
+ settings: {
+ primaryCurrency: 'ETH'
}
};
diff --git a/app/components/UI/TransactionReview/TransactionReviewSummary/__snapshots__/index.test.js.snap b/app/components/UI/TransactionReview/TransactionReviewSummary/__snapshots__/index.test.js.snap
index 9da1e1b1c48..f37d4c9950e 100644
--- a/app/components/UI/TransactionReview/TransactionReviewSummary/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionReview/TransactionReviewSummary/__snapshots__/index.test.js.snap
@@ -1,18 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TransactionReviewSummary should render correctly 1`] = `
-
+
@@ -22,15 +19,15 @@ exports[`TransactionReviewSummary should render correctly 1`] = `
Object {
"alignItems": "center",
"borderColor": "#848c96",
- "borderRadius": 4,
+ "borderRadius": 12,
"borderWidth": 1,
- "color": "#848c96",
+ "color": "#000000",
"fontFamily": "CircularStd-Medium",
- "fontSize": 12,
+ "fontSize": 10,
"fontWeight": "400",
- "lineHeight": 22,
+ "paddingHorizontal": 8,
+ "paddingVertical": 4,
"textAlign": "center",
- "width": "50%",
}
}
/>
@@ -41,7 +38,9 @@ exports[`TransactionReviewSummary should render correctly 1`] = `
"fontFamily": "CircularStd-Medium",
"fontSize": 44,
"fontWeight": "400",
- "paddingVertical": 4,
+ "paddingBottom": 4,
+ "paddingTop": 16,
+ "textAlign": "center",
"textTransform": "uppercase",
}
}
diff --git a/app/components/UI/TransactionReview/TransactionReviewSummary/index.js b/app/components/UI/TransactionReview/TransactionReviewSummary/index.js
index e7db15148ad..fa760eb9ada 100644
--- a/app/components/UI/TransactionReview/TransactionReviewSummary/index.js
+++ b/app/components/UI/TransactionReview/TransactionReviewSummary/index.js
@@ -1,71 +1,50 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, Text, View } from 'react-native';
-import {
- weiToFiat,
- balanceToFiat,
- renderFromTokenMinimalUnit,
- renderFromWei,
- fromTokenMinimalUnit
-} from '../../../../util/number';
-import { colors, fontStyles, baseStyles } from '../../../../styles/common';
+import { colors, fontStyles } from '../../../../styles/common';
import { strings } from '../../../../../locales/i18n';
-import { connect } from 'react-redux';
-import {
- APPROVE_FUNCTION_SIGNATURE,
- decodeTransferData,
- getTicker,
- getNormalizedTxState
-} from '../../../../util/transactions';
-import contractMap from 'eth-contract-metadata';
-import IonicIcon from 'react-native-vector-icons/Ionicons';
-import { safeToChecksumAddress } from '../../../../util/address';
+import WarningMessage from '../../../Views/SendFlow/WarningMessage';
const styles = StyleSheet.create({
confirmBadge: {
...fontStyles.normal,
alignItems: 'center',
borderColor: colors.grey400,
- borderRadius: 4,
+ borderRadius: 12,
borderWidth: 1,
- color: colors.grey400,
- fontSize: 12,
- lineHeight: 22,
- textAlign: 'center',
- width: '50%'
+ color: colors.black,
+ fontSize: 10,
+ paddingVertical: 4,
+ paddingHorizontal: 8,
+ textAlign: 'center'
},
summary: {
backgroundColor: colors.beige,
- padding: 24
+ padding: 24,
+ paddingTop: 12,
+ paddingBottom: 16,
+ alignItems: 'center'
},
- summaryFiat: {
+ summaryPrimary: {
...fontStyles.normal,
color: colors.fontPrimary,
fontSize: 44,
- paddingVertical: 4,
- textTransform: 'uppercase'
+ paddingTop: 16,
+ paddingBottom: 4,
+ textTransform: 'uppercase',
+ textAlign: 'center'
},
- summaryEth: {
+ summarySecondary: {
...fontStyles.normal,
- color: colors.grey400,
+ color: colors.black,
fontSize: 24,
- textTransform: 'uppercase'
+ textTransform: 'uppercase',
+ textAlign: 'center'
},
warning: {
- flex: 1,
- flexDirection: 'row',
- borderColor: colors.grey400,
- borderBottomWidth: 1,
- padding: 16,
- backgroundColor: colors.yellow100
- },
- warningText: {
- flex: 1,
- ...fontStyles.normal,
- marginHorizontal: 8,
- color: colors.grey500,
- textAlign: 'left',
- fontSize: 12
+ width: '100%',
+ paddingHorizontal: 24,
+ paddingTop: 12
}
});
@@ -74,111 +53,41 @@ const styles = StyleSheet.create({
*/
class TransactionReviewSummary extends PureComponent {
static propTypes = {
- /**
- * Transaction object associated with this transaction
- */
- transaction: PropTypes.object,
/**
* ETH to current currency conversion rate
*/
conversionRate: PropTypes.number,
/**
- * Currency code of the currently-active currency
+ * Transaction corresponding action key
*/
- currentCurrency: PropTypes.string,
+ actionKey: PropTypes.string,
/**
- * Object containing token exchange rates in the format address => exchangeRate
+ * Transaction amount in ETH before gas
*/
- contractExchangeRates: PropTypes.object,
+ assetAmount: PropTypes.string,
/**
- * Transaction corresponding action key
+ * Transaction amount in fiat before gas
*/
- actionKey: PropTypes.string,
+ fiatValue: PropTypes.string,
/**
- * Array of ERC20 assets
+ * Approve type transaction or not
*/
- tokens: PropTypes.array,
+ approveTransaction: PropTypes.bool,
/**
- * Current provider ticker
+ * ETH or fiat, depending on user setting
*/
- ticker: PropTypes.string
+ primaryCurrency: PropTypes.string
};
- state = {
- assetAmount: undefined,
- conversionRate: undefined,
- fiatValue: undefined
- };
-
- componentDidMount = () => {
- const {
- transaction: { data, to },
- tokens
- } = this.props;
- let assetAmount, conversionRate, fiatValue;
- const approveTransaction = data && data.substr(0, 10) === APPROVE_FUNCTION_SIGNATURE;
- if (approveTransaction) {
- let contract = contractMap[safeToChecksumAddress(to)];
- if (!contract) {
- contract = tokens.find(({ address }) => address === safeToChecksumAddress(to));
- }
- const symbol = (contract && contract.symbol) || 'ERC20';
- assetAmount = `${decodeTransferData('transfer', data)[1]} ${symbol}`;
- } else {
- [assetAmount, conversionRate, fiatValue] = this.getRenderValues()();
- }
- this.setState({ assetAmount, conversionRate, fiatValue, approveTransaction });
- };
-
- getRenderValues = () => {
- const {
- transaction: { value, selectedAsset, assetType },
- currentCurrency,
- contractExchangeRates,
- ticker
- } = this.props;
- const values = {
- ETH: () => {
- const assetAmount = `${renderFromWei(value)} ${getTicker(ticker)}`;
- const conversionRate = this.props.conversionRate;
- const fiatValue = weiToFiat(value, conversionRate, currentCurrency);
- return [assetAmount, conversionRate, fiatValue];
- },
- ERC20: () => {
- const assetAmount = `${renderFromTokenMinimalUnit(value, selectedAsset.decimals)} ${
- selectedAsset.symbol
- }`;
- const conversionRate = contractExchangeRates[selectedAsset.address];
- const fiatValue = balanceToFiat(
- (value && fromTokenMinimalUnit(value, selectedAsset.decimals)) || 0,
- this.props.conversionRate,
- conversionRate,
- currentCurrency
- );
- return [assetAmount, conversionRate, fiatValue];
- },
- ERC721: () => {
- const assetAmount = strings('unit.token_id') + selectedAsset.tokenId;
- const conversionRate = true;
- const fiatValue = selectedAsset.name;
- return [assetAmount, conversionRate, fiatValue];
- },
- default: () => [undefined, undefined, undefined]
- };
- return values[assetType] || values.default;
- };
+ renderWarning = () => {`${strings('transaction.approve_warning')} ${this.props.assetAmount}`};
render = () => {
- const { actionKey } = this.props;
- const { assetAmount, conversionRate, fiatValue, approveTransaction } = this.state;
+ const { actionKey, assetAmount, conversionRate, fiatValue, approveTransaction, primaryCurrency } = this.props;
return (
-
+
{!!approveTransaction && (
-
- {`${strings(
- 'transaction.approve_warning'
- )} ${assetAmount}`}
+
)}
@@ -187,11 +96,15 @@ class TransactionReviewSummary extends PureComponent {
{!conversionRate ? (
- {assetAmount}
+ {assetAmount}
) : (
- {fiatValue}
- {assetAmount}
+
+ {primaryCurrency === 'ETH' ? assetAmount : fiatValue}
+
+
+ {primaryCurrency === 'ETH' ? fiatValue : assetAmount}
+
)}
@@ -200,13 +113,4 @@ class TransactionReviewSummary extends PureComponent {
};
}
-const mapStateToProps = state => ({
- conversionRate: state.engine.backgroundState.CurrencyRateController.conversionRate,
- currentCurrency: state.engine.backgroundState.CurrencyRateController.currentCurrency,
- contractExchangeRates: state.engine.backgroundState.TokenRatesController.contractExchangeRates,
- tokens: state.engine.backgroundState.AssetsController.tokens,
- transaction: getNormalizedTxState(state),
- ticker: state.engine.backgroundState.NetworkController.provider.ticker
-});
-
-export default connect(mapStateToProps)(TransactionReviewSummary);
+export default TransactionReviewSummary;
diff --git a/app/components/UI/TransactionReview/__snapshots__/index.test.js.snap b/app/components/UI/TransactionReview/__snapshots__/index.test.js.snap
index 1333e01084a..daec782932d 100644
--- a/app/components/UI/TransactionReview/__snapshots__/index.test.js.snap
+++ b/app/components/UI/TransactionReview/__snapshots__/index.test.js.snap
@@ -1,50 +1,59 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TransactionReview should render correctly 1`] = `
-
+
+
+
-
-
-
-
+
-
+
+
-
-
-
+
+
+
`;
diff --git a/app/components/UI/TransactionReview/index.js b/app/components/UI/TransactionReview/index.js
index afa2d31aca7..c7480de7162 100644
--- a/app/components/UI/TransactionReview/index.js
+++ b/app/components/UI/TransactionReview/index.js
@@ -1,31 +1,37 @@
import React, { PureComponent } from 'react';
-import ActionView from '../ActionView';
import PropTypes from 'prop-types';
import { StyleSheet, Text, View, InteractionManager } from 'react-native';
import { colors, fontStyles } from '../../../styles/common';
import { connect } from 'react-redux';
import { strings } from '../../../../locales/i18n';
-import { getTransactionReviewActionKey, getNormalizedTxState } from '../../../util/transactions';
-import ScrollableTabView from 'react-native-scrollable-tab-view';
+import {
+ getTransactionReviewActionKey,
+ getNormalizedTxState,
+ APPROVE_FUNCTION_SIGNATURE,
+ decodeTransferData,
+ getTicker
+} from '../../../util/transactions';
+import {
+ weiToFiat,
+ balanceToFiat,
+ renderFromTokenMinimalUnit,
+ renderFromWei,
+ fromTokenMinimalUnit
+} from '../../../util/number';
+import { safeToChecksumAddress } from '../../../util/address';
+import Device from '../../../util/Device';
+import contractMap from 'eth-contract-metadata';
import DefaultTabBar from 'react-native-scrollable-tab-view/DefaultTabBar';
import TransactionReviewInformation from './TransactionReviewInformation';
-import TransactionReviewData from './TransactionReviewData';
import TransactionReviewSummary from './TransactionReviewSummary';
+import TransactionReviewData from './TransactionReviewData';
import Analytics from '../../../core/Analytics';
import { ANALYTICS_EVENT_OPTS } from '../../../util/analytics';
-import TransactionDirection from '../../Views/TransactionDirection';
+import TransactionHeader from '../TransactionHeader';
+import AccountInfoCard from '../AccountInfoCard';
+import ActionView from '../ActionView';
const styles = StyleSheet.create({
- root: {
- backgroundColor: colors.white,
- flex: 1
- },
- reviewForm: {
- flex: 1
- },
- overview: {
- flex: 1
- },
tabUnderlineStyle: {
height: 2,
backgroundColor: colors.blue
@@ -39,16 +45,31 @@ const styles = StyleSheet.create({
letterSpacing: 0.5,
...fontStyles.bold
},
- error: {
+ actionViewWrapper: {
+ height: Device.isMediumDevice() ? 200 : 385
+ },
+ actionViewChildren: {
+ height: 300
+ },
+ accountInfoCardWrapper: {
+ paddingHorizontal: 24,
+ paddingBottom: 12
+ },
+ errorWrapper: {
+ marginHorizontal: 24,
+ marginBottom: 12,
+ paddingHorizontal: 10,
+ paddingVertical: 8,
backgroundColor: colors.red000,
+ borderColor: colors.red,
+ borderRadius: 8,
+ borderWidth: 1,
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ error: {
color: colors.red,
- marginTop: 5,
- paddingVertical: 8,
- paddingHorizontal: 5,
- textAlign: 'center',
fontSize: 12,
- letterSpacing: 0.5,
- marginHorizontal: 14,
...fontStyles.normal
}
});
@@ -85,32 +106,115 @@ class TransactionReview extends PureComponent {
/**
* Callback to validate transaction in parent state
*/
- validate: PropTypes.func
+ validate: PropTypes.func,
+ /**
+ * Browser/tab information
+ */
+ browser: PropTypes.object,
+ /**
+ * ETH to current currency conversion rate
+ */
+ conversionRate: PropTypes.number,
+ /**
+ * Currency code of the currently-active currency
+ */
+ currentCurrency: PropTypes.string,
+ /**
+ * Object containing token exchange rates in the format address => exchangeRate
+ */
+ contractExchangeRates: PropTypes.object,
+ /**
+ * Array of ERC20 assets
+ */
+ tokens: PropTypes.array,
+ /**
+ * Current provider ticker
+ */
+ ticker: PropTypes.string,
+ /**
+ * ETH or fiat, depending on user setting
+ */
+ primaryCurrency: PropTypes.string
};
state = {
toFocused: false,
actionKey: strings('transactions.tx_review_confirm'),
showHexData: false,
- error: undefined
+ dataVisible: false,
+ error: undefined,
+ assetAmount: undefined,
+ conversionRate: undefined,
+ fiatValue: undefined
};
componentDidMount = async () => {
const {
validate,
transaction,
- transaction: { data }
+ transaction: { data, to },
+ tokens
} = this.props;
let { showHexData } = this.props;
+ let assetAmount, conversionRate, fiatValue;
showHexData = showHexData || data;
+ const approveTransaction = data && data.substr(0, 10) === APPROVE_FUNCTION_SIGNATURE;
const error = validate && (await validate());
const actionKey = await getTransactionReviewActionKey(transaction);
- this.setState({ error, actionKey, showHexData });
+ if (approveTransaction) {
+ let contract = contractMap[safeToChecksumAddress(to)];
+ if (!contract) {
+ contract = tokens.find(({ address }) => address === safeToChecksumAddress(to));
+ }
+ const symbol = (contract && contract.symbol) || 'ERC20';
+ assetAmount = `${decodeTransferData('transfer', data)[1]} ${symbol}`;
+ } else {
+ [assetAmount, conversionRate, fiatValue] = this.getRenderValues()();
+ }
+ this.setState({ error, actionKey, showHexData, assetAmount, conversionRate, fiatValue, approveTransaction });
InteractionManager.runAfterInteractions(() => {
Analytics.trackEvent(ANALYTICS_EVENT_OPTS.TRANSACTIONS_CONFIRM_STARTED);
});
};
+ getRenderValues = () => {
+ const {
+ transaction: { value, selectedAsset, assetType },
+ currentCurrency,
+ contractExchangeRates,
+ ticker
+ } = this.props;
+ const values = {
+ ETH: () => {
+ const assetAmount = `${renderFromWei(value)} ${getTicker(ticker)}`;
+ const conversionRate = this.props.conversionRate;
+ const fiatValue = weiToFiat(value, conversionRate, currentCurrency);
+ return [assetAmount, conversionRate, fiatValue];
+ },
+ ERC20: () => {
+ const assetAmount = `${renderFromTokenMinimalUnit(value, selectedAsset.decimals)} ${
+ selectedAsset.symbol
+ }`;
+ const conversionRate = contractExchangeRates[selectedAsset.address];
+ const fiatValue = balanceToFiat(
+ (value && fromTokenMinimalUnit(value, selectedAsset.decimals)) || 0,
+ this.props.conversionRate,
+ conversionRate,
+ currentCurrency
+ );
+ return [assetAmount, conversionRate, fiatValue];
+ },
+ ERC721: () => {
+ const assetAmount = strings('unit.token_id') + selectedAsset.tokenId;
+ const conversionRate = true;
+ const fiatValue = selectedAsset.name;
+ return [assetAmount, conversionRate, fiatValue];
+ },
+ default: () => [undefined, undefined, undefined]
+ };
+ return values[assetType] || values.default;
+ };
+
edit = () => {
const { onModeChange } = this.props;
Analytics.trackEvent(ANALYTICS_EVENT_OPTS.TRANSACTIONS_EDIT_TRANSACTION);
@@ -130,55 +234,90 @@ class TransactionReview extends PureComponent {
);
}
- renderTransactionDetails = () => {
- const { showHexData, actionKey } = this.state;
- const { transaction } = this.props;
- return (
-
- {showHexData && transaction.data ? (
-
-
-
-
- ) : (
-
- )}
-
- );
+ toggleDataView = () => {
+ this.setState({ dataVisible: !this.state.dataVisible });
};
+ getUrlFromBrowser() {
+ const { browser } = this.props;
+ let url;
+ browser.tabs.forEach(tab => {
+ if (tab.id === browser.activeTab) {
+ url = tab.url;
+ }
+ });
+ return url;
+ }
+
render = () => {
- const { transactionConfirmed } = this.props;
- const { actionKey, error } = this.state;
- return (
-
-
-
-
-
- {this.renderTransactionDetails()}
- {!!error && {error}}
+ const { transactionConfirmed, primaryCurrency } = this.props;
+ const {
+ actionKey,
+ error,
+ assetAmount,
+ conversionRate,
+ fiatValue,
+ approveTransaction,
+ dataVisible
+ } = this.state;
+ const currentPageInformation = { url: this.getUrlFromBrowser() };
+ const content = !dataVisible ? (
+ <>
+
+
+ {!!error && (
+
+ {error}
-
-
+ )}
+
+
+
+
+
+
+
+
+
+
+ >
+ ) : (
+
);
+ return <>{content}>;
};
}
const mapStateToProps = state => ({
accounts: state.engine.backgroundState.AccountTrackerController.accounts,
+ tokens: state.engine.backgroundState.AssetsController.tokens,
+ currentCurrency: state.engine.backgroundState.CurrencyRateController.currentCurrency,
+ contractExchangeRates: state.engine.backgroundState.TokenRatesController.contractExchangeRates,
+ conversionRate: state.engine.backgroundState.CurrencyRateController.conversionRate,
+ ticker: state.engine.backgroundState.NetworkController.provider.ticker,
showHexData: state.settings.showHexData,
- transaction: getNormalizedTxState(state)
+ transaction: getNormalizedTxState(state),
+ browser: state.browser,
+ primaryCurrency: state.settings.primaryCurrency
});
export default connect(mapStateToProps)(TransactionReview);
diff --git a/app/components/UI/TransactionReview/index.test.js b/app/components/UI/TransactionReview/index.test.js
index b02b3b8b84f..60f846fc440 100644
--- a/app/components/UI/TransactionReview/index.test.js
+++ b/app/components/UI/TransactionReview/index.test.js
@@ -15,11 +15,28 @@ describe('TransactionReview', () => {
},
AccountTrackerController: {
accounts: []
+ },
+ AssetsController: {
+ tokens: []
+ },
+ CurrencyRateController: {
+ currentCurrency: 'usd'
+ },
+ TokenRatesController: {
+ contractExchangeRates: {
+ '0x': '0.1'
+ }
+ },
+ NetworkController: {
+ provider: {
+ ticker: 'ETH'
+ }
}
}
},
settings: {
- showHexData: true
+ showHexData: true,
+ primaryCurrency: 'ETH'
},
transaction: {
value: '',
@@ -30,6 +47,9 @@ describe('TransactionReview', () => {
to: '0x2',
selectedAsset: undefined,
assetType: undefined
+ },
+ browser: {
+ tabs: []
}
};
diff --git a/app/components/Views/Approval/__snapshots__/index.test.js.snap b/app/components/Views/Approval/__snapshots__/index.test.js.snap
index 4db97781134..c968ce8b76f 100644
--- a/app/components/Views/Approval/__snapshots__/index.test.js.snap
+++ b/app/components/Views/Approval/__snapshots__/index.test.js.snap
@@ -1,14 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Approval should render correctly 1`] = `
-
-
+
`;
diff --git a/app/components/Views/Approval/index.js b/app/components/Views/Approval/index.js
index 91ccd298847..ed3ab1b151b 100644
--- a/app/components/Views/Approval/index.js
+++ b/app/components/Views/Approval/index.js
@@ -1,11 +1,11 @@
import React, { PureComponent } from 'react';
-import { SafeAreaView, StyleSheet, Alert, InteractionManager } from 'react-native';
+import { StyleSheet, Alert, InteractionManager } from 'react-native';
import Engine from '../../../core/Engine';
import PropTypes from 'prop-types';
import TransactionEditor from '../../UI/TransactionEditor';
+import Modal from 'react-native-modal';
import { BNToHex, hexToBN } from '../../../util/number';
import { getTransactionOptionsTitle } from '../../UI/Navbar';
-import { colors } from '../../../styles/common';
import { resetTransaction } from '../../../actions/transaction';
import { connect } from 'react-redux';
import NotificationManager from '../../../core/NotificationManager';
@@ -21,9 +21,9 @@ const EDIT = 'edit';
const APPROVAL = 'Approval';
const styles = StyleSheet.create({
- wrapper: {
- backgroundColor: colors.white,
- flex: 1
+ bottomModal: {
+ justifyContent: 'flex-end',
+ margin: 0
}
});
@@ -53,7 +53,15 @@ class Approval extends PureComponent {
/**
* A string representing the network name
*/
- networkType: PropTypes.string
+ networkType: PropTypes.string,
+ /**
+ * Hides or shows the dApp transaction modal
+ */
+ toggleDappTransactionModal: PropTypes.func,
+ /**
+ * Tells whether or not dApp transaction modal is visible
+ */
+ dappTransactionModalVisible: PropTypes.bool
};
state = {
@@ -157,7 +165,7 @@ class Approval extends PureComponent {
};
onCancel = () => {
- this.props.navigation.pop();
+ this.props.toggleDappTransactionModal();
this.state.mode === REVIEW && this.trackOnCancel();
this.showWalletConnectNotification();
};
@@ -182,7 +190,7 @@ class Approval extends PureComponent {
TransactionController.hub.once(`${transaction.id}:finished`, transactionMeta => {
if (transactionMeta.status === 'submitted') {
this.setState({ transactionHandled: true });
- this.props.navigation.pop();
+ this.props.toggleDappTransactionModal();
NotificationManager.watchSubmittedTransaction({
...transactionMeta,
assetType: transaction.assetType
@@ -258,10 +266,23 @@ class Approval extends PureComponent {
}
render = () => {
- const { transaction } = this.props;
+ const { transaction, dappTransactionModalVisible } = this.props;
const { mode } = this.state;
return (
-
+
-
+
);
};
}
diff --git a/app/components/Views/Send/index.js b/app/components/Views/Send/index.js
index 6baa11a0e2f..c9d56bc06ea 100644
--- a/app/components/Views/Send/index.js
+++ b/app/components/Views/Send/index.js
@@ -11,6 +11,7 @@ import { strings } from '../../../../locales/i18n';
import { getTransactionOptionsTitle } from '../../UI/Navbar';
import { connect } from 'react-redux';
import { resetTransaction, setTransactionObject } from '../../../actions/transaction';
+import { toggleDappTransactionModal } from '../../../actions/modals';
import NotificationManager from '../../../core/NotificationManager';
import NetworkList, { getNetworkTypeById } from '../../../util/networks';
import contractMap from 'eth-contract-metadata';
@@ -98,7 +99,15 @@ class Send extends PureComponent {
/**
* Object containing token balances in the format address => balance
*/
- contractBalances: PropTypes.object
+ contractBalances: PropTypes.object,
+ /**
+ /* Hides or shows dApp transaction modal
+ */
+ toggleDappTransactionModal: PropTypes.func,
+ /**
+ /* dApp transaction modal visible or not
+ */
+ dappTransactionModalVisible: PropTypes.bool
};
state = {
@@ -152,7 +161,9 @@ class Send extends PureComponent {
const {
navigation,
transaction: { assetType, selectedAsset },
- contractBalances
+ contractBalances,
+ dappTransactionModalVisible,
+ toggleDappTransactionModal
} = this.props;
navigation &&
navigation.setParams({
@@ -160,6 +171,7 @@ class Send extends PureComponent {
dispatch: this.onModeChange,
disableModeChange: assetType === 'ERC20' && contractBalances[selectedAsset.address] === undefined
});
+ dappTransactionModalVisible && toggleDappTransactionModal();
this.mounted = true;
await this.reset();
this.checkForDeeplinks();
@@ -644,13 +656,15 @@ const mapStateToProps = state => ({
tokens: state.engine.backgroundState.AssetsController.tokens,
network: state.engine.backgroundState.NetworkController.network,
identities: state.engine.backgroundState.PreferencesController.identities,
- selectedAddress: state.engine.backgroundState.PreferencesController.selectedAddress
+ selectedAddress: state.engine.backgroundState.PreferencesController.selectedAddress,
+ dappTransactionModalVisible: state.modals.dappTransactionModalVisible
});
const mapDispatchToProps = dispatch => ({
resetTransaction: () => dispatch(resetTransaction()),
setTransactionObject: transaction => dispatch(setTransactionObject(transaction)),
- showAlert: config => dispatch(showAlert(config))
+ showAlert: config => dispatch(showAlert(config)),
+ toggleDappTransactionModal: () => dispatch(toggleDappTransactionModal())
});
export default connect(
diff --git a/app/components/Views/SendFlow/Confirm/__snapshots__/index.test.js.snap b/app/components/Views/SendFlow/Confirm/__snapshots__/index.test.js.snap
index 839dddd0cfc..ab1045d7d6a 100644
--- a/app/components/Views/SendFlow/Confirm/__snapshots__/index.test.js.snap
+++ b/app/components/Views/SendFlow/Confirm/__snapshots__/index.test.js.snap
@@ -91,7 +91,7 @@ exports[`Confirm should render correctly 1`] = `
toggleCustomGasModal={[Function]}
totalFiat=""
totalGasFiat=""
- totalValue=""
+ totalValue={}
transactionValue=""
/>
+ {renderFromWei(transactionTotalAmountBN)} {parsedTicker}
+
+ );
transactionTotalAmountFiat = weiToFiat(transactionTotalAmountBN, conversionRate, currentCurrency);
transactionTo = to;
} else if (selectedAsset.tokenId) {
@@ -403,7 +414,11 @@ class Confirm extends PureComponent {
}
transactionValueFiat = weiToFiat(valueBN, conversionRate, currentCurrency);
const transactionTotalAmountBN = weiTransactionFee && weiTransactionFee.add(valueBN);
- transactionTotalAmount = `${renderFromWei(weiTransactionFee)} ${parsedTicker}`;
+ transactionTotalAmount = (
+
+ {renderFromWei(weiTransactionFee)} {parsedTicker}
+
+ );
transactionTotalAmountFiat = weiToFiat(transactionTotalAmountBN, conversionRate, currentCurrency);
} else {
let amount;
@@ -420,7 +435,11 @@ class Confirm extends PureComponent {
transactionValueFiat =
balanceToFiat(transferValue, conversionRate, exchangeRate, currentCurrency) || `0 ${currentCurrency}`;
const transactionValueFiatNumber = balanceToFiatNumber(transferValue, conversionRate, exchangeRate);
- transactionTotalAmount = `${transactionValue} + ${renderFromWei(weiTransactionFee)} ${parsedTicker}`;
+ transactionTotalAmount = (
+
+ {transactionValue} + ${renderFromWei(weiTransactionFee)} {parsedTicker}
+
+ );
transactionTotalAmountFiat = renderFiatAddition(
transactionValueFiatNumber,
transactionFeeFiatNumber,
@@ -871,7 +890,7 @@ class Confirm extends PureComponent {
transactionFeeFiat = '',
transactionFee,
transactionTo = '',
- transactionTotalAmount = '',
+ transactionTotalAmount = ,
transactionTotalAmountFiat = '',
errorMessage,
transactionConfirmed,
diff --git a/app/components/Views/SendFlow/CustomGas/index.js b/app/components/Views/SendFlow/CustomGas/index.js
index 4fdbac3eed2..ac526d15003 100644
--- a/app/components/Views/SendFlow/CustomGas/index.js
+++ b/app/components/Views/SendFlow/CustomGas/index.js
@@ -374,6 +374,7 @@ class CustomGas extends PureComponent {
onGasLimitChange = value => {
let warningGasLimit;
const { customGasPrice } = this.state;
+ //Added because apiEstimateModifiedToWEI doesn't like empty strings
const gasPrice = customGasPrice === '' ? '0' : customGasPrice;
const bnValue = new BN(value);
if (!value || value === '' || !isDecimal(value)) warningGasLimit = strings('transaction.invalid_gas');
diff --git a/app/reducers/modals/index.js b/app/reducers/modals/index.js
index 05d69f6f2c4..fe4b9b9ebc1 100644
--- a/app/reducers/modals/index.js
+++ b/app/reducers/modals/index.js
@@ -3,7 +3,8 @@ const initialState = {
accountsModalVisible: false,
collectibleContractModalVisible: false,
receiveModalVisible: false,
- receiveAsset: undefined
+ receiveAsset: undefined,
+ dappTransactionModalVisible: false
};
const modalsReducer = (state = initialState, action) => {
@@ -30,6 +31,11 @@ const modalsReducer = (state = initialState, action) => {
...state,
collectibleContractModalVisible: !state.collectibleContractModalVisible
};
+ case 'TOGGLE_DAPP_TRANSACTION_MODAL':
+ return {
+ ...state,
+ dappTransactionModalVisible: !state.dappTransactionModalVisible
+ };
default:
return state;
}
diff --git a/locales/en.json b/locales/en.json
index 37fd2fcf39f..16437b23191 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -490,8 +490,11 @@
"hex_data": "Hex Data",
"review_details": "DETAILS",
"review_data": "DATA",
+ "data": "Data",
+ "data_description": "Data associated with this transaction",
"review_function_type": "FUNCTION TYPE",
- "review_hex_data": "HEX DATA",
+ "review_function": "Function",
+ "review_hex_data": "Hex data",
"insufficient": "Insufficient funds",
"insufficient_tokens": "Insufficient {{token}}",
"invalid_address": "Invalid address",
@@ -527,6 +530,7 @@
"transaction_fee": "Network fee",
"transaction_fee_less": "No fee",
"total_amount": "Total amount",
+ "view_data": "View Data",
"adjust_transaction_fee": "Adjust transaction fee",
"could_not_resolve_ens": "Couldn't resolve ENS",
"asset": "Asset",
@@ -541,6 +545,7 @@
"gas_limit": "Gas Limit:",
"gas_price": "Gas Price: (GWEI)",
"save": "Save",
+ "total": "Total",
"warning_gas_limit": "Gas limit must be greater than 20999 and less than 7920027",
"cost_explanation": "Select the network fee you are willing to pay. The higher the fee, the better chances and faster your transaction will go through."
},