From 4b2e0d3bebc78f7dd094c47fc05db3aa9494c83f Mon Sep 17 00:00:00 2001 From: apanizo Date: Thu, 7 Jun 2018 13:30:43 +0200 Subject: [PATCH] WA-238 Add Owner logic phase not updated the UI --- .../component/AddOwner/AddOwnerForm/index.jsx | 71 +++++++++++++ .../safe/component/AddOwner/Review/index.jsx | 43 ++++++++ src/routes/safe/component/AddOwner/actions.js | 16 +++ src/routes/safe/component/AddOwner/index.jsx | 99 +++++++++++++++++++ .../safe/component/AddOwner/selector.js | 11 +++ src/routes/safe/component/Safe/Owners.jsx | 13 ++- src/routes/safe/component/Safe/index.jsx | 9 +- .../safe/component/Transactions/index.jsx | 1 + 8 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 src/routes/safe/component/AddOwner/AddOwnerForm/index.jsx create mode 100644 src/routes/safe/component/AddOwner/Review/index.jsx create mode 100644 src/routes/safe/component/AddOwner/actions.js create mode 100644 src/routes/safe/component/AddOwner/index.jsx create mode 100644 src/routes/safe/component/AddOwner/selector.js diff --git a/src/routes/safe/component/AddOwner/AddOwnerForm/index.jsx b/src/routes/safe/component/AddOwner/AddOwnerForm/index.jsx new file mode 100644 index 00000000..721869f2 --- /dev/null +++ b/src/routes/safe/component/AddOwner/AddOwnerForm/index.jsx @@ -0,0 +1,71 @@ +// @flow +import * as React from 'react' +import Field from '~/components/forms/Field' +import TextField from '~/components/forms/TextField' +import Checkbox from '~/components/forms/Checkbox' +import { composeValidators, required, mustBeEthereumAddress, uniqueAddress } from '~/components/forms/validator' +import Block from '~/components/layout/Block' +import Heading from '~/components/layout/Heading' + +export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners' + +export const NAME_PARAM = 'name' +export const OWNER_ADDRESS_PARAM = 'ownerAddress' +export const INCREASE_PARAM = 'increase' + +export const safeFieldsValidation = (values: Object) => { + const errors = {} + + if (Number.parseInt(values.owners, 10) < Number.parseInt(values.confirmations, 10)) { + errors.confirmations = CONFIRMATIONS_ERROR + } + + return errors +} + +type Props = { + numOwners: number, + threshold: number, + addresses: string[] +} + +const AddOwnerForm = ({ addresses, numOwners, threshold }: Props) => () => ( + + + Add Owner + + + {`Actual number of owners: ${numOwners}, with threshold: ${threshold}`} + + + + + + + + + + Increase owner? + + +) + +export default AddOwnerForm diff --git a/src/routes/safe/component/AddOwner/Review/index.jsx b/src/routes/safe/component/AddOwner/Review/index.jsx new file mode 100644 index 00000000..6bc31b77 --- /dev/null +++ b/src/routes/safe/component/AddOwner/Review/index.jsx @@ -0,0 +1,43 @@ +// @flow +import * as React from 'react' +import { CircularProgress } from 'material-ui/Progress' +import Block from '~/components/layout/Block' +import Bold from '~/components/layout/Bold' +import Heading from '~/components/layout/Heading' +import Paragraph from '~/components/layout/Paragraph' +import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/component/AddOwner/AddOwnerForm' + +type FormProps = { + values: Object, + submitting: boolean, +} + +const spinnerStyle = { + minHeight: '50px', +} + +const Review = () => ({ values, submitting }: FormProps) => { + const text = values[INCREASE_PARAM] + ? 'This operation will increase the threshold of the safe' + : 'This operation will not modify the threshold of the safe' + + return ( + + Review the Add Owner operation + + Owner Name: {values[NAME_PARAM]} + + + Owner Address: {values[OWNER_ADDRESS_PARAM]} + + + {text} + + + { submitting && } + + + ) +} + +export default Review diff --git a/src/routes/safe/component/AddOwner/actions.js b/src/routes/safe/component/AddOwner/actions.js new file mode 100644 index 00000000..e0b10a5a --- /dev/null +++ b/src/routes/safe/component/AddOwner/actions.js @@ -0,0 +1,16 @@ +// @flow +import fetchThreshold from '~/routes/safe/store/actions/fetchThreshold' +import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions' + +type FetchThreshold = typeof fetchThreshold +type FetchTransactions = typeof fetchTransactions + +export type Actions = { + fetchThreshold: FetchThreshold, + fetchTransactions: FetchTransactions, +} + +export default { + fetchThreshold, + fetchTransactions, +} diff --git a/src/routes/safe/component/AddOwner/index.jsx b/src/routes/safe/component/AddOwner/index.jsx new file mode 100644 index 00000000..4869314f --- /dev/null +++ b/src/routes/safe/component/AddOwner/index.jsx @@ -0,0 +1,99 @@ +// @flow +import * as React from 'react' +import { List } from 'immutable' +import Stepper from '~/components/Stepper' +import { sleep } from '~/utils/timer' +import { connect } from 'react-redux' +import { type Safe } from '~/routes/safe/store/model/safe' +import { type Owner } from '~/routes/safe/store/model/owner' +import { getSafeEthereumInstance, createTransaction } from '~/routes/safe/component/AddTransaction/createTransactions' +import AddOwnerForm, { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from './AddOwnerForm' +import Review from './Review' +import selector, { type SelectorProps } from './selector' +import actions, { type Actions } from './actions' + +const getSteps = () => [ + 'Fill Owner Form', 'Review Withdrawn', +] + +type Props = SelectorProps & Actions & { + safe: Safe, + threshold: number, +} + +type State = { + done: boolean, +} + +export const ADD_OWNER_RESET_BUTTON_TEXT = 'RESET' + +const getOwnerAddressesFrom = (owners: List) => { + if (!owners) { + return [] + } + + return owners.map((owner: Owner) => owner.get('address')) +} + +class AddOwner extends React.Component { + state = { + done: false, + } + + onAddOwner = async (values: Object) => { + try { + const { + safe, threshold, userAddress, fetchTransactions, // fetchOwners + } = this.props + const nonce = Date.now() + const newThreshold = values[INCREASE_PARAM] ? threshold + 1 : threshold + const newOwnerAddress = values[OWNER_ADDRESS_PARAM] + const newOwnerName = values[NAME_PARAM] + const safeAddress = safe.get('address') + const gnosisSafe = await getSafeEthereumInstance(safeAddress) + const data = gnosisSafe.contract.addOwnerWithThreshold.getData(newOwnerAddress, newThreshold) + await createTransaction(safe, `Add Owner ${newOwnerName}`, safeAddress, 0, nonce, userAddress, data) + await sleep(1500) + fetchTransactions() + // fetchOwners(safeAddress) + this.setState({ done: true }) + } catch (error) { + this.setState({ done: false }) + // eslint-disable-next-line + console.log('Error while adding owner ' + error) + } + } + + onReset = () => { + this.setState({ done: false }) + } + + render() { + const { safe } = this.props + const { done } = this.state + const steps = getSteps() + const finishedButton = + const addresses = getOwnerAddressesFrom(safe.get('owners')) + + return ( + + + + { AddOwnerForm } + + + { Review } + + + + ) + } +} + +export default connect(selector, actions)(AddOwner) diff --git a/src/routes/safe/component/AddOwner/selector.js b/src/routes/safe/component/AddOwner/selector.js new file mode 100644 index 00000000..9e7bfef1 --- /dev/null +++ b/src/routes/safe/component/AddOwner/selector.js @@ -0,0 +1,11 @@ +// @flow +import { createStructuredSelector } from 'reselect' +import { userAccountSelector } from '~/wallets/store/selectors/index' + +export type SelectorProps = { + userAddress: userAccountSelector, +} + +export default createStructuredSelector({ + userAddress: userAccountSelector, +}) diff --git a/src/routes/safe/component/Safe/Owners.jsx b/src/routes/safe/component/Safe/Owners.jsx index e4801fb0..4386d7ab 100644 --- a/src/routes/safe/component/Safe/Owners.jsx +++ b/src/routes/safe/component/Safe/Owners.jsx @@ -6,6 +6,7 @@ import Collapse from 'material-ui/transitions/Collapse' import ListItemText from '~/components/List/ListItemText' import List, { ListItem, ListItemIcon } from 'material-ui/List' import Avatar from 'material-ui/Avatar' +import Button from '~/components/layout/Button' import Group from 'material-ui-icons/Group' import Person from 'material-ui-icons/Person' import ExpandLess from 'material-ui-icons/ExpandLess' @@ -21,10 +22,13 @@ const styles = { type Props = Open & WithStyles & { owners: List, + onAddOwner: () => void, } +export const ADD_OWNER_BUTTON_TEXT = 'Add' + const Owners = openHoc(({ - open, toggle, owners, classes, + open, toggle, owners, classes, onAddOwner, }: Props) => ( @@ -35,6 +39,13 @@ const Owners = openHoc(({ {open ? : } + diff --git a/src/routes/safe/component/Safe/index.jsx b/src/routes/safe/component/Safe/index.jsx index 788b2561..648d315e 100644 --- a/src/routes/safe/component/Safe/index.jsx +++ b/src/routes/safe/component/Safe/index.jsx @@ -13,6 +13,7 @@ import Withdrawn from '~/routes/safe/component/Withdrawn' import Transactions from '~/routes/safe/component/Transactions' import AddTransaction from '~/routes/safe/component/AddTransaction' import Threshold from '~/routes/safe/component/Threshold' +import AddOwner from '~/routes/safe/component/AddOwner' import Address from './Address' import Balance from './Balance' @@ -66,6 +67,12 @@ class GnoSafe extends React.PureComponent { this.setState({ component: }) } + onAddOwner = () => { + const { safe } = this.props + + this.setState({ component: }) + } + render() { const { safe, balance } = this.props const { component } = this.state @@ -75,7 +82,7 @@ class GnoSafe extends React.PureComponent { - +
diff --git a/src/routes/safe/component/Transactions/index.jsx b/src/routes/safe/component/Transactions/index.jsx index e8a22e87..1518ed62 100644 --- a/src/routes/safe/component/Transactions/index.jsx +++ b/src/routes/safe/component/Transactions/index.jsx @@ -25,6 +25,7 @@ class Transactions extends React.Component { await sleep(1200) fetchTransactions() fetchThreshold(safeAddress) + // fetchOwners(safeAddress) } render() {