mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-23 08:18:17 +00:00
Improve form validation (#1772)
* Change gas price validation to be string input based * Change sanitization to use Nunber * Have validators use Number over parseFloat * Fix css validation class * Add valid css to address field * Add data field validation * Remove unused import * Fix button being hidden on inputs * Dead code removal * Unify textarea and input class validation * Adjust validity styling to only apply after a value has been inputted * Do not pass custom props to DOM
This commit is contained in:
parent
32416469e4
commit
8d27d0ba4d
@ -21,7 +21,7 @@ export const AddressField: React.SFC<Props> = ({ isReadOnly, isSelfAddress, isCh
|
|||||||
{translate(isSelfAddress ? 'X_ADDRESS' : 'SEND_ADDR')}
|
{translate(isSelfAddress ? 'X_ADDRESS' : 'SEND_ADDR')}
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
isValid={isValid}
|
||||||
type="text"
|
type="text"
|
||||||
value={isCheckSummed ? toChecksumAddress(currentTo.raw) : currentTo.raw}
|
value={isCheckSummed ? toChecksumAddress(currentTo.raw) : currentTo.raw}
|
||||||
placeholder={donationAddressMap.ETH}
|
placeholder={donationAddressMap.ETH}
|
||||||
|
@ -23,9 +23,7 @@ export const AmountField: React.SFC<Props> = ({
|
|||||||
<label className="AmountField-group input-group input-group-inline">
|
<label className="AmountField-group input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('SEND_AMOUNT_SHORT')}</div>
|
<div className="input-group-header">{translate('SEND_AMOUNT_SHORT')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${
|
isValid={isAmountValid(raw, customValidator, isValid)}
|
||||||
isAmountValid(raw, customValidator, isValid) ? '' : 'invalid'
|
|
||||||
}`}
|
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="1"
|
placeholder="1"
|
||||||
value={raw}
|
value={raw}
|
||||||
|
@ -66,9 +66,8 @@ export default class AddCustomTokenForm extends React.PureComponent<Props, State
|
|||||||
<label className="AddCustom-field form-group" key={field.name}>
|
<label className="AddCustom-field form-group" key={field.name}>
|
||||||
<div className="input-group-header">{field.label}</div>
|
<div className="input-group-header">{field.label}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`${
|
isValid={!errors[field.name]}
|
||||||
errors[field.name] ? 'invalid' : field.value ? 'valid' : ''
|
className="input-group-input-small"
|
||||||
} input-group-input-small`}
|
|
||||||
type="text"
|
type="text"
|
||||||
name={field.name}
|
name={field.name}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
|
@ -20,7 +20,12 @@ class DetailsClass extends Component<StateProps> {
|
|||||||
<div className="tx-modal-details">
|
<div className="tx-modal-details">
|
||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">Network</div>
|
<div className="input-group-header">Network</div>
|
||||||
<Input readOnly={true} value={`${network} network - provided by ${service}`} />
|
<Input
|
||||||
|
isValid={true}
|
||||||
|
showValidAsPlain={true}
|
||||||
|
readOnly={true}
|
||||||
|
value={`${network} network - provided by ${service}`}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<SerializedTransaction
|
<SerializedTransaction
|
||||||
|
@ -117,7 +117,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="col-sm-9 input-group flex-grow-1">
|
<label className="col-sm-9 input-group flex-grow-1">
|
||||||
<div className="input-group-header">{translate('CUSTOM_NODE_NAME')}</div>
|
<div className="input-group-header">{translate('CUSTOM_NODE_NAME')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${this.state.name && invalids.name ? 'invalid' : ''}`}
|
isValid={!(this.state.name && invalids.name)}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="My Node"
|
placeholder="My Node"
|
||||||
value={this.state.name}
|
value={this.state.name}
|
||||||
@ -142,9 +142,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="col-sm-6 input-group input-group-inline">
|
<label className="col-sm-6 input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_NAME')}</div>
|
<div className="input-group-header">{translate('CUSTOM_NETWORK_NAME')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${
|
isValid={!(this.state.customNetworkId && invalids.customNetworkId)}
|
||||||
this.state.customNetworkId && invalids.customNetworkId ? 'invalid' : ''
|
|
||||||
}`}
|
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="My Custom Network"
|
placeholder="My Custom Network"
|
||||||
value={this.state.customNetworkId}
|
value={this.state.customNetworkId}
|
||||||
@ -154,9 +152,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="col-sm-3 input-group input-group-inline">
|
<label className="col-sm-3 input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_CURRENCY')}</div>
|
<div className="input-group-header">{translate('CUSTOM_NETWORK_CURRENCY')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${
|
isValid={!(this.state.customNetworkUnit && invalids.customNetworkUnit)}
|
||||||
this.state.customNetworkUnit && invalids.customNetworkUnit ? 'invalid' : ''
|
|
||||||
}`}
|
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="ETH"
|
placeholder="ETH"
|
||||||
value={this.state.customNetworkUnit}
|
value={this.state.customNetworkUnit}
|
||||||
@ -166,11 +162,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="col-sm-3 input-group input-group-inline">
|
<label className="col-sm-3 input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_CHAIN_ID')}</div>
|
<div className="input-group-header">{translate('CUSTOM_NETWORK_CHAIN_ID')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${
|
isValid={!(this.state.customNetworkChainId && invalids.customNetworkChainId)}
|
||||||
this.state.customNetworkChainId && invalids.customNetworkChainId
|
|
||||||
? 'invalid'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="1"
|
placeholder="1"
|
||||||
value={this.state.customNetworkChainId}
|
value={this.state.customNetworkChainId}
|
||||||
@ -183,7 +175,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="input-group input-group-inline">
|
<label className="input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_URL')}</div>
|
<div className="input-group-header">{translate('CUSTOM_NETWORK_URL')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${this.state.url && invalids.url ? 'invalid' : ''}`}
|
isValid={!(this.state.url && invalids.url)}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="https://127.0.0.1:8545/"
|
placeholder="https://127.0.0.1:8545/"
|
||||||
value={this.state.url}
|
value={this.state.url}
|
||||||
@ -207,9 +199,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="col-sm-6 input-group input-group-inline">
|
<label className="col-sm-6 input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('INPUT_USERNAME_LABEL')}</div>
|
<div className="input-group-header">{translate('INPUT_USERNAME_LABEL')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${
|
isValid={!(this.state.username && invalids.username)}
|
||||||
this.state.username && invalids.username ? 'invalid' : ''
|
|
||||||
}`}
|
|
||||||
type="text"
|
type="text"
|
||||||
value={this.state.username}
|
value={this.state.username}
|
||||||
onChange={e => this.setState({ username: e.currentTarget.value })}
|
onChange={e => this.setState({ username: e.currentTarget.value })}
|
||||||
@ -218,9 +208,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
|||||||
<label className="col-sm-6 input-group input-group-inline">
|
<label className="col-sm-6 input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('INPUT_PASSWORD_LABEL')}</div>
|
<div className="input-group-header">{translate('INPUT_PASSWORD_LABEL')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${
|
isValid={!(this.state.password && invalids.password)}
|
||||||
this.state.password && invalids.password ? 'invalid' : ''
|
|
||||||
}`}
|
|
||||||
type="password"
|
type="password"
|
||||||
value={this.state.password}
|
value={this.state.password}
|
||||||
onChange={e => this.setState({ password: e.currentTarget.value })}
|
onChange={e => this.setState({ password: e.currentTarget.value })}
|
||||||
|
@ -6,12 +6,12 @@ import { Input } from 'components/ui';
|
|||||||
|
|
||||||
export const DataField: React.SFC<{}> = () => (
|
export const DataField: React.SFC<{}> = () => (
|
||||||
<DataFieldFactory
|
<DataFieldFactory
|
||||||
withProps={({ data: { raw }, dataExists, onChange, readOnly }) => (
|
withProps={({ data: { raw }, validData, onChange, readOnly }) => (
|
||||||
<div className="input-group-wrapper">
|
<div className="input-group-wrapper">
|
||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translate('OFFLINE_STEP2_LABEL_6')}</div>
|
<div className="input-group-header">{translate('OFFLINE_STEP2_LABEL_6')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={dataExists ? 'is-valid' : 'is-invalid'}
|
isValid={validData}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={donationAddressMap.ETH}
|
placeholder={donationAddressMap.ETH}
|
||||||
value={raw}
|
value={raw}
|
||||||
|
@ -7,7 +7,7 @@ import { isEtherTransaction } from 'selectors/transaction';
|
|||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
export interface CallBackProps {
|
export interface CallBackProps {
|
||||||
data: AppState['transaction']['fields']['data'];
|
data: AppState['transaction']['fields']['data'];
|
||||||
dataExists: boolean;
|
validData: boolean;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
onChange(ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>): void;
|
onChange(ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>): void;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Query } from 'components/renderCbs';
|
import { Query } from 'components/renderCbs';
|
||||||
import { getData, getDataExists } from 'selectors/transaction';
|
import { getData } from 'selectors/transaction';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { CallBackProps } from 'components/DataFieldFactory';
|
import { CallBackProps } from 'components/DataFieldFactory';
|
||||||
|
import { isHexString } from 'ethereumjs-util';
|
||||||
|
|
||||||
interface OwnProps {
|
interface OwnProps {
|
||||||
withProps(props: CallBackProps): React.ReactElement<any> | null;
|
withProps(props: CallBackProps): React.ReactElement<any> | null;
|
||||||
@ -11,19 +12,19 @@ interface OwnProps {
|
|||||||
}
|
}
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
data: AppState['transaction']['fields']['data'];
|
data: AppState['transaction']['fields']['data'];
|
||||||
dataExists: boolean;
|
validData: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = OwnProps & StateProps;
|
type Props = OwnProps & StateProps;
|
||||||
|
|
||||||
class DataInputClass extends Component<Props> {
|
class DataInputClass extends Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const { data, onChange, dataExists } = this.props;
|
const { data, onChange, validData } = this.props;
|
||||||
return (
|
return (
|
||||||
<Query
|
<Query
|
||||||
params={['readOnly']}
|
params={['readOnly']}
|
||||||
withQuery={({ readOnly }) =>
|
withQuery={({ readOnly }) =>
|
||||||
this.props.withProps({ data, onChange, readOnly: !!readOnly, dataExists })
|
this.props.withProps({ data, onChange, readOnly: !!readOnly, validData })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -32,5 +33,5 @@ class DataInputClass extends Component<Props> {
|
|||||||
|
|
||||||
export const DataInput = connect((state: AppState) => ({
|
export const DataInput = connect((state: AppState) => ({
|
||||||
data: getData(state),
|
data: getData(state),
|
||||||
dataExists: getDataExists(state)
|
validData: getData(state).raw === '' || isHexString(getData(state).raw)
|
||||||
}))(DataInputClass);
|
}))(DataInputClass);
|
||||||
|
@ -30,7 +30,7 @@ export const GasLimitField: React.SFC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={gasLimitValidator(raw) ? 'is-valid' : 'is-invalid'}
|
isValid={gasLimitValidator(raw)}
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="21000"
|
placeholder="21000"
|
||||||
readOnly={!!readOnly}
|
readOnly={!!readOnly}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
&-refresh {
|
&-refresh {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 1rem;
|
bottom: 0rem;
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ class NonceField extends React.Component<Props> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={`Nonce-field-input ${!!value ? 'is-valid' : 'is-invalid'}`}
|
isValid={!!value}
|
||||||
|
className="Nonce-field-input"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="7"
|
placeholder="7"
|
||||||
value={raw}
|
value={raw}
|
||||||
|
@ -9,7 +9,6 @@ import { NonceField, GasLimitField, DataField } from 'components';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { getAutoGasLimitEnabled } from 'selectors/config';
|
import { getAutoGasLimitEnabled } from 'selectors/config';
|
||||||
import { isValidGasPrice } from 'selectors/transaction';
|
import { isValidGasPrice } from 'selectors/transaction';
|
||||||
import { sanitizeNumericalInput } from 'libs/values';
|
|
||||||
import { Input } from 'components/ui';
|
import { Input } from 'components/ui';
|
||||||
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
||||||
import { getScheduleGasPrice, getTimeBounty } from 'selectors/schedule';
|
import { getScheduleGasPrice, getTimeBounty } from 'selectors/schedule';
|
||||||
@ -83,9 +82,11 @@ class AdvancedGas extends React.Component<Props, State> {
|
|||||||
<div className="input-group-header">
|
<div className="input-group-header">
|
||||||
{translateRaw('OFFLINE_STEP2_LABEL_3')} (gwei)
|
{translateRaw('OFFLINE_STEP2_LABEL_3')} (gwei)
|
||||||
</div>
|
</div>
|
||||||
|
{/*We leave type as string instead of number, because things such as multiple decimals
|
||||||
|
or invalid exponent notation does not fire the onchange handler
|
||||||
|
so the component will not display as invalid for such things */}
|
||||||
<Input
|
<Input
|
||||||
className={!!gasPrice.raw && !validGasPrice ? 'invalid' : ''}
|
isValid={validGasPrice}
|
||||||
type="number"
|
|
||||||
placeholder="40"
|
placeholder="40"
|
||||||
value={gasPrice.raw}
|
value={gasPrice.raw}
|
||||||
onChange={this.handleGasPriceChange}
|
onChange={this.handleGasPriceChange}
|
||||||
@ -173,7 +174,7 @@ class AdvancedGas extends React.Component<Props, State> {
|
|||||||
|
|
||||||
private handleGasPriceChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
private handleGasPriceChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||||
const { value } = ev.currentTarget;
|
const { value } = ev.currentTarget;
|
||||||
this.props.inputGasPrice(sanitizeNumericalInput(value));
|
this.props.inputGasPrice(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
private handleToggleAutoGasLimit = (_: React.FormEvent<HTMLInputElement>) => {
|
private handleToggleAutoGasLimit = (_: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
@ -54,6 +54,9 @@ class FeeSummary extends React.Component<Props> {
|
|||||||
scheduleGasLimit
|
scheduleGasLimit
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
if (!gasPrice.value || gasPrice.value.eqn(0) || !gasLimit.value || gasLimit.value.eqn(0)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (isGasEstimating) {
|
if (isGasEstimating) {
|
||||||
return (
|
return (
|
||||||
<div className="FeeSummary is-loading">
|
<div className="FeeSummary is-loading">
|
||||||
|
@ -69,7 +69,8 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
|
|||||||
<div className={`TogglablePassword input-group input-group-inline`}>
|
<div className={`TogglablePassword input-group input-group-inline`}>
|
||||||
{isTextareaWhenVisible && isVisible ? (
|
{isTextareaWhenVisible && isVisible ? (
|
||||||
<TextArea
|
<TextArea
|
||||||
className={`${className} ${!isValid ? 'invalid' : ''}`}
|
isValid={!!isValid}
|
||||||
|
className={className}
|
||||||
value={value}
|
value={value}
|
||||||
name={name}
|
name={name}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
@ -84,11 +85,12 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Input
|
<Input
|
||||||
|
isValid={!!isValid}
|
||||||
value={value}
|
value={value}
|
||||||
name={name}
|
name={name}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
type={isVisible ? 'text' : 'password'}
|
type={isVisible ? 'text' : 'password'}
|
||||||
className={`${className} ${!isValid ? 'invalid' : ''} border-rad-right-0`}
|
className={`${className} border-rad-right-0`}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onFocus={onFocus}
|
onFocus={onFocus}
|
||||||
|
@ -132,7 +132,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="DWModal-path-custom">
|
<div className="DWModal-path-custom">
|
||||||
<Input
|
<Input
|
||||||
className={customPath ? (isValidPath(customPath) ? 'valid' : 'invalid') : ''}
|
isValid={customPath ? isValidPath(customPath) : true}
|
||||||
value={customPath}
|
value={customPath}
|
||||||
placeholder="m/44'/60'/0'/0"
|
placeholder="m/44'/60'/0'/0"
|
||||||
onChange={this.handleChangeCustomPath}
|
onChange={this.handleChangeCustomPath}
|
||||||
|
@ -65,9 +65,8 @@ export class KeystoreDecrypt extends PureComponent {
|
|||||||
|
|
||||||
{isWalletPending ? <Spinner /> : ''}
|
{isWalletPending ? <Spinner /> : ''}
|
||||||
<Input
|
<Input
|
||||||
className={`${password.length > 0 ? 'is-valid' : 'is-invalid'} ${
|
isValid={password.length > 0}
|
||||||
file.length && isWalletPending ? 'hidden' : ''
|
className={`${file.length && isWalletPending ? 'hidden' : ''}`}
|
||||||
}`}
|
|
||||||
disabled={!file}
|
disabled={!file}
|
||||||
value={password}
|
value={password}
|
||||||
onChange={this.onPasswordChange}
|
onChange={this.onPasswordChange}
|
||||||
|
@ -67,6 +67,8 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
|
|||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<p>{translate('ADD_LABEL_8')}</p>
|
<p>{translate('ADD_LABEL_8')}</p>
|
||||||
<Input
|
<Input
|
||||||
|
isValid={true}
|
||||||
|
showValidAsPlain={true}
|
||||||
value={pass}
|
value={pass}
|
||||||
onChange={this.onPasswordChange}
|
onChange={this.onPasswordChange}
|
||||||
placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
|
placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
|
||||||
|
@ -74,7 +74,7 @@ export class PrivateKeyDecrypt extends PureComponent<Props> {
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translate('ADD_LABEL_3')}</div>
|
<div className="input-group-header">{translate('ADD_LABEL_3')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`form-control ${password.length > 0 ? 'is-valid' : 'is-invalid'}`}
|
isValid={password.length > 0}
|
||||||
value={password}
|
value={password}
|
||||||
onChange={this.onPasswordChange}
|
onChange={this.onPasswordChange}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
|
@ -60,7 +60,8 @@ class ViewOnlyDecryptClass extends PureComponent<Props, State> {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
className={`ViewOnly-input ${isValid ? 'is-valid' : 'is-invalid'}`}
|
isValid={isValid}
|
||||||
|
className="ViewOnly-input"
|
||||||
value={address}
|
value={address}
|
||||||
onChange={this.changeAddress}
|
onChange={this.changeAddress}
|
||||||
placeholder={translateRaw('VIEW_ONLY_ENTER')}
|
placeholder={translateRaw('VIEW_ONLY_ENTER')}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
|
|
||||||
interface RequiredProps {
|
|
||||||
condition: boolean;
|
|
||||||
conditionalProps: {
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional
|
|
||||||
*/
|
|
||||||
export const withConditional = <WrappedComponentProps extends {}>(
|
|
||||||
PassedComponent: React.ComponentType<WrappedComponentProps>
|
|
||||||
) =>
|
|
||||||
class extends Component<WrappedComponentProps & RequiredProps, {}> {
|
|
||||||
public render() {
|
|
||||||
const { condition, conditionalProps, ...passedProps } = this.props as any;
|
|
||||||
return condition ? (
|
|
||||||
<PassedComponent {...{ ...passedProps, ...(conditionalProps as object) }} />
|
|
||||||
) : (
|
|
||||||
<PassedComponent {...passedProps} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export * from './Conditional';
|
|
@ -1,6 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { withConditional } from 'components/hocs';
|
|
||||||
import { Input } from 'components/ui';
|
|
||||||
|
|
||||||
const inpt: React.SFC<React.InputHTMLAttributes<any>> = props => <Input {...props} />;
|
|
||||||
export const ConditionalInput = withConditional(inpt);
|
|
@ -1,33 +1,65 @@
|
|||||||
import React, { HTMLProps } from 'react';
|
import React, { HTMLProps } from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
import './Input.scss';
|
import './Input.scss';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
hasBlurred: boolean;
|
hasBlurred: boolean;
|
||||||
|
/**
|
||||||
|
* @description when the input has not had any values inputted yet
|
||||||
|
* e.g. "Pristine" condition
|
||||||
|
*/
|
||||||
|
isStateless: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Input extends React.Component<HTMLProps<HTMLInputElement>, State> {
|
interface OwnProps extends HTMLProps<HTMLInputElement> {
|
||||||
|
isValid: boolean;
|
||||||
|
showValidAsPlain?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Input extends React.Component<OwnProps, State> {
|
||||||
public state: State = {
|
public state: State = {
|
||||||
hasBlurred: false
|
hasBlurred: false,
|
||||||
|
isStateless: true
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
const { showValidAsPlain, isValid, ...htmlProps } = this.props;
|
||||||
|
const hasValue = !!this.props.value && this.props.value.toString().length > 0;
|
||||||
|
const classname = classnames(
|
||||||
|
this.props.className,
|
||||||
|
'input-group-input',
|
||||||
|
'form-control',
|
||||||
|
this.state.isStateless
|
||||||
|
? ''
|
||||||
|
: isValid ? (showValidAsPlain ? '' : `is-valid valid`) : `is-invalid invalid`,
|
||||||
|
this.state.hasBlurred && 'has-blurred',
|
||||||
|
hasValue && 'has-value'
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
{...this.props}
|
{...htmlProps}
|
||||||
onBlur={e => {
|
onBlur={e => {
|
||||||
this.setState({ hasBlurred: true });
|
this.setState({ hasBlurred: true });
|
||||||
if (this.props && this.props.onBlur) {
|
if (this.props && this.props.onBlur) {
|
||||||
this.props.onBlur(e);
|
this.props.onBlur(e);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onChange={this.handleOnChange}
|
||||||
onWheel={this.props.type === 'number' ? this.preventNumberScroll : undefined}
|
onWheel={this.props.type === 'number' ? this.preventNumberScroll : undefined}
|
||||||
className={`input-group-input ${this.props.className} ${
|
className={classname}
|
||||||
this.state.hasBlurred ? 'has-blurred' : ''
|
|
||||||
} ${!!this.props.value && this.props.value.toString().length > 0 ? 'has-value' : ''}`}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleOnChange = (args: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
if (this.state.isStateless) {
|
||||||
|
this.setState({ isStateless: false });
|
||||||
|
}
|
||||||
|
if (this.props.onChange) {
|
||||||
|
this.props.onChange(args);
|
||||||
|
}
|
||||||
|
};
|
||||||
// When number inputs are scrolled on while in focus, the number changes. So we blur
|
// When number inputs are scrolled on while in focus, the number changes. So we blur
|
||||||
// it if it's focused to prevent that behavior, without preventing the scroll.
|
// it if it's focused to prevent that behavior, without preventing the scroll.
|
||||||
private preventNumberScroll(ev: React.WheelEvent<HTMLInputElement>) {
|
private preventNumberScroll(ev: React.WheelEvent<HTMLInputElement>) {
|
||||||
|
@ -11,7 +11,7 @@ export default class SimpleSelect extends PureComponent<Props, {}> {
|
|||||||
return (
|
return (
|
||||||
<select
|
<select
|
||||||
value={this.props.value || this.props.options[0]}
|
value={this.props.value || this.props.options[0]}
|
||||||
className={'form-control'}
|
className="form-control"
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
>
|
>
|
||||||
{this.props.options.map((obj, i) => {
|
{this.props.options.map((obj, i) => {
|
||||||
|
@ -1,30 +1,62 @@
|
|||||||
import React, { HTMLProps } from 'react';
|
import React, { HTMLProps } from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
import './Input.scss';
|
import './Input.scss';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
hasBlurred: boolean;
|
hasBlurred: boolean;
|
||||||
|
/**
|
||||||
|
* @description when the input has not had any values inputted yet
|
||||||
|
* e.g. "Pristine" condition
|
||||||
|
*/
|
||||||
|
isStateless: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextArea extends React.Component<HTMLProps<HTMLTextAreaElement>, State> {
|
interface OwnProps extends HTMLProps<HTMLTextAreaElement> {
|
||||||
|
isValid: boolean;
|
||||||
|
showValidAsPlain?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextArea extends React.Component<OwnProps, State> {
|
||||||
public state: State = {
|
public state: State = {
|
||||||
hasBlurred: false
|
hasBlurred: false,
|
||||||
|
isStateless: true
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
const { showValidAsPlain, isValid, ...htmlProps } = this.props;
|
||||||
|
const classname = classnames(
|
||||||
|
this.props.className,
|
||||||
|
'input-group-input',
|
||||||
|
'form-control',
|
||||||
|
this.state.isStateless
|
||||||
|
? ''
|
||||||
|
: isValid ? (showValidAsPlain ? '' : `is-valid valid`) : `is-invalid invalid`,
|
||||||
|
this.state.hasBlurred && 'has-blurred'
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
{...this.props}
|
{...htmlProps}
|
||||||
onBlur={e => {
|
onBlur={e => {
|
||||||
this.setState({ hasBlurred: true });
|
this.setState({ hasBlurred: true });
|
||||||
if (this.props && this.props.onBlur) {
|
if (this.props && this.props.onBlur) {
|
||||||
this.props.onBlur(e);
|
this.props.onBlur(e);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`input-group-input ${this.props.className} ${
|
onChange={this.handleOnChange}
|
||||||
this.state.hasBlurred ? 'has-blurred' : ''
|
className={classname}
|
||||||
}`}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleOnChange = (args: React.FormEvent<HTMLTextAreaElement>) => {
|
||||||
|
if (this.state.isStateless) {
|
||||||
|
this.setState({ isStateless: false });
|
||||||
|
}
|
||||||
|
if (this.props.onChange) {
|
||||||
|
this.props.onChange(args);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TextArea;
|
export default TextArea;
|
||||||
|
@ -17,6 +17,5 @@ export { default as TextArea } from './TextArea';
|
|||||||
export { default as Address } from './Address';
|
export { default as Address } from './Address';
|
||||||
export { default as CodeBlock } from './CodeBlock';
|
export { default as CodeBlock } from './CodeBlock';
|
||||||
export { default as Toggle } from './Toggle';
|
export { default as Toggle } from './Toggle';
|
||||||
export * from './ConditionalInput';
|
|
||||||
export * from './Expandable';
|
export * from './Expandable';
|
||||||
export * from './InlineSpinner';
|
export * from './InlineSpinner';
|
||||||
|
@ -65,7 +65,7 @@ class BroadcastTx extends Component<Props> {
|
|||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="0xf86b0284ee6b2800825208944bbeeb066ed09b7aed07bf39eee0460dfa26152088016345785d8a00008029a03ba7a0cc6d1756cd771f2119cf688b6d4dc9d37096089f0331fe0de0d1cc1254a02f7bcd19854c8d46f8de09e457aec25b127ab4328e1c0d24bfbff8702ee1f474"
|
placeholder="0xf86b0284ee6b2800825208944bbeeb066ed09b7aed07bf39eee0460dfa26152088016345785d8a00008029a03ba7a0cc6d1756cd771f2119cf688b6d4dc9d37096089f0331fe0de0d1cc1254a02f7bcd19854c8d46f8de09e457aec25b127ab4328e1c0d24bfbff8702ee1f474"
|
||||||
className={stateTransaction ? '' : 'invalid'}
|
isValid={!!stateTransaction}
|
||||||
value={userInput}
|
value={userInput}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
/>
|
/>
|
||||||
|
@ -42,7 +42,7 @@ class TxHashInput extends React.Component<Props, State> {
|
|||||||
public render() {
|
public render() {
|
||||||
const { recentTxs } = this.props;
|
const { recentTxs } = this.props;
|
||||||
const { hash } = this.state;
|
const { hash } = this.state;
|
||||||
const validClass = hash ? (isValidTxHash(hash) ? 'is-valid' : 'is-invalid') : '';
|
|
||||||
let selectOptions: Option[] = [];
|
let selectOptions: Option[] = [];
|
||||||
|
|
||||||
if (recentTxs && recentTxs.length) {
|
if (recentTxs && recentTxs.length) {
|
||||||
@ -75,8 +75,9 @@ class TxHashInput extends React.Component<Props, State> {
|
|||||||
|
|
||||||
<Input
|
<Input
|
||||||
value={hash}
|
value={hash}
|
||||||
|
isValid={hash ? isValidTxHash(hash) : true}
|
||||||
placeholder="0x16e521..."
|
placeholder="0x16e521..."
|
||||||
className={`TxHashInput-field ${validClass}`}
|
className="TxHashInput-field"
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import translate from 'translations';
|
import translate from 'translations';
|
||||||
import classnames from 'classnames';
|
|
||||||
import { DataFieldFactory } from 'components/DataFieldFactory';
|
import { DataFieldFactory } from 'components/DataFieldFactory';
|
||||||
import { SendButtonFactory } from 'components/SendButtonFactory';
|
import { SendButtonFactory } from 'components/SendButtonFactory';
|
||||||
import WalletDecrypt, { DISABLE_WALLETS } from 'components/WalletDecrypt';
|
import WalletDecrypt, { DISABLE_WALLETS } from 'components/WalletDecrypt';
|
||||||
@ -31,16 +30,15 @@ class DeployClass extends Component<DispatchProps> {
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translate('CONTRACT_BYTECODE')}</div>
|
<div className="input-group-header">{translate('CONTRACT_BYTECODE')}</div>
|
||||||
<DataFieldFactory
|
<DataFieldFactory
|
||||||
withProps={({ data: { raw, value }, onChange, readOnly }) => (
|
withProps={({ data: { raw }, onChange, readOnly, validData }) => (
|
||||||
<TextArea
|
<TextArea
|
||||||
|
isValid={validData && !!raw}
|
||||||
name="byteCode"
|
name="byteCode"
|
||||||
placeholder="0x8f87a973e..."
|
placeholder="0x8f87a973e..."
|
||||||
rows={6}
|
rows={6}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
className={classnames('Deploy-field-input', {
|
className="Deploy-field-input"
|
||||||
'is-valid': value && value.length > 0
|
|
||||||
})}
|
|
||||||
value={raw}
|
value={raw}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AmountFieldFactory } from 'components/AmountFieldFactory';
|
import { AmountFieldFactory } from 'components/AmountFieldFactory';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
|
||||||
import { Input } from 'components/ui';
|
import { Input } from 'components/ui';
|
||||||
|
|
||||||
export const AmountField: React.SFC = () => (
|
export const AmountField: React.SFC = () => (
|
||||||
@ -12,11 +12,10 @@ export const AmountField: React.SFC = () => (
|
|||||||
<Input
|
<Input
|
||||||
name="value"
|
name="value"
|
||||||
value={raw}
|
value={raw}
|
||||||
|
isValid={isValid || raw === ''}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
className={classnames('InteractExplorer-field-input', 'form-control', {
|
className="InteractExplorer-field-input"
|
||||||
'is-invalid': !(isValid || raw === '')
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -116,6 +116,7 @@ class InteractExplorerClass extends Component<Props, State> {
|
|||||||
<div className="input-group-header">{name + ' ' + type}</div>
|
<div className="input-group-header">{name + ' ' + type}</div>
|
||||||
<Input
|
<Input
|
||||||
className="InteractExplorer-func-in-input"
|
className="InteractExplorer-func-in-input"
|
||||||
|
isValid={!!(inputs[name] && inputs[name].rawData)}
|
||||||
name={name}
|
name={name}
|
||||||
value={(inputs[name] && inputs[name].rawData) || ''}
|
value={(inputs[name] && inputs[name].rawData) || ''}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
@ -138,7 +139,8 @@ class InteractExplorerClass extends Component<Props, State> {
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header"> ↳ {name + ' ' + type}</div>
|
<div className="input-group-header"> ↳ {name + ' ' + type}</div>
|
||||||
<Input
|
<Input
|
||||||
className="InteractExplorer-func-out-input "
|
className="InteractExplorer-func-out-input"
|
||||||
|
isValid={!!decodedFieldValue}
|
||||||
value={decodedFieldValue}
|
value={decodedFieldValue}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
|
@ -4,7 +4,6 @@ import { getNetworkContracts } from 'selectors/config';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { AppState } from 'reducers';
|
import { AppState } from 'reducers';
|
||||||
import { isValidETHAddress, isValidAbiJson } from 'libs/validators';
|
import { isValidETHAddress, isValidAbiJson } from 'libs/validators';
|
||||||
import classnames from 'classnames';
|
|
||||||
import { NetworkContract } from 'types/network';
|
import { NetworkContract } from 'types/network';
|
||||||
import { donationAddressMap } from 'config';
|
import { donationAddressMap } from 'config';
|
||||||
import { Input, TextArea, CodeBlock, Dropdown } from 'components/ui';
|
import { Input, TextArea, CodeBlock, Dropdown } from 'components/ui';
|
||||||
@ -126,9 +125,8 @@ class InteractForm extends Component<Props, State> {
|
|||||||
name="contract_address"
|
name="contract_address"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
value={currentTo.raw}
|
value={currentTo.raw}
|
||||||
className={classnames('InteractForm-address-field-input', {
|
isValid={isValid}
|
||||||
invalid: !isValid
|
className="InteractForm-address-field-input"
|
||||||
})}
|
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
@ -144,7 +142,8 @@ class InteractForm extends Component<Props, State> {
|
|||||||
contract.name === 'Custom' ? (
|
contract.name === 'Custom' ? (
|
||||||
<TextArea
|
<TextArea
|
||||||
placeholder={this.abiJsonPlaceholder}
|
placeholder={this.abiJsonPlaceholder}
|
||||||
className={`InteractForm-interface-field-input ${validAbiJson ? '' : 'invalid'}`}
|
isValid={!!validAbiJson}
|
||||||
|
className="InteractForm-interface-field-input"
|
||||||
onChange={this.handleInput('abiJson')}
|
onChange={this.handleInput('abiJson')}
|
||||||
value={abiJson}
|
value={abiJson}
|
||||||
rows={6}
|
rows={6}
|
||||||
@ -155,7 +154,8 @@ class InteractForm extends Component<Props, State> {
|
|||||||
) : (
|
) : (
|
||||||
<TextArea
|
<TextArea
|
||||||
placeholder={this.abiJsonPlaceholder}
|
placeholder={this.abiJsonPlaceholder}
|
||||||
className={`InteractForm-interface-field-input ${validAbiJson ? '' : 'invalid'}`}
|
isValid={!!validAbiJson}
|
||||||
|
className="InteractForm-interface-field-input"
|
||||||
onChange={this.handleInput('abiJson')}
|
onChange={this.handleInput('abiJson')}
|
||||||
value={abiJson}
|
value={abiJson}
|
||||||
rows={6}
|
rows={6}
|
||||||
|
@ -37,9 +37,8 @@ class NameInput extends Component<Props, State> {
|
|||||||
<label className="input-group input-group-inline ENSInput-name">
|
<label className="input-group input-group-inline ENSInput-name">
|
||||||
<Input
|
<Input
|
||||||
value={domainToCheck}
|
value={domainToCheck}
|
||||||
className={`${
|
isValid={!!domainToCheck && isValidDomain}
|
||||||
!domainToCheck ? '' : isValidDomain ? '' : 'invalid'
|
className="border-rad-right-0"
|
||||||
} border-rad-right-0`}
|
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="mycrypto"
|
placeholder="mycrypto"
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
|
@ -21,6 +21,8 @@ const PaperWallet: React.SFC<Props> = props => (
|
|||||||
<h1 className="GenPaper-title">{translate('GEN_LABEL_5')}</h1>
|
<h1 className="GenPaper-title">{translate('GEN_LABEL_5')}</h1>
|
||||||
<Input
|
<Input
|
||||||
value={stripHexPrefix(props.privateKey)}
|
value={stripHexPrefix(props.privateKey)}
|
||||||
|
showValidAsPlain={true}
|
||||||
|
isValid={true}
|
||||||
aria-label={translateRaw('X_PRIVKEY')}
|
aria-label={translateRaw('X_PRIVKEY')}
|
||||||
aria-describedby="x_PrivKeyDesc"
|
aria-describedby="x_PrivKeyDesc"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -61,7 +61,13 @@ export default class MnemonicWord extends React.Component<Props, State> {
|
|||||||
{word}
|
{word}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<Input className="MnemonicWord-word-input" value={word} readOnly={true} />
|
<Input
|
||||||
|
className="MnemonicWord-word-input"
|
||||||
|
value={word}
|
||||||
|
readOnly={true}
|
||||||
|
showValidAsPlain={true}
|
||||||
|
isValid={true}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,7 +38,7 @@ class ScheduleDepositFieldClass extends Component<Props> {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={!!scheduleDeposit.raw && !validScheduleDeposit ? 'invalid' : ''}
|
isValid={scheduleDeposit.raw && validScheduleDeposit}
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="0.00001"
|
placeholder="0.00001"
|
||||||
value={scheduleDeposit.raw}
|
value={scheduleDeposit.raw}
|
||||||
|
@ -34,7 +34,7 @@ class ScheduleGasLimitFieldClass extends React.Component<Props> {
|
|||||||
<InlineSpinner active={gasEstimationPending} text="Calculating" />
|
<InlineSpinner active={gasEstimationPending} text="Calculating" />
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={!!scheduleGasLimit.raw && !validScheduleGasLimit ? 'invalid' : ''}
|
isValid={scheduleGasLimit.raw && validScheduleGasLimit}
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK.toString()}
|
placeholder={EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK.toString()}
|
||||||
value={scheduleGasLimit.raw}
|
value={scheduleGasLimit.raw}
|
||||||
|
@ -27,7 +27,7 @@ class ScheduleGasPriceFieldClass extends React.Component<Props> {
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translateRaw('SCHEDULE_GAS_PRICE')} (gwei)</div>
|
<div className="input-group-header">{translateRaw('SCHEDULE_GAS_PRICE')} (gwei)</div>
|
||||||
<Input
|
<Input
|
||||||
className={!!scheduleGasPrice.raw && !validScheduleGasPrice ? 'invalid' : ''}
|
isValid={scheduleGasPrice.raw && validScheduleGasPrice}
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="40"
|
placeholder="40"
|
||||||
value={scheduleGasPrice.raw}
|
value={scheduleGasPrice.raw}
|
||||||
|
@ -25,7 +25,7 @@ export const TimeBountyField: React.SFC<Props> = ({ isReadOnly }) => (
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
isValid={isValid}
|
||||||
type="text"
|
type="text"
|
||||||
value={currentTimeBounty.raw}
|
value={currentTimeBounty.raw}
|
||||||
placeholder={translateRaw('SCHEDULE_TIMEBOUNTY_PLACEHOLDER')}
|
placeholder={translateRaw('SCHEDULE_TIMEBOUNTY_PLACEHOLDER')}
|
||||||
|
@ -32,7 +32,7 @@ export const WindowSizeField: React.SFC<Props> = ({ isReadOnly }) => (
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
isValid={isValid}
|
||||||
type="text"
|
type="text"
|
||||||
value={currentWindowSize.raw}
|
value={currentWindowSize.raw}
|
||||||
placeholder={
|
placeholder={
|
||||||
|
@ -14,7 +14,7 @@ export const WindowStartField: React.SFC<Props> = ({ isReadOnly }) => (
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translate('SCHEDULE_BLOCK')}</div>
|
<div className="input-group-header">{translate('SCHEDULE_BLOCK')}</div>
|
||||||
<Input
|
<Input
|
||||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
isValid={isValid}
|
||||||
type="text"
|
type="text"
|
||||||
value={currentWindowStart.raw}
|
value={currentWindowStart.raw}
|
||||||
placeholder={translateRaw('SCHEDULE_BLOCK_PLACEHOLDER')}
|
placeholder={translateRaw('SCHEDULE_BLOCK_PLACEHOLDER')}
|
||||||
|
@ -57,7 +57,8 @@ export class SignMessage extends Component<Props, State> {
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translate('MSG_MESSAGE')}</div>
|
<div className="input-group-header">{translate('MSG_MESSAGE')}</div>
|
||||||
<TextArea
|
<TextArea
|
||||||
className={`SignMessage-inputBox ${message ? 'is-valid' : 'is-invalid'}`}
|
isValid={!!message}
|
||||||
|
className="SignMessage-inputBox"
|
||||||
placeholder={messagePlaceholder}
|
placeholder={messagePlaceholder}
|
||||||
value={message}
|
value={message}
|
||||||
onChange={this.handleMessageChange}
|
onChange={this.handleMessageChange}
|
||||||
|
@ -41,7 +41,8 @@ export class VerifyMessage extends Component<Props, State> {
|
|||||||
<label className="input-group">
|
<label className="input-group">
|
||||||
<div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
|
<div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
|
||||||
<TextArea
|
<TextArea
|
||||||
className={`VerifyMessage-inputBox ${signature ? 'is-valid' : 'is-invalid'}`}
|
isValid={!!signature}
|
||||||
|
className="VerifyMessage-inputBox"
|
||||||
placeholder={signaturePlaceholder}
|
placeholder={signaturePlaceholder}
|
||||||
value={signature}
|
value={signature}
|
||||||
onChange={this.handleSignatureChange}
|
onChange={this.handleSignatureChange}
|
||||||
|
@ -316,12 +316,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
|||||||
<div className="input-group input-group-inline">
|
<div className="input-group input-group-inline">
|
||||||
<Input
|
<Input
|
||||||
id="origin-swap-input"
|
id="origin-swap-input"
|
||||||
className={`input-group-input ${
|
isValid={this.isMinMaxValid(origin.amount, origin.label, destination.label)}
|
||||||
!!origin.amount &&
|
|
||||||
this.isMinMaxValid(origin.amount, origin.label, destination.label)
|
|
||||||
? ''
|
|
||||||
: 'invalid'
|
|
||||||
}`}
|
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={translateRaw('SEND_AMOUNT_SHORT')}
|
placeholder={translateRaw('SEND_AMOUNT_SHORT')}
|
||||||
value={isNaN(origin.amount) ? '' : origin.amount}
|
value={isNaN(origin.amount) ? '' : origin.amount}
|
||||||
@ -341,12 +336,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
|||||||
<div className="input-group-header">{translate('SWAP_RECEIVE_INPUT_LABEL')}</div>
|
<div className="input-group-header">{translate('SWAP_RECEIVE_INPUT_LABEL')}</div>
|
||||||
<Input
|
<Input
|
||||||
id="destination-swap-input"
|
id="destination-swap-input"
|
||||||
className={`${
|
isValid={this.isMinMaxValid(origin.amount, origin.label, destination.label)}
|
||||||
!!destination.amount &&
|
|
||||||
this.isMinMaxValid(origin.amount, origin.label, destination.label)
|
|
||||||
? ''
|
|
||||||
: 'invalid'
|
|
||||||
}`}
|
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={translateRaw('SEND_AMOUNT_SHORT')}
|
placeholder={translateRaw('SEND_AMOUNT_SHORT')}
|
||||||
value={isNaN(destination.amount) ? '' : destination.amount}
|
value={isNaN(destination.amount) ? '' : destination.amount}
|
||||||
|
@ -37,7 +37,12 @@ class FieldsClass extends Component<Props> {
|
|||||||
<div className="col-xs-12">
|
<div className="col-xs-12">
|
||||||
<AddressFieldFactory
|
<AddressFieldFactory
|
||||||
withProps={({ currentTo }) => (
|
withProps={({ currentTo }) => (
|
||||||
<Input type="text" value={currentTo.raw} readOnly={true} />
|
<Input
|
||||||
|
type="text"
|
||||||
|
value={currentTo.raw}
|
||||||
|
readOnly={true}
|
||||||
|
isValid={!!currentTo.raw}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -60,6 +65,8 @@ class FieldsClass extends Component<Props> {
|
|||||||
)}
|
)}
|
||||||
{isValid && (
|
{isValid && (
|
||||||
<Input
|
<Input
|
||||||
|
isValid={true}
|
||||||
|
showValidAsPlain={true}
|
||||||
type="text"
|
type="text"
|
||||||
value={`${currentValue.raw} ${this.props.unit}`}
|
value={`${currentValue.raw} ${this.props.unit}`}
|
||||||
readOnly={true}
|
readOnly={true}
|
||||||
|
@ -21,6 +21,7 @@ export default class PaymentInfo extends PureComponent<Props, {}> {
|
|||||||
})}
|
})}
|
||||||
<Input
|
<Input
|
||||||
className="SwapPayment-address"
|
className="SwapPayment-address"
|
||||||
|
isValid={!!this.props.paymentAddress}
|
||||||
value={this.props.paymentAddress || undefined}
|
value={this.props.paymentAddress || undefined}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
|
@ -79,7 +79,8 @@ export default class ReceivingAddress extends PureComponent<StateProps & ActionP
|
|||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
className={`SwapAddress-address-input ${!validAddress ? 'invalid' : ''}`}
|
isValid={validAddress}
|
||||||
|
className="SwapAddress-address-input"
|
||||||
type="text"
|
type="text"
|
||||||
value={destinationAddress}
|
value={destinationAddress}
|
||||||
onChange={this.onChangeDestinationAddress}
|
onChange={this.onChangeDestinationAddress}
|
||||||
|
@ -83,7 +83,13 @@ Rate: ${rates[pair].rate} ${origin.label}/${destination.label}`;
|
|||||||
<small>{translate('SWAP_SUPPORT_LINK_BROKEN')}</small>
|
<small>{translate('SWAP_SUPPORT_LINK_BROKEN')}</small>
|
||||||
</p>
|
</p>
|
||||||
{open ? (
|
{open ? (
|
||||||
<TextArea defaultValue={fallbackBody} className="form-control input-sm" rows={9} />
|
<TextArea
|
||||||
|
isValid={true}
|
||||||
|
showValidAsPlain={true}
|
||||||
|
defaultValue={fallbackBody}
|
||||||
|
className="form-control input-sm"
|
||||||
|
rows={9}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -140,10 +140,10 @@ export function isValidPath(dPath: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const isValidValue = (value: string) =>
|
export const isValidValue = (value: string) =>
|
||||||
!!(value && isFinite(parseFloat(value)) && parseFloat(value) >= 0);
|
!!(value && isFinite(Number(value)) && Number(value) >= 0);
|
||||||
|
|
||||||
export const gasLimitValidator = (gasLimit: number | string) => {
|
export const gasLimitValidator = (gasLimit: number | string) => {
|
||||||
const gasLimitFloat = typeof gasLimit === 'string' ? parseFloat(gasLimit) : gasLimit;
|
const gasLimitFloat = typeof gasLimit === 'string' ? Number(gasLimit) : gasLimit;
|
||||||
return (
|
return (
|
||||||
validNumber(gasLimitFloat) &&
|
validNumber(gasLimitFloat) &&
|
||||||
gasLimitFloat >= GAS_LIMIT_LOWER_BOUND &&
|
gasLimitFloat >= GAS_LIMIT_LOWER_BOUND &&
|
||||||
@ -152,7 +152,7 @@ export const gasLimitValidator = (gasLimit: number | string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const gasPriceValidator = (gasPrice: number | string): boolean => {
|
export const gasPriceValidator = (gasPrice: number | string): boolean => {
|
||||||
const gasPriceFloat = typeof gasPrice === 'string' ? parseFloat(gasPrice) : gasPrice;
|
const gasPriceFloat = typeof gasPrice === 'string' ? Number(gasPrice) : gasPrice;
|
||||||
return (
|
return (
|
||||||
validNumber(gasPriceFloat) &&
|
validNumber(gasPriceFloat) &&
|
||||||
gasPriceFloat >= GAS_PRICE_GWEI_LOWER_BOUND &&
|
gasPriceFloat >= GAS_PRICE_GWEI_LOWER_BOUND &&
|
||||||
@ -172,7 +172,7 @@ export const timeBountyValidator = (timeBounty: BN | number | string | null): bo
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeBountyFloat = typeof timeBounty === 'string' ? parseFloat(timeBounty) : timeBounty;
|
const timeBountyFloat = typeof timeBounty === 'string' ? Number(timeBounty) : timeBounty;
|
||||||
|
|
||||||
return validNumber(timeBountyFloat);
|
return validNumber(timeBountyFloat);
|
||||||
};
|
};
|
||||||
|
@ -44,7 +44,7 @@ export const buildEIP681TokenRequest = (
|
|||||||
}`;
|
}`;
|
||||||
|
|
||||||
export const sanitizeNumericalInput = (input: string): string => {
|
export const sanitizeNumericalInput = (input: string): string => {
|
||||||
const inputFloat = parseFloat(input);
|
const inputFloat = Number(input);
|
||||||
|
|
||||||
if (!input || isNaN(inputFloat)) {
|
if (!input || isNaN(inputFloat)) {
|
||||||
return input;
|
return input;
|
||||||
|
@ -31,12 +31,12 @@ export function* handleGasLimitInput({ payload }: InputGasLimitAction): SagaIter
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function* handleGasPriceInput({ payload }: InputGasPriceAction): SagaIterator {
|
export function* handleGasPriceInput({ payload }: InputGasPriceAction): SagaIterator {
|
||||||
const priceFloat = parseFloat(payload);
|
const gasPrice = Number(payload);
|
||||||
const validGasPrice: boolean = yield call(gasPriceValidator, priceFloat);
|
const validGasPrice: boolean = yield call(gasPriceValidator, gasPrice);
|
||||||
yield put(
|
yield put(
|
||||||
setGasPriceField({
|
setGasPriceField({
|
||||||
raw: payload,
|
raw: payload,
|
||||||
value: validGasPrice ? gasPriceToBase(priceFloat) : Wei('0')
|
value: validGasPrice ? gasPriceToBase(gasPrice) : Wei('0')
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
z-index: 999;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user