createTransaction action

This commit is contained in:
Mikhail Mikheev 2019-05-24 18:43:06 +04:00
parent ad183dfabb
commit c3fba307c2
9 changed files with 141 additions and 99 deletions

View File

@ -12,9 +12,10 @@ import Layout from './component/Layout'
import actions, { type Actions } from './actions' import actions, { type Actions } from './actions'
import selector, { type SelectorProps } from './selector' import selector, { type SelectorProps } from './selector'
type Props = Actions & SelectorProps & { type Props = Actions &
openSnackbar: (message: string, variant: Variant) => void, SelectorProps & {
} openSnackbar: (message: string, variant: Variant) => void,
}
type State = { type State = {
hasError: boolean, hasError: boolean,
@ -67,13 +68,15 @@ class HeaderComponent extends React.PureComponent<Props, State> {
return <ConnectDetails onConnect={this.onConnect} /> return <ConnectDetails onConnect={this.onConnect} />
} }
return (<UserDetails return (
provider={provider} <UserDetails
network={network} provider={provider}
userAddress={userAddress} network={network}
connected={available} userAddress={userAddress}
onDisconnect={this.onDisconnect} connected={available}
/>) onDisconnect={this.onDisconnect}
/>
)
} }
render() { render() {
@ -84,14 +87,13 @@ class HeaderComponent extends React.PureComponent<Props, State> {
} }
} }
const Header = connect(selector, actions)(HeaderComponent) const Header = connect(
selector,
actions,
)(HeaderComponent)
const HeaderSnack = () => ( const HeaderSnack = () => (
<SharedSnackbarConsumer> <SharedSnackbarConsumer>{({ openSnackbar }) => <Header openSnackbar={openSnackbar} />}</SharedSnackbarConsumer>
{({ openSnackbar }) => (
<Header openSnackbar={openSnackbar} />
)}
</SharedSnackbarConsumer>
) )
export default HeaderSnack export default HeaderSnack

View File

@ -19,6 +19,7 @@ type Props = {
ethBalance: string, ethBalance: string,
tokens: List<Token>, tokens: List<Token>,
selectedToken: string, selectedToken: string,
createTransaction: Function,
} }
type ActiveScreen = 'chooseTxType' | 'sendFunds' | 'reviewTx' type ActiveScreen = 'chooseTxType' | 'sendFunds' | 'reviewTx'
@ -47,6 +48,7 @@ const Send = ({
ethBalance, ethBalance,
tokens, tokens,
selectedToken, selectedToken,
createTransaction,
}: Props) => { }: Props) => {
const [activeScreen, setActiveScreen] = useState<ActiveScreen>('sendFunds') const [activeScreen, setActiveScreen] = useState<ActiveScreen>('sendFunds')
const [tx, setTx] = useState<TxStateType>({}) const [tx, setTx] = useState<TxStateType>({})
@ -98,6 +100,7 @@ const Send = ({
safeName={safeName} safeName={safeName}
ethBalance={ethBalance} ethBalance={ethBalance}
onClickBack={onClickBack} onClickBack={onClickBack}
createTransaction={createTransaction}
/> />
)} )}
</React.Fragment> </React.Fragment>

View File

@ -2,6 +2,7 @@
import React from 'react' import React from 'react'
import OpenInNew from '@material-ui/icons/OpenInNew' import OpenInNew from '@material-ui/icons/OpenInNew'
import { withStyles } from '@material-ui/core/styles' import { withStyles } from '@material-ui/core/styles'
import { SharedSnackbarConsumer } from '~/components/SharedSnackBar/Context'
import Close from '@material-ui/icons/Close' import Close from '@material-ui/icons/Close'
import IconButton from '@material-ui/core/IconButton' import IconButton from '@material-ui/core/IconButton'
import Paragraph from '~/components/layout/Paragraph' import Paragraph from '~/components/layout/Paragraph'
@ -19,7 +20,6 @@ import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
import ArrowDown from '../assets/arrow-down.svg' import ArrowDown from '../assets/arrow-down.svg'
import { secondary } from '~/theme/variables' import { secondary } from '~/theme/variables'
import { styles } from './style' import { styles } from './style'
import { createTransaction } from '~/logic/safe/transactions'
type Props = { type Props = {
onClose: () => void, onClose: () => void,
@ -30,6 +30,7 @@ type Props = {
onClickBack: Function, onClickBack: Function,
ethBalance: string, ethBalance: string,
tx: Object, tx: Object,
createTransaction: Function,
} }
const openIconStyle = { const openIconStyle = {
@ -38,81 +39,98 @@ const openIconStyle = {
} }
const ReviewTx = ({ const ReviewTx = ({
onClose, classes, safeAddress, etherScanLink, safeName, ethBalance, tx, onClickBack, onClose,
classes,
safeAddress,
etherScanLink,
safeName,
ethBalance,
tx,
onClickBack,
createTransaction,
}: Props) => ( }: Props) => (
<React.Fragment> <SharedSnackbarConsumer>
<Row align="center" grow className={classes.heading}> {({ openSnackbar }) => (
<Paragraph weight="bolder" className={classes.headingText} noMargin> <React.Fragment>
Send Funds <Row align="center" grow className={classes.heading}>
</Paragraph> <Paragraph weight="bolder" className={classes.headingText} noMargin>
<Paragraph className={classes.annotation}>2 of 2</Paragraph> Send Funds
<IconButton onClick={onClose} disableRipple>
<Close className={classes.closeIcon} />
</IconButton>
</Row>
<Hairline />
<Block className={classes.container}>
<SafeInfo safeAddress={safeAddress} etherScanLink={etherScanLink} safeName={safeName} ethBalance={ethBalance} />
<Row margin="md">
<Col xs={1}>
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
</Col>
<Col xs={11} center="xs" layout="column">
<Hairline />
</Col>
</Row>
<Row margin="xs">
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
Recipient
</Paragraph>
</Row>
<Row margin="md" align="center">
<Col xs={1}>
<Identicon address={tx.recipientAddress} diameter={32} />
</Col>
<Col xs={11} layout="column">
<Paragraph weight="bolder" onClick={copyToClipboard} noMargin>
{tx.recipientAddress}
<Link to={etherScanLink} target="_blank">
<OpenInNew style={openIconStyle} />
</Link>
</Paragraph> </Paragraph>
</Col> <Paragraph className={classes.annotation}>2 of 2</Paragraph>
</Row> <IconButton onClick={onClose} disableRipple>
<Row margin="xs"> <Close className={classes.closeIcon} />
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin> </IconButton>
Amount </Row>
</Paragraph> <Hairline />
</Row> <Block className={classes.container}>
<Row margin="md" align="center"> <SafeInfo
<Img src={tx.token.logoUri} height={28} alt={tx.token.name} onError={setImageToPlaceholder} /> safeAddress={safeAddress}
<Paragraph size="md" noMargin> etherScanLink={etherScanLink}
{tx.amount} safeName={safeName}
{' '} ethBalance={ethBalance}
{tx.token.symbol} />
</Paragraph> <Row margin="md">
</Row> <Col xs={1}>
</Block> <img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
<Hairline style={{ position: 'absolute', bottom: 85 }} /> </Col>
<Row align="center" className={classes.buttonRow}> <Col xs={11} center="xs" layout="column">
<Button className={classes.button} minWidth={140} onClick={onClickBack}> <Hairline />
Back </Col>
</Button> </Row>
<Button <Row margin="xs">
type="submit" <Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
className={classes.button} Recipient
onClick={async () => { </Paragraph>
await createTransaction(safeAddress, tx.recipientAddress, tx.amount, tx.token) </Row>
onClose() <Row margin="md" align="center">
}} <Col xs={1}>
variant="contained" <Identicon address={tx.recipientAddress} diameter={32} />
minWidth={140} </Col>
color="primary" <Col xs={11} layout="column">
> <Paragraph weight="bolder" onClick={copyToClipboard} noMargin>
SUBMIT {tx.recipientAddress}
</Button> <Link to={etherScanLink} target="_blank">
</Row> <OpenInNew style={openIconStyle} />
</React.Fragment> </Link>
</Paragraph>
</Col>
</Row>
<Row margin="xs">
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
Amount
</Paragraph>
</Row>
<Row margin="md" align="center">
<Img src={tx.token.logoUri} height={28} alt={tx.token.name} onError={setImageToPlaceholder} />
<Paragraph size="md" noMargin>
{tx.amount}
{' '}
{tx.token.symbol}
</Paragraph>
</Row>
</Block>
<Hairline style={{ position: 'absolute', bottom: 85 }} />
<Row align="center" className={classes.buttonRow}>
<Button className={classes.button} minWidth={140} onClick={onClickBack}>
Back
</Button>
<Button
type="submit"
className={classes.button}
onClick={() => {
createTransaction(safeAddress, tx.recipientAddress, tx.amount, tx.token, openSnackbar)
onClose()
}}
variant="contained"
minWidth={140}
color="primary"
>
SUBMIT
</Button>
</Row>
</React.Fragment>
)}
</SharedSnackbarConsumer>
) )
export default withStyles(styles)(ReviewTx) export default withStyles(styles)(ReviewTx)

View File

@ -41,6 +41,7 @@ type Props = {
safeName: string, safeName: string,
etherScanLink: string, etherScanLink: string,
ethBalance: string, ethBalance: string,
createTransaction: Function,
} }
type Action = 'Token' | 'Send' | 'Receive' type Action = 'Token' | 'Send' | 'Receive'
@ -93,7 +94,15 @@ class Balances extends React.Component<Props, State> {
hideZero, showToken, showReceive, sendFunds, hideZero, showToken, showReceive, sendFunds,
} = this.state } = this.state
const { const {
classes, granted, tokens, safeAddress, activeTokens, safeName, etherScanLink, ethBalance, classes,
granted,
tokens,
safeAddress,
activeTokens,
safeName,
etherScanLink,
ethBalance,
createTransaction,
} = this.props } = this.props
const columns = generateColumns() const columns = generateColumns()
@ -190,6 +199,7 @@ class Balances extends React.Component<Props, State> {
ethBalance={ethBalance} ethBalance={ethBalance}
tokens={activeTokens} tokens={activeTokens}
selectedToken={sendFunds.selectedToken} selectedToken={sendFunds.selectedToken}
createTransaction={createTransaction}
/> />
<Modal <Modal
title="Receive Tokens" title="Receive Tokens"

View File

@ -23,6 +23,7 @@ import Balances from './Balances'
type Props = SelectorProps & { type Props = SelectorProps & {
classes: Object, classes: Object,
granted: boolean, granted: boolean,
createTransaction: Function,
} }
type State = { type State = {
@ -88,7 +89,7 @@ class Layout extends React.Component<Props, State> {
render() { render() {
const { const {
safe, provider, network, classes, granted, tokens, activeTokens, safe, provider, network, classes, granted, tokens, activeTokens, createTransaction,
} = this.props } = this.props
const { tabIndex } = this.state const { tabIndex } = this.state
@ -137,6 +138,7 @@ class Layout extends React.Component<Props, State> {
safeAddress={address} safeAddress={address}
safeName={name} safeName={name}
etherScanLink={etherScanLink} etherScanLink={etherScanLink}
createTransaction={createTransaction}
/> />
)} )}
</React.Fragment> </React.Fragment>

View File

@ -14,7 +14,7 @@ type FormProps = {
} }
type Props = { type Props = {
symbol: string symbol: string,
} }
const spinnerStyle = { const spinnerStyle = {
@ -25,14 +25,14 @@ const ReviewTx = ({ symbol }: Props) => (controls: React$Node, { values, submitt
<OpenPaper controls={controls}> <OpenPaper controls={controls}>
<Heading tag="h2">Review the move token funds</Heading> <Heading tag="h2">Review the move token funds</Heading>
<Paragraph align="left"> <Paragraph align="left">
<Bold>Destination: </Bold> {values[TKN_DESTINATION_PARAM]} <Bold>Destination: </Bold>
{' '}
{values[TKN_DESTINATION_PARAM]}
</Paragraph> </Paragraph>
<Paragraph align="left"> <Paragraph align="left">
<Bold>{`Amount to transfer: ${values[TKN_VALUE_PARAM]} ${symbol}`}</Bold> <Bold>{`Amount to transfer: ${values[TKN_VALUE_PARAM]} ${symbol}`}</Bold>
</Paragraph> </Paragraph>
<Block style={spinnerStyle}> <Block style={spinnerStyle}>{submitting && <CircularProgress size={50} />}</Block>
{ submitting && <CircularProgress size={50} /> }
</Block>
</OpenPaper> </OpenPaper>
) )

View File

@ -1,13 +1,16 @@
// @flow // @flow
import fetchSafe from '~/routes/safe/store/actions/fetchSafe' import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
import fetchTokenBalances from '~/routes/safe/store/actions/fetchTokenBalances' import fetchTokenBalances from '~/routes/safe/store/actions/fetchTokenBalances'
import createTransaction from '~/routes/safe/store/actions/createTransaction'
export type Actions = { export type Actions = {
fetchSafe: typeof fetchSafe, fetchSafe: typeof fetchSafe,
fetchTokenBalances: typeof fetchTokenBalances, fetchTokenBalances: typeof fetchTokenBalances,
createTransaction: typeof createTransaction,
} }
export default { export default {
fetchSafe, fetchSafe,
fetchTokenBalances, fetchTokenBalances,
createTransaction,
} }

View File

@ -52,7 +52,7 @@ class SafeView extends React.Component<Props> {
render() { render() {
const { const {
safe, provider, activeTokens, granted, userAddress, network, tokens, safe, provider, activeTokens, granted, userAddress, network, tokens, createTransaction,
} = this.props } = this.props
return ( return (
@ -65,6 +65,7 @@ class SafeView extends React.Component<Props> {
userAddress={userAddress} userAddress={userAddress}
network={network} network={network}
granted={granted} granted={granted}
createTransaction={createTransaction}
/> />
</Page> </Page>
) )

View File

@ -13,7 +13,7 @@ import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchToke
export const ADD_TRANSACTIONS = 'ADD_TRANSACTIONS' export const ADD_TRANSACTIONS = 'ADD_TRANSACTIONS'
export const addTransactions = createAction<string, *>(ADD_TRANSACTIONS) export const addTransactions = createAction<string, *>(ADD_TRANSACTIONS)
export const createTransaction = async (safeAddress: string, to: string, valueInEth: string, token: Token) => async ( const createTransaction = (safeAddress: string, to: string, valueInEth: string, token: Token, openSnackbar: Function) => async (
dispatch: ReduxDispatch<GlobalState>, dispatch: ReduxDispatch<GlobalState>,
) => { ) => {
const safeInstance = await getSafeEthereumInstance(safeAddress) const safeInstance = await getSafeEthereumInstance(safeAddress)
@ -35,6 +35,7 @@ export const createTransaction = async (safeAddress: string, to: string, valueIn
let txHash let txHash
if (isExecution) { if (isExecution) {
txHash = await executeTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from) txHash = await executeTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from)
openSnackbar('Transaction has been submitted', 'success')
} else { } else {
// txHash = await approveTransaction(safeAddress, to, valueInWei, txData, CALL, nonce) // txHash = await approveTransaction(safeAddress, to, valueInWei, txData, CALL, nonce)
} }
@ -42,3 +43,5 @@ export const createTransaction = async (safeAddress: string, to: string, valueIn
return txHash return txHash
} }
export default createTransaction