Merge pull request #92 from andrerfneves/bugfix/review

Bugfix/review
This commit is contained in:
André Neves 2019-03-27 22:25:58 -04:00 committed by GitHub
commit 2ecf0b5cee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 188 additions and 141 deletions

View File

@ -15,11 +15,11 @@ describe('Startup', () => {
test('should open the window', () => expect(app.client.getWindowCount()).resolves.toEqual(1));
test('should have the right title', () => {
expect(app.client.getTitle()).resolves.toEqual('ZEC Wallet');
expect(app.client.getTitle()).resolves.toEqual('Zepio');
});
test('should show the text "ZEC Wallet Starting" in loading screen', async () => expect(app.client.element('#loading-screen:first-child p').getHTML()).resolves.toEqual(
expect.stringContaining('ZEC Wallet Starting'),
test('should show the text "Zepio Starting" in loading screen', async () => expect(app.client.element('#loading-screen:first-child p').getHTML()).resolves.toEqual(
expect.stringContaining('Zepio Starting'),
));
test('should show the zcash logo in loading screen', () => expect(app.client.getAttribute('#loading-screen:first-child img', 'src')).resolves.toEqual(

View File

@ -5,4 +5,4 @@ route: /
# UI Components
Use the sidebar menu to browse the styleguide of React components available for the ZEC Wallet application.
Use the sidebar menu to browse the styleguide of React components available for the Zepio application.

View File

@ -29,7 +29,6 @@ const InnerWrapperBottom = styled.div`
background-color: ${props => props.theme.colors.sidebarItemHoveredBg};
padding-bottom: 3px;
border-top: 1px solid ${props => props.theme.colors.sidebarBorderRight};
`;
const DetailsItemWrapper = styled.div`
@ -66,14 +65,8 @@ const DetailsItemValue = styled.div`
/* eslint-disable max-len */
type StyledLinkProps = PropsWithTheme<{ isActive: boolean }>;
const StyledLink = styled.a`
color: ${(props: StyledLinkProps) => (props.isActive
? props.theme.colors.sidebarItemActive
: props.theme.colors.sidebarItem
)};
background-color: ${(props: StyledLinkProps) => (props.isActive
? props.theme.colors.sidebarItemHoveredBg
: 'transparent'
)};
color: ${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarItemActive : props.theme.colors.sidebarItem)};
background-color: ${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarItemHoveredBg : 'transparent')};
font-size: ${(props: StyledLinkProps) => `${props.theme.fontSize.regular}em`};
text-decoration: none;
font-weight: ${(props: StyledLinkProps) => String(props.theme.fontWeight.bold)};
@ -88,15 +81,19 @@ const StyledLink = styled.a`
outline: none;
transition: all 0.03s ${(props: StyledLinkProps) => props.theme.transitionEase};
border-right: ${(props: StyledLinkProps) => (props.isActive ? `3px solid ${props.theme.colors.sidebarActiveItemBorder}` : 'none')};
border-top: 1px solid ${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarBorderRight : 'transparent')};
border-bottom: 1px solid ${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarBorderRight : 'transparent')};
border-top: 1px solid
${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarBorderRight : 'transparent')};
border-bottom: 1px solid
${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarBorderRight : 'transparent')};
&:hover {
border-top: 1px solid ${props => props.theme.colors.sidebarBorderRight};
border-bottom: 1px solid ${props => props.theme.colors.sidebarBorderRight};
background-color: ${(props: StyledLinkProps) => props.theme.colors.sidebarItemHoveredBg};
color: ${(props: StyledLinkProps) => (props.isActive ? props.theme.colors.sidebarItemActive : props.theme.colors.sidebarItemHovered)}
color: ${(props: StyledLinkProps) => (props.isActive
? props.theme.colors.sidebarItemActive
: props.theme.colors.sidebarItemHovered)};
}
`;
@ -128,7 +125,12 @@ type Props = {
};
export const Component = ({
options, location, history, theme, zcashNetwork, embeddedDaemon,
options,
location,
history,
theme,
zcashNetwork,
embeddedDaemon,
}: Props) => (
<Wrapper id='sidebar'>
<InnerWrapperTop>
@ -137,17 +139,15 @@ export const Component = ({
? location.pathname === item.route
: location.pathname.startsWith(item.route);
if (!embeddedDaemon && item.route === '/console') return null;
return (
<StyledLink
isActive={isActive}
key={item.route}
onClick={() => (isActive ? {} : history.push(item.route))}
>
<Icon
isActive={isActive}
src={item.icon(isActive, theme.mode)}
alt={`${item.route}`}
/>
<Icon isActive={isActive} src={item.icon(isActive, theme.mode)} alt={`${item.route}`} />
{item.label}
</StyledLink>
);
@ -155,20 +155,12 @@ export const Component = ({
</InnerWrapperTop>
<InnerWrapperBottom>
<DetailsItemWrapper>
<DetailsItemLabel>
Daemon
</DetailsItemLabel>
<DetailsItemValue>
{embeddedDaemon ? 'Built-in' : 'Custom'}
</DetailsItemValue>
<DetailsItemLabel>Daemon</DetailsItemLabel>
<DetailsItemValue>{embeddedDaemon ? 'Built-in' : 'Custom'}</DetailsItemValue>
</DetailsItemWrapper>
<DetailsItemWrapper>
<DetailsItemLabel>
Network
</DetailsItemLabel>
<DetailsItemValue>
{zcashNetwork}
</DetailsItemValue>
<DetailsItemLabel>Network</DetailsItemLabel>
<DetailsItemValue>{zcashNetwork}</DetailsItemValue>
</DetailsItemWrapper>
</InnerWrapperBottom>
</Wrapper>

View File

@ -20,6 +20,7 @@ import { ColumnComponent } from './column';
import { formatNumber } from '../utils/format-number';
import { openExternal } from '../utils/open-external';
import { getCoinName } from '../utils/get-coin-name';
const Wrapper = styled.div`
width: 460px;
@ -144,6 +145,7 @@ const Component = ({
const isReceived = type === 'receive';
const receivedIcon = theme.mode === DARK ? ReceivedIconDark : ReceivedIconLight;
const sentIcon = theme.mode === DARK ? SentIconDark : SentIconLight;
const coinName = getCoinName();
return (
<Wrapper>
@ -159,7 +161,7 @@ const Component = ({
isBold
size={2.625}
value={formatNumber({
append: `${isReceived ? '+' : '-'}ZEC `,
append: `${isReceived ? '+' : '-'}${coinName} `,
value: amount,
})}
color={
@ -194,7 +196,7 @@ const Component = ({
? 'N/A'
: formatNumber({
value: new BigNumber(fees).toFormat(4),
append: 'ZEC ',
append: `${coinName} `,
})
}
/>

View File

@ -18,6 +18,7 @@ import { ModalComponent } from './modal';
import { TransactionDetailsComponent } from './transaction-details';
import { formatNumber } from '../utils/format-number';
import { getCoinName } from '../utils/get-coin-name';
const Wrapper = styled(RowComponent)`
background-color: ${props => props.theme.colors.transactionItemBg};
@ -90,11 +91,13 @@ const Component = ({
transactionId,
theme,
}: Transaction) => {
const coinName = getCoinName();
const isReceived = type === 'receive';
const transactionTime = dateFns.format(new Date(date), 'HH:mm A');
const transactionValueInZec = formatNumber({
value: amount,
append: `${isReceived ? '+' : '-'}ZEC `,
append: `${isReceived ? '+' : '-'}${coinName} `,
});
const transactionValueInUsd = formatNumber({
value: amount * zecPrice,
@ -117,15 +120,8 @@ const Component = ({
<RowComponent alignItems='center'>
<Icon src={isReceived ? receivedIcon : sentIcon} alt='Transaction Type Icon' />
<TransactionColumn>
<TransactionTypeLabel
isReceived={isReceived}
value={type}
isBold
/>
<TransactionLabel
value={transactionTime}
isReceived={isReceived}
/>
<TransactionTypeLabel isReceived={isReceived} value={type} isBold />
<TransactionLabel value={transactionTime} isReceived={isReceived} />
</TransactionColumn>
</RowComponent>
<TransactionAddress value={address} />
@ -134,11 +130,7 @@ const Component = ({
<TextComponent
isBold
value={transactionValueInZec}
color={
isReceived
? theme.colors.transactionReceived
: theme.colors.transactionSent
}
color={isReceived ? theme.colors.transactionReceived : theme.colors.transactionSent}
/>
<TransactionLabel value={transactionValueInUsd} />
</ColumnComponent>

View File

@ -15,6 +15,7 @@ import ScanIconLight from '../assets/images/scan_icon_light.svg';
import { DARK } from '../constants/themes';
import { formatNumber } from '../utils/format-number';
import { getCoinName } from '../utils/get-coin-name';
const AddressWrapper = styled.div`
align-items: center;
@ -204,13 +205,15 @@ class Component extends PureComponent<Props, State> {
const copyIcon = theme.mode === DARK ? CopyIconDark : CopyIconLight;
const coinName = getCoinName();
return (
<ColumnComponent id='wallet-address' width='100%'>
<AddressWrapper>
<InnerWrapper>
<AddressBalance
id='wallet-address-balance'
value={formatNumber({ append: 'ZEC ', value: balance })}
value={formatNumber({ append: `${coinName} `, value: balance })}
/>
<Address
id='wallet-address-text'
@ -241,14 +244,12 @@ class Component extends PureComponent<Props, State> {
<QRCode value={address} />
</QRCodeWrapper>
<AddressDetailsWrapper>
<AddressDetailsLabel>
Address
</AddressDetailsLabel>
<AddressDetailsLabel>Address</AddressDetailsLabel>
<AddressDetailsValue value={address} />
<AddressDetailsLabel>
Funds
</AddressDetailsLabel>
<AddressDetailsValue value={formatNumber({ append: 'ZEC ', value: balance })} />
<AddressDetailsLabel>Funds</AddressDetailsLabel>
<AddressDetailsValue
value={formatNumber({ append: `${coinName} `, value: balance })}
/>
</AddressDetailsWrapper>
</QRCodeContainer>
)}

View File

@ -1,14 +1,13 @@
// @flow
import React from 'react';
import styled from 'styled-components';
import styled, { withTheme } from 'styled-components';
import { TextComponent } from './text';
import { RowComponent } from './row';
import { formatNumber } from '../utils/format-number';
import { appTheme } from '../theme';
import { getCoinName } from '../utils/get-coin-name';
const Wrapper = styled.div`
display: flex;
@ -52,43 +51,49 @@ type Props = {
shielded: number,
transparent: number,
zecPrice: number,
theme: AppTheme,
};
export const WalletSummaryComponent = ({
total, shielded, transparent, zecPrice,
}: Props) => (
<Wrapper>
<AllAddresses value='ALL ADDRESSES' isBold />
<ValueBox>
<TextComponent
size={appTheme.fontSize.medium * 2.5}
value={`ZEC ${formatNumber({ value: total })}`}
isBold
/>
<USDValue
value={`USD $${formatNumber({ value: total * zecPrice })}`}
size={appTheme.fontSize.medium * 2}
/>
</ValueBox>
<RowComponent>
export const Component = ({
total, shielded, transparent, zecPrice, theme,
}: Props) => {
const coinName = getCoinName();
return (
<Wrapper>
<AllAddresses value='ALL ADDRESSES' isBold />
<ValueBox>
<ShieldedValue value='&#9679; SHIELDED' isBold size={appTheme.fontSize.small} />
<TextComponent
value={`ZEC ${formatNumber({ value: shielded })}`}
size={theme.fontSize.medium * 2.5}
value={`${coinName} ${formatNumber({ value: total })}`}
isBold
size={appTheme.fontSize.medium}
/>
<USDValue value={`USD $${formatNumber({ value: shielded * zecPrice })}`} />
</ValueBox>
<ValueBox>
<Label value='&#9679; TRANSPARENT' isBold size={appTheme.fontSize.small} />
<TextComponent
value={`ZEC ${formatNumber({ value: transparent })}`}
isBold
size={appTheme.fontSize.medium}
<USDValue
value={`USD $${formatNumber({ value: total * zecPrice })}`}
size={theme.fontSize.medium * 2}
/>
<USDValue value={`USD $${formatNumber({ value: transparent * zecPrice })}`} />
</ValueBox>
</RowComponent>
</Wrapper>
);
<RowComponent>
<ValueBox>
<ShieldedValue value='&#9679; SHIELDED' isBold size={theme.fontSize.small} />
<TextComponent
value={`${coinName} ${formatNumber({ value: shielded })}`}
isBold
size={theme.fontSize.medium}
/>
<USDValue value={`USD $${formatNumber({ value: shielded * zecPrice })}`} />
</ValueBox>
<ValueBox>
<Label value='&#9679; TRANSPARENT' isBold size={theme.fontSize.small} />
<TextComponent
value={`${coinName} ${formatNumber({ value: transparent })}`}
isBold
size={theme.fontSize.medium}
/>
<USDValue value={`USD $${formatNumber({ value: transparent * zecPrice })}`} />
</ValueBox>
</RowComponent>
</Wrapper>
);
};
export const WalletSummaryComponent = withTheme(Component);

View File

@ -24,7 +24,7 @@ export const withDaemonStatusCheck = <PassedProps: {}>(
state = {
isRunning: false,
progress: 0,
message: 'ZEC Wallet Starting',
message: 'Zepio Starting',
};
componentDidMount() {
@ -64,7 +64,7 @@ export const withDaemonStatusCheck = <PassedProps: {}>(
}
})
.catch((error) => {
const statusMessage = error.message === 'Something went wrong' ? 'ZEC Wallet Starting' : error.message;
const statusMessage = error.message === 'Something went wrong' ? 'Zepio Starting' : error.message;
const isRpcOff = Math.trunc(error.statusCode / 100) === 5;

View File

@ -52,7 +52,9 @@ const mapDispatchToProps = (dispatch: Dispatch): MapDispatchToProps => ({
updateZcashNetwork: (newNetwork) => {
electronStore.set(ZCASH_NETWORK, newNetwork);
electron.remote.app.relaunch();
electron.remote.app.relaunch({
args: Array.from(new Set(electron.remote.process.argv.slice(1).concat(['--relaunch']))),
});
electron.remote.app.quit();
},
});

View File

@ -0,0 +1,4 @@
// @flow
import { isTestnet } from '../../config/is-testnet';
export const getCoinName = () => (isTestnet() ? 'TAZ' : 'ZEC');

View File

@ -22,6 +22,7 @@ import { ConfirmDialogComponent } from '../components/confirm-dialog';
import { formatNumber } from '../utils/format-number';
import { ascii2hex } from '../utils/ascii-to-hexadecimal';
import { isHex } from '../utils/is-hex';
import { getCoinName } from '../utils/get-coin-name';
import SentIcon from '../assets/images/transaction_sent_icon_dark.svg';
import MenuIconDark from '../assets/images/menu_icon_dark.svg';
@ -71,7 +72,7 @@ const AmountWrapper = styled.div`
position: relative;
&:before {
content: 'ZEC';
content: ${getCoinName()};
font-family: ${props => props.theme.fontFamily};
position: absolute;
margin-top: 16px;
@ -551,12 +552,13 @@ class Component extends PureComponent<Props, State> {
if (!fee) return '0.0';
const feeValue = new BigNumber(fee);
const coinName = getCoinName();
if (feeValue.isEqualTo(FEES.LOW)) return `Low ZEC ${feeValue.toString()}`;
if (feeValue.isEqualTo(FEES.MEDIUM)) return `Medium ZEC ${feeValue.toString()}`;
if (feeValue.isEqualTo(FEES.HIGH)) return `High ZEC ${feeValue.toString()}`;
if (feeValue.isEqualTo(FEES.LOW)) return `Low ${coinName} ${feeValue.toString()}`;
if (feeValue.isEqualTo(FEES.MEDIUM)) return `Medium ${coinName} ${feeValue.toString()}`;
if (feeValue.isEqualTo(FEES.HIGH)) return `High ${coinName} ${feeValue.toString()}`;
return `Custom ZEC ${feeValue.toString()}`;
return `Custom ${coinName} ${feeValue.toString()}`;
};
renderValidationStatus = () => {
@ -703,6 +705,12 @@ class Component extends PureComponent<Props, State> {
return isHex(memo);
};
shouldShowMemoField = () => {
const { to } = this.state;
return to && to.startsWith('z');
};
render() {
const {
addresses, balance, zecPrice, isSending, error, operationId, theme,
@ -722,15 +730,16 @@ class Component extends PureComponent<Props, State> {
const isEmpty = amount === '';
const fixedAmount = isEmpty || new BigNumber(amount).eq(0) ? 0 : this.getAmountWithFee();
const coinName = getCoinName();
const zecBalance = formatNumber({ value: balance, append: 'ZEC ' });
const zecBalance = formatNumber({ value: balance, append: `${coinName} ` });
const zecBalanceInUsd = formatNumber({
value: new BigNumber(balance).times(zecPrice).toNumber(),
append: 'USD $',
});
const valueSent = formatNumber({
value: new BigNumber(fixedAmount).toFormat(4),
append: 'ZEC ',
append: `${coinName} `,
});
const valueSentInUsd = formatNumber({
value: new BigNumber(fixedAmount).times(zecPrice).toNumber(),
@ -741,6 +750,7 @@ class Component extends PureComponent<Props, State> {
const arrowUpIcon = theme.mode === DARK ? ArrowUpIconDark : ArrowUpIconLight;
const shouldShowMemoField = this.shouldShowMemoField();
const isValidMemo = this.isMemoContentValid();
return (
@ -752,7 +762,10 @@ class Component extends PureComponent<Props, State> {
value={from}
placeholder='Select a address'
options={addresses.map(({ address, balance: addressBalance }) => ({
label: `[ ${formatNumber({ append: 'ZEC ', value: addressBalance })} ] ${address}`,
label: `[ ${formatNumber({
append: `${coinName} `,
value: addressBalance,
})} ] ${address}`,
value: address,
}))}
capitalize={false}
@ -772,7 +785,7 @@ class Component extends PureComponent<Props, State> {
type='number'
onChange={this.handleChange('amount')}
value={String(amount)}
placeholder='ZEC 0.0'
placeholder={`${coinName} 0.0`}
min={0.01}
name='amount'
/>
@ -785,14 +798,18 @@ class Component extends PureComponent<Props, State> {
renderRight={to ? this.renderValidationStatus : () => null}
name='to'
/>
<Label value='Memo' />
<InputComponent
onChange={this.handleChange('memo')}
value={memo}
inputType='textarea'
placeholder='Enter a text here'
name='memo'
/>
{shouldShowMemoField && (
<>
<Label value='Memo' />
<InputComponent
onChange={this.handleChange('memo')}
value={memo}
inputType='textarea'
placeholder='Enter a text here'
name='memo'
/>
</>
)}
{!isValidMemo && <TextComponent value='Please enter a valid hexadecimal memo' />}
<ActionsWrapper>
<ShowFeeButton
@ -805,16 +822,18 @@ class Component extends PureComponent<Props, State> {
<SeeMoreIcon src={seeMoreIcon} alt='Show more icon' />
<TextComponent value={`${showFee ? 'Hide' : 'Show'} Additional Options`} />
</ShowFeeButton>
<HexadecimalWrapper>
<Checkbox
onChange={event => this.setState({ isHexMemo: event.target.checked })}
checked={isHexMemo}
/>
<HexadecimalText
onClick={() => this.setState(prevState => ({ isHexMemo: !prevState.isHexMemo }))}
value='Hexadecimal Memo'
/>
</HexadecimalWrapper>
{shouldShowMemoField && (
<HexadecimalWrapper>
<Checkbox
onChange={event => this.setState({ isHexMemo: event.target.checked })}
checked={isHexMemo}
/>
<HexadecimalText
onClick={() => this.setState(prevState => ({ isHexMemo: !prevState.isHexMemo }))}
value='Hexadecimal Memo'
/>
</HexadecimalWrapper>
)}
</ActionsWrapper>
<RevealsMain>
<Transition

View File

@ -1,5 +1,5 @@
// @flow
/* eslint-disable no-unused-vars */
/* eslint-disable import/no-extraneous-dependencies */
import fs from 'fs';
import os from 'os';
@ -392,8 +392,8 @@ export class SettingsView extends PureComponent<Props, State> {
options={themeOptions}
/>
</ThemeSelectWrapper>
<ConfirmDialogComponent
{/* Hidden due to Sapling inability to export view keys on sapling addresses yet */}
{/* <ConfirmDialogComponent
title={EXPORT_VIEW_KEYS_TITLE}
renderTrigger={toggleVisibility => (
<SettingsWrapper>
@ -434,7 +434,7 @@ export class SettingsView extends PureComponent<Props, State> {
)}
</ModalContent>
)}
</ConfirmDialogComponent>
</ConfirmDialogComponent> */}
<SettingsWrapper>
<ConfirmDialogComponent

View File

@ -0,0 +1,15 @@
// @flow
import eres from 'eres';
import processExists from 'process-exists';
// eslint-disable-next-line
export default (processName: string): Promise<void> => new Promise((resolve) => {
const interval = setInterval(async () => {
const [, isRunning] = await eres(processExists(processName));
if (!isRunning) {
clearInterval(interval);
resolve();
}
}, 500);
});

View File

@ -12,7 +12,7 @@ import uuid from 'uuid/v4';
import findProcess from 'find-process';
/* eslint-disable-next-line import/named */
import { mainWindow } from '../electron';
import waitForDaemonClose from './wait-for-daemon-close';
import getBinariesPath from './get-binaries-path';
import getOsFolder from './get-os-folder';
import getDaemonName from './get-daemon-name';
@ -71,10 +71,16 @@ const runDaemon: () => Promise<?ChildProcess> = () => new Promise(async (resolve
return reject(new Error(err));
}
if (!mainWindow.isDestroyed()) mainWindow.webContents.send('zcashd-params-download', 'ZEC Wallet Starting');
if (!mainWindow.isDestroyed()) mainWindow.webContents.send('zcashd-params-download', 'Zepio Starting');
log('Fetch Params finished!');
store.set('DAEMON_FETCHING_PARAMS', false);
// In case of --relaunch on argv, we need wait to close the old zcash daemon
// a workaround is use a interval to check if there is a old process running
if (process.argv.find(arg => arg === '--relaunch')) {
await waitForDaemonClose(ZCASHD_PROCESS_NAME);
}
const [, isRunning] = await eres(processExists(ZCASHD_PROCESS_NAME));
// This will parse and save rpcuser and rpcpassword in the store

View File

@ -1,10 +1,10 @@
{
"name": "zec-react-wallet",
"name": "zepio",
"version": "0.4.6",
"description": "Zcash Reference Wallet",
"description": "Zepio",
"main": "config/main.js",
"license": "MIT",
"homepage": "https://zfnd.org/",
"homepage": "https://zepiowallet.com",
"scripts": {
"start": "yarn check --integrity && concurrently \"cross-env BROWSER=none yarn dev\" \"wait-on http://0.0.0.0:8080 && yarn electron:dev\"",
"dev": "webpack-dev-server --config config/webpack-dev.config.js --mode development --open --hot",
@ -140,7 +140,7 @@
],
"build": {
"appId": "com.zcashfoundation",
"productName": "ZEC Wallet",
"productName": "Zepio",
"asar": true,
"directories": {
"buildResources": "build",

View File

@ -2,24 +2,33 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="shortcut icon" href="favicon.ico" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,700" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css?family=Roboto:300,400,700"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Source+Code+Pro"
rel="stylesheet"
/>
<style>
input[type='number']::-webkit-outer-spin-button,
input[type='number']::-webkit-inner-spin-button {
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
input[type="number"] {
-moz-appearance: textfield;
}
</style>
<title>ZEC Wallet</title>
<title>Zepio</title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>