From 048b8084df6bc02ac0fd83c7e89ac385f13369a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 26 Aug 2019 10:12:52 +0200 Subject: [PATCH 01/61] Update the style of the buttons in modal windows --- .../ManageOwners/AddOwnerModal/screens/Review/index.jsx | 4 ++-- .../AddOwnerModal/screens/ThresholdForm/index.jsx | 4 ++-- .../components/Settings/ManageOwners/EditOwnerModal/index.jsx | 4 ++-- .../RemoveOwnerModal/screens/CheckOwner/index.jsx | 3 ++- .../ManageOwners/RemoveOwnerModal/screens/Review/index.jsx | 4 ++-- .../RemoveOwnerModal/screens/ThresholdForm/index.jsx | 4 ++-- .../ManageOwners/ReplaceOwnerModal/screens/Review/index.jsx | 4 ++-- src/routes/safe/components/Settings/RemoveSafeModal/index.jsx | 2 +- src/routes/safe/components/Settings/RemoveSafeModal/style.js | 1 + .../Settings/ThresholdSettings/ChangeThreshold/index.jsx | 4 ++-- .../Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx | 3 +-- 11 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx index 25217f5b..d7aa8ad3 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx @@ -154,15 +154,15 @@ const ReviewAddOwner = ({ - - diff --git a/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/CheckOwner/index.jsx b/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/CheckOwner/index.jsx index ff2ff84f..06946a08 100644 --- a/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/CheckOwner/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/CheckOwner/index.jsx @@ -79,13 +79,14 @@ const CheckOwner = ({ - - diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx index 1acc998e..f44cf32a 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx @@ -104,12 +104,11 @@ const ApproveTxModal = ({ - {granted && ( )} diff --git a/src/routes/safe/components/Balances/style.js b/src/routes/safe/components/Balances/style.js index 628ddecb..a0cc0584 100644 --- a/src/routes/safe/components/Balances/style.js +++ b/src/routes/safe/components/Balances/style.js @@ -30,15 +30,13 @@ export const styles = (theme: Object) => ({ justifyContent: 'flex-end', visibility: 'hidden', }, - send: { - minWidth: '0px', - marginRight: sm, - width: '70px', - }, receive: { - minWidth: '0px', width: '95px', }, + send: { + width: '70px', + marginLeft: sm, + }, leftIcon: { marginRight: xs, }, diff --git a/src/routes/safe/components/Layout.jsx b/src/routes/safe/components/Layout.jsx index d7716453..95b2635a 100644 --- a/src/routes/safe/components/Layout.jsx +++ b/src/routes/safe/components/Layout.jsx @@ -1,5 +1,6 @@ // @flow import * as React from 'react' +import classNames from 'classnames/bind' import OpenInNew from '@material-ui/icons/OpenInNew' import Tabs from '@material-ui/core/Tabs' import Tab from '@material-ui/core/Tab' @@ -9,8 +10,10 @@ import Block from '~/components/layout/Block' import Identicon from '~/components/Identicon' import Heading from '~/components/layout/Heading' import Row from '~/components/layout/Row' +import Button from '~/components/layout/Button' import Link from '~/components/layout/Link' import Paragraph from '~/components/layout/Paragraph' +import Img from '~/components/layout/Img' import NoSafe from '~/components/NoSafe' import { type SelectorProps } from '~/routes/safe/container/selector' import { getEtherScanLink } from '~/logic/wallets/getWeb3' @@ -22,6 +25,10 @@ import { type Actions } from '../container/actions' import Balances from './Balances' import Transactions from './Transactions' import Settings from './Settings' +import { styles } from './style' + +const ReceiveTx = require('./assets/tx-receive.svg') +const SendTx = require('./assets/tx-send.svg') export const BALANCES_TAB_BTN_TEST_ID = 'balances-tab-btn' export const SETTINGS_TAB_BTN_TEST_ID = 'settings-tab-btn' @@ -142,6 +149,35 @@ class Layout extends React.Component { + + + + {granted && ( + + )} + + diff --git a/src/routes/safe/components/Settings/RemoveSafeModal/style.js b/src/routes/safe/components/Settings/RemoveSafeModal/style.js index 6218de0f..99780564 100644 --- a/src/routes/safe/components/Settings/RemoveSafeModal/style.js +++ b/src/routes/safe/components/Settings/RemoveSafeModal/style.js @@ -3,7 +3,7 @@ import { lg, md, sm, error, background, } from '~/theme/variables' -export const styles = (theme: Object) => ({ +export const styles = () => ({ heading: { padding: `${sm} ${lg}`, justifyContent: 'space-between', diff --git a/src/routes/safe/components/assets/tx-receive.svg b/src/routes/safe/components/assets/tx-receive.svg new file mode 100644 index 00000000..ed5db3ba --- /dev/null +++ b/src/routes/safe/components/assets/tx-receive.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/routes/safe/components/assets/tx-send.svg b/src/routes/safe/components/assets/tx-send.svg new file mode 100644 index 00000000..b782bd49 --- /dev/null +++ b/src/routes/safe/components/assets/tx-send.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/routes/safe/components/style.js b/src/routes/safe/components/style.js new file mode 100644 index 00000000..14e11688 --- /dev/null +++ b/src/routes/safe/components/style.js @@ -0,0 +1,54 @@ +// @flow +import { sm, xs, smallFontSize } from '~/theme/variables' + +export const styles = () => ({ + container: { + display: 'flex', + alignItems: 'center', + }, + name: { + marginLeft: sm, + textOverflow: 'ellipsis', + overflow: 'hidden', + whiteSpace: 'nowrap', + }, + user: { + justifyContent: 'left', + }, + open: { + paddingLeft: sm, + width: 'auto', + '&:hover': { + cursor: 'pointer', + }, + }, + readonly: { + fontSize: smallFontSize, + letterSpacing: '0.5px', + color: '#ffffff', + backgroundColor: '#a2a8ba', + fontFamily: 'Roboto Mono, monospace', + textTransform: 'uppercase', + padding: `0 ${sm}`, + marginLeft: sm, + borderRadius: xs, + lineHeight: '28px', + }, + balance: { + marginLeft: 'auto', + overflow: 'hidden', + border: '1px solid #c8ced4', + borderRadius: '3px', + padding: '20px', + }, + receive: { + width: '95px', + }, + send: { + width: '70px', + marginLeft: sm, + }, + leftIcon: { + marginRight: xs, + }, +}) From fb95d6a6ffc5f4e6a308086b08522a7f5f58a11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 26 Aug 2019 11:54:52 +0200 Subject: [PATCH 03/61] Fix style of buttons --- src/routes/safe/components/Balances/Receive/index.jsx | 5 +---- .../Balances/SendModal/screens/ReviewTx/index.jsx | 3 +-- .../Balances/SendModal/screens/SendFunds/index.jsx | 2 +- .../Balances/Tokens/screens/AddCustomToken/index.jsx | 4 ++-- .../Balances/Tokens/screens/AddCustomToken/style.js | 3 --- src/routes/safe/components/Balances/style.js | 8 +++++--- .../TxsTable/ExpandedTx/CancelTxModal/index.jsx | 3 +-- src/routes/safe/components/style.js | 6 ++++-- 8 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/routes/safe/components/Balances/Receive/index.jsx b/src/routes/safe/components/Balances/Receive/index.jsx index 50c3300a..414b6929 100644 --- a/src/routes/safe/components/Balances/Receive/index.jsx +++ b/src/routes/safe/components/Balances/Receive/index.jsx @@ -48,9 +48,6 @@ const styles = () => ({ height: '84px', justifyContent: 'center', }, - button: { - height: '42px', - }, addressContainer: { marginTop: '28px', }, @@ -109,7 +106,7 @@ const Receive = ({ - diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx index 9d233a14..a41c1c02 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx @@ -138,12 +138,11 @@ const ReviewTx = ({ - - diff --git a/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/style.js b/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/style.js index b09dcabb..3dd3b0ab 100644 --- a/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/style.js +++ b/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/style.js @@ -28,7 +28,4 @@ export const styles = () => ({ height: '84px', justifyContent: 'center', }, - button: { - height: '42px', - }, }) diff --git a/src/routes/safe/components/Balances/style.js b/src/routes/safe/components/Balances/style.js index a0cc0584..5538c94f 100644 --- a/src/routes/safe/components/Balances/style.js +++ b/src/routes/safe/components/Balances/style.js @@ -1,5 +1,5 @@ // @flow -import { sm, xs } from '~/theme/variables' +import { sm } from '~/theme/variables' export const styles = (theme: Object) => ({ root: { @@ -32,13 +32,15 @@ export const styles = (theme: Object) => ({ }, receive: { width: '95px', + minWidth: '95px', }, send: { - width: '70px', + width: '75px', + minWidth: '75px', marginLeft: sm, }, leftIcon: { - marginRight: xs, + marginRight: sm, }, links: { textDecoration: 'underline', diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/CancelTxModal/index.jsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/CancelTxModal/index.jsx index ad18d01c..05c25121 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/CancelTxModal/index.jsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/CancelTxModal/index.jsx @@ -65,12 +65,11 @@ const CancelTxModal = ({ - + + + + )} + + + + ) +} + +export default withStyles(styles)(SendCustomTx) From 00d44a4c969985a8ec24f8fa6dd4c7b6575bdbeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Wed, 28 Aug 2019 18:16:29 +0200 Subject: [PATCH 11/61] Add send custom tx styles --- .../SendModal/screens/SendCustomTx/style.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js new file mode 100644 index 00000000..841c5d43 --- /dev/null +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js @@ -0,0 +1,37 @@ +// @flow +import { lg, md, sm } from '~/theme/variables' + +export const styles = () => ({ + heading: { + padding: `${sm} ${lg}`, + justifyContent: 'flex-start', + boxSizing: 'border-box', + maxHeight: '75px', + }, + annotation: { + letterSpacing: '-1px', + color: '#a2a8ba', + marginRight: 'auto', + marginLeft: '20px', + }, + manage: { + fontSize: '24px', + }, + closeIcon: { + height: '35px', + width: '35px', + }, + formContainer: { + padding: `${md} ${lg}`, + }, + buttonRow: { + height: '84px', + justifyContent: 'center', + }, + dataInput: { + '& TextField-root-294': { + lineHeight: 'auto', + border: 'green', + }, + }, +}) From e0544241aed44d72a1b4e790fa03a4a1e5373ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Wed, 28 Aug 2019 18:41:08 +0200 Subject: [PATCH 12/61] Remove props from SendModal --- src/routes/safe/components/Balances/SendModal/index.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/index.jsx b/src/routes/safe/components/Balances/SendModal/index.jsx index cca7b405..b07b9ae2 100644 --- a/src/routes/safe/components/Balances/SendModal/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/index.jsx @@ -85,7 +85,6 @@ const Send = ({ {activeScreen === 'sendFunds' && ( Date: Mon, 2 Sep 2019 09:55:28 +0200 Subject: [PATCH 13/61] Refactor UI --- .../components/Balances/SendModal/index.jsx | 29 ++-- .../SendModal/screens/SendCustomTx/index.jsx | 135 ++++++++++++------ src/routes/safe/components/Balances/index.jsx | 21 +-- src/routes/safe/components/Balances/style.js | 2 +- src/routes/safe/components/Layout.jsx | 91 ++++++------ .../safe/components/assets/tx-receive.svg | 3 - src/routes/safe/components/assets/tx-send.svg | 3 - src/routes/safe/components/style.js | 12 +- 8 files changed, 158 insertions(+), 138 deletions(-) delete mode 100644 src/routes/safe/components/assets/tx-receive.svg delete mode 100644 src/routes/safe/components/assets/tx-send.svg diff --git a/src/routes/safe/components/Balances/SendModal/index.jsx b/src/routes/safe/components/Balances/SendModal/index.jsx index b07b9ae2..abd535f1 100644 --- a/src/routes/safe/components/Balances/SendModal/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/index.jsx @@ -36,7 +36,7 @@ type TxStateType = | Object const styles = () => ({ - smallerModalWindow: { + scalableModalWindow: { height: 'auto', position: 'static', }, @@ -57,30 +57,33 @@ const Send = ({ }: Props) => { const [activeScreen, setActiveScreen] = useState(activeScreenType || 'chooseTxType') const [tx, setTx] = useState({}) - const smallerModalSize = activeScreen === 'chooseTxType' - const handleTxCreation = (txInfo) => { - setActiveScreen('reviewTx') - setTx(txInfo) - } - const handleCustomTxCreation = (customTxInfo) => { - setActiveScreen('reviewCustomTx') - setTx(customTxInfo) - } useEffect(() => { setActiveScreen(activeScreenType || 'chooseTxType') setTx({}) }, [isOpen]) + const scalableModalSize = activeScreen === 'chooseTxType' || activeScreen === 'sendCustomTx' + + const handleTxCreation = (txInfo) => { + setActiveScreen('reviewTx') + setTx(txInfo) + } + + const handleCustomTxCreation = (customTxInfo) => { + setActiveScreen('reviewCustomTx') + setTx(customTxInfo) + } + return ( - + <> {activeScreen === 'chooseTxType' && } {activeScreen === 'sendFunds' && ( )} - + ) } diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index 39b9a025..1369c392 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -2,6 +2,7 @@ import React from 'react' import { withStyles } from '@material-ui/core/styles' import Close from '@material-ui/icons/Close' +import InputAdornment from '@material-ui/core/InputAdornment' import IconButton from '@material-ui/core/IconButton' import Paragraph from '~/components/layout/Paragraph' import Row from '~/components/layout/Row' @@ -10,6 +11,7 @@ import Col from '~/components/layout/Col' import Button from '~/components/layout/Button' import Block from '~/components/layout/Block' import Hairline from '~/components/layout/Hairline' +import ButtonLink from '~/components/layout/ButtonLink' import Field from '~/components/forms/Field' import TextField from '~/components/forms/TextField' import TextareaField from '~/components/forms/TextareaField' @@ -17,6 +19,9 @@ import { composeValidators, required, mustBeEthereumAddress, + mustBeFloat, + maxValue, + greaterThan, } from '~/components/forms/validator' import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo' import ArrowDown from '../assets/arrow-down.svg' @@ -47,10 +52,14 @@ const SendCustomTx = ({ onSubmit(values) } - const formMutators = {} + const formMutators = { + setMax: (args, state, utils) => { + utils.changeValue(state, 'amount', () => ethBalance) + }, + } return ( - + <> Send custom transactions @@ -72,52 +81,86 @@ const SendCustomTx = ({ - {() => ( - - - - - - - - - - - - - - - - - - )} + {(...args) => { + const mutators = args[3] + + return ( + <> + + + + + + + + + Amount + + + Send max + + + + + + ETH, + }} + /> + + + + + + + + + + + + + + ) + }} - + ) } diff --git a/src/routes/safe/components/Balances/index.jsx b/src/routes/safe/components/Balances/index.jsx index eb781720..149ccc25 100644 --- a/src/routes/safe/components/Balances/index.jsx +++ b/src/routes/safe/components/Balances/index.jsx @@ -6,13 +6,14 @@ import Checkbox from '@material-ui/core/Checkbox' import TableRow from '@material-ui/core/TableRow' import TableCell from '@material-ui/core/TableCell' import { withStyles } from '@material-ui/core/styles' +import CallMade from '@material-ui/icons/CallMade' +import CallReceived from '@material-ui/icons/CallReceived' import { type Token } from '~/logic/tokens/store/model/token' import Col from '~/components/layout/Col' import Row from '~/components/layout/Row' import Button from '~/components/layout/Button' import ButtonLink from '~/components/layout/ButtonLink' import Paragraph from '~/components/layout/Paragraph' -import Img from '~/components/layout/Img' import Modal from '~/components/Modal' import { type Column, cellWidth } from '~/components/Table/TableHead' import Table from '~/components/Table' @@ -25,9 +26,6 @@ import SendModal from './SendModal' import Receive from './Receive' import { styles } from './style' -const ReceiveTx = require('../assets/tx-receive.svg') -const SendTx = require('../assets/tx-send.svg') - export const MANAGE_TOKENS_BUTTON_TEST_ID = 'manage-tokens-btn' export const BALANCE_ROW_TEST_ID = 'balance-row' @@ -171,17 +169,6 @@ class Balances extends React.Component { ))} - {granted && ( )} @@ -202,7 +189,7 @@ class Balances extends React.Component { className={classes.receive} onClick={this.onShow('Receive')} > - + Receive diff --git a/src/routes/safe/components/Balances/style.js b/src/routes/safe/components/Balances/style.js index 5538c94f..224dac23 100644 --- a/src/routes/safe/components/Balances/style.js +++ b/src/routes/safe/components/Balances/style.js @@ -33,11 +33,11 @@ export const styles = (theme: Object) => ({ receive: { width: '95px', minWidth: '95px', + marginLeft: sm, }, send: { width: '75px', minWidth: '75px', - marginLeft: sm, }, leftIcon: { marginRight: sm, diff --git a/src/routes/safe/components/Layout.jsx b/src/routes/safe/components/Layout.jsx index e62d4b3a..5957e5fd 100644 --- a/src/routes/safe/components/Layout.jsx +++ b/src/routes/safe/components/Layout.jsx @@ -4,6 +4,8 @@ import classNames from 'classnames/bind' import OpenInNew from '@material-ui/icons/OpenInNew' import Tabs from '@material-ui/core/Tabs' import Tab from '@material-ui/core/Tab' +import CallMade from '@material-ui/icons/CallMade' +import CallReceived from '@material-ui/icons/CallReceived' import { withStyles } from '@material-ui/core/styles' import Hairline from '~/components/layout/Hairline' import Block from '~/components/layout/Block' @@ -13,7 +15,6 @@ import Row from '~/components/layout/Row' import Button from '~/components/layout/Button' import Link from '~/components/layout/Link' import Paragraph from '~/components/layout/Paragraph' -import Img from '~/components/layout/Img' import Modal from '~/components/Modal' import SendModal from './Balances/SendModal' import Receive from './Balances/Receive' @@ -21,7 +22,7 @@ import NoSafe from '~/components/NoSafe' import { type SelectorProps } from '~/routes/safe/container/selector' import { getEtherScanLink } from '~/logic/wallets/getWeb3' import { - sm, xs, secondary, smallFontSize, border, secondaryText, + secondary, border, } from '~/theme/variables' import { copyToClipboard } from '~/utils/clipboard' import { type Actions } from '../container/actions' @@ -30,9 +31,6 @@ import Transactions from './Transactions' import Settings from './Settings' import { styles } from './style' -const ReceiveTx = require('./assets/tx-receive.svg') -const SendTx = require('./assets/tx-send.svg') - export const BALANCES_TAB_BTN_TEST_ID = 'balances-tab-btn' export const SETTINGS_TAB_BTN_TEST_ID = 'settings-tab-btn' export const TRANSACTIONS_TAB_BTN_TEST_ID = 'transactions-tab-btn' @@ -59,40 +57,6 @@ const openIconStyle = { color: secondary, } -const styles = () => ({ - container: { - display: 'flex', - alignItems: 'center', - }, - name: { - marginLeft: sm, - textOverflow: 'ellipsis', - overflow: 'hidden', - whiteSpace: 'nowrap', - }, - user: { - justifyContent: 'left', - }, - open: { - paddingLeft: sm, - width: 'auto', - '&:hover': { - cursor: 'pointer', - }, - }, - readonly: { - fontSize: smallFontSize, - letterSpacing: '0.5px', - color: '#ffffff', - backgroundColor: secondaryText, - textTransform: 'uppercase', - padding: `0 ${sm}`, - marginLeft: sm, - borderRadius: xs, - lineHeight: '28px', - }, -}) - class Layout extends React.Component { constructor(props) { super(props) @@ -166,17 +130,6 @@ class Layout extends React.Component { - {granted && ( )} + @@ -241,6 +205,31 @@ class Layout extends React.Component { createTransaction={createTransaction} /> )} + + + + ) } diff --git a/src/routes/safe/components/assets/tx-receive.svg b/src/routes/safe/components/assets/tx-receive.svg deleted file mode 100644 index ed5db3ba..00000000 --- a/src/routes/safe/components/assets/tx-receive.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/routes/safe/components/assets/tx-send.svg b/src/routes/safe/components/assets/tx-send.svg deleted file mode 100644 index b782bd49..00000000 --- a/src/routes/safe/components/assets/tx-send.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/routes/safe/components/style.js b/src/routes/safe/components/style.js index 1ddc0acf..3a579e8a 100644 --- a/src/routes/safe/components/style.js +++ b/src/routes/safe/components/style.js @@ -1,5 +1,7 @@ // @flow -import { sm, xs, smallFontSize } from '~/theme/variables' +import { + sm, xs, smallFontSize, secondaryText, +} from '~/theme/variables' export const styles = () => ({ container: { @@ -26,14 +28,16 @@ export const styles = () => ({ fontSize: smallFontSize, letterSpacing: '0.5px', color: '#ffffff', - backgroundColor: '#a2a8ba', - fontFamily: 'Roboto Mono, monospace', + backgroundColor: secondaryText, textTransform: 'uppercase', padding: `0 ${sm}`, marginLeft: sm, borderRadius: xs, lineHeight: '28px', }, + iconSmall: { + fontSize: 16, + }, balance: { marginLeft: 'auto', overflow: 'hidden', @@ -44,11 +48,11 @@ export const styles = () => ({ receive: { width: '95px', minWidth: '95px', + marginLeft: sm, }, send: { width: '75px', minWidth: '75px', - marginLeft: sm, }, leftIcon: { marginRight: sm, From 1adeda041cbe467fc22560543a0cb1a244df3416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 2 Sep 2019 10:34:19 +0200 Subject: [PATCH 14/61] Update data placeholder and text --- .../Balances/SendModal/screens/SendCustomTx/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index 1369c392..169b8c45 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -134,8 +134,8 @@ const SendCustomTx = ({ From 256c78816f992a6b1a8d02d7a481dcd807284bbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 2 Sep 2019 11:21:56 +0200 Subject: [PATCH 15/61] Make send button disabled if not owner connected --- src/routes/safe/components/Layout.jsx | 27 +++++++++++++-------------- src/routes/safe/components/style.js | 1 - 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/routes/safe/components/Layout.jsx b/src/routes/safe/components/Layout.jsx index 5957e5fd..c4534d70 100644 --- a/src/routes/safe/components/Layout.jsx +++ b/src/routes/safe/components/Layout.jsx @@ -130,20 +130,19 @@ class Layout extends React.Component { - {granted && ( - - )} + From b88972e7a051246fbf17a3443c81d7ca937a51b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 2 Sep 2019 19:01:22 +0200 Subject: [PATCH 17/61] Add basic custom tx review --- .../components/Balances/SendModal/index.jsx | 24 ++- .../screens/ReviewCustomTx/index.jsx | 144 ++++++++++++++++++ .../SendModal/screens/ReviewCustomTx/style.js | 51 +++++++ 3 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx create mode 100644 src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js diff --git a/src/routes/safe/components/Balances/SendModal/index.jsx b/src/routes/safe/components/Balances/SendModal/index.jsx index abd535f1..8ffae44a 100644 --- a/src/routes/safe/components/Balances/SendModal/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/index.jsx @@ -9,6 +9,7 @@ import ChooseTxType from './screens/ChooseTxType' import SendFunds from './screens/SendFunds' import ReviewTx from './screens/ReviewTx' import SendCustomTx from './screens/SendCustomTx' +import ReviewCustomTx from './screens/ReviewCustomTx' type Props = { onClose: () => void, @@ -38,6 +39,9 @@ type TxStateType = const styles = () => ({ scalableModalWindow: { height: 'auto', + }, + scalableStaticModalWindow: { + height: 'auto', position: 'static', }, }) @@ -63,7 +67,8 @@ const Send = ({ setTx({}) }, [isOpen]) - const scalableModalSize = activeScreen === 'chooseTxType' || activeScreen === 'sendCustomTx' + const scalableModalSize = activeScreen === 'sendCustomTx' || activeScreen === 'reviewCustomTx' + const scalableStaticModalSize = activeScreen === 'chooseTxType' const handleTxCreation = (txInfo) => { setActiveScreen('reviewTx') @@ -81,7 +86,10 @@ const Send = ({ description="Send Tokens Form" handleClose={onClose} open={isOpen} - paperClassName={cn(scalableModalSize && classes.scalableModalWindow)} + paperClassName={cn( + scalableStaticModalSize && classes.scalableStaticModalWindow, + scalableModalSize && classes.scalableModalWindow, + )} > <> {activeScreen === 'chooseTxType' && } @@ -121,6 +129,18 @@ const Send = ({ initialValues={tx} /> )} + {activeScreen === 'reviewCustomTx' && ( + + )} ) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx new file mode 100644 index 00000000..e7767ce1 --- /dev/null +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -0,0 +1,144 @@ +// @flow +import React from 'react' +import OpenInNew from '@material-ui/icons/OpenInNew' +import { withStyles } from '@material-ui/core/styles' +import Close from '@material-ui/icons/Close' +import IconButton from '@material-ui/core/IconButton' +import { SharedSnackbarConsumer } from '~/components/SharedSnackBar' +import Paragraph from '~/components/layout/Paragraph' +import Row from '~/components/layout/Row' +import Link from '~/components/layout/Link' +import Col from '~/components/layout/Col' +import Button from '~/components/layout/Button' +import Img from '~/components/layout/Img' +import Block from '~/components/layout/Block' +import Identicon from '~/components/Identicon' +import { copyToClipboard } from '~/utils/clipboard' +import Hairline from '~/components/layout/Hairline' +import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo' +import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils' +import ArrowDown from '../assets/arrow-down.svg' +import { secondary } from '~/theme/variables' +import { styles } from './style' + +type Props = { + onClose: () => void, + setActiveScreen: Function, + classes: Object, + safeAddress: string, + etherScanLink: string, + safeName: string, + ethBalance: string, + tx: Object, +} + +const openIconStyle = { + height: '16px', + color: secondary, +} + +const ReviewCustomTx = ({ + onClose, + setActiveScreen, + classes, + safeAddress, + etherScanLink, + safeName, + ethBalance, + tx, +}: Props) => ( + + {() => { + const submitTx = async () => { + + } + + return ( + <> + + + Send Funds + + 2 of 2 + + + + + + + + + + Arrow Down + + + + + + + + Recipient + + + + + + + + + {tx.recipientAddress} + + + + + + + + + Value + + + + Ether + + {tx.value} + {'ETH'} + + + + + + {tx.data} + + + + + + + + + + + ) + }} + +) + +export default withStyles(styles)(ReviewCustomTx) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js new file mode 100644 index 00000000..cfb0904b --- /dev/null +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js @@ -0,0 +1,51 @@ +// @flow +import { + lg, md, sm, secondaryText, border, +} from '~/theme/variables' + +export const styles = () => ({ + heading: { + padding: `${sm} ${lg}`, + justifyContent: 'flex-start', + boxSizing: 'border-box', + maxHeight: '75px', + }, + annotation: { + letterSpacing: '-1px', + color: secondaryText, + marginRight: 'auto', + marginLeft: '20px', + }, + headingText: { + fontSize: '24px', + }, + closeIcon: { + height: '35px', + width: '35px', + }, + container: { + padding: `${md} ${lg}`, + }, + value: { + marginLeft: sm, + }, + outerData: { + borderRadius: '5px', + border: `1px solid ${border}`, + padding: '11px', + }, + data: { + wordBreak: 'break-all', + overflow: 'auto', + fontSize: '14px', + fontFamily: 'Averta', + maxHeight: '100px', + letterSpacing: 'normal', + fontStretch: 'normal', + lineHeight: '1.43', + }, + buttonRow: { + height: '84px', + justifyContent: 'center', + }, +}) From 0f38ebd60a5cd85b86023e900c754bf8ff9146ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Thu, 5 Sep 2019 11:15:53 +0200 Subject: [PATCH 18/61] Create transaction from review custome tx modal window --- .../SendModal/screens/ReviewCustomTx/index.jsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index e7767ce1..80758280 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -17,6 +17,7 @@ import { copyToClipboard } from '~/utils/clipboard' import Hairline from '~/components/layout/Hairline' import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo' import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils' +import { getWeb3 } from '~/logic/wallets/getWeb3' import ArrowDown from '../assets/arrow-down.svg' import { secondary } from '~/theme/variables' import { styles } from './style' @@ -30,6 +31,7 @@ type Props = { safeName: string, ethBalance: string, tx: Object, + createTransaction: Function, } const openIconStyle = { @@ -46,11 +48,18 @@ const ReviewCustomTx = ({ safeName, ethBalance, tx, + createTransaction, }: Props) => ( - {() => { + {({ openSnackbar }) => { const submitTx = async () => { + const web3 = getWeb3() + const txRecipient = tx.recipientAddress + let txData = tx.data + let txValue = tx.value ? web3.utils.toWei(tx.value, 'ether') : 0 + createTransaction(safeAddress, txRecipient, txValue, txData, openSnackbar) + onClose() } return ( @@ -104,7 +113,7 @@ const ReviewCustomTx = ({ - Ether + {'Ether'} {tx.value} {'ETH'} From 6372674fa67128a28ae40c860203b61410a526aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Thu, 5 Sep 2019 11:36:15 +0200 Subject: [PATCH 19/61] Handle custom transactions in transaction list --- .../screens/ReviewCustomTx/index.jsx | 6 ++-- .../ExpandedTx/TxDescription/index.jsx | 28 +++++++++++++++++-- .../ExpandedTx/TxDescription/utils.js | 5 ++++ .../Transactions/TxsTable/columns.js | 2 ++ .../safe/store/actions/fetchTransactions.js | 4 +++ src/routes/safe/store/models/transaction.js | 2 ++ 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index 80758280..bf7b607f 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -55,8 +55,8 @@ const ReviewCustomTx = ({ const submitTx = async () => { const web3 = getWeb3() const txRecipient = tx.recipientAddress - let txData = tx.data - let txValue = tx.value ? web3.utils.toWei(tx.value, 'ether') : 0 + const txData = tx.data + const txValue = tx.value ? web3.utils.toWei(tx.value, 'ether') : 0 createTransaction(safeAddress, txRecipient, txValue, txData, openSnackbar) onClose() @@ -113,7 +113,7 @@ const ReviewCustomTx = ({ - {'Ether'} + Ether {tx.value} {'ETH'} diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx index 8508e9d3..b4123640 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx @@ -13,11 +13,15 @@ export const TRANSACTIONS_DESC_ADD_OWNER_TEST_ID = 'tx-description-add-owner' export const TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID = 'tx-description-remove-owner' export const TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID = 'tx-description-change-threshold' export const TRANSACTIONS_DESC_SEND_TEST_ID = 'tx-description-send' +export const TRANSACTIONS_DESC_CUSTOM_TEST_ID = 'tx-description-custom' export const styles = () => ({ txDataContainer: { padding: `${lg} ${md}`, }, + txData: { + wordBreak: 'break-all', + }, }) type Props = { @@ -37,6 +41,11 @@ type DescriptionDescProps = { newThreshold?: string, } +type CustomDescProps = { + data: String, + classes: Obeject, +} + const TransferDescription = ({ value = '', symbol, recipient }: TransferDescProps) => ( @@ -46,7 +55,7 @@ const TransferDescription = ({ value = '', symbol, recipient }: TransferDescProp {' '} {symbol} {' '} -to: + to:
@@ -79,9 +88,19 @@ const SettingsDescription = ({ removedOwner, addedOwner, newThreshold }: Descrip ) +const CustomDescription = ({ data, classes }: CustomDescProps) => ( + <> + + Data (hex encoded): +
+ {data} +
+ +) + const TxDescription = ({ tx, classes }: Props) => { const { - recipient, value, modifySettingsTx, removedOwner, addedOwner, newThreshold, cancellationTx, + recipient, value, modifySettingsTx, removedOwner, addedOwner, newThreshold, cancellationTx, customTx, data, } = getTxData(tx) return ( @@ -89,7 +108,10 @@ const TxDescription = ({ tx, classes }: Props) => { {modifySettingsTx && ( )} - {!cancellationTx && !modifySettingsTx && ( + {customTx && ( + + )} + {!cancellationTx && !modifySettingsTx && !customTx && ( )}
diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js index dd9744da..affddad6 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js @@ -10,6 +10,8 @@ type DecodedTxData = { newThreshold?: string, addedOwner?: string, cancellationTx?: boolean, + customTx?: boolean, + data: string, } export const getTxData = (tx: Transaction): DecodedTxData => { @@ -47,6 +49,9 @@ export const getTxData = (tx: Transaction): DecodedTxData => { } } else if (tx.cancellationTx) { txData.cancellationTx = true + } else if (tx.customTx) { + txData.data = tx.data + txData.customTx = true } return txData diff --git a/src/routes/safe/components/Transactions/TxsTable/columns.js b/src/routes/safe/components/Transactions/TxsTable/columns.js index 2a61828d..a908e375 100644 --- a/src/routes/safe/components/Transactions/TxsTable/columns.js +++ b/src/routes/safe/components/Transactions/TxsTable/columns.js @@ -50,6 +50,8 @@ export const getTxTableData = (transactions: List): List = Record({ cancelled: false, modifySettingsTx: false, cancellationTx: false, + customTx: false, status: 'awaiting', isTokenTransfer: false, decodedParams: {}, From 36b817d34fc4366d6cb2db16e2e2c5848913f349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Thu, 5 Sep 2019 11:55:08 +0200 Subject: [PATCH 20/61] Add ethereum contract address validator --- src/components/forms/AddressInput/index.jsx | 4 ++++ src/components/forms/validator.js | 8 ++++++++ .../Balances/SendModal/screens/SendCustomTx/index.jsx | 1 + 3 files changed, 13 insertions(+) diff --git a/src/components/forms/AddressInput/index.jsx b/src/components/forms/AddressInput/index.jsx index 71217c95..1ad3ea3a 100644 --- a/src/components/forms/AddressInput/index.jsx +++ b/src/components/forms/AddressInput/index.jsx @@ -7,6 +7,7 @@ import { composeValidators, required, mustBeEthereumAddress, + mustBeEthereumContractAddress, } from '~/components/forms/validator' import { getAddressFromENS } from '~/logic/wallets/getWeb3' @@ -19,6 +20,7 @@ type Props = { testId?: string, validators?: Function[], inputAdornment?: React.Element, + mustBeContract?: boolean, } const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name) @@ -35,6 +37,7 @@ const AddressInput = ({ testId, inputAdornment, validators = [], + mustBeContract, }: Props): React.Element<*> => ( <> { return isAddress ? undefined : 'Address should be a valid Ethereum address or ENS name' }) +export const mustBeEthereumContractAddress = simpleMemoize(async (address: Field) => { + const contractCode: string = await getWeb3().eth.getCode(address) + + return (!contractCode || contractCode.replace('0x', '').replace(/0/g, '') === '') + ? 'Address should be a valid Ethereum contract address or ENS name' + : undefined +}) + export const minMaxLength = (minLen: string | number, maxLen: string | number) => (value: string) => (value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols`) export const ADDRESS_REPEATED_ERROR = 'Address already introduced' diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index c580078d..76cc8d46 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -99,6 +99,7 @@ const SendCustomTx = ({ text="Recipient*" className={classes.addressInput} fieldMutator={mutators.setRecipient} + mustBeContract /> From 188b00fd622af96e85ea2d6f745568bb5b3cd01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Thu, 5 Sep 2019 12:14:05 +0200 Subject: [PATCH 21/61] Fix labels --- .../Balances/SendModal/screens/ReviewCustomTx/index.jsx | 5 +++++ .../Balances/SendModal/screens/ReviewCustomTx/style.js | 1 + .../Balances/SendModal/screens/SendCustomTx/index.jsx | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index bf7b607f..72546ede 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -119,6 +119,11 @@ const ReviewCustomTx = ({ {'ETH'} + + + Data (hex encoded) + + diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js index cfb0904b..374c1840 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js @@ -33,6 +33,7 @@ export const styles = () => ({ borderRadius: '5px', border: `1px solid ${border}`, padding: '11px', + minHeight: '21px', }, data: { wordBreak: 'break-all', diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index 76cc8d46..bc1d47b5 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -106,7 +106,7 @@ const SendCustomTx = ({ - Amount + Value Send max From 425d481a7d143664946f4f3bff96309080242c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Thu, 5 Sep 2019 12:32:00 +0200 Subject: [PATCH 22/61] Fix value icon in custom tx review modal --- .../Balances/SendModal/screens/ReviewCustomTx/index.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index 72546ede..13208568 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -18,6 +18,7 @@ import Hairline from '~/components/layout/Hairline' import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo' import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils' import { getWeb3 } from '~/logic/wallets/getWeb3' +import { getEthAsToken } from '~/logic/tokens/utils/tokenHelpers' import ArrowDown from '../assets/arrow-down.svg' import { secondary } from '~/theme/variables' import { styles } from './style' @@ -113,7 +114,7 @@ const ReviewCustomTx = ({ - Ether + Ether {tx.value} {'ETH'} From a04757ab59fd5b43eac3c74ef1f379b7e1ce4a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 9 Sep 2019 10:12:03 +0200 Subject: [PATCH 23/61] Fix composeValidators --- src/components/forms/validator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/forms/validator.js b/src/components/forms/validator.js index 119058ad..284c90e5 100644 --- a/src/components/forms/validator.js +++ b/src/components/forms/validator.js @@ -83,7 +83,7 @@ export const uniqueAddress = (addresses: string[] | List) => simpleMemoi return addressAlreadyExists ? ADDRESS_REPEATED_ERROR : undefined }) -export const composeValidators = (...validators: Function[]): FieldValidator => (value: Field) => validators.reduce((error, validator) => error || validator(value), undefined) +export const composeValidators = (...validators: Function[]): FieldValidator => (value: Field) => validators.reduce((error, validator) => error || (validator && validator(value)), undefined) export const inLimit = (limit: number, base: number, baseText: string, symbol: string = 'ETH') => (value: string) => { const amount = Number(value) From 277bbce1794b9a5605dfeaf3cfdd3499a1418cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 9 Sep 2019 10:45:08 +0200 Subject: [PATCH 24/61] Remove React Fragments --- src/components/Header/component/CircleDot.jsx | 4 ++-- .../open/components/ReviewInformation/index.jsx | 8 ++++---- src/routes/open/components/SafeNameForm/index.jsx | 4 ++-- .../safe/components/Balances/Receive/index.jsx | 4 ++-- .../SendModal/screens/ChooseTxType/index.jsx | 4 ++-- .../safe/components/Balances/Tokens/index.jsx | 4 ++-- .../Tokens/screens/AddCustomToken/index.jsx | 8 ++++---- .../Balances/Tokens/screens/TokenList/index.jsx | 4 ++-- .../AddOwnerModal/screens/Review/index.jsx | 6 +++--- .../AddOwnerModal/screens/ThresholdForm/index.jsx | 14 +++++++------- .../Settings/ManageOwners/EditOwnerModal/index.jsx | 4 ++-- .../ReplaceOwnerModal/screens/Review/index.jsx | 6 +++--- src/routes/safeList/components/Layout.jsx | 7 +++---- 13 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/components/Header/component/CircleDot.jsx b/src/components/Header/component/CircleDot.jsx index 32ff7f54..7c54d1e2 100644 --- a/src/components/Header/component/CircleDot.jsx +++ b/src/components/Header/component/CircleDot.jsx @@ -77,7 +77,7 @@ const KeyRing = ({ const img = isWarning ? triangle : key return ( - + <> {!hideDot && } - + ) } diff --git a/src/routes/open/components/ReviewInformation/index.jsx b/src/routes/open/components/ReviewInformation/index.jsx index 056e72c0..0a142121 100644 --- a/src/routes/open/components/ReviewInformation/index.jsx +++ b/src/routes/open/components/ReviewInformation/index.jsx @@ -80,7 +80,7 @@ const ReviewComponent = ({ values, classes, network }: Props) => { const numOwners = getNumOwnersFrom(values) return ( - + <> @@ -151,18 +151,18 @@ const ReviewComponent = ({ values, classes, network }: Props) => { wallet. Make sure you have ETH in this wallet to fund this transaction. - + ) } const ReviewPage = withStyles(styles)(ReviewComponent) const Review = ({ network }: LayoutProps) => (controls: React.Node, { values }: Object) => ( - + <> - + ) export default Review diff --git a/src/routes/open/components/SafeNameForm/index.jsx b/src/routes/open/components/SafeNameForm/index.jsx index aade39f6..da603793 100644 --- a/src/routes/open/components/SafeNameForm/index.jsx +++ b/src/routes/open/components/SafeNameForm/index.jsx @@ -33,7 +33,7 @@ const styles = () => ({ }) const SafeName = ({ classes }: Props) => ( - + <> You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new wallet @@ -67,7 +67,7 @@ const SafeName = ({ classes }: Props) => ( Ethereum blockchain. These funds cannot be accessed by Gnosis at any point. - + ) const SafeNameForm = withStyles(styles)(SafeName) diff --git a/src/routes/safe/components/Balances/Receive/index.jsx b/src/routes/safe/components/Balances/Receive/index.jsx index 414b6929..eabe9ef7 100644 --- a/src/routes/safe/components/Balances/Receive/index.jsx +++ b/src/routes/safe/components/Balances/Receive/index.jsx @@ -72,7 +72,7 @@ type Props = { const Receive = ({ classes, onClose, safeAddress, safeName, etherScanLink, }: Props) => ( - + <> Receive funds @@ -110,7 +110,7 @@ const Receive = ({ Done - + ) export default withStyles(styles)(Receive) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx index f9132350..96649b9d 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx @@ -39,7 +39,7 @@ type Props = { } const ChooseTxType = ({ classes, onClose, setActiveScreen }: Props) => ( - + <> Send @@ -72,7 +72,7 @@ const ChooseTxType = ({ classes, onClose, setActiveScreen }: Props) => ( - + ) export default withStyles(styles)(ChooseTxType) diff --git a/src/routes/safe/components/Balances/Tokens/index.jsx b/src/routes/safe/components/Balances/Tokens/index.jsx index b5ac8569..70f80291 100644 --- a/src/routes/safe/components/Balances/Tokens/index.jsx +++ b/src/routes/safe/components/Balances/Tokens/index.jsx @@ -40,7 +40,7 @@ const Tokens = (props: Props) => { } = props return ( - + <> Manage Tokens @@ -72,7 +72,7 @@ const Tokens = (props: Props) => { tokens={tokens} /> )} - + ) } diff --git a/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/index.jsx b/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/index.jsx index babc3d8f..dbe9cc5d 100644 --- a/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/index.jsx +++ b/src/routes/safe/components/Balances/Tokens/screens/AddCustomToken/index.jsx @@ -119,10 +119,10 @@ const AddCustomToken = (props: Props) => { } return ( - + <> {() => ( - + <> Add custom token @@ -196,10 +196,10 @@ const AddCustomToken = (props: Props) => { Save - + )} - + ) } diff --git a/src/routes/safe/components/Balances/Tokens/screens/TokenList/index.jsx b/src/routes/safe/components/Balances/Tokens/screens/TokenList/index.jsx index dd68c257..ad39c8cc 100644 --- a/src/routes/safe/components/Balances/Tokens/screens/TokenList/index.jsx +++ b/src/routes/safe/components/Balances/Tokens/screens/TokenList/index.jsx @@ -124,7 +124,7 @@ class Tokens extends React.Component { const filteredTokens = filterBy(filter, tokens) return ( - + <> @@ -179,7 +179,7 @@ class Tokens extends React.Component { ) })} - + ) } } diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx index d7aa8ad3..a952e8d6 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.jsx @@ -44,7 +44,7 @@ const ReviewAddOwner = ({ onSubmit() } return ( - + <> Add new owner @@ -97,7 +97,7 @@ const ReviewAddOwner = ({ - {owners.map(owner => ( + {owners.map((owner) => ( @@ -169,7 +169,7 @@ const ReviewAddOwner = ({ Submit - + ) } diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/ThresholdForm/index.jsx b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/ThresholdForm/index.jsx index c68b3db8..0c5af1de 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/ThresholdForm/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/ThresholdForm/index.jsx @@ -39,7 +39,7 @@ const ThresholdForm = ({ } return ( - + <> Add new owner @@ -52,7 +52,7 @@ const ThresholdForm = ({ {() => ( - + <> @@ -68,8 +68,8 @@ const ThresholdForm = ({ ( - + render={(props) => ( + <> {[...Array(Number(owners.size + 1))].map((x, index) => ( @@ -82,7 +82,7 @@ const ThresholdForm = ({ {props.meta.error} )} - + )} validate={composeValidators(required, mustBeInteger, minValue(1), maxValue(owners.size + 1))} data-testid="threshold-select-input" @@ -115,10 +115,10 @@ owner(s) Review - + )} - + ) } diff --git a/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.jsx b/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.jsx index ce2d3e96..6fe47db6 100644 --- a/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.jsx @@ -73,7 +73,7 @@ const EditOwnerComponent = ({ {() => ( - + <> - + )} diff --git a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.jsx b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.jsx index bfa72933..bfce4e73 100644 --- a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.jsx @@ -58,7 +58,7 @@ const ReviewRemoveOwner = ({ } return ( - + <> Replace owner @@ -112,7 +112,7 @@ const ReviewRemoveOwner = ({ {owners.map( - owner => owner.address !== ownerAddress && ( + (owner) => owner.address !== ownerAddress && ( @@ -215,7 +215,7 @@ const ReviewRemoveOwner = ({ Submit - + ) } diff --git a/src/routes/safeList/components/Layout.jsx b/src/routes/safeList/components/Layout.jsx index e684accf..a7dde521 100644 --- a/src/routes/safeList/components/Layout.jsx +++ b/src/routes/safeList/components/Layout.jsx @@ -14,12 +14,11 @@ const SafeList = ({ safes, provider }: Props) => { const safesAvailable = safes && safes.count() > 0 return ( - + <> { safesAvailable ? - : - } - + : } + ) } From efdba0fd57a42eca47848119a5f0f4dcbcd5d547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 9 Sep 2019 11:31:42 +0200 Subject: [PATCH 25/61] Fix modal window form footers --- .../SendModal/screens/SendCustomTx/index.jsx | 77 +++++++++-------- .../SendModal/screens/SendFunds/index.jsx | 82 ++++++++++--------- 2 files changed, 84 insertions(+), 75 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index bc1d47b5..82539198 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -74,22 +74,27 @@ const SendCustomTx = ({ - - - - - Arrow Down - - - - - - - {(...args) => { - const mutators = args[3] + + {(...args) => { + const mutators = args[3] - return ( - <> + return ( + <> + + + + + Arrow Down + + + + + - - - - - - - ) - }} - - + + + + + + + + ) + }} + ) } diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx index dbf7c6b8..21206abc 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx @@ -81,24 +81,28 @@ const SendFunds = ({ - - - - - Arrow Down - - - - - - - {(...args) => { - const formState = args[2] - const mutators = args[3] - const { token } = formState.values - - return ( - <> + + {(...args) => { + const formState = args[2] + const mutators = args[3] + const { token } = formState.values + return ( + <> + + + + + Arrow Down + + + + + - - - - - - - ) - }} - - + + + + + + + + ) + }} + ) } From 014103de3cb0012034ec83f03f68beb323984af3 Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Mon, 9 Sep 2019 15:10:24 +0400 Subject: [PATCH 26/61] change step name, replace text for owners/confirmations step --- src/routes/open/components/Layout.jsx | 4 ++-- .../open/components/SafeOwnersConfirmationsForm/index.jsx | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/routes/open/components/Layout.jsx b/src/routes/open/components/Layout.jsx index 0e6a30e5..800c43aa 100644 --- a/src/routes/open/components/Layout.jsx +++ b/src/routes/open/components/Layout.jsx @@ -13,10 +13,10 @@ import { getOwnerNameBy, getOwnerAddressBy, FIELD_CONFIRMATIONS } from '~/routes import { history } from '~/store' import { secondary } from '~/theme/variables' -const getSteps = () => ['Start', 'Owners and confirmations', 'Review'] +const getSteps = () => ['Name', 'Owners and confirmations', 'Review'] const initialValuesFrom = (userAccount: string) => ({ - [getOwnerNameBy(0)]: 'My Metamask (me)', + [getOwnerNameBy(0)]: 'My Wallet', [getOwnerAddressBy(0)]: userAccount, [FIELD_CONFIRMATIONS]: '1', }) diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx index 126c94cc..54b6ac95 100644 --- a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx +++ b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx @@ -109,7 +109,13 @@ const SafeOwners = (props: Props) => { <> - Specify the owners of the Safe. + Your Safe will have one or more owners. We have prefilled the first owner with your connected wallet details, + but you are free to change this to a different owner. +
+
+ Add additional owners (e.g. wallets of your teammates) and specify how many of them have to confirm a + transaction before it gets executed. In general, the more confirmations required, the more secure is your + Safe.
From ef3d9b4b0fb0b4323a07f515f278cd50215929b7 Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Mon, 9 Sep 2019 16:24:32 +0400 Subject: [PATCH 27/61] calculate gas for deploying a safe --- src/logic/contracts/safeContracts.js | 17 +++++++ src/routes/open/components/Layout.jsx | 4 +- .../components/ReviewInformation/index.jsx | 49 ++++++++++++++----- src/routes/open/container/Open.jsx | 5 +- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/logic/contracts/safeContracts.js b/src/logic/contracts/safeContracts.js index 32e4e5fc..7c757acf 100644 --- a/src/logic/contracts/safeContracts.js +++ b/src/logic/contracts/safeContracts.js @@ -75,6 +75,23 @@ export const deploySafeContract = async (safeAccounts: string[], numConfirmation return proxyFactoryMaster.createProxy(safeMaster.address, gnosisSafeData, { from: userAccount, gas, gasPrice }) } +export const estimateGasForDeployingSafe = async ( + safeAccounts: string[], + numConfirmations: number, + userAccount: string, +) => { + const gnosisSafeData = await safeMaster.contract.methods + .setup(safeAccounts, numConfirmations, ZERO_ADDRESS, '0x', ZERO_ADDRESS, 0, ZERO_ADDRESS) + .encodeABI() + const proxyFactoryData = proxyFactoryMaster.contract.methods + .createProxy(safeMaster.address, gnosisSafeData) + .encodeABI() + const gas = await calculateGasOf(proxyFactoryData, userAccount, proxyFactoryMaster.address) + const gasPrice = await calculateGasPrice() + + return gas * parseInt(gasPrice, 10) +} + export const getGnosisSafeInstanceAt = async (safeAddress: string) => { const web3 = getWeb3() const GnosisSafe = await getGnosisSafeContract(web3) diff --git a/src/routes/open/components/Layout.jsx b/src/routes/open/components/Layout.jsx index 800c43aa..75fe9fba 100644 --- a/src/routes/open/components/Layout.jsx +++ b/src/routes/open/components/Layout.jsx @@ -69,7 +69,9 @@ const Layout = ({ > {SafeNameField} {SafeOwnersFields} - {Review} + + {Review} + ) : ( diff --git a/src/routes/open/components/ReviewInformation/index.jsx b/src/routes/open/components/ReviewInformation/index.jsx index 056e72c0..fd4157b6 100644 --- a/src/routes/open/components/ReviewInformation/index.jsx +++ b/src/routes/open/components/ReviewInformation/index.jsx @@ -3,6 +3,7 @@ import * as React from 'react' import classNames from 'classnames' import { withStyles } from '@material-ui/core/styles' import OpenInNew from '@material-ui/icons/OpenInNew' +import { estimateGasForDeployingSafe } from '~/logic/contracts/safeContracts' import { getNamesFrom, getAccountsFrom } from '~/routes/open/utils/safeDataExtractor' import Block from '~/components/layout/Block' import Identicon from '~/components/Identicon' @@ -15,9 +16,11 @@ import { sm, md, lg, border, secondary, background, } from '~/theme/variables' import Hairline from '~/components/layout/Hairline' -import { getEtherScanLink } from '~/logic/wallets/getWeb3' +import { getEtherScanLink, getWeb3 } from '~/logic/wallets/getWeb3' import { FIELD_NAME, FIELD_CONFIRMATIONS, getNumOwnersFrom } from '../fields' +const { useEffect, useState } = React + const openIconStyle = { height: '16px', color: secondary, @@ -65,22 +68,42 @@ const styles = () => ({ }, }) -type LayoutProps = { +type Props = { network: string, -} - -type Props = LayoutProps & { values: Object, classes: Object, + userAccount: string, } -const ReviewComponent = ({ values, classes, network }: Props) => { +const ReviewComponent = ({ + values, classes, network, userAccount, +}: Props) => { + const [gasCosts, setGasCosts] = useState('0.00') const names = getNamesFrom(values) const addresses = getAccountsFrom(values) const numOwners = getNumOwnersFrom(values) + useEffect(() => { + let isCurrent = true + const estimateGas = async () => { + const web3 = getWeb3() + const { fromWei, toBN } = web3.utils + const estimatedGasCosts = await estimateGasForDeployingSafe(addresses, numOwners, userAccount) + const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether') + if (isCurrent) { + setGasCosts(gasCostsAsEth) + } + } + + estimateGas() + + return () => { + isCurrent = false + } + }, []) + return ( - + <> @@ -148,21 +171,25 @@ const ReviewComponent = ({ values, classes, network }: Props) => { You're about to create a new Safe and will have to confirm a transaction with your currently connected - wallet. Make sure you have ETH in this wallet to fund this transaction. + wallet. Make sure you have + {' '} + {gasCosts} + {' '} +ETH in this wallet to fund this transaction. - + ) } const ReviewPage = withStyles(styles)(ReviewComponent) const Review = ({ network }: LayoutProps) => (controls: React.Node, { values }: Object) => ( - + <> - + ) export default Review diff --git a/src/routes/open/container/Open.jsx b/src/routes/open/container/Open.jsx index 7d65b08f..5f9b6c13 100644 --- a/src/routes/open/container/Open.jsx +++ b/src/routes/open/container/Open.jsx @@ -29,7 +29,6 @@ export const createSafe = async (values: Object, userAccount: string, addSafe: A const name = getSafeNameFrom(values) const owners = getNamesFrom(values) - await initContracts() const safe = await deploySafeContract(accounts, numConfirmations, userAccount) await checkReceiptStatus(safe.tx) @@ -55,6 +54,10 @@ export const createSafe = async (values: Object, userAccount: string, addSafe: A } class Open extends React.Component { + async componentDidMount() { + await initContracts() + } + onCallSafeContractSubmit = async (values) => { try { const { userAccount, addSafe } = this.props From 73bd3aa6e881a89ad66bc13a8a54d3af85af391f Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Mon, 9 Sep 2019 16:50:16 +0400 Subject: [PATCH 28/61] load safe text replacements --- .eslintrc | 4 +-- .../load/components/DetailsForm/index.jsx | 27 +++++++++++++++++-- src/routes/load/components/Layout.jsx | 2 +- .../open/components/SafeNameForm/index.jsx | 4 +-- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.eslintrc b/.eslintrc index 392bf94e..f04dfa1b 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,7 @@ { - "extends": ["airbnb", "plugin:flowtype/recommended"], + "extends": ["airbnb", "plugin:flowtype/recommended", "plugin:jsx-a11y/recommended"], "parser": "babel-eslint", - "plugins": ["jest", "flowtype"], + "plugins": ["jsx-a11y", "jest", "flowtype"], "rules": { "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], "react/forbid-prop-types": [1, { "forbid": ["object", "any"] }], diff --git a/src/routes/load/components/DetailsForm/index.jsx b/src/routes/load/components/DetailsForm/index.jsx index 28caf11e..0ce657c1 100644 --- a/src/routes/load/components/DetailsForm/index.jsx +++ b/src/routes/load/components/DetailsForm/index.jsx @@ -16,6 +16,7 @@ import OpenPaper from '~/components/Stepper/OpenPaper' import { FIELD_LOAD_NAME, FIELD_LOAD_ADDRESS } from '~/routes/load/components/fields' import { getWeb3 } from '~/logic/wallets/getWeb3' import { getSafeMasterContract } from '~/logic/contracts/safeContracts' +import { secondary } from '~/theme/variables' type Props = { classes: Object, @@ -33,6 +34,11 @@ const styles = () => ({ color: '#03AE60', height: '20px', }, + links: { + '&>a': { + color: secondary, + }, + }, }) export const SAFE_INSTANCE_ERROR = 'Address given is not a safe instance' @@ -86,8 +92,8 @@ const Details = ({ classes, errors, form }: Props) => ( <> - Adding an existing Safe only requires the Safe address. Optionally you can give it a name. In case your - connected client is not the owner of the Safe, the interface will essentially provide you a read-only view. + Adding an existing Safe only requires the Safe address. Your connected wallet does not have to be the owner of + this Safe. In this case, the interface will provide you a read-only view. @@ -122,6 +128,23 @@ const Details = ({ classes, errors, form }: Props) => ( text="Safe Address" /> + + + By continuing you consent with the + {' '} + + terms of use + + {' '} + and + {' '} + + privacy policy + + . Most importantly, you confirm that your funds are held securely in the Gnosis Safe, a smart contract on the + Ethereum blockchain. These funds cannot be accessed by Gnosis at any point. + + ) diff --git a/src/routes/load/components/Layout.jsx b/src/routes/load/components/Layout.jsx index d10c0696..c1c53f51 100644 --- a/src/routes/load/components/Layout.jsx +++ b/src/routes/load/components/Layout.jsx @@ -13,7 +13,7 @@ import { history } from '~/store' import { secondary } from '~/theme/variables' import { type SelectorProps } from '~/routes/load/container/selector' -const getSteps = () => ['Details', 'Owners', 'Review'] +const getSteps = () => ['Name and address', 'Owners', 'Review'] type Props = SelectorProps & { onLoadSafeSubmit: (values: Object) => Promise, diff --git a/src/routes/open/components/SafeNameForm/index.jsx b/src/routes/open/components/SafeNameForm/index.jsx index aade39f6..da603793 100644 --- a/src/routes/open/components/SafeNameForm/index.jsx +++ b/src/routes/open/components/SafeNameForm/index.jsx @@ -33,7 +33,7 @@ const styles = () => ({ }) const SafeName = ({ classes }: Props) => ( - + <> You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new wallet @@ -67,7 +67,7 @@ const SafeName = ({ classes }: Props) => ( Ethereum blockchain. These funds cannot be accessed by Gnosis at any point. - + ) const SafeNameForm = withStyles(styles)(SafeName) From bef4631c71733be4e893de4f8f47488b9b98d65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 9 Sep 2019 14:51:04 +0200 Subject: [PATCH 29/61] Improve designs in Receive modal --- .../components/Balances/Receive/index.jsx | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/routes/safe/components/Balances/Receive/index.jsx b/src/routes/safe/components/Balances/Receive/index.jsx index eabe9ef7..53987fd6 100644 --- a/src/routes/safe/components/Balances/Receive/index.jsx +++ b/src/routes/safe/components/Balances/Receive/index.jsx @@ -14,13 +14,13 @@ import Row from '~/components/layout/Row' import Hairline from '~/components/layout/Hairline' import Col from '~/components/layout/Col' import { - xxl, lg, sm, md, background, secondary, + lg, md, secondary, secondaryText, } from '~/theme/variables' import { copyToClipboard } from '~/utils/clipboard' const styles = () => ({ heading: { - padding: `${sm} ${lg}`, + padding: `${md} ${lg}`, justifyContent: 'space-between', maxHeight: '75px', boxSizing: 'border-box', @@ -32,24 +32,27 @@ const styles = () => ({ height: '35px', width: '35px', }, - detailsContainer: { - backgroundColor: background, - }, qrContainer: { backgroundColor: '#fff', padding: md, - borderRadius: '3px', - boxShadow: '0 0 5px 0 rgba(74, 85, 121, 0.5)', + borderRadius: '6px', + border: `1px solid ${secondaryText}`, }, safeName: { - margin: `${xxl} 0 20px`, + margin: `${lg} 0 ${lg}`, }, buttonRow: { height: '84px', justifyContent: 'center', + '& > button': { + fontFamily: 'Averta', + fontSize: '16px', + boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)', + }, }, addressContainer: { - marginTop: '28px', + marginTop: '25px', + marginBottom: '25px', }, address: { marginLeft: '6px', @@ -81,7 +84,7 @@ const Receive = ({ - + {safeName} @@ -106,7 +109,7 @@ const Receive = ({ - From e09795c7ef0e99a099d3ae86ecc8b8223ca447fb Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Mon, 9 Sep 2019 18:36:29 +0400 Subject: [PATCH 30/61] Manage owners responsiveness fix --- src/routes/safe/components/Settings/ManageOwners/index.jsx | 2 +- src/routes/safe/components/Settings/ManageOwners/style.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Settings/ManageOwners/index.jsx b/src/routes/safe/components/Settings/ManageOwners/index.jsx index 6630ce43..5ca2f0b4 100644 --- a/src/routes/safe/components/Settings/ManageOwners/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/index.jsx @@ -145,7 +145,7 @@ class ManageOwners extends React.Component { defaultFixed noBorder > - {(sortedData: Array) => sortedData.map((row: any, index: number) => ( + {(sortedData: List) => sortedData.map((row: any, index: number) => ( ({ actions: { justifyContent: 'flex-end', visibility: 'hidden', + minWidth: '100px', }, noBorderBottom: { '& > td': { From a43002787fcaf6120d6f402cc8f2cf013ec86727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Mon, 9 Sep 2019 20:19:12 +0200 Subject: [PATCH 31/61] Improve designs in Send modal --- .../Balances/SendModal/SafeInfo/index.jsx | 2 +- .../components/Balances/SendModal/index.jsx | 6 ++-- .../SendModal/screens/ChooseTxType/index.jsx | 32 +++++++++++++++---- .../screens/ReviewCustomTx/index.jsx | 7 ++-- .../SendModal/screens/ReviewCustomTx/style.js | 10 +++++- .../SendModal/screens/ReviewTx/index.jsx | 7 ++-- .../SendModal/screens/ReviewTx/style.js | 13 +++++--- .../SendModal/screens/SendCustomTx/index.jsx | 5 +-- .../SendModal/screens/SendCustomTx/style.js | 12 +++++-- .../SendModal/screens/SendFunds/index.jsx | 5 +-- .../SendModal/screens/SendFunds/style.js | 12 +++++-- .../SendModal/screens/assets/code.svg | 3 ++ .../SendModal/screens/assets/token.svg | 3 ++ 13 files changed, 86 insertions(+), 31 deletions(-) create mode 100644 src/routes/safe/components/Balances/SendModal/screens/assets/code.svg create mode 100644 src/routes/safe/components/Balances/SendModal/screens/assets/token.svg diff --git a/src/routes/safe/components/Balances/SendModal/SafeInfo/index.jsx b/src/routes/safe/components/Balances/SendModal/SafeInfo/index.jsx index 0246c0bf..03084b4d 100644 --- a/src/routes/safe/components/Balances/SendModal/SafeInfo/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/SafeInfo/index.jsx @@ -24,7 +24,7 @@ const styles = () => ({ letterSpacing: -0.5, backgroundColor: border, width: 'fit-content', - padding: '6px', + padding: '5px 10px', marginTop: xs, borderRadius: '3px', }, diff --git a/src/routes/safe/components/Balances/SendModal/index.jsx b/src/routes/safe/components/Balances/SendModal/index.jsx index 8ffae44a..ba0f93bb 100644 --- a/src/routes/safe/components/Balances/SendModal/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/index.jsx @@ -67,8 +67,7 @@ const Send = ({ setTx({}) }, [isOpen]) - const scalableModalSize = activeScreen === 'sendCustomTx' || activeScreen === 'reviewCustomTx' - const scalableStaticModalSize = activeScreen === 'chooseTxType' + const scalableModalSize = activeScreen === 'chooseTxType' const handleTxCreation = (txInfo) => { setActiveScreen('reviewTx') @@ -87,8 +86,7 @@ const Send = ({ handleClose={onClose} open={isOpen} paperClassName={cn( - scalableStaticModalSize && classes.scalableStaticModalWindow, - scalableModalSize && classes.scalableModalWindow, + scalableModalSize ? classes.scalableStaticModalWindow : classes.scalableModalWindow, )} > <> diff --git a/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx index 96649b9d..3bb6e459 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ChooseTxType/index.jsx @@ -1,5 +1,6 @@ // @flow import * as React from 'react' +import classNames from 'classnames/bind' import { withStyles } from '@material-ui/core/styles' import Close from '@material-ui/icons/Close' import IconButton from '@material-ui/core/IconButton' @@ -8,11 +9,14 @@ import Button from '~/components/layout/Button' import Row from '~/components/layout/Row' import Col from '~/components/layout/Col' import Hairline from '~/components/layout/Hairline' -import { lg, sm } from '~/theme/variables' +import Img from '~/components/layout/Img' +import Token from '../assets/token.svg' +import Code from '../assets/code.svg' +import { lg, md, sm } from '~/theme/variables' const styles = () => ({ heading: { - padding: `${sm} ${lg}`, + padding: `${md} ${lg}`, justifyContent: 'space-between', boxSizing: 'border-box', maxHeight: '75px', @@ -26,10 +30,22 @@ const styles = () => ({ }, buttonColumn: { padding: '52px 0', + '& > button': { + fontSize: '16px', + fontFamily: 'Averta', + }, }, - secondButton: { - marginTop: 10, + firstButton: { + boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)', + marginBottom: 15, }, + iconSmall: { + fontSize: 16, + }, + leftIcon: { + marginRight: sm, + }, + }) type Props = { @@ -57,18 +73,20 @@ const ChooseTxType = ({ classes, onClose, setActiveScreen }: Props) => ( minHeight={52} onClick={() => setActiveScreen('sendFunds')} variant="contained" + className={classes.firstButton} > - SEND FUNDS + Send funds + Send funds diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index 13208568..2a8c6d80 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -135,7 +135,7 @@ const ReviewCustomTx = ({ - diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js index 374c1840..75fc858a 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/style.js @@ -5,7 +5,7 @@ import { export const styles = () => ({ heading: { - padding: `${sm} ${lg}`, + padding: `${md} ${lg}`, justifyContent: 'flex-start', boxSizing: 'border-box', maxHeight: '75px', @@ -48,5 +48,13 @@ export const styles = () => ({ buttonRow: { height: '84px', justifyContent: 'center', + '& > button': { + fontFamily: 'Averta', + fontSize: '16px', + }, + }, + submitButton: { + boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)', + marginLeft: '15px', }, }) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx index b330156d..c20fd85c 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx @@ -138,7 +138,7 @@ const ReviewTx = ({ - diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/style.js b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/style.js index 94c10bc8..6b44b167 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/style.js +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/style.js @@ -5,7 +5,7 @@ import { export const styles = () => ({ heading: { - padding: `${sm} ${lg}`, + padding: `${md} ${lg}`, justifyContent: 'flex-start', boxSizing: 'border-box', maxHeight: '75px', @@ -32,8 +32,13 @@ export const styles = () => ({ buttonRow: { height: '84px', justifyContent: 'center', - position: 'absolute', - bottom: 0, - width: '100%', + '& > button': { + fontFamily: 'Averta', + fontSize: '16px', + }, + }, + submitButton: { + boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)', + marginLeft: '15px', }, }) diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index 82539198..9aba3543 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -151,16 +151,17 @@ const SendCustomTx = ({ - diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js index 841c5d43..96a1149e 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/style.js @@ -1,9 +1,9 @@ // @flow -import { lg, md, sm } from '~/theme/variables' +import { lg, md } from '~/theme/variables' export const styles = () => ({ heading: { - padding: `${sm} ${lg}`, + padding: `${md} ${lg}`, justifyContent: 'flex-start', boxSizing: 'border-box', maxHeight: '75px', @@ -27,6 +27,14 @@ export const styles = () => ({ buttonRow: { height: '84px', justifyContent: 'center', + '& > button': { + fontFamily: 'Averta', + fontSize: '16px', + }, + }, + submitButton: { + boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)', + marginLeft: '15px', }, dataInput: { '& TextField-root-294': { diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx index 21206abc..22b1eff9 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx @@ -161,16 +161,17 @@ const SendFunds = ({ - diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/style.js b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/style.js index e1d9ef62..b2740346 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/style.js +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/style.js @@ -1,11 +1,11 @@ // @flow import { - lg, md, sm, secondaryText, + lg, md, secondaryText, } from '~/theme/variables' export const styles = () => ({ heading: { - padding: `${sm} ${lg}`, + padding: `${md} ${lg}`, justifyContent: 'flex-start', boxSizing: 'border-box', maxHeight: '75px', @@ -29,5 +29,13 @@ export const styles = () => ({ buttonRow: { height: '84px', justifyContent: 'center', + '& > button': { + fontFamily: 'Averta', + fontSize: '16px', + }, + }, + submitButton: { + boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)', + marginLeft: '15px', }, }) diff --git a/src/routes/safe/components/Balances/SendModal/screens/assets/code.svg b/src/routes/safe/components/Balances/SendModal/screens/assets/code.svg new file mode 100644 index 00000000..ad056d55 --- /dev/null +++ b/src/routes/safe/components/Balances/SendModal/screens/assets/code.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/routes/safe/components/Balances/SendModal/screens/assets/token.svg b/src/routes/safe/components/Balances/SendModal/screens/assets/token.svg new file mode 100644 index 00000000..f2abb8c5 --- /dev/null +++ b/src/routes/safe/components/Balances/SendModal/screens/assets/token.svg @@ -0,0 +1,3 @@ + + + From 8aad19bcf34b7dc12edd413e4ccb388b3e5d941d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Tue, 10 Sep 2019 12:58:21 +0200 Subject: [PATCH 32/61] Fix styles for send and receive funds buttons --- src/routes/safe/components/Balances/style.js | 8 ++++++++ src/routes/safe/components/style.js | 10 ++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/routes/safe/components/Balances/style.js b/src/routes/safe/components/Balances/style.js index 224dac23..b49a7a1a 100644 --- a/src/routes/safe/components/Balances/style.js +++ b/src/routes/safe/components/Balances/style.js @@ -34,10 +34,18 @@ export const styles = (theme: Object) => ({ width: '95px', minWidth: '95px', marginLeft: sm, + borderRadius: '4px', + '& > span': { + fontSize: '14px', + }, }, send: { width: '75px', minWidth: '75px', + borderRadius: '4px', + '& > span': { + fontSize: '14px', + }, }, leftIcon: { marginRight: sm, diff --git a/src/routes/safe/components/style.js b/src/routes/safe/components/style.js index 8ef1345b..17d5315d 100644 --- a/src/routes/safe/components/style.js +++ b/src/routes/safe/components/style.js @@ -41,17 +41,23 @@ export const styles = () => ({ balance: { marginLeft: 'auto', overflow: 'hidden', - borderRadius: '3px', - padding: '20px', }, receive: { width: '95px', minWidth: '95px', marginLeft: sm, + borderRadius: '4px', + '& > span': { + fontSize: '14px', + }, }, send: { width: '75px', minWidth: '75px', + borderRadius: '4px', + '& > span': { + fontSize: '14px', + }, }, leftIcon: { marginRight: sm, From 1af8ffad4c45e7c756435a321c2950fd69cc8901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Tue, 10 Sep 2019 13:15:04 +0200 Subject: [PATCH 33/61] Fix value validator in send custom transaction --- .../Balances/SendModal/screens/ReviewCustomTx/index.jsx | 4 ++-- .../Balances/SendModal/screens/SendCustomTx/index.jsx | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index 2a8c6d80..a78d959f 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -116,8 +116,8 @@ const ReviewCustomTx = ({ Ether - {tx.value} - {'ETH'} + {tx.value || 0} + {' ETH'} diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx index 9aba3543..d1c9e8d5 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCustomTx/index.jsx @@ -20,7 +20,6 @@ import { composeValidators, mustBeFloat, maxValue, - greaterThan, } from '~/components/forms/validator' import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo' import ArrowDown from '../assets/arrow-down.svg' @@ -126,7 +125,6 @@ const SendCustomTx = ({ type="text" validate={composeValidators( mustBeFloat, - greaterThan(0), maxValue(ethBalance), )} placeholder="Value*" From 0096ed24e5b7c2b6265c33e56dfb1c94c23b3d9f Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Tue, 10 Sep 2019 18:22:45 +0400 Subject: [PATCH 34/61] Make name mandatory for create/load safe flows --- src/routes/load/components/DetailsForm/index.jsx | 11 +++++++++-- src/routes/open/components/Layout.jsx | 4 ++-- src/routes/open/components/SafeNameForm/index.jsx | 10 ++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/routes/load/components/DetailsForm/index.jsx b/src/routes/load/components/DetailsForm/index.jsx index 0ce657c1..bfbdb1a3 100644 --- a/src/routes/load/components/DetailsForm/index.jsx +++ b/src/routes/load/components/DetailsForm/index.jsx @@ -50,8 +50,15 @@ export const SAFE_MASTERCOPY_ERROR = 'Mastercopy used by this safe is not the sa export const safeFieldsValidation = async (values: Object) => { const errors = {} const web3 = getWeb3() + const safeName = values[FIELD_LOAD_NAME] const safeAddress = values[FIELD_LOAD_ADDRESS] + + if (!safeName) { + errors[FIELD_LOAD_NAME] = 'Required' + } + if (!safeAddress || mustBeEthereumAddress(safeAddress) !== undefined) { + errors[FIELD_LOAD_ADDRESS] = 'Required' return errors } @@ -92,8 +99,8 @@ const Details = ({ classes, errors, form }: Props) => ( <> - Adding an existing Safe only requires the Safe address. Your connected wallet does not have to be the owner of - this Safe. In this case, the interface will provide you a read-only view. + You are about to load an existing Gnosis Safe. First, choose a name and enter the Safe address. The name is only + stored locally and will never be shared with Gnosis or any third parties diff --git a/src/routes/open/components/Layout.jsx b/src/routes/open/components/Layout.jsx index 75fe9fba..d66b3a70 100644 --- a/src/routes/open/components/Layout.jsx +++ b/src/routes/open/components/Layout.jsx @@ -7,7 +7,7 @@ import Block from '~/components/layout/Block' import Heading from '~/components/layout/Heading' import Row from '~/components/layout/Row' import Review from '~/routes/open/components/ReviewInformation' -import SafeNameField from '~/routes/open/components/SafeNameForm' +import SafeNameField, { safeNameValidation } from '~/routes/open/components/SafeNameForm' import SafeOwnersFields from '~/routes/open/components/SafeOwnersConfirmationsForm' import { getOwnerNameBy, getOwnerAddressBy, FIELD_CONFIRMATIONS } from '~/routes/open/components/fields' import { history } from '~/store' @@ -67,7 +67,7 @@ const Layout = ({ mutators={formMutators} testId="create-safe-form" > - {SafeNameField} + {SafeNameField} {SafeOwnersFields} {Review} diff --git a/src/routes/open/components/SafeNameForm/index.jsx b/src/routes/open/components/SafeNameForm/index.jsx index da603793..d243115f 100644 --- a/src/routes/open/components/SafeNameForm/index.jsx +++ b/src/routes/open/components/SafeNameForm/index.jsx @@ -10,6 +10,16 @@ import Paragraph from '~/components/layout/Paragraph' import OpenPaper from '~/components/Stepper/OpenPaper' import { sm, secondary } from '~/theme/variables' +export const safeNameValidation = async (values: Object) => { + const errors = {} + + if (!values[FIELD_NAME]) { + errors[FIELD_NAME] = 'Required' + } + + return errors +} + type Props = { classes: Object, } From b44c30923dd1a219e0a4fcbeeaa3720571ec67cb Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Tue, 10 Sep 2019 18:58:28 +0400 Subject: [PATCH 35/61] Stepper clickable steps --- src/components/Stepper/index.jsx | 32 +++++++++++++++---- .../load/components/DetailsForm/index.jsx | 7 ++-- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/components/Stepper/index.jsx b/src/components/Stepper/index.jsx index d256c24f..942f6c10 100644 --- a/src/components/Stepper/index.jsx +++ b/src/components/Stepper/index.jsx @@ -143,12 +143,24 @@ const GnoStepper = (props: Props) => { return ( - {steps.map((label) => ( - - {label} - {activePage(controls, ...rest)} - - ))} + {steps.map((label, index) => { + const labelProps = {} + const isClickable = index < page + + if (isClickable) { + labelProps.onClick = () => { + setPage(index) + } + labelProps.className = classes.pointerCursor + } + + return ( + + {label} + {activePage(controls, ...rest)} + + ) + })} ) }} @@ -162,6 +174,14 @@ const styles = { flex: '1 1 auto', backgroundColor: 'transparent', }, + pointerCursor: { + '& > .MuiStepLabel-iconContainer': { + cursor: 'pointer', + }, + '& > .MuiStepLabel-labelContainer': { + cursor: 'pointer', + }, + }, } export default withStyles(styles)(GnoStepper) diff --git a/src/routes/load/components/DetailsForm/index.jsx b/src/routes/load/components/DetailsForm/index.jsx index bfbdb1a3..f8889afb 100644 --- a/src/routes/load/components/DetailsForm/index.jsx +++ b/src/routes/load/components/DetailsForm/index.jsx @@ -97,10 +97,13 @@ export const safeFieldsValidation = async (values: Object) => { const Details = ({ classes, errors, form }: Props) => ( <> - + You are about to load an existing Gnosis Safe. First, choose a name and enter the Safe address. The name is only - stored locally and will never be shared with Gnosis or any third parties + stored locally and will never be shared with Gnosis or any third parties. +
+ Your connected wallet does not have to be the owner of this Safe. In this case, the interface will provide you a + read-only view.
From 3c05220008db613c497db225ec2fd1a591e7c067 Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Wed, 11 Sep 2019 19:35:36 +0400 Subject: [PATCH 36/61] Add etherscan/copy buttons in load/create safe flows --- src/components/CopyBtn/copy.svg | 5 ++ src/components/CopyBtn/index.jsx | 35 ++++++++++++ src/components/EtherscanBtn/index.jsx | 53 +++++++++++++++++++ src/components/EtherscanBtn/search.svg | 5 ++ src/components/EtherscanLink/index.jsx | 2 +- .../load/components/OwnerList/index.jsx | 26 +++------ .../components/ReviewInformation/index.jsx | 40 +++++--------- .../components/ReviewInformation/index.jsx | 34 +++++------- src/routes/open/container/selector.js | 2 +- .../components/Balances/Receive/index.jsx | 4 +- .../safe/components/Balances/Tokens/index.jsx | 4 +- src/routes/safe/components/Settings/style.js | 2 +- 12 files changed, 138 insertions(+), 74 deletions(-) create mode 100644 src/components/CopyBtn/copy.svg create mode 100644 src/components/CopyBtn/index.jsx create mode 100644 src/components/EtherscanBtn/index.jsx create mode 100644 src/components/EtherscanBtn/search.svg diff --git a/src/components/CopyBtn/copy.svg b/src/components/CopyBtn/copy.svg new file mode 100644 index 00000000..51341f1a --- /dev/null +++ b/src/components/CopyBtn/copy.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/CopyBtn/index.jsx b/src/components/CopyBtn/index.jsx new file mode 100644 index 00000000..b76f441a --- /dev/null +++ b/src/components/CopyBtn/index.jsx @@ -0,0 +1,35 @@ +// @flow +import React from 'react' +import { withStyles } from '@material-ui/core/styles' +import Img from '~/components/layout/Img' +import { copyToClipboard } from '~/utils/clipboard' +import { xs } from '~/theme/variables' +import CopyIcon from './copy.svg' + +const styles = () => ({ + container: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + cursor: 'pointer', + padding: xs, + borderRadius: '50%', + transition: 'background-color .2s ease-in-out', + '&:hover': { + backgroundColor: '#F0EFEE', + }, + }, +}) + +type CopyBtnProps = { + content: string, + classes: Object, +} + +const CopyBtn = ({ content, classes }: CopyBtnProps) => (navigator.clipboard ? ( +
+ Click to copy copyToClipboard(content)} /> +
+) : null) + +export default withStyles(styles)(CopyBtn) diff --git a/src/components/EtherscanBtn/index.jsx b/src/components/EtherscanBtn/index.jsx new file mode 100644 index 00000000..ffae1448 --- /dev/null +++ b/src/components/EtherscanBtn/index.jsx @@ -0,0 +1,53 @@ +// @flow +import React from 'react' +import { withStyles } from '@material-ui/core/styles' +import { connect } from 'react-redux' +import Img from '~/components/layout/Img' +import { getEtherScanLink } from '~/logic/wallets/getWeb3' +import { xs } from '~/theme/variables' +import { networkSelector } from '~/logic/wallets/store/selectors' +import SearchIcon from './search.svg' + + +const styles = () => ({ + container: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + padding: xs, + borderRadius: '50%', + transition: 'background-color .2s ease-in-out', + '&:hover': { + backgroundColor: '#F0EFEE', + }, + }, +}) + +type EtherscanBtnProps = { + type: 'tx' | 'address', + value: string, + currentNetwork: string, + classes: Object, +} + +const EtherscanBtn = ({ + type, value, currentNetwork, classes, +}: EtherscanBtnProps) => ( + + Etherscan + +) + +const EtherscanBtnWithStyles = withStyles(styles)(EtherscanBtn) + +export default connect( + (state) => ({ currentNetwork: networkSelector(state) }), + null, +)(EtherscanBtnWithStyles) diff --git a/src/components/EtherscanBtn/search.svg b/src/components/EtherscanBtn/search.svg new file mode 100644 index 00000000..ac49ba3e --- /dev/null +++ b/src/components/EtherscanBtn/search.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/EtherscanLink/index.jsx b/src/components/EtherscanLink/index.jsx index 1e1e743e..f824f6e9 100644 --- a/src/components/EtherscanLink/index.jsx +++ b/src/components/EtherscanLink/index.jsx @@ -26,6 +26,6 @@ const EtherscanLink = ({ type, value, currentNetwork }: EtherscanLinkProps) => ( ) export default connect( - state => ({ currentNetwork: networkSelector(state) }), + (state) => ({ currentNetwork: networkSelector(state) }), null, )(EtherscanLink) diff --git a/src/routes/load/components/OwnerList/index.jsx b/src/routes/load/components/OwnerList/index.jsx index f111163c..8dab61dc 100644 --- a/src/routes/load/components/OwnerList/index.jsx +++ b/src/routes/load/components/OwnerList/index.jsx @@ -1,7 +1,6 @@ // @flow import React, { useState, useEffect } from 'react' import { withStyles } from '@material-ui/core/styles' -import OpenInNew from '@material-ui/icons/OpenInNew' import Block from '~/components/layout/Block' import Field from '~/components/forms/Field' import { required } from '~/components/forms/validator' @@ -10,22 +9,17 @@ import Identicon from '~/components/Identicon' import OpenPaper from '~/components/Stepper/OpenPaper' import Col from '~/components/layout/Col' import Row from '~/components/layout/Row' -import Link from '~/components/layout/Link' import Paragraph from '~/components/layout/Paragraph' import Hairline from '~/components/layout/Hairline' +import EtherscanBtn from '~/components/EtherscanBtn' +import CopyBtn from '~/components/CopyBtn' import { - sm, md, lg, border, secondary, disabled, extraSmallFontSize, + sm, md, lg, border, disabled, extraSmallFontSize, } from '~/theme/variables' import { getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields' -import { getEtherScanLink } from '~/logic/wallets/getWeb3' import { FIELD_LOAD_ADDRESS, THRESHOLD } from '~/routes/load/components/fields' import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts' -const openIconStyle = { - height: '16px', - color: secondary, -} - const styles = () => ({ details: { padding: lg, @@ -45,6 +39,7 @@ const styles = () => ({ }, address: { paddingLeft: '6px', + marginRight: sm, }, open: { paddingLeft: sm, @@ -70,11 +65,7 @@ const styles = () => ({ }, }) -type LayoutProps = { - network: string, -} - -type Props = LayoutProps & { +type Props = { values: Object, classes: Object, updateInitialProps: (initialValues: Object) => void, @@ -92,7 +83,7 @@ const calculateSafeValues = (owners: Array, threshold: Number, values: O const OwnerListComponent = (props: Props) => { const [owners, setOwners] = useState>([]) const { - values, updateInitialProps, network, classes, + values, updateInitialProps, classes, } = props useEffect(() => { @@ -153,9 +144,8 @@ const OwnerListComponent = (props: Props) => { {address} - - - + +
diff --git a/src/routes/load/components/ReviewInformation/index.jsx b/src/routes/load/components/ReviewInformation/index.jsx index 940586a3..72617944 100644 --- a/src/routes/load/components/ReviewInformation/index.jsx +++ b/src/routes/load/components/ReviewInformation/index.jsx @@ -2,29 +2,23 @@ import * as React from 'react' import classNames from 'classnames' import { withStyles } from '@material-ui/core/styles' -import OpenInNew from '@material-ui/icons/OpenInNew' import Block from '~/components/layout/Block' import Identicon from '~/components/Identicon' import OpenPaper from '~/components/Stepper/OpenPaper' import Col from '~/components/layout/Col' import Row from '~/components/layout/Row' -import Link from '~/components/layout/Link' +import EtherscanBtn from '~/components/EtherscanBtn' import Paragraph from '~/components/layout/Paragraph' +import CopyBtn from '~/components/CopyBtn' import Hairline from '~/components/layout/Hairline' import { - xs, sm, lg, border, secondary, + xs, sm, lg, border, } from '~/theme/variables' import { shortVersionOf } from '~/logic/wallets/ethAddresses' import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor' import { getOwnerNameBy, getOwnerAddressBy, getNumOwnersFrom } from '~/routes/open/components/fields' -import { getEtherScanLink } from '~/logic/wallets/getWeb3' import { FIELD_LOAD_NAME, FIELD_LOAD_ADDRESS, THRESHOLD } from '~/routes/load/components/fields' -const openIconStyle = { - height: '16px', - color: secondary, -} - const styles = () => ({ root: { minHeight: '300px', @@ -51,6 +45,9 @@ const styles = () => ({ }, user: { justifyContent: 'left', + '& > p': { + marginRight: sm, + }, }, open: { paddingLeft: sm, @@ -65,15 +62,12 @@ const styles = () => ({ }, address: { paddingLeft: '6px', + marginRight: sm, }, }) -type LayoutProps = { - network: string, +type Props = { userAddress: string, -} - -type Props = LayoutProps & { values: Object, classes: Object, } @@ -97,9 +91,7 @@ const checkUserAddressOwner = (values: Object, userAddress: string): boolean => class ReviewComponent extends React.PureComponent { render() { - const { - values, classes, network, userAddress, - } = this.props + const { values, classes, userAddress } = this.props const isOwner = checkUserAddressOwner(values, userAddress) const owners = getAccountsFrom(values) @@ -132,9 +124,8 @@ class ReviewComponent extends React.PureComponent { {shortVersionOf(safeAddress, 4)} - - - + +
@@ -177,13 +168,8 @@ class ReviewComponent extends React.PureComponent { {address} - - - + + diff --git a/src/routes/open/components/ReviewInformation/index.jsx b/src/routes/open/components/ReviewInformation/index.jsx index fd4157b6..dc36073f 100644 --- a/src/routes/open/components/ReviewInformation/index.jsx +++ b/src/routes/open/components/ReviewInformation/index.jsx @@ -2,30 +2,25 @@ import * as React from 'react' import classNames from 'classnames' import { withStyles } from '@material-ui/core/styles' -import OpenInNew from '@material-ui/icons/OpenInNew' import { estimateGasForDeployingSafe } from '~/logic/contracts/safeContracts' import { getNamesFrom, getAccountsFrom } from '~/routes/open/utils/safeDataExtractor' import Block from '~/components/layout/Block' +import EtherscanBtn from '~/components/EtherscanBtn' +import CopyBtn from '~/components/CopyBtn' import Identicon from '~/components/Identicon' import OpenPaper from '~/components/Stepper/OpenPaper' import Col from '~/components/layout/Col' import Row from '~/components/layout/Row' -import Link from '~/components/layout/Link' import Paragraph from '~/components/layout/Paragraph' import { - sm, md, lg, border, secondary, background, + sm, md, lg, border, background, } from '~/theme/variables' import Hairline from '~/components/layout/Hairline' -import { getEtherScanLink, getWeb3 } from '~/logic/wallets/getWeb3' +import { getWeb3 } from '~/logic/wallets/getWeb3' import { FIELD_NAME, FIELD_CONFIRMATIONS, getNumOwnersFrom } from '../fields' const { useEffect, useState } = React -const openIconStyle = { - height: '16px', - color: secondary, -} - const styles = () => ({ root: { minHeight: '300px', @@ -58,6 +53,9 @@ const styles = () => ({ }, user: { justifyContent: 'left', + '& > p': { + marginRight: sm, + }, }, open: { paddingLeft: sm, @@ -69,15 +67,12 @@ const styles = () => ({ }) type Props = { - network: string, values: Object, classes: Object, userAccount: string, } -const ReviewComponent = ({ - values, classes, network, userAccount, -}: Props) => { +const ReviewComponent = ({ values, classes, userAccount }: Props) => { const [gasCosts, setGasCosts] = useState('0.00') const names = getNamesFrom(values) const addresses = getAccountsFrom(values) @@ -152,13 +147,8 @@ const ReviewComponent = ({ {addresses[index]} - - - + + @@ -184,10 +174,10 @@ ETH in this wallet to fund this transaction. const ReviewPage = withStyles(styles)(ReviewComponent) -const Review = ({ network }: LayoutProps) => (controls: React.Node, { values }: Object) => ( +const Review = () => (controls: React.Node, { values }: Object) => ( <> - + ) diff --git a/src/routes/open/container/selector.js b/src/routes/open/container/selector.js index 24fb891d..be0e8be9 100644 --- a/src/routes/open/container/selector.js +++ b/src/routes/open/container/selector.js @@ -2,7 +2,7 @@ import { createStructuredSelector } from 'reselect' import { providerNameSelector, userAccountSelector, networkSelector } from '~/logic/wallets/store/selectors' -export default createStructuredSelector({ +export default createStructuredSelector({ provider: providerNameSelector, network: networkSelector, userAccount: userAccountSelector, diff --git a/src/routes/safe/components/Balances/Receive/index.jsx b/src/routes/safe/components/Balances/Receive/index.jsx index 50c3300a..577bad56 100644 --- a/src/routes/safe/components/Balances/Receive/index.jsx +++ b/src/routes/safe/components/Balances/Receive/index.jsx @@ -75,7 +75,7 @@ type Props = { const Receive = ({ classes, onClose, safeAddress, safeName, etherScanLink, }: Props) => ( - + <> Receive funds @@ -113,7 +113,7 @@ const Receive = ({ Done - + ) export default withStyles(styles)(Receive) diff --git a/src/routes/safe/components/Balances/Tokens/index.jsx b/src/routes/safe/components/Balances/Tokens/index.jsx index b5ac8569..70f80291 100644 --- a/src/routes/safe/components/Balances/Tokens/index.jsx +++ b/src/routes/safe/components/Balances/Tokens/index.jsx @@ -40,7 +40,7 @@ const Tokens = (props: Props) => { } = props return ( - + <> Manage Tokens @@ -72,7 +72,7 @@ const Tokens = (props: Props) => { tokens={tokens} /> )} - + ) } diff --git a/src/routes/safe/components/Settings/style.js b/src/routes/safe/components/Settings/style.js index f3afabd0..fa4ef97b 100644 --- a/src/routes/safe/components/Settings/style.js +++ b/src/routes/safe/components/Settings/style.js @@ -24,7 +24,7 @@ export const styles = () => ({ alignItems: 'center', cursor: 'pointer', '&:first-child': { - borderRadius: '8px', + borderTopLeftRadius: '8px', }, }, active: { From 6edc37b571bd9f69c48789f6b4cb57e27111544e Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Thu, 12 Sep 2019 13:36:05 +0400 Subject: [PATCH 37/61] Allow passing button labels to Stepper component, add CopyBtn tooltip --- src/components/CopyBtn/index.jsx | 4 ++-- src/components/Stepper/Controls/index.jsx | 28 +++++++++++++++-------- src/components/Stepper/index.jsx | 5 +++- src/routes/load/components/Layout.jsx | 3 +++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/components/CopyBtn/index.jsx b/src/components/CopyBtn/index.jsx index b76f441a..d3de19e1 100644 --- a/src/components/CopyBtn/index.jsx +++ b/src/components/CopyBtn/index.jsx @@ -27,8 +27,8 @@ type CopyBtnProps = { } const CopyBtn = ({ content, classes }: CopyBtnProps) => (navigator.clipboard ? ( -
- Click to copy copyToClipboard(content)} /> +
+ Copy to clipboard copyToClipboard(content)} />
) : null) diff --git a/src/components/Stepper/Controls/index.jsx b/src/components/Stepper/Controls/index.jsx index 0a77d573..ef03c501 100644 --- a/src/components/Stepper/Controls/index.jsx +++ b/src/components/Stepper/Controls/index.jsx @@ -26,24 +26,34 @@ type Props = { lastPage: boolean, disabled: boolean, penultimate: boolean, + currentStep?: number, + buttonLabels?: Array, } const Controls = ({ - onPrevious, firstPage, penultimate, lastPage, disabled, + onPrevious, + firstPage, + penultimate, + lastPage, + disabled, + currentStep, + buttonLabels, }: Props) => { - // eslint-disable-next-line - const next = firstPage ? 'Start' : penultimate ? 'Review' : lastPage ? 'Submit' : 'Next' const back = firstPage ? 'Cancel' : 'Back' + let next + if (!buttonLabels) { + // eslint-disable-next-line + next = firstPage ? 'Start' : penultimate ? 'Review' : lastPage ? 'Submit' : 'Next' + } else { + // $FlowFixMe + next = buttonLabels[currentStep] + } + return ( - diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx index a78d959f..e391ada9 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCustomTx/index.jsx @@ -127,7 +127,7 @@ const ReviewCustomTx = ({ - + {tx.data} @@ -135,7 +135,7 @@ const ReviewCustomTx = ({ -