add sendmax and button link for the amount field in sending funds form
This commit is contained in:
parent
7bac5ae822
commit
2010a6b7eb
|
@ -81,6 +81,7 @@
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-final-form": "5.1.0",
|
"react-final-form": "5.1.0",
|
||||||
|
"react-final-form-listeners": "^1.0.2",
|
||||||
"react-hot-loader": "4.8.7",
|
"react-hot-loader": "4.8.7",
|
||||||
"react-infinite-scroll-component": "^4.5.2",
|
"react-infinite-scroll-component": "^4.5.2",
|
||||||
"react-redux": "7.0.3",
|
"react-redux": "7.0.3",
|
||||||
|
|
|
@ -15,6 +15,7 @@ type Props = {
|
||||||
padding?: number,
|
padding?: number,
|
||||||
validation?: (values: Object) => Object | Promise<Object>,
|
validation?: (values: Object) => Object | Promise<Object>,
|
||||||
initialValues?: Object,
|
initialValues?: Object,
|
||||||
|
formMutators: Object,
|
||||||
}
|
}
|
||||||
|
|
||||||
const stylesBasedOn = (padding: number): $Shape<CSSStyleDeclaration> => ({
|
const stylesBasedOn = (padding: number): $Shape<CSSStyleDeclaration> => ({
|
||||||
|
@ -24,15 +25,16 @@ const stylesBasedOn = (padding: number): $Shape<CSSStyleDeclaration> => ({
|
||||||
})
|
})
|
||||||
|
|
||||||
const GnoForm = ({
|
const GnoForm = ({
|
||||||
onSubmit, validation, initialValues, children, padding = 0,
|
onSubmit, validation, initialValues, children, padding = 0, formMutators,
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<Form
|
<Form
|
||||||
validate={validation}
|
validate={validation}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
|
mutators={formMutators}
|
||||||
render={({ handleSubmit, ...rest }) => (
|
render={({ handleSubmit, ...rest }) => (
|
||||||
<form onSubmit={handleSubmit} style={stylesBasedOn(padding)}>
|
<form onSubmit={handleSubmit} style={stylesBasedOn(padding)}>
|
||||||
{children(rest.submitting, rest.validating, rest)}
|
{children(rest.submitting, rest.validating, rest, rest.form.mutators)}
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// @flow
|
||||||
|
/* eslint-disable react/button-has-type */
|
||||||
|
/* eslint-disable react/default-props-match-prop-types */
|
||||||
|
import * as React from 'react'
|
||||||
|
import cn from 'classnames/bind'
|
||||||
|
import styles from './index.scss'
|
||||||
|
|
||||||
|
const cx = cn.bind(styles)
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
type: 'button' | 'submit' | 'reset',
|
||||||
|
size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl',
|
||||||
|
weight?: 'light' | 'regular' | 'bolder' | 'bold',
|
||||||
|
color?: 'soft' | 'medium' | 'dark' | 'white' | 'fancy' | 'primary' | 'secondary' | 'warning' | 'disabled',
|
||||||
|
}
|
||||||
|
|
||||||
|
const GnoButtonLink = ({ type, size, weight, color, ...props }: Props) => (
|
||||||
|
<button type={type} className={cx(styles.btnLink, size, color, weight)} {...props} />
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
GnoButtonLink.defaultProps = {
|
||||||
|
type: 'button',
|
||||||
|
size: 'md',
|
||||||
|
weight: 'regular',
|
||||||
|
color: 'secondary',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GnoButtonLink
|
|
@ -0,0 +1,79 @@
|
||||||
|
.btnLink {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm {
|
||||||
|
font-size: $smallFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md {
|
||||||
|
font-size: $mediumFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg {
|
||||||
|
font-size: $largeFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xl {
|
||||||
|
font-size: $extraLargeFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xxl {
|
||||||
|
font-size: $xxlFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light {
|
||||||
|
font-weight: $lightFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
.regular {
|
||||||
|
font-weight: $regularFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bolder {
|
||||||
|
font-weight: $bolderFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bold {
|
||||||
|
font-weight: $boldFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
.soft {
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.medium {
|
||||||
|
color: #686868;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancy {
|
||||||
|
color: $fancy;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
color: $warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
color: $fontColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
color: $secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
color: $disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
.white {
|
||||||
|
color: white;
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ const cx = classNames.bind(styles)
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string,
|
className?: string,
|
||||||
children: React$Node,
|
children: React$Node,
|
||||||
margin?: 'sm' | 'md' | 'lg' | 'xl',
|
margin?: 'xs' | 'sm' | 'md' | 'lg' | 'xl',
|
||||||
align?: 'center' | 'end' | 'start',
|
align?: 'center' | 'end' | 'start',
|
||||||
grow?: boolean,
|
grow?: boolean,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
.grow {
|
.grow {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.marginXs {
|
||||||
|
margin-bottom: $xs;
|
||||||
|
}
|
||||||
|
|
||||||
.marginSm {
|
.marginSm {
|
||||||
margin-bottom: $sm;
|
margin-bottom: $sm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
|
import { OnChange } from 'react-final-form-listeners'
|
||||||
import { withStyles } from '@material-ui/core/styles'
|
import { withStyles } from '@material-ui/core/styles'
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem'
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
|
@ -17,6 +18,7 @@ import { selectedTokenStyles, selectStyles } from './style'
|
||||||
type SelectFieldProps = {
|
type SelectFieldProps = {
|
||||||
tokens: List<Token>,
|
tokens: List<Token>,
|
||||||
classes: Object,
|
classes: Object,
|
||||||
|
onTokenChange: Function,
|
||||||
}
|
}
|
||||||
|
|
||||||
type SelectedTokenProps = {
|
type SelectedTokenProps = {
|
||||||
|
@ -47,7 +49,7 @@ const SelectedToken = ({ token, classes }: SelectedTokenProps) => (
|
||||||
|
|
||||||
const SelectedTokenStyled = withStyles(selectedTokenStyles)(SelectedToken)
|
const SelectedTokenStyled = withStyles(selectedTokenStyles)(SelectedToken)
|
||||||
|
|
||||||
const TokenSelectField = ({ tokens, classes }: SelectFieldProps) => (
|
const TokenSelectField = ({ tokens, onTokenChange, classes }: SelectFieldProps) => (
|
||||||
<Field
|
<Field
|
||||||
name="token"
|
name="token"
|
||||||
component={SelectField}
|
component={SelectField}
|
||||||
|
@ -65,6 +67,11 @@ const TokenSelectField = ({ tokens, classes }: SelectFieldProps) => (
|
||||||
<ListItemText primary={token.name} secondary={`${token.balance} ${token.symbol}`} />
|
<ListItemText primary={token.name} secondary={`${token.balance} ${token.symbol}`} />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
|
<OnChange name="token">
|
||||||
|
{() => {
|
||||||
|
onTokenChange()
|
||||||
|
}}
|
||||||
|
</OnChange>
|
||||||
</Field>
|
</Field>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,12 @@ import Row from '~/components/layout/Row'
|
||||||
import GnoForm from '~/components/forms/GnoForm'
|
import GnoForm from '~/components/forms/GnoForm'
|
||||||
import Link from '~/components/layout/Link'
|
import Link from '~/components/layout/Link'
|
||||||
import Col from '~/components/layout/Col'
|
import Col from '~/components/layout/Col'
|
||||||
import Field from '~/components/forms/Field'
|
|
||||||
import TextField from '~/components/forms/TextField'
|
|
||||||
import Block from '~/components/layout/Block'
|
import Block from '~/components/layout/Block'
|
||||||
import Bold from '~/components/layout/Bold'
|
import Bold from '~/components/layout/Bold'
|
||||||
import Hairline from '~/components/layout/Hairline'
|
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 {
|
import {
|
||||||
lg, md, sm, secondary, xs,
|
lg, md, sm, secondary, xs,
|
||||||
} from '~/theme/variables'
|
} from '~/theme/variables'
|
||||||
|
@ -73,6 +74,16 @@ const SendFunds = ({
|
||||||
classes, onClose, safeAddress, etherScanLink, safeName, ethBalance, tokens,
|
classes, onClose, safeAddress, etherScanLink, safeName, ethBalance, tokens,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const handleSubmit = () => {}
|
const handleSubmit = () => {}
|
||||||
|
const formMutators = {
|
||||||
|
setMax: (args, state, utils) => {
|
||||||
|
const { token } = state.formState.values
|
||||||
|
|
||||||
|
utils.changeValue(state, 'amount', () => token && token.balance)
|
||||||
|
},
|
||||||
|
onTokenChange: (args, state, utils) => {
|
||||||
|
utils.changeValue(state, 'amount', () => '')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -121,45 +132,55 @@ ETH
|
||||||
<Hairline />
|
<Hairline />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<GnoForm onSubmit={handleSubmit}>
|
<GnoForm onSubmit={handleSubmit} formMutators={formMutators}>
|
||||||
{() => (
|
{(...args) => {
|
||||||
<React.Fragment>
|
const mutators = args[3]
|
||||||
<Row margin="md">
|
return (
|
||||||
<Col xs={12}>
|
<React.Fragment>
|
||||||
<Field
|
<Row margin="md">
|
||||||
name="recipientAddress"
|
<Col xs={12}>
|
||||||
component={TextField}
|
<Field
|
||||||
type="text"
|
name="recipientAddress"
|
||||||
validate={composeValidators(required, mustBeEthereumAddress)}
|
component={TextField}
|
||||||
placeholder="Recipient*"
|
type="text"
|
||||||
text="Recipient*"
|
validate={composeValidators(required, mustBeEthereumAddress)}
|
||||||
className={classes.addressInput}
|
placeholder="Recipient*"
|
||||||
/>
|
text="Recipient*"
|
||||||
</Col>
|
className={classes.addressInput}
|
||||||
</Row>
|
/>
|
||||||
<Row>
|
</Col>
|
||||||
<Col>
|
</Row>
|
||||||
<TokenSelectField tokens={tokens} />
|
<Row margin="sm">
|
||||||
</Col>
|
<Col>
|
||||||
</Row>
|
<TokenSelectField tokens={tokens} onTokenChange={mutators.onTokenChange} />
|
||||||
<Row>
|
</Col>
|
||||||
<Col layout="column">
|
</Row>
|
||||||
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }}>
|
<Row margin="xs">
|
||||||
Amount
|
<Col between="lg">
|
||||||
</Paragraph>
|
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
|
||||||
<Field
|
Amount
|
||||||
name="amount"
|
</Paragraph>
|
||||||
component={TextField}
|
<ButtonLink weight="bold" onClick={mutators.setMax}>
|
||||||
type="text"
|
Send max
|
||||||
validate={composeValidators(required)}
|
</ButtonLink>
|
||||||
placeholder="Amount*"
|
</Col>
|
||||||
text="Amount*"
|
</Row>
|
||||||
className={classes.addressInput}
|
<Row>
|
||||||
/>
|
<Col>
|
||||||
</Col>
|
<Field
|
||||||
</Row>
|
name="amount"
|
||||||
</React.Fragment>
|
component={TextField}
|
||||||
)}
|
type="text"
|
||||||
|
validate={composeValidators(required)}
|
||||||
|
placeholder="Amount*"
|
||||||
|
text="Amount*"
|
||||||
|
className={classes.addressInput}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
</GnoForm>
|
</GnoForm>
|
||||||
</Block>
|
</Block>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -1416,7 +1416,7 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.2"
|
regenerator-runtime "^0.13.2"
|
||||||
|
|
||||||
"@babel/runtime@^7.4.4":
|
"@babel/runtime@^7.1.5", "@babel/runtime@^7.4.4":
|
||||||
version "7.4.4"
|
version "7.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d"
|
||||||
integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==
|
integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==
|
||||||
|
@ -13669,6 +13669,13 @@ react-fast-compare@^2.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
|
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
|
||||||
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
|
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
|
||||||
|
|
||||||
|
react-final-form-listeners@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-final-form-listeners/-/react-final-form-listeners-1.0.2.tgz#b52da984300281cf1f69a6412e86df6249e2bf1c"
|
||||||
|
integrity sha512-AaUUHcXRhD3esC80yUfYPI8FJ3TUiMu0f4hk18QL8NMCWjokg6NWS32WkRJsH3bLWDoiy7+uNVOAAyO/XoupyA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.1.5"
|
||||||
|
|
||||||
react-final-form@5.1.0:
|
react-final-form@5.1.0:
|
||||||
version "5.1.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-5.1.0.tgz#f9402dfdf9325e5605cd8c9c7f4ef3e9ecf0702c"
|
resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-5.1.0.tgz#f9402dfdf9325e5605cd8c9c7f4ef3e9ecf0702c"
|
||||||
|
|
Loading…
Reference in New Issue