Trim spaces from AddressInput (#1142)
* Remove spaces * Change naming convention to make clear that only edge whitespaces are removed Fix function documentation in string util * Add trim spaces from address input in AddToken and AddAsset * Use validator type * Trim spaces on Safe App links Co-authored-by: Mati Dastugue <mdastugu@amazon.com> Co-authored-by: Mati Dastugue <matias.dastugue@altoros.com> Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com>
This commit is contained in:
parent
bbfa7d8166
commit
89c17180de
|
@ -220,17 +220,17 @@
|
|||
"web3": "1.2.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/history": "4.6.2",
|
||||
"@types/lodash.memoize": "^4.1.6",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/react-redux": "^7.1.9",
|
||||
"@testing-library/jest-dom": "5.11.1",
|
||||
"@testing-library/react": "10.4.7",
|
||||
"@testing-library/user-event": "12.0.13",
|
||||
"@types/history": "4.6.2",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/lodash.memoize": "^4.1.6",
|
||||
"@types/node": "14.0.25",
|
||||
"@types/react": "^16.9.43",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/react-redux": "^7.1.9",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/styled-components": "^5.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "3.7.0",
|
||||
"@typescript-eslint/parser": "3.7.0",
|
||||
|
@ -254,6 +254,7 @@
|
|||
"node-sass": "^4.14.1",
|
||||
"prettier": "2.0.5",
|
||||
"react-app-rewired": "^2.1.6",
|
||||
"source-map-explorer": "^2.4.2",
|
||||
"truffle": "5.1.35",
|
||||
"typescript": "^3.9.7",
|
||||
"wait-on": "5.1.0",
|
||||
|
|
|
@ -3,13 +3,27 @@ import { Field } from 'react-final-form'
|
|||
import { OnChange } from 'react-final-form-listeners'
|
||||
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, mustBeEthereumAddress, required } from 'src/components/forms/validator'
|
||||
import { Validator, composeValidators, mustBeEthereumAddress, required } from 'src/components/forms/validator'
|
||||
import { trimSpaces } from 'src/utils/strings'
|
||||
import { getAddressFromENS } from 'src/logic/wallets/getWeb3'
|
||||
import { isValidEnsName } from 'src/logic/wallets/ethAddresses'
|
||||
|
||||
// an idea for second field was taken from here
|
||||
// https://github.com/final-form/react-final-form-listeners/blob/master/src/OnBlur.js
|
||||
|
||||
export interface AddressInputProps {
|
||||
fieldMutator: (address: string) => void
|
||||
name?: string
|
||||
text?: string
|
||||
placeholder?: string
|
||||
inputAdornment?: { endAdornment: React.ReactElement } | undefined
|
||||
testId: string
|
||||
validators?: Validator[]
|
||||
defaultValue?: string
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
const AddressInput = ({
|
||||
className = '',
|
||||
name = 'recipientAddress',
|
||||
|
@ -21,7 +35,7 @@ const AddressInput = ({
|
|||
validators = [],
|
||||
defaultValue,
|
||||
disabled,
|
||||
}: any) => (
|
||||
}: AddressInputProps): React.ReactElement => (
|
||||
<>
|
||||
<Field
|
||||
className={className}
|
||||
|
@ -38,14 +52,15 @@ const AddressInput = ({
|
|||
/>
|
||||
<OnChange name={name}>
|
||||
{async (value) => {
|
||||
if (isValidEnsName(value)) {
|
||||
const address = trimSpaces(value)
|
||||
if (isValidEnsName(address)) {
|
||||
try {
|
||||
const resolverAddr = await getAddressFromENS(value)
|
||||
const resolverAddr = await getAddressFromENS(address)
|
||||
fieldMutator(resolverAddr)
|
||||
} catch (err) {
|
||||
console.error('Failed to resolve address for ENS name: ', err)
|
||||
}
|
||||
}
|
||||
} else fieldMutator(address)
|
||||
}}
|
||||
</OnChange>
|
||||
</>
|
||||
|
|
|
@ -3,15 +3,19 @@
|
|||
import React from 'react'
|
||||
import { Field } from 'react-final-form'
|
||||
|
||||
import { trimSpaces } from 'src/utils/strings'
|
||||
|
||||
const DebounceValidationField = ({ debounce = 1000, validate, ...rest }: any) => {
|
||||
let clearTimeout
|
||||
|
||||
const localValidation = (value, values, fieldState) => {
|
||||
const url = trimSpaces(value)
|
||||
|
||||
if (fieldState.active) {
|
||||
return new Promise((resolve) => {
|
||||
if (clearTimeout) clearTimeout()
|
||||
const timerId = setTimeout(() => {
|
||||
resolve(validate(value, values, fieldState))
|
||||
resolve(validate(url, values, fieldState))
|
||||
}, debounce)
|
||||
clearTimeout = () => {
|
||||
clearTimeout(timerId)
|
||||
|
@ -19,11 +23,11 @@ const DebounceValidationField = ({ debounce = 1000, validate, ...rest }: any) =>
|
|||
}
|
||||
})
|
||||
} else {
|
||||
return validate(value, values, fieldState)
|
||||
return validate(url, values, fieldState)
|
||||
}
|
||||
}
|
||||
|
||||
return <Field {...rest} validate={localValidation} />
|
||||
return <Field {...rest} format={trimSpaces} validate={localValidation} />
|
||||
}
|
||||
|
||||
export default DebounceValidationField
|
||||
|
|
|
@ -7,7 +7,7 @@ import memoize from 'lodash.memoize'
|
|||
type ValidatorReturnType = string | undefined
|
||||
type GenericValidatorType = (...args: unknown[]) => ValidatorReturnType
|
||||
type AsyncValidator = (...args: unknown[]) => Promise<ValidatorReturnType>
|
||||
type Validator = GenericValidatorType | AsyncValidator
|
||||
export type Validator = GenericValidatorType | AsyncValidator
|
||||
|
||||
export const required = (value?: string): ValidatorReturnType => {
|
||||
const required = 'Required'
|
||||
|
|
|
@ -107,7 +107,6 @@ const Details = ({ classes, errors, form }) => {
|
|||
<Block className={classes.root} margin="lg">
|
||||
<Col xs={11}>
|
||||
<AddressInput
|
||||
component={TextField}
|
||||
fieldMutator={(val) => {
|
||||
form.mutators.setValue(FIELD_LOAD_ADDRESS, val)
|
||||
}}
|
||||
|
@ -123,7 +122,6 @@ const Details = ({ classes, errors, form }) => {
|
|||
name={FIELD_LOAD_ADDRESS}
|
||||
placeholder="Safe Address*"
|
||||
text="Safe Address"
|
||||
type="text"
|
||||
testId="load-safe-address-field"
|
||||
/>
|
||||
</Col>
|
||||
|
|
|
@ -135,7 +135,6 @@ const SafeOwners = (props) => {
|
|||
</Col>
|
||||
<Col className={classes.ownerAddress} xs={6}>
|
||||
<AddressInput
|
||||
component={TextField}
|
||||
fieldMutator={(val) => {
|
||||
form.mutators.setValue(addressName, val)
|
||||
}}
|
||||
|
@ -151,7 +150,6 @@ const SafeOwners = (props) => {
|
|||
name={addressName}
|
||||
placeholder="Owner Address*"
|
||||
text="Owner Address"
|
||||
type="text"
|
||||
validators={[getAddressValidator(otherAccounts, index)]}
|
||||
testId={`create-safe-address-field-${index}`}
|
||||
/>
|
||||
|
|
|
@ -5,6 +5,7 @@ import Autocomplete from '@material-ui/lab/Autocomplete'
|
|||
import { List } from 'immutable'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { trimSpaces } from 'src/utils/strings'
|
||||
|
||||
import { styles } from './style'
|
||||
|
||||
|
@ -75,19 +76,20 @@ const AddressBookInput = ({
|
|||
|
||||
const [inputAddValue, setInputAddValue] = useState(recipientAddress)
|
||||
|
||||
const onAddressInputChanged = async (addressValue: string): Promise<void> => {
|
||||
setInputAddValue(addressValue)
|
||||
let resolvedAddress = addressValue
|
||||
const onAddressInputChanged = async (value: string): Promise<void> => {
|
||||
const normalizedAddress = trimSpaces(value)
|
||||
setInputAddValue(normalizedAddress)
|
||||
let resolvedAddress = normalizedAddress
|
||||
let isValidText
|
||||
if (inputTouched && !addressValue) {
|
||||
if (inputTouched && !normalizedAddress) {
|
||||
setIsValidForm(false)
|
||||
setValidationText('Required')
|
||||
setIsValidAddress(false)
|
||||
return
|
||||
}
|
||||
if (addressValue) {
|
||||
if (isValidEnsName(addressValue)) {
|
||||
resolvedAddress = await getAddressFromENS(addressValue)
|
||||
if (normalizedAddress) {
|
||||
if (isValidEnsName(normalizedAddress)) {
|
||||
resolvedAddress = await getAddressFromENS(normalizedAddress)
|
||||
setInputAddValue(resolvedAddress)
|
||||
}
|
||||
isValidText = mustBeEthereumAddress(resolvedAddress)
|
||||
|
@ -101,13 +103,13 @@ const AddressBookInput = ({
|
|||
const filteredADBK = adbkToFilter.filter((adbkEntry) => {
|
||||
const { address, name } = adbkEntry
|
||||
return (
|
||||
name.toLowerCase().includes(addressValue.toLowerCase()) ||
|
||||
address.toLowerCase().includes(addressValue.toLowerCase())
|
||||
name.toLowerCase().includes(normalizedAddress.toLowerCase()) ||
|
||||
address.toLowerCase().includes(normalizedAddress.toLowerCase())
|
||||
)
|
||||
})
|
||||
setADBKList(filteredADBK)
|
||||
if (!isValidText) {
|
||||
setSelectedEntry({ address: addressValue })
|
||||
setSelectedEntry({ address: normalizedAddress })
|
||||
}
|
||||
}
|
||||
setIsValidForm(isValidText === undefined)
|
||||
|
|
|
@ -48,7 +48,7 @@ const formMutators = {
|
|||
|
||||
const useStyles = makeStyles(styles as any)
|
||||
|
||||
const SendFunds = ({ initialValues, onClose, onNext, recipientAddress, selectedToken = '' }) => {
|
||||
const SendFunds = ({ initialValues, onClose, onNext, recipientAddress, selectedToken = '' }): React.ReactElement => {
|
||||
const classes = useStyles()
|
||||
const tokens = useSelector(extendedSafeTokensSelector)
|
||||
const addressBook = useSelector(getAddressBook)
|
||||
|
|
|
@ -9,7 +9,8 @@ import { getSymbolAndDecimalsFromContract } from './utils'
|
|||
import Field from 'src/components/forms/Field'
|
||||
import GnoForm from 'src/components/forms/GnoForm'
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, minMaxLength, mustBeEthereumAddress, required } from 'src/components/forms/validator'
|
||||
import AddressInput from 'src/components/forms/AddressInput'
|
||||
import { composeValidators, minMaxLength, required } from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Button from 'src/components/layout/Button'
|
||||
import Col from 'src/components/layout/Col'
|
||||
|
@ -80,93 +81,102 @@ const AddCustomAsset = (props) => {
|
|||
}
|
||||
}
|
||||
|
||||
const formMutators = {
|
||||
setAssetAddress: (args, state, utils) => {
|
||||
utils.changeValue(state, 'address', () => args[0])
|
||||
},
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
setActiveScreen(parentList)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<GnoForm initialValues={formValues} onSubmit={handleSubmit} testId={ADD_CUSTOM_ASSET_FORM}>
|
||||
{() => (
|
||||
<>
|
||||
<Block className={classes.formContainer}>
|
||||
<Paragraph className={classes.title} noMargin size="lg" weight="bolder">
|
||||
Add custom asset
|
||||
</Paragraph>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
name="address"
|
||||
placeholder="Asset contract address*"
|
||||
testId={ADD_CUSTOM_ASSET_ADDRESS_INPUT_TEST_ID}
|
||||
text="Token contract address*"
|
||||
type="text"
|
||||
validate={composeValidators(
|
||||
required,
|
||||
mustBeEthereumAddress,
|
||||
doesntExistInAssetsList(nftAssetsList),
|
||||
addressIsAssetContract,
|
||||
)}
|
||||
/>
|
||||
<FormSpy
|
||||
onChange={formSpyOnChangeHandler}
|
||||
subscription={{
|
||||
values: true,
|
||||
errors: true,
|
||||
validating: true,
|
||||
dirty: true,
|
||||
submitSucceeded: true,
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Col layout="column" xs={6}>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
name="symbol"
|
||||
placeholder="Token symbol*"
|
||||
testId={ADD_CUSTOM_ASSET_SYMBOLS_INPUT_TEST_ID}
|
||||
text="Token symbol"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(2, 12))}
|
||||
/>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
disabled
|
||||
name="decimals"
|
||||
placeholder="Token decimals*"
|
||||
testId={ADD_CUSTOM_ASSET_DECIMALS_INPUT_TEST_ID}
|
||||
text="Token decimals*"
|
||||
type="text"
|
||||
/>
|
||||
<Block justify="center">
|
||||
<GnoForm
|
||||
initialValues={formValues}
|
||||
onSubmit={handleSubmit}
|
||||
formMutators={formMutators}
|
||||
testId={ADD_CUSTOM_ASSET_FORM}
|
||||
>
|
||||
{(...args) => {
|
||||
const mutators = args[3]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Block className={classes.formContainer}>
|
||||
<Paragraph className={classes.title} noMargin size="lg" weight="bolder">
|
||||
Add custom asset
|
||||
</Paragraph>
|
||||
<AddressInput
|
||||
fieldMutator={mutators.setAssetAddress}
|
||||
className={classes.addressInput}
|
||||
name="address"
|
||||
placeholder="Asset contract address*"
|
||||
testId={ADD_CUSTOM_ASSET_ADDRESS_INPUT_TEST_ID}
|
||||
text="Asset contract address*"
|
||||
validators={[doesntExistInAssetsList(nftAssetsList), addressIsAssetContract]}
|
||||
/>
|
||||
<FormSpy
|
||||
onChange={formSpyOnChangeHandler}
|
||||
subscription={{
|
||||
values: true,
|
||||
errors: true,
|
||||
validating: true,
|
||||
dirty: true,
|
||||
submitSucceeded: true,
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Col layout="column" xs={6}>
|
||||
<Field
|
||||
className={classes.checkbox}
|
||||
component={Checkbox}
|
||||
name="showForAllSafes"
|
||||
type="checkbox"
|
||||
label="Activate assets for all Safes"
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
name="symbol"
|
||||
placeholder="Token symbol*"
|
||||
testId={ADD_CUSTOM_ASSET_SYMBOLS_INPUT_TEST_ID}
|
||||
text="Token symbol"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(2, 12))}
|
||||
/>
|
||||
</Block>
|
||||
</Col>
|
||||
<Col align="center" layout="column" xs={6}>
|
||||
<Paragraph className={classes.tokenImageHeading}>Token Image</Paragraph>
|
||||
<Img alt="Token image" height={100} src={TokenPlaceholder} />
|
||||
</Col>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
disabled
|
||||
name="decimals"
|
||||
placeholder="Token decimals*"
|
||||
testId={ADD_CUSTOM_ASSET_DECIMALS_INPUT_TEST_ID}
|
||||
text="Token decimals*"
|
||||
type="text"
|
||||
/>
|
||||
<Block justify="center">
|
||||
<Field
|
||||
className={classes.checkbox}
|
||||
component={Checkbox}
|
||||
name="showForAllSafes"
|
||||
type="checkbox"
|
||||
label="Activate assets for all Safes"
|
||||
/>
|
||||
</Block>
|
||||
</Col>
|
||||
<Col align="center" layout="column" xs={6}>
|
||||
<Paragraph className={classes.tokenImageHeading}>Token Image</Paragraph>
|
||||
<Img alt="Token image" height={100} src={TokenPlaceholder} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Block>
|
||||
<Hairline />
|
||||
<Row align="center" className={classes.buttonRow}>
|
||||
<Button minHeight={42} minWidth={140} onClick={goBack}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="primary" minHeight={42} minWidth={140} type="submit" variant="contained">
|
||||
Save
|
||||
</Button>
|
||||
</Row>
|
||||
</Block>
|
||||
<Hairline />
|
||||
<Row align="center" className={classes.buttonRow}>
|
||||
<Button minHeight={42} minWidth={140} onClick={goBack}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="primary" minHeight={42} minWidth={140} type="submit" variant="contained">
|
||||
Save
|
||||
</Button>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</GnoForm>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -9,7 +9,8 @@ import { addressIsTokenContract, doesntExistInTokenList } from './validators'
|
|||
import Field from 'src/components/forms/Field'
|
||||
import GnoForm from 'src/components/forms/GnoForm'
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, minMaxLength, mustBeEthereumAddress, required } from 'src/components/forms/validator'
|
||||
import AddressInput from 'src/components/forms/AddressInput'
|
||||
import { composeValidators, minMaxLength, required } from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Button from 'src/components/layout/Button'
|
||||
import Col from 'src/components/layout/Col'
|
||||
|
@ -101,93 +102,102 @@ const AddCustomToken = (props) => {
|
|||
}
|
||||
}
|
||||
|
||||
const formMutators = {
|
||||
setTokenAddress: (args, state, utils) => {
|
||||
utils.changeValue(state, 'address', () => args[0])
|
||||
},
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
setActiveScreen(parentList)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<GnoForm initialValues={formValues} onSubmit={handleSubmit} testId={ADD_CUSTOM_TOKEN_FORM}>
|
||||
{() => (
|
||||
<>
|
||||
<Block className={classes.formContainer}>
|
||||
<Paragraph className={classes.title} noMargin size="lg" weight="bolder">
|
||||
Add custom token
|
||||
</Paragraph>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
name="address"
|
||||
placeholder="Token contract address*"
|
||||
testId={ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID}
|
||||
text="Token contract address*"
|
||||
type="text"
|
||||
validate={composeValidators(
|
||||
required,
|
||||
mustBeEthereumAddress,
|
||||
doesntExistInTokenList(tokens),
|
||||
addressIsTokenContract,
|
||||
)}
|
||||
/>
|
||||
<FormSpy
|
||||
onChange={formSpyOnChangeHandler}
|
||||
subscription={{
|
||||
values: true,
|
||||
errors: true,
|
||||
validating: true,
|
||||
dirty: true,
|
||||
submitSucceeded: true,
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Col layout="column" xs={6}>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
name="symbol"
|
||||
placeholder="Token symbol*"
|
||||
testId={ADD_CUSTOM_TOKEN_SYMBOLS_INPUT_TEST_ID}
|
||||
text="Token symbol"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(2, 12))}
|
||||
/>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
disabled
|
||||
name="decimals"
|
||||
placeholder="Token decimals*"
|
||||
testId={ADD_CUSTOM_TOKEN_DECIMALS_INPUT_TEST_ID}
|
||||
text="Token decimals*"
|
||||
type="text"
|
||||
/>
|
||||
<Block justify="center">
|
||||
<GnoForm
|
||||
initialValues={formValues}
|
||||
onSubmit={handleSubmit}
|
||||
formMutators={formMutators}
|
||||
testId={ADD_CUSTOM_TOKEN_FORM}
|
||||
>
|
||||
{(...args) => {
|
||||
const mutators = args[3]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Block className={classes.formContainer}>
|
||||
<Paragraph className={classes.title} noMargin size="lg" weight="bolder">
|
||||
Add custom token
|
||||
</Paragraph>
|
||||
<AddressInput
|
||||
fieldMutator={mutators.setTokenAddress}
|
||||
className={classes.addressInput}
|
||||
name="address"
|
||||
placeholder="Token contract address*"
|
||||
testId={ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID}
|
||||
text="Token contract address*"
|
||||
validators={[doesntExistInTokenList(tokens), addressIsTokenContract]}
|
||||
/>
|
||||
<FormSpy
|
||||
onChange={formSpyOnChangeHandler}
|
||||
subscription={{
|
||||
values: true,
|
||||
errors: true,
|
||||
validating: true,
|
||||
dirty: true,
|
||||
submitSucceeded: true,
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Col layout="column" xs={6}>
|
||||
<Field
|
||||
className={classes.checkbox}
|
||||
component={Checkbox}
|
||||
name="showForAllSafes"
|
||||
type="checkbox"
|
||||
label="Activate token for all Safes"
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
name="symbol"
|
||||
placeholder="Token symbol*"
|
||||
testId={ADD_CUSTOM_TOKEN_SYMBOLS_INPUT_TEST_ID}
|
||||
text="Token symbol"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(2, 12))}
|
||||
/>
|
||||
</Block>
|
||||
</Col>
|
||||
<Col align="center" layout="column" xs={6}>
|
||||
<Paragraph className={classes.tokenImageHeading}>Token Image</Paragraph>
|
||||
<Img alt="Token image" height={100} src={TokenPlaceholder} />
|
||||
</Col>
|
||||
<Field
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
disabled
|
||||
name="decimals"
|
||||
placeholder="Token decimals*"
|
||||
testId={ADD_CUSTOM_TOKEN_DECIMALS_INPUT_TEST_ID}
|
||||
text="Token decimals*"
|
||||
type="text"
|
||||
/>
|
||||
<Block justify="center">
|
||||
<Field
|
||||
className={classes.checkbox}
|
||||
component={Checkbox}
|
||||
name="showForAllSafes"
|
||||
type="checkbox"
|
||||
label="Activate token for all Safes"
|
||||
/>
|
||||
</Block>
|
||||
</Col>
|
||||
<Col align="center" layout="column" xs={6}>
|
||||
<Paragraph className={classes.tokenImageHeading}>Token Image</Paragraph>
|
||||
<Img alt="Token image" height={100} src={TokenPlaceholder} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Block>
|
||||
<Hairline />
|
||||
<Row align="center" className={classes.buttonRow}>
|
||||
<Button minHeight={42} minWidth={140} onClick={goBack}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="primary" minHeight={42} minWidth={140} type="submit" variant="contained">
|
||||
Save
|
||||
</Button>
|
||||
</Row>
|
||||
</Block>
|
||||
<Hairline />
|
||||
<Row align="center" className={classes.buttonRow}>
|
||||
<Button minHeight={42} minWidth={140} onClick={goBack}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="primary" minHeight={42} minWidth={140} type="submit" variant="contained">
|
||||
Save
|
||||
</Button>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</GnoForm>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -120,7 +120,6 @@ const OwnerForm = ({ classes, onClose, onSubmit, ownerAddress, ownerName }) => {
|
|||
<Col xs={8}>
|
||||
<AddressInput
|
||||
className={classes.addressInput}
|
||||
component={TextField}
|
||||
fieldMutator={mutators.setOwnerAddress}
|
||||
name="ownerAddress"
|
||||
placeholder="Owner address*"
|
||||
|
|
|
@ -45,3 +45,10 @@ export const textShortener = ({ charsEnd = 10, charsStart = 10, ellipsis = '...'
|
|||
|
||||
return `${textStart}${ellipsis}${textEnd}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Util to remove whitespace from both sides of a string.
|
||||
* @param {string} value
|
||||
* @returns {string} string without side whitespaces
|
||||
*/
|
||||
export const trimSpaces = (value: string): string => (value === undefined ? '' : value.trim())
|
||||
|
|
Loading…
Reference in New Issue