Merge pull request #41 from andrerfneves/feature/transaction-confirm-modal

Feature/transaction confirm modal
This commit is contained in:
André Neves 2019-01-23 21:00:24 -05:00 committed by GitHub
commit f949cb226d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 496 additions and 150 deletions

View File

@ -50,54 +50,64 @@ type Props = {
renderTrigger: (() => void) => Element<*>,
title: string,
onConfirm: () => void,
onClose?: () => void,
showButtons?: boolean,
width?: number,
isLoading?: boolean,
children: Element<*>,
children: (() => void) => Element<*>,
};
export const ConfirmDialogComponent = ({
children,
title,
onConfirm,
onClose,
renderTrigger,
showButtons,
isLoading,
width,
}: Props) => (
<ModalComponent
renderTrigger={renderTrigger}
closeOnBackdropClick={false}
closeOnEsc={false}
>
{toggle => (
<Wrapper width={width}>
<CloseIconWrapper>
<CloseIconImg src={CloseIcon} onClick={toggle} />
</CloseIconWrapper>
<TitleWrapper>
<TextComponent value={title} align='center' />
</TitleWrapper>
<Divider />
{React.Children.map(children, _ => _)}
{showButtons && (
<>
<Btn label='Confirm' onClick={onConfirm} isLoading={isLoading} />
<Btn
label='Cancel'
onClick={toggle}
variant='secondary'
disabled={isLoading}
/>
</>
)}
</Wrapper>
)}
</ModalComponent>
);
}: Props) => {
const handleClose = toggle => () => {
toggle();
if (onClose) onClose();
};
return (
<ModalComponent
renderTrigger={renderTrigger}
closeOnBackdropClick={false}
closeOnEsc={false}
>
{toggle => (
<Wrapper width={width}>
<CloseIconWrapper>
<CloseIconImg src={CloseIcon} onClick={handleClose(toggle)} />
</CloseIconWrapper>
<TitleWrapper>
<TextComponent value={title} align='center' />
</TitleWrapper>
<Divider opacity={0.3} />
{children(handleClose(toggle))}
{showButtons && (
<>
<Btn label='Confirm' onClick={onConfirm} isLoading={isLoading} />
<Btn
label='Cancel'
onClick={handleClose(toggle)}
variant='secondary'
disabled={isLoading}
/>
</>
)}
</Wrapper>
)}
</ModalComponent>
);
};
ConfirmDialogComponent.defaultProps = {
showButtons: true,
width: 460,
isLoading: false,
onClose: () => {},
};

View File

@ -24,7 +24,7 @@ import { DoczWrapper } from '../theme.js'
onConfirm={() => alert('Confirm')}
renderTrigger={toggle => <button onClick={toggle}> Open! </button>}
>
<div>Confirm content</div>
{toggle => <div>Confirm content</div>}
</ConfirmDialogComponent>
)}
</DoczWrapper>

View File

@ -6,4 +6,6 @@ export const Divider = styled.div`
height: 1px;
background-color: ${props => props.color || props.theme.colors.text};
opacity: ${props => props.opacity || 1};
margin-bottom: ${props => props.marginBottom || 0};
margin-top: ${props => props.marginTop || 0};
`;

View File

@ -1,5 +1,5 @@
// @flow
import React from 'react';
import React, { type Element } from 'react';
import styled from 'styled-components';
import theme from '../theme';
@ -11,6 +11,7 @@ const getDefaultStyles = t => styled[t]`
props => props.bgColor || props.theme.colors.inputBackground};
color: ${props => props.theme.colors.text};
padding: 15px;
padding-right: ${props => (props.withRightElement ? '85px' : '15px')};
width: 100%;
outline: none;
font-family: ${props => props.theme.fontFamily};
@ -20,6 +21,16 @@ const getDefaultStyles = t => styled[t]`
}
`;
const Wrapper = styled.div`
position: relative;
`;
const RightElement = styled.div`
position: absolute;
top: 15px;
right: 15px;
`;
const Input = getDefaultStyles('input');
const Textarea = getDefaultStyles('textarea');
@ -32,6 +43,7 @@ type Props = {
disabled?: boolean,
type?: string,
step?: number,
renderRight?: () => Element<*> | null,
bgColor?: string,
};
@ -39,12 +51,16 @@ export const InputComponent = ({
inputType,
bgColor,
onChange = () => {},
renderRight = () => null,
...props
}: Props) => {
const rightElement = renderRight();
const inputTypes = {
input: () => (
<Input
onChange={evt => onChange(evt.target.value)}
withRightElement={Boolean(rightElement)}
bgColor={bgColor}
{...props}
/>
@ -62,7 +78,12 @@ export const InputComponent = ({
throw new Error(`Invalid input type: ${String(inputType)}`);
}
return inputTypes[inputType || 'input']();
return (
<Wrapper>
{inputTypes[inputType || 'input']()}
{rightElement && <RightElement>{rightElement}</RightElement>}
</Wrapper>
);
};
InputComponent.defaultProps = {
@ -70,5 +91,9 @@ InputComponent.defaultProps = {
rows: 4,
disabled: false,
type: 'text',
renderRight: () => null,
onChange: () => {},
onFocus: () => {},
step: 1,
bgColor: theme.colors.inputBackground,
};

View File

@ -1,8 +1,8 @@
// @flow
export default {
LOW: 1,
MEDIUM: 5,
HIGH: 9,
LOW: 0.001,
MEDIUM: 0.005,
HIGH: 0.009,
CUSTOM: 'custom',
};

View File

@ -11,6 +11,8 @@ import {
sendTransactionSuccess,
sendTransactionError,
resetSendTransaction,
validateAddressSuccess,
validateAddressError,
} from '../redux/modules/send';
import filterObjectNullKeys from '../utils/filterObjectNullKeys';
@ -33,6 +35,7 @@ const mapStateToProps = ({ walletSummary, sendStatus }: AppState) => ({
error: sendStatus.error,
isSending: sendStatus.isSending,
operationId: sendStatus.operationId,
isToAddressValid: sendStatus.isToAddressValid,
});
const mapDispatchToProps = (dispatch: Dispatch) => ({
@ -61,12 +64,67 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
),
);
// eslint-disable-next-line
// eslint-disable-next-line max-len
if (sendErr || !operationId) return dispatch(sendTransactionError({ error: sendErr.message }));
dispatch(sendTransactionSuccess({ operationId }));
/**
Output is a list of operation status objects.
[
{operationid: opid-12ee,
status: queued},
{operationid: opd-098a, status: executing},
{operationid: opid-9876, status: failed}
]
When the operation succeeds, the status object will also include the result.
{operationid: opid-0e0e, status:success, execution_time:25, result: {txid:af3887654,...}}
then the promise will only be resolved when a "success" or "failure" status is obtained
*/
const interval = setInterval(async () => {
const [, status] = await eres(rpc.z_getoperationstatus());
const operationStatus = status.find(({ id }) => operationId === id);
if (operationStatus && operationStatus.status === 'success') {
clearInterval(interval);
dispatch(
sendTransactionSuccess({ operationId: operationStatus.result.txid }),
);
}
if (operationStatus && operationStatus.status === 'failed') {
clearInterval(interval);
dispatch(
sendTransactionError({ error: operationStatus.error.message }),
);
}
}, 2000);
},
resetSendView: () => dispatch(resetSendTransaction()),
validateAddress: async ({ address }: { address: string }) => {
if (address.startsWith('z')) {
const [, validationResult] = await eres(rpc.z_validateaddress(address));
return dispatch(
validateAddressSuccess({
isValid: Boolean(validationResult && validationResult.isvalid),
}),
);
}
const [, validationResult] = await eres(rpc.validateaddress(address));
if (validationResult) {
return dispatch(
validateAddressSuccess({
isValid: Boolean(validationResult && validationResult.isvalid),
}),
);
}
return dispatch(validateAddressError());
},
});
// $FlowFixMe

View File

@ -5,6 +5,8 @@ export const SEND_TRANSACTION = 'SEND_TRANSACTION';
export const SEND_TRANSACTION_SUCCESS = 'SEND_TRANSACTION_SUCCESS';
export const SEND_TRANSACTION_ERROR = 'SEND_TRANSACTION_ERROR';
export const RESET_SEND_TRANSACTION = 'RESET_SEND_TRANSACTION';
export const VALIDATE_ADDRESS_SUCCESS = 'VALIDATE_ADDRESS_SUCCESS';
export const VALIDATE_ADDRESS_ERROR = 'VALIDATE_ADDRESS_SUCCESS';
export const sendTransaction = () => ({
type: SEND_TRANSACTION,
@ -34,34 +36,65 @@ export const resetSendTransaction = () => ({
payload: {},
});
export const validateAddressSuccess = ({ isValid }: { isValid: boolean }) => ({
type: VALIDATE_ADDRESS_SUCCESS,
payload: {
isValid,
},
});
export const validateAddressError = () => ({
type: VALIDATE_ADDRESS_ERROR,
payload: {},
});
export type State = {
isSending: boolean,
isToAddressValid: boolean,
error: string | null,
operationId: string | null,
};
const initialState = {
const initialState: State = {
isSending: false,
error: null,
operationId: null,
isToAddressValid: false,
};
export default (state: State = initialState, action: Action): State => {
switch (action.type) {
case SEND_TRANSACTION:
return { isSending: true, error: null, operationId: null };
return {
...state,
isSending: true,
error: null,
operationId: null,
};
case SEND_TRANSACTION_SUCCESS:
return {
...state,
isSending: false,
error: null,
operationId: action.payload.operationId,
};
case SEND_TRANSACTION_ERROR:
return {
...state,
isSending: false,
error: action.payload.error,
operationId: null,
};
case VALIDATE_ADDRESS_SUCCESS:
return {
...state,
isToAddressValid: action.payload.isValid,
};
case VALIDATE_ADDRESS_ERROR:
return {
...state,
isToAddressValid: false,
};
case RESET_SEND_TRANSACTION:
return initialState;
default:

View File

@ -73,6 +73,7 @@ const appTheme = {
selectButtonShadow,
transactionsDetailsLabel,
statusPillLabel,
modalItemLabel: transactionsDate,
blackTwo,
buttonBorderColor,
},

View File

@ -1,6 +1,6 @@
// @flow
import React, { PureComponent } from 'react';
import styled from 'styled-components';
import styled, { keyframes } from 'styled-components';
import { BigNumber } from 'bignumber.js';
import FEES from '../constants/fees';
@ -13,15 +13,39 @@ import { RowComponent } from '../components/row';
import { ColumnComponent } from '../components/column';
import { Divider } from '../components/divider';
import { Button } from '../components/button';
import MenuIcon from '../assets/images/menu_icon.svg';
import { ConfirmDialogComponent } from '../components/confirm-dialog';
import formatNumber from '../utils/formatNumber';
import type { SendTransactionInput } from '../containers/send';
import type { State as SendState } from '../redux/modules/send';
import SentIcon from '../assets/images/transaction_sent_icon.svg';
import MenuIcon from '../assets/images/menu_icon.svg';
import ValidIcon from '../assets/images/green_check.png';
import InvalidIcon from '../assets/images/error_icon.png';
import LoadingIcon from '../assets/images/sync_icon.png';
import theme from '../theme';
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const Loader = styled.img`
width: 25px;
height: 25px;
animation: 2s linear infinite;
animation-name: ${rotate};
margin-bottom: 10px;
`;
const FormWrapper = styled.div`
margin-top: ${props => props.theme.layoutContentPaddingTop};
width: 71%;
@ -134,10 +158,75 @@ const FormButton = styled(Button)`
}
`;
const SuccessWrapper = styled(ColumnComponent)`
const ModalContent = styled(ColumnComponent)`
min-height: 400px;
align-items: center;
justify-content: center;
height: 100%;
p {
word-break: break-all;
}
`;
const ConfirmItemWrapper = styled(RowComponent)`
padding: 22.5px 33.5px;
width: 100%;
`;
const ItemLabel = styled(TextComponent)`
font-weight: ${props => props.theme.fontWeight.bold};
font-size: ${props => props.theme.fontSize.small};
color: ${props => props.color || props.theme.colors.modalItemLabel};
margin-bottom: 3.5px;
`;
const SendZECValue = styled(TextComponent)`
color: ${props => props.theme.colors.transactionSent};
font-size: ${props => `${props.theme.fontSize.large}em`};
font-weight: ${props => props.theme.fontWeight.bold};
`;
const SendUSDValue = styled(TextComponent)`
opacity: 0.5;
font-weight: ${props => props.theme.fontWeight.light};
font-size: ${props => `${props.theme.fontSize.medium}em`};
`;
const Icon = styled.img`
width: 35px;
height: 35px;
margin-left: 15px;
`;
const ValidateStatusIcon = styled.img`
width: 13px;
height: 13px;
margin-right: 7px;
`;
const ShowFeeButton = styled.button`
background: none;
border: none;
cursor: pointer;
width: 100%;
color: ${props => props.theme.colors.text};
outline: none;
display: flex;
align-items: center;
margin-top: 30px;
opacity: 0.7;
&:hover {
opacity: 1;
}
`;
const SeeMoreIcon = styled.img`
width: 25px;
height: 25px;
border: 1px solid ${props => props.theme.colors.text};
border-radius: 100%;
margin-right: 11.5px;
`;
type Props = SendState & {
@ -146,6 +235,7 @@ type Props = SendState & {
addresses: string[],
sendTransaction: SendTransactionInput => void,
resetSendView: () => void,
validateAddress: ({ address: string }) => void,
};
type State = {
@ -173,31 +263,35 @@ export class SendView extends PureComponent<Props, State> {
componentDidMount() {
const { resetSendView } = this.props;
resetSendView();
}
handleChange = (field: string) => (value: string) => {
this.setState(() => ({ [field]: value }));
const { validateAddress } = this.props;
if (field === 'to') {
// eslint-disable-next-line max-len
this.setState({ [field]: value }, () => validateAddress({ address: value }));
} else {
this.setState(() => ({ [field]: value }));
}
};
handleChangeFeeType = (value: string) => {
this.setState(
{
feeType: value,
if (value === FEES.CUSTOM) {
this.setState({
feeType: FEES.CUSTOM,
fee: null,
},
() => {
if (
value === String(FEES.LOW)
|| value === String(FEES.MEDIUM)
|| value === String(FEES.HIGH)
) {
this.setState(() => ({
fee: Number(value),
}));
}
},
);
});
} else {
const fee = new BigNumber(value);
this.setState({
feeType: fee.toString(),
fee: fee.toNumber(),
});
}
};
handleSubmit = () => {
@ -217,12 +311,133 @@ export class SendView extends PureComponent<Props, State> {
});
};
showModal = (toggle: void => void) => () => {
const {
from, amount, to, fee,
} = this.state;
const { isToAddressValid } = this.props;
if (!from || !amount || !to || !fee || !isToAddressValid) return;
toggle();
};
reset = () => {
const { resetSendView } = this.props;
this.setState(initialState, () => resetSendView());
};
getFeeText = () => {
const { fee } = this.state;
const feeValue = new BigNumber(fee);
if (feeValue.isEqualTo(FEES.LOW)) return `Low ZEC ${feeValue.toString()}`;
// eslint-disable-next-line max-len
if (feeValue.isEqualTo(FEES.MEDIUM)) return `Medium ZEC ${feeValue.toString()}`;
if (feeValue.isEqualTo(FEES.HIGH)) return `High ZEC ${feeValue.toString()}`;
return `Custom ZEC ${feeValue.toString()}`;
};
renderValidationStatus = () => {
const { isToAddressValid } = this.props;
return isToAddressValid ? (
<RowComponent alignItems='center'>
<ValidateStatusIcon src={ValidIcon} />
<ItemLabel value='VALID' color={theme.colors.transactionReceived} />
</RowComponent>
) : (
<RowComponent alignItems='center'>
<ValidateStatusIcon src={InvalidIcon} />
<ItemLabel value='INVALID' color={theme.colors.transactionSent} />
</RowComponent>
);
};
renderModalContent = ({
valueSent,
valueSentInUsd,
toggle,
}: {
valueSent: string,
valueSentInUsd: string,
toggle: () => void,
}) => {
const { operationId, isSending, error } = this.props;
const { from, to } = this.state;
if (isSending) {
return (
<>
<Loader src={LoadingIcon} />
<TextComponent value='Processing transaction...' />
</>
);
}
if (operationId) {
return (
<>
<TextComponent
value={`Transaction ID: ${operationId}`}
align='center'
/>
<button
type='button'
onClick={() => {
this.reset();
toggle();
}}
>
Send again!
</button>
</>
);
}
if (error) return <TextComponent value={error} />;
return (
<>
<ConfirmItemWrapper alignItems='center'>
<ColumnComponent>
<ItemLabel value='AMOUNT' />
<SendZECValue value={`-${valueSent}`} />
<SendUSDValue value={`-${valueSentInUsd}`} />
</ColumnComponent>
<ColumnComponent>
<Icon src={SentIcon} alt='Transaction Type Icon' />
</ColumnComponent>
</ConfirmItemWrapper>
<Divider opacity={0.3} />
<ConfirmItemWrapper alignItems='center'>
<ColumnComponent>
<ItemLabel value='FEE' />
<TextComponent value={this.getFeeText()} />
</ColumnComponent>
</ConfirmItemWrapper>
<Divider opacity={0.3} />
<ConfirmItemWrapper alignItems='center'>
<ColumnComponent>
<ItemLabel value='FROM' />
<TextComponent value={from} />
</ColumnComponent>
</ConfirmItemWrapper>
<Divider opacity={0.3} />
<ConfirmItemWrapper alignItems='center'>
<ColumnComponent>
<ItemLabel value='TO' />
<TextComponent value={to} />
</ColumnComponent>
</ConfirmItemWrapper>
<Divider opacity={0.3} marginBottom='27.5px' />
</>
);
};
render() {
const {
addresses,
@ -233,13 +448,7 @@ export class SendView extends PureComponent<Props, State> {
operationId,
} = this.props;
const {
showFee,
from,
amount,
to,
memo,
fee,
feeType,
showFee, from, amount, to, memo, fee, feeType,
} = this.state;
const isEmpty = amount === '';
@ -260,20 +469,9 @@ export class SendView extends PureComponent<Props, State> {
append: 'USD $',
});
return operationId ? (
<SuccessWrapper>
<TextComponent value={`Processing operation: ${operationId}`} />
<TextComponent value={`Amount: ${amount}`} />
<TextComponent value={`From: ${from}`} />
<TextComponent value={`To: ${to}`} />
<button type='button' onClick={this.reset}>
Send again!
</button>
</SuccessWrapper>
) : (
return (
<RowComponent justifyContent='space-between'>
<FormWrapper>
{error && <TextComponent value={error} />}
<InputLabelComponent value='From' />
<SelectComponent
onChange={this.handleChange('from')}
@ -297,6 +495,7 @@ export class SendView extends PureComponent<Props, State> {
onChange={this.handleChange('to')}
value={to}
placeholder='Enter Address'
renderRight={to ? this.renderValidationStatus : () => null}
/>
<InputLabelComponent value='Memo' />
<InputComponent
@ -309,9 +508,7 @@ export class SendView extends PureComponent<Props, State> {
onClick={() => this.setState(state => ({ showFee: !state.showFee }))
}
>
<SeeMoreButton isOpen={showFee}>
<SeeMoreIcon src={MenuIcon} alt='' />
</SeeMoreButton>
<SeeMoreIcon src={MenuIcon} alt='Show more icon' />
<TextComponent
value={`${showFee ? 'Hide' : 'Show'} Additional Options`}
/>
@ -355,20 +552,33 @@ export class SendView extends PureComponent<Props, State> {
<TextComponent value={zecBalance} size={1.25} isBold />
<InfoCardUSD value={zecBalanceInUsd} size={0.84375} />
</InfoContent>
<Divider opacity={0.5} />
<Divider opacity={0.3} />
<InfoContent>
<InfoCardLabel value='Sending' />
<TextComponent value={valueSent} size={1.25} isBold />
<InfoCardUSD value={valueSentInUsd} size={0.84375} />
</InfoContent>
</InfoCard>
<FormButton
label='Send'
variant='secondary'
focused
onClick={this.handleSubmit}
isLoading={isSending}
/>
<ConfirmDialogComponent
title='Please Confirm Transaction Details'
onConfirm={this.handleSubmit}
renderTrigger={toggle => (
<FormButton
label='Send'
variant='secondary'
focused
onClick={this.showModal(toggle)}
/>
)}
showButtons={!isSending && !error && !operationId}
onClose={this.reset}
>
{toggle => (
<ModalContent>
{this.renderModalContent({ valueSent, valueSentInUsd, toggle })}
</ModalContent>
)}
</ConfirmDialogComponent>
<FormButton label='Cancel' variant='secondary' />
</SendWrapper>
</RowComponent>

View File

@ -224,26 +224,28 @@ export class SettingsView extends PureComponent<Props, State> {
showButtons={!successExportViewKeys}
width={750}
>
<ModalContent>
{successExportViewKeys ? (
viewKeys.map(({ zAddress, key }) => (
<>
<InputLabelComponent value={zAddress} />
<RowComponent alignItems='center'>
<InputComponent
value={key}
onFocus={(event) => {
event.currentTarget.select();
}}
/>
<ClipboardButton text={key} />
</RowComponent>
</>
))
) : (
<TextComponent value='Ut id vulputate arcu. Curabitur mattis aliquam magna sollicitudin vulputate. Morbi tempus bibendum porttitor. Quisque dictum ac ipsum a luctus. Donec et lacus ac erat consectetur molestie a id erat.' />
)}
</ModalContent>
{() => (
<ModalContent>
{successExportViewKeys ? (
viewKeys.map(({ zAddress, key }) => (
<>
<InputLabelComponent value={zAddress} />
<RowComponent alignItems='center'>
<InputComponent
value={key}
onFocus={(event) => {
event.currentTarget.select();
}}
/>
<ClipboardButton text={key} />
</RowComponent>
</>
))
) : (
<TextComponent value='Ut id vulputate arcu. Curabitur mattis aliquam magna sollicitudin vulputate. Morbi tempus bibendum porttitor. Quisque dictum ac ipsum a luctus. Donec et lacus ac erat consectetur molestie a id erat.' />
)}
</ModalContent>
)}
</ConfirmDialogComponent>
<ConfirmDialogComponent
@ -259,26 +261,28 @@ export class SettingsView extends PureComponent<Props, State> {
showButtons={!successExportPrivateKeys}
width={750}
>
<ModalContent>
{successExportPrivateKeys ? (
privateKeys.map(({ zAddress, key }) => (
<>
<InputLabelComponent value={zAddress} />
<RowComponent alignItems='center'>
<InputComponent
value={key}
onFocus={(event) => {
event.currentTarget.select();
}}
/>
<ClipboardButton text={key} />
</RowComponent>
</>
))
) : (
<TextComponent value='Ut id vulputate arcu. Curabitur mattis aliquam magna sollicitudin vulputate. Morbi tempus bibendum porttitor. Quisque dictum ac ipsum a luctus. Donec et lacus ac erat consectetur molestie a id erat.' />
)}
</ModalContent>
{() => (
<ModalContent>
{successExportPrivateKeys ? (
privateKeys.map(({ zAddress, key }) => (
<>
<InputLabelComponent value={zAddress} />
<RowComponent alignItems='center'>
<InputComponent
value={key}
onFocus={(event) => {
event.currentTarget.select();
}}
/>
<ClipboardButton text={key} />
</RowComponent>
</>
))
) : (
<TextComponent value='Ut id vulputate arcu. Curabitur mattis aliquam magna sollicitudin vulputate. Morbi tempus bibendum porttitor. Quisque dictum ac ipsum a luctus. Donec et lacus ac erat consectetur molestie a id erat.' />
)}
</ModalContent>
)}
</ConfirmDialogComponent>
<ConfirmDialogComponent
@ -295,22 +299,25 @@ export class SettingsView extends PureComponent<Props, State> {
width={900}
isLoading={isLoading}
>
<ModalContent>
<InputLabelComponent value='Please paste your private keys here, one per line. The keys will be imported into your zcashd node' />
<InputComponent
value={importedPrivateKeys}
onChange={value => this.setState({ importedPrivateKeys: value })}
inputType='textarea'
rows={10}
/>
{successImportPrivateKeys && (
<TextComponent
value='Private keys imported in your node'
align='center'
{() => (
<ModalContent>
<InputLabelComponent value='Please paste your private keys here, one per line. The keys will be imported into your zcashd node' />
<InputComponent
value={importedPrivateKeys}
onChange={value => this.setState({ importedPrivateKeys: value })
}
inputType='textarea'
rows={10}
/>
)}
{error && <TextComponent value={error} align='center' />}
</ModalContent>
{successImportPrivateKeys && (
<TextComponent
value='Private keys imported in your node'
align='center'
/>
)}
{error && <TextComponent value={error} align='center' />}
</ModalContent>
)}
</ConfirmDialogComponent>
<SettingWrapper>

View File

@ -746,8 +746,8 @@ export type APIMethods = {
z_exportwallet: (filename: string) => Promise<string>,
z_getbalance: (address: string, minconf?: number) => Promise<number>,
z_getnewaddress: (type: ?string) => Promise<string>,
z_getoperationresult: (operationid?: string[]) => Promise<Object[]>,
z_getoperationstatus: (operationid?: string[]) => Promise<Object[]>,
z_getoperationresult: (operationid?: string) => Promise<Object[]>,
z_getoperationstatus: (operationids?: string) => Promise<Object[]>,
z_gettotalbalance: (
minconf?: number,
includeWatchonly?: boolean,