hotfix: merge with develop
This commit is contained in:
commit
f552b92861
19
.babelrc
19
.babelrc
|
@ -1,11 +1,8 @@
|
|||
{
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-flow"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-object-rest-spread"
|
||||
]
|
||||
}
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"],
|
||||
"plugins": [
|
||||
"@babel/plugin-transform-regenerator",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-object-rest-spread"
|
||||
]
|
||||
}
|
||||
|
|
96
.eslintrc
96
.eslintrc
|
@ -1,47 +1,49 @@
|
|||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": ["airbnb", "plugin:flowtype/recommended"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"plugins": ["flowtype", "jest"],
|
||||
"settings": {
|
||||
"flowtype": {
|
||||
"onlyFilesWithFlowAnnotation": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"jsx-quotes": ["error", "prefer-single"],
|
||||
"import/prefer-default-export": ["off"],
|
||||
"react/jsx-filename-extension": [1, { "extensions": [".js"] }],
|
||||
"jsx-a11y/anchor-is-valid": [
|
||||
"error",
|
||||
{
|
||||
"components": ["Link"],
|
||||
"specialLink": ["to", "hrefLeft", "hrefRight"],
|
||||
"aspects": ["noHref", "invalidHref", "preferButton"]
|
||||
}
|
||||
],
|
||||
"jsx-a11y/no-autofocus": [
|
||||
0,
|
||||
{
|
||||
"ignoreNonDOM": true
|
||||
}
|
||||
],
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 120,
|
||||
"tabWidth": 2,
|
||||
"ignoreUrls": true,
|
||||
"ignoreComments": true,
|
||||
"ignoreStrings": true,
|
||||
"ignorePattern": "<p[^>]*>.*?</p>",
|
||||
"ignoreTrailingComments": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": ["airbnb", "plugin:flowtype/recommended"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"plugins": ["flowtype", "jest"],
|
||||
"settings": {
|
||||
"flowtype": {
|
||||
"onlyFilesWithFlowAnnotation": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"jsx-quotes": ["error", "prefer-single"],
|
||||
"import/prefer-default-export": ["off"],
|
||||
"react/jsx-filename-extension": [1, { "extensions": [".js"] }],
|
||||
"jsx-a11y/anchor-is-valid": [
|
||||
"error",
|
||||
{
|
||||
"components": ["Link"],
|
||||
"specialLink": ["to", "hrefLeft", "hrefRight"],
|
||||
"aspects": ["noHref", "invalidHref", "preferButton"]
|
||||
}
|
||||
],
|
||||
"jsx-a11y/no-autofocus": [
|
||||
0,
|
||||
{
|
||||
"ignoreNonDOM": true
|
||||
}
|
||||
],
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 120,
|
||||
"tabWidth": 2,
|
||||
"ignoreUrls": true,
|
||||
"ignoreComments": true,
|
||||
"ignoreStrings": true,
|
||||
"ignorePattern": "<p[^>]*>.*?</p>",
|
||||
"ignoreTrailingComments": true
|
||||
}
|
||||
],
|
||||
"consistent-return": 0,
|
||||
"react/destructuring-assignment": 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { SidebarComponent } from '../../app/components/sidebar';
|
|||
describe('<Sidebar />', () => {
|
||||
describe('render()', () => {
|
||||
test('should render correctly', () => {
|
||||
// $FlowFixMe
|
||||
const { asFragment } = render(
|
||||
<MemoryRouter>
|
||||
<SidebarComponent />
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
name: Button
|
||||
---
|
||||
|
||||
import { Playground, PropsTable } from 'docz'
|
||||
|
||||
import { Button } from './button.js'
|
||||
import { DoczWrapper } from '../theme.js'
|
||||
|
||||
# Button
|
||||
|
||||
<PropsTable of={Button} />
|
||||
|
||||
## Primary
|
||||
|
||||
<Playground>
|
||||
<div style={{ backgroundColor: '#000', padding: '20px' }}>
|
||||
<DoczWrapper>{() => <Button label="Click me!" />}</DoczWrapper>
|
||||
</div>
|
||||
</Playground>
|
||||
|
||||
## Secondary
|
||||
|
||||
<Playground>
|
||||
<div style={{ backgroundColor: '#000', padding: '20px' }}>
|
||||
<DoczWrapper>{() => <Button label="Click me!" onClick={() => alert('Clicked')} variant="secondary" />}</DoczWrapper>
|
||||
</div>
|
||||
</Playground>
|
||||
|
||||
## Primary Disabled
|
||||
|
||||
<Playground>
|
||||
<div style={{ backgroundColor: '#000', padding: '20px' }}>
|
||||
<DoczWrapper>{() => <Button label="Click me!" onClick={() => alert('Clicked')} disabled />}</DoczWrapper>
|
||||
</div>
|
||||
</Playground>
|
||||
|
||||
## Secondary Disabled
|
||||
|
||||
<Playground>
|
||||
<div style={{ backgroundColor: '#000', padding: '20px' }}>
|
||||
<DoczWrapper>
|
||||
{() => <Button label="Click me!" onClick={() => alert('Clicked')} disabled variant="secondary" />}
|
||||
</DoczWrapper>
|
||||
</div>
|
||||
</Playground>
|
||||
|
||||
## Link Button
|
||||
|
||||
<Playground>
|
||||
<div style={{ backgroundColor: '#000', padding: '20px' }}>
|
||||
<DoczWrapper>{() => <Button label="Click me!" isLink to="/my-route" />}</DoczWrapper>
|
||||
</div>
|
||||
</Playground>
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
name: Input
|
||||
---
|
||||
|
||||
import { Playground, PropsTable } from 'docz'
|
||||
|
||||
import { InputComponent } from './input.js'
|
||||
import { DoczWrapper } from '../theme.js'
|
||||
|
||||
# Input
|
||||
|
||||
<PropsTable of={InputComponent} />
|
||||
|
||||
## Text Input
|
||||
|
||||
<Playground>
|
||||
<DoczWrapper>{() => <InputComponent inputType="input" value="Hello World!" onChange={console.log} />}</DoczWrapper>
|
||||
</Playground>
|
||||
|
||||
## Textarea
|
||||
|
||||
<Playground>
|
||||
<DoczWrapper>
|
||||
{() => <InputComponent inputType="textarea" value="I'm ZCash Electron Wallet" onChange={console.log} rows={10} />}
|
||||
</DoczWrapper>
|
||||
</Playground>
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
name: QRCode
|
||||
---
|
||||
|
||||
import { Playground, PropsTable } from 'docz'
|
||||
|
||||
import { QRCode } from './qrcode.js'
|
||||
|
||||
# QRCode
|
||||
|
||||
<PropsTable of={QRCode} />
|
||||
|
||||
## Basic usage
|
||||
|
||||
<Playground>
|
||||
<QRCode value="https://astrocoders.com" />
|
||||
</Playground>
|
||||
|
||||
## Custom size
|
||||
|
||||
<Playground>
|
||||
<QRCode value="https://astrocoders.com" size={500} />
|
||||
</Playground>
|
|
@ -0,0 +1,94 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
// $FlowFixMe
|
||||
import { darken } from 'polished';
|
||||
|
||||
const defaultStyles = `
|
||||
padding: 10px 30px;
|
||||
font-family: ${
|
||||
// $FlowFixMe
|
||||
props => props.theme.fontFamily
|
||||
};
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
min-width: 100px;
|
||||
border-radius: 100px;
|
||||
transition: background-color 0.1s ease-in-out;
|
||||
`;
|
||||
|
||||
const Primary = styled.button`
|
||||
${defaultStyles};
|
||||
background-color: ${props => props.theme.colors.primary};
|
||||
color: ${props => props.theme.colors.secondary};
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background-color: ${props => darken(0.1, props.theme.colors.primary(props))};
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #3e3c42;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.8;
|
||||
}
|
||||
`;
|
||||
|
||||
const Secondary = styled.button`
|
||||
${defaultStyles};
|
||||
background-color: Transparent;
|
||||
color: ${props => props.theme.colors.secondary};
|
||||
border: 2px solid #3e3c42;
|
||||
|
||||
&:hover {
|
||||
border-color: ${props => props.theme.colors.primary};
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: Transparent;
|
||||
cursor: not-allowed;
|
||||
color: #3e3c42;
|
||||
|
||||
&:hover {
|
||||
border-color: #3e3c42;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
label: string,
|
||||
onClick?: () => void,
|
||||
to?: string,
|
||||
variant?: 'primary' | 'secondary',
|
||||
disabled?: boolean,
|
||||
};
|
||||
|
||||
export const Button = ({
|
||||
onClick, label, to, variant, disabled,
|
||||
}: Props) => {
|
||||
if (to && onClick) throw new Error('Should define either "to" or "onClick"');
|
||||
|
||||
const component = variant === 'primary' ? (
|
||||
<Primary onClick={onClick} disabled={disabled}>
|
||||
{label}
|
||||
</Primary>
|
||||
) : (
|
||||
<Secondary onClick={onClick} disabled={disabled}>
|
||||
{label}
|
||||
</Secondary>
|
||||
);
|
||||
|
||||
return to ? <Link to={String(to)}>{component}</Link> : component;
|
||||
};
|
||||
|
||||
Button.defaultProps = {
|
||||
to: null,
|
||||
variant: 'primary',
|
||||
onClick: null,
|
||||
disabled: false,
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
// TODO: Missing styles
|
||||
|
||||
const defaultStyles = `
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
font-family: ${props => props.theme.fontFamily}
|
||||
`;
|
||||
|
||||
const Input = styled.input.attrs({
|
||||
type: 'text',
|
||||
})`
|
||||
${defaultStyles};
|
||||
`;
|
||||
|
||||
const Textarea = styled.textarea`
|
||||
${defaultStyles};
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
inputType?: 'input' | 'textarea' | 'dropdown',
|
||||
value: string,
|
||||
onChange: string => void,
|
||||
rows?: number,
|
||||
disabled?: boolean,
|
||||
type?: string,
|
||||
};
|
||||
|
||||
export const InputComponent = ({ inputType, onChange, ...props }: Props) => {
|
||||
const inputTypes = {
|
||||
input: () => <Input onChange={evt => onChange(evt.target.value)} {...props} />,
|
||||
textarea: () => <Textarea onChange={evt => onChange(evt.target.value)} {...props} />,
|
||||
dropdown: () => null,
|
||||
};
|
||||
|
||||
if (!Object.keys(inputTypes).find(key => key === inputType)) {
|
||||
throw new Error(`Invalid input type: ${inputType}`);
|
||||
}
|
||||
|
||||
return inputTypes[inputType]();
|
||||
};
|
||||
|
||||
InputComponent.defaultProps = {
|
||||
inputType: 'input',
|
||||
rows: 4,
|
||||
disabled: false,
|
||||
type: 'text',
|
||||
};
|
|
@ -22,9 +22,5 @@ export const LayoutComponent = (props: Props) => {
|
|||
// $FlowFixMe
|
||||
const { children } = props; // eslint-disable-line
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
{children}
|
||||
</Layout>
|
||||
);
|
||||
return <Layout>{children}</Layout>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import QR from 'qrcode.react';
|
||||
|
||||
type Props = {
|
||||
value: string,
|
||||
size?: number,
|
||||
};
|
||||
|
||||
export const QRCode = ({ value, size }: Props) => <QR value={value} size={size} />;
|
||||
|
||||
QRCode.defaultProps = {
|
||||
size: 128,
|
||||
};
|
|
@ -4,3 +4,4 @@ export const DASHBOARD_ROUTE = '/';
|
|||
export const SEND_ROUTE = '/send';
|
||||
export const RECEIVE_ROUTE = '/receive';
|
||||
export const SETTINGS_ROUTE = '/settings';
|
||||
export const CONSOLE_ROUTE = '/console';
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
DASHBOARD_ROUTE,
|
||||
SEND_ROUTE,
|
||||
RECEIVE_ROUTE,
|
||||
SETTINGS_ROUTE,
|
||||
DASHBOARD_ROUTE, SEND_ROUTE, RECEIVE_ROUTE, SETTINGS_ROUTE, CONSOLE_ROUTE,
|
||||
} from './routes';
|
||||
|
||||
export const MENU_OPTIONS = [
|
||||
|
@ -20,6 +17,10 @@ export const MENU_OPTIONS = [
|
|||
label: 'Receive',
|
||||
route: RECEIVE_ROUTE,
|
||||
},
|
||||
{
|
||||
label: 'Console',
|
||||
route: CONSOLE_ROUTE,
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
route: SETTINGS_ROUTE,
|
||||
|
|
|
@ -9,25 +9,15 @@ import { createRootReducer } from './modules/reducer';
|
|||
|
||||
export const history = createBrowserHistory();
|
||||
|
||||
const shouldEnableDevTools = (
|
||||
process.env.NODE_ENV !== 'production'
|
||||
|| process.env.NODE_ENV !== 'staging'
|
||||
) && window.devToolsExtension;
|
||||
const shouldEnableDevTools = (process.env.NODE_ENV !== 'production' || process.env.NODE_ENV !== 'staging') && window.devToolsExtension;
|
||||
|
||||
export const configureStore = (initialState: Object) => {
|
||||
const middleware = applyMiddleware(
|
||||
thunk,
|
||||
routerMiddleware(history),
|
||||
);
|
||||
const middleware = applyMiddleware(thunk, routerMiddleware(history));
|
||||
|
||||
const enhancer = compose(
|
||||
middleware,
|
||||
shouldEnableDevTools ? window.devToolsExtension() : f => f,
|
||||
);
|
||||
|
||||
return createStore(
|
||||
createRootReducer(history),
|
||||
initialState,
|
||||
enhancer,
|
||||
);
|
||||
return createStore(createRootReducer(history), initialState, enhancer);
|
||||
};
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
import { combineReducers } from 'redux';
|
||||
import { connectRouter } from 'connected-react-router';
|
||||
import type { History } from 'react-router-dom';
|
||||
import type { RouterHistory } from 'react-router-dom';
|
||||
|
||||
import todoReducer from './todo';
|
||||
|
||||
export const createRootReducer = (history: History) => combineReducers({
|
||||
export const createRootReducer = (history: RouterHistory) => combineReducers({
|
||||
todos: todoReducer,
|
||||
router: connectRouter(history),
|
||||
});
|
||||
|
|
|
@ -52,10 +52,7 @@ export const updateTodo = (id: string, text: string) => ({
|
|||
const initialState = [];
|
||||
|
||||
// Reducers
|
||||
export default (
|
||||
state: Array<TodoType> = initialState,
|
||||
action: Action,
|
||||
): Array<TodoType> => {
|
||||
export default (state: Array<TodoType> = initialState, action: Action): Array<TodoType> => {
|
||||
switch (action.type) {
|
||||
case ADD_TODO:
|
||||
return [...state, action.payload];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import { compose } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { RouterComponent } from './router';
|
||||
|
@ -9,7 +9,10 @@ const mapStateToProps = (state: AppState) => ({
|
|||
todos: state.todos,
|
||||
});
|
||||
|
||||
export const Router = withRouter(connect(
|
||||
mapStateToProps,
|
||||
null,
|
||||
)(RouterComponent));
|
||||
export const Router = compose(
|
||||
withRouter,
|
||||
connect(
|
||||
mapStateToProps,
|
||||
null,
|
||||
),
|
||||
)(RouterComponent);
|
||||
|
|
|
@ -10,12 +10,11 @@ import { SendView } from '../views/send';
|
|||
import { ReceiveView } from '../views/receive';
|
||||
import { SettingsView } from '../views/settings';
|
||||
import { NotFoundView } from '../views/not-found';
|
||||
import { ConsoleView } from '../views/console';
|
||||
import { LayoutComponent } from '../components/layout';
|
||||
|
||||
import {
|
||||
DASHBOARD_ROUTE,
|
||||
SEND_ROUTE,
|
||||
RECEIVE_ROUTE,
|
||||
SETTINGS_ROUTE,
|
||||
DASHBOARD_ROUTE, SEND_ROUTE, RECEIVE_ROUTE, SETTINGS_ROUTE, CONSOLE_ROUTE,
|
||||
} from '../constants/routes';
|
||||
|
||||
export const RouterComponent = () => (
|
||||
|
@ -25,23 +24,11 @@ export const RouterComponent = () => (
|
|||
{/* $FlowFixMe */}
|
||||
<LayoutComponent>
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={DASHBOARD_ROUTE}
|
||||
component={DashboardView}
|
||||
/>
|
||||
<Route
|
||||
path={SEND_ROUTE}
|
||||
component={SendView}
|
||||
/>
|
||||
<Route
|
||||
path={RECEIVE_ROUTE}
|
||||
component={ReceiveView}
|
||||
/>
|
||||
<Route
|
||||
path={SETTINGS_ROUTE}
|
||||
component={SettingsView}
|
||||
/>
|
||||
<Route exact path={DASHBOARD_ROUTE} component={DashboardView} />
|
||||
<Route path={SEND_ROUTE} component={SendView} />
|
||||
<Route path={RECEIVE_ROUTE} component={ReceiveView} />
|
||||
<Route path={SETTINGS_ROUTE} component={SettingsView} />
|
||||
<Route path={CONSOLE_ROUTE} component={ConsoleView} />
|
||||
<Route component={NotFoundView} />
|
||||
</Switch>
|
||||
</LayoutComponent>
|
||||
|
|
|
@ -4,9 +4,9 @@ import { PureComponent } from 'react';
|
|||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
type Props = {
|
||||
location: Object;
|
||||
location: Object,
|
||||
children: any,
|
||||
}
|
||||
};
|
||||
|
||||
class ScrollTop extends PureComponent<Props> {
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
|
|
16
app/theme.js
16
app/theme.js
|
@ -7,7 +7,7 @@ import { normalize } from 'polished'; // eslint-disable-line
|
|||
|
||||
import { DARK } from './constants/themes';
|
||||
|
||||
const darkOne = '#212124';
|
||||
const darkOne = '#7B00DD';
|
||||
const lightOne = '#ffffff';
|
||||
const brandOne = '#624cda';
|
||||
const brandTwo = '#a6ede2';
|
||||
|
@ -17,13 +17,13 @@ const appTheme = {
|
|||
fontFamily: 'PT Sans',
|
||||
colors: {
|
||||
primary: theme('mode', {
|
||||
light: darkOne,
|
||||
dark: lightOne,
|
||||
}),
|
||||
secondary: theme('mode', {
|
||||
light: lightOne,
|
||||
dark: darkOne,
|
||||
}),
|
||||
secondary: theme('mode', {
|
||||
light: darkOne,
|
||||
dark: lightOne,
|
||||
}),
|
||||
sidebarBg: brandOne,
|
||||
sidebarItem: brandTwo,
|
||||
sidebarItemActive: lightOne,
|
||||
|
@ -36,11 +36,7 @@ const appTheme = {
|
|||
|
||||
/* eslint-disable react/prop-types */
|
||||
// $FlowFixMe
|
||||
export const DoczWrapper = ({ children }) => (
|
||||
<ThemeProvider theme={appTheme}>
|
||||
{children()}
|
||||
</ThemeProvider>
|
||||
);
|
||||
export const DoczWrapper = ({ children }) => <ThemeProvider theme={appTheme}>{children()}</ThemeProvider>;
|
||||
|
||||
export const GlobalStyle = createGlobalStyle`${normalize()}`;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
type State = {| |};
|
||||
type State = {||};
|
||||
|
||||
export type Action = { type: $Subtype<string>, payload: Object };
|
||||
export type GetState = () => State;
|
||||
|
|
|
@ -4,5 +4,5 @@ export type TodoType = {
|
|||
id: string,
|
||||
text: string,
|
||||
editing: boolean,
|
||||
createdAt: number
|
||||
createdAt: number,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
/* eslint-disable-next-line import/no-extraneous-dependencies */
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
type Props = {};
|
||||
|
||||
type State = {
|
||||
log: string | null,
|
||||
};
|
||||
|
||||
export class ConsoleView extends Component<Props, State> {
|
||||
state = {
|
||||
log: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
ipcRenderer.on('zcashd-log', (event, message) => {
|
||||
this.setState(() => ({
|
||||
log: message,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='dashboard'>
|
||||
{this.state.log
|
||||
&& this.state.log.split('\n').map(item => (
|
||||
<Fragment key={`${item.slice(0, 10)}`}>
|
||||
{item}
|
||||
<br />
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,4 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
export const DashboardView = () => (
|
||||
<div className='dashboard'>
|
||||
dashboard
|
||||
</div>
|
||||
);
|
||||
export const DashboardView = () => <div className='dashboard'>dashboard</div>;
|
||||
|
|
|
@ -2,8 +2,4 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
export const NotFoundView = () => (
|
||||
<div className='not found'>
|
||||
not found
|
||||
</div>
|
||||
);
|
||||
export const NotFoundView = () => <div className='not found'>not found</div>;
|
||||
|
|
|
@ -2,8 +2,4 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
export const ReceiveView = () => (
|
||||
<div className='send'>
|
||||
receive
|
||||
</div>
|
||||
);
|
||||
export const ReceiveView = () => <div className='send'>receive</div>;
|
||||
|
|
|
@ -2,8 +2,4 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
export const SendView = () => (
|
||||
<div className='send'>
|
||||
send
|
||||
</div>
|
||||
);
|
||||
export const SendView = () => <div className='send'>send</div>;
|
||||
|
|
|
@ -2,8 +2,4 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
export const SettingsView = () => (
|
||||
<div className='settings'>
|
||||
settings
|
||||
</div>
|
||||
);
|
||||
export const SettingsView = () => <div className='settings'>settings</div>;
|
||||
|
|
|
@ -20,25 +20,14 @@ type Props = {
|
|||
|
||||
export default (props: Props) => {
|
||||
const {
|
||||
addTodo,
|
||||
todos,
|
||||
deleteTodo,
|
||||
toggleEdit,
|
||||
updateTodo,
|
||||
cancelUpdateTodo,
|
||||
addTodo, todos, deleteTodo, toggleEdit, updateTodo, cancelUpdateTodo,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className='todo'>
|
||||
<div className='todo__heading'>
|
||||
<img
|
||||
src={checklist}
|
||||
alt='Testing File Loader'
|
||||
className='todo__image'
|
||||
/>
|
||||
<h1 className='todo__header'>
|
||||
Todo List App
|
||||
</h1>
|
||||
<img src={checklist} alt='Testing File Loader' className='todo__image' />
|
||||
<h1 className='todo__header'>Todo List App</h1>
|
||||
</div>
|
||||
<TodoInput addTodo={addTodo} />
|
||||
<TodoList
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,20 @@
|
|||
@echo off
|
||||
|
||||
IF NOT EXIST %AppData%\Zcash (
|
||||
mkdir %AppData%\Zcash
|
||||
)
|
||||
|
||||
IF NOT EXIST %AppData%\ZcashParams (
|
||||
mkdir %AppData%\ZcashParams
|
||||
)
|
||||
|
||||
IF NOT EXIST %AppData%\Zcash\zcash.conf (
|
||||
(
|
||||
echo addnode=mainnet.z.cash
|
||||
echo rpcuser=username
|
||||
echo rpcpassword=password%random%%random%
|
||||
echo daemon=1
|
||||
echo showmetrics=0
|
||||
echo gen=0
|
||||
) > %AppData%\Zcash\zcash.conf
|
||||
)
|
Binary file not shown.
|
@ -0,0 +1,209 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
PARAMS_DIR="$HOME/Library/Application Support/ZcashParams"
|
||||
else
|
||||
PARAMS_DIR="$HOME/.zcash-params"
|
||||
fi
|
||||
|
||||
SPROUT_PKEY_NAME='sprout-proving.key'
|
||||
SPROUT_VKEY_NAME='sprout-verifying.key'
|
||||
SAPLING_SPEND_NAME='sapling-spend.params'
|
||||
SAPLING_OUTPUT_NAME='sapling-output.params'
|
||||
SAPLING_SPROUT_GROTH16_NAME='sprout-groth16.params'
|
||||
SPROUT_URL="https://z.cash/downloads"
|
||||
SPROUT_IPFS="/ipfs/QmZKKx7Xup7LiAtFRhYsE1M7waXcv9ir9eCECyXAFGxhEo"
|
||||
|
||||
SHA256CMD="$(command -v sha256sum || echo shasum)"
|
||||
SHA256ARGS="$(command -v sha256sum >/dev/null || echo '-a 256')"
|
||||
|
||||
WGETCMD="$(command -v wget || echo '')"
|
||||
IPFSCMD="$(command -v ipfs || echo '')"
|
||||
CURLCMD="$(command -v curl || echo '')"
|
||||
|
||||
# fetch methods can be disabled with ZC_DISABLE_SOMETHING=1
|
||||
ZC_DISABLE_WGET="${ZC_DISABLE_WGET:-}"
|
||||
ZC_DISABLE_IPFS="${ZC_DISABLE_IPFS:-}"
|
||||
ZC_DISABLE_CURL="${ZC_DISABLE_CURL:-}"
|
||||
|
||||
function fetch_wget {
|
||||
if [ -z "$WGETCMD" ] || ! [ -z "$ZC_DISABLE_WGET" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
local dlname="$2"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Retrieving (wget): $SPROUT_URL/$filename
|
||||
EOF
|
||||
|
||||
wget \
|
||||
--progress=dot:giga \
|
||||
--output-document="$dlname" \
|
||||
--continue \
|
||||
--retry-connrefused --waitretry=3 --timeout=30 \
|
||||
"$SPROUT_URL/$filename"
|
||||
}
|
||||
|
||||
function fetch_ipfs {
|
||||
if [ -z "$IPFSCMD" ] || ! [ -z "$ZC_DISABLE_IPFS" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
local dlname="$2"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Retrieving (ipfs): $SPROUT_IPFS/$filename
|
||||
EOF
|
||||
|
||||
ipfs get --output "$dlname" "$SPROUT_IPFS/$filename"
|
||||
}
|
||||
|
||||
function fetch_curl {
|
||||
if [ -z "$CURLCMD" ] || ! [ -z "$ZC_DISABLE_CURL" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
local dlname="$2"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Retrieving (curl): $SPROUT_URL/$filename
|
||||
EOF
|
||||
|
||||
curl \
|
||||
--output "$dlname" \
|
||||
-# -L -C - \
|
||||
"$SPROUT_URL/$filename"
|
||||
|
||||
}
|
||||
|
||||
function fetch_failure {
|
||||
cat >&2 <<EOF
|
||||
|
||||
Failed to fetch the Zcash zkSNARK parameters!
|
||||
Try installing one of the following programs and make sure you're online:
|
||||
|
||||
* ipfs
|
||||
* wget
|
||||
* curl
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
function fetch_params {
|
||||
local filename="$1"
|
||||
local output="$2"
|
||||
local dlname="${output}.dl"
|
||||
local expectedhash="$3"
|
||||
|
||||
if ! [ -f "$output" ]
|
||||
then
|
||||
for method in wget ipfs curl failure; do
|
||||
if "fetch_$method" "$filename" "$dlname"; then
|
||||
echo "Download successful!"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
"$SHA256CMD" $SHA256ARGS -c <<EOF
|
||||
$expectedhash $dlname
|
||||
EOF
|
||||
|
||||
# Check the exit code of the shasum command:
|
||||
CHECKSUM_RESULT=$?
|
||||
if [ $CHECKSUM_RESULT -eq 0 ]; then
|
||||
mv -v "$dlname" "$output"
|
||||
else
|
||||
echo "Failed to verify parameter checksums!" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Use flock to prevent parallel execution.
|
||||
function lock() {
|
||||
local lockfile=/tmp/fetch_params.lock
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
if shlock -f ${lockfile} -p $$; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# create lock file
|
||||
eval "exec 200>$lockfile"
|
||||
# acquire the lock
|
||||
flock -n 200 \
|
||||
&& return 0 \
|
||||
|| return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function exit_locked_error {
|
||||
echo "Only one instance of fetch-params.sh can be run at a time." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
lock fetch-params.sh \
|
||||
|| exit_locked_error
|
||||
|
||||
cat <<EOF
|
||||
Zcash - fetch-params.sh
|
||||
|
||||
This script will fetch the Zcash zkSNARK parameters and verify their
|
||||
integrity with sha256sum.
|
||||
|
||||
If they already exist locally, it will exit now and do nothing else.
|
||||
EOF
|
||||
|
||||
# Now create PARAMS_DIR and insert a README if necessary:
|
||||
if ! [ -d "$PARAMS_DIR" ]
|
||||
then
|
||||
mkdir -p "$PARAMS_DIR"
|
||||
README_PATH="$PARAMS_DIR/README"
|
||||
cat >> "$README_PATH" <<EOF
|
||||
This directory stores common Zcash zkSNARK parameters. Note that it is
|
||||
distinct from the daemon's -datadir argument because the parameters are
|
||||
large and may be shared across multiple distinct -datadir's such as when
|
||||
setting up test networks.
|
||||
EOF
|
||||
|
||||
# This may be the first time the user's run this script, so give
|
||||
# them some info, especially about bandwidth usage:
|
||||
cat <<EOF
|
||||
The parameters are currently just under 911MB in size, so plan accordingly
|
||||
for your bandwidth constraints. If the files are already present and
|
||||
have the correct sha256sum, no networking is used.
|
||||
|
||||
Creating params directory. For details about this directory, see:
|
||||
$README_PATH
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
cd "$PARAMS_DIR"
|
||||
|
||||
# Sprout parameters:
|
||||
fetch_params "$SPROUT_PKEY_NAME" "$PARAMS_DIR/$SPROUT_PKEY_NAME" "8bc20a7f013b2b58970cddd2e7ea028975c88ae7ceb9259a5344a16bc2c0eef7"
|
||||
fetch_params "$SPROUT_VKEY_NAME" "$PARAMS_DIR/$SPROUT_VKEY_NAME" "4bd498dae0aacfd8e98dc306338d017d9c08dd0918ead18172bd0aec2fc5df82"
|
||||
|
||||
# Sapling parameters:
|
||||
fetch_params "$SAPLING_SPEND_NAME" "$PARAMS_DIR/$SAPLING_SPEND_NAME" "8e48ffd23abb3a5fd9c5589204f32d9c31285a04b78096ba40a79b75677efc13"
|
||||
fetch_params "$SAPLING_OUTPUT_NAME" "$PARAMS_DIR/$SAPLING_OUTPUT_NAME" "2f0ebbcbb9bb0bcffe95a397e7eba89c29eb4dde6191c339db88570e3f3fb0e4"
|
||||
fetch_params "$SAPLING_SPROUT_GROTH16_NAME" "$PARAMS_DIR/$SAPLING_SPROUT_GROTH16_NAME" "b685d700c60328498fbde589c8c7c484c722b788b265b72af448a5bf0ee55b50"
|
||||
}
|
||||
|
||||
main
|
||||
rm -f /tmp/fetch_params.lock
|
||||
exit 0
|
|
@ -0,0 +1,24 @@
|
|||
// @flow
|
||||
|
||||
import path from 'path';
|
||||
import cp from 'child_process';
|
||||
|
||||
import getBinariesPath from './get-binaries-path';
|
||||
import log from './logger';
|
||||
|
||||
export default (): Promise<*> => new Promise((resolve, reject) => {
|
||||
const processName = path.join(getBinariesPath(), 'zcash-fetch-params');
|
||||
|
||||
const childProcess = cp.spawn(processName);
|
||||
|
||||
childProcess.stdout.on('data', data => log(data.toString()));
|
||||
childProcess.stderr.on('data', data => log(data.toString()));
|
||||
childProcess.on('error', reject);
|
||||
childProcess.on('exit', (code, err) => {
|
||||
if (code !== 0 || err) {
|
||||
reject(new Error(err));
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,99 @@
|
|||
// @flow
|
||||
|
||||
/* eslint-disable consistent-return */
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import cp from 'child_process';
|
||||
import crypto from 'crypto';
|
||||
import util from 'util';
|
||||
|
||||
import eres from 'eres';
|
||||
import got from 'got';
|
||||
import Queue from 'p-queue';
|
||||
|
||||
// eslint-disable-next-line
|
||||
import { app } from '../electron';
|
||||
import getBinariesPath from './get-binaries-path';
|
||||
import log from './logger';
|
||||
|
||||
const queue = new Queue({ concurrency: 1, autoStart: false });
|
||||
|
||||
const httpClient = got.extend({ baseUrl: 'https://z.cash/downloads/', retry: 3, useElectronNet: true });
|
||||
|
||||
const FILES: Array<{ name: string, hash: string }> = [
|
||||
{ name: 'sprout-proving.key', hash: '8bc20a7f013b2b58970cddd2e7ea028975c88ae7ceb9259a5344a16bc2c0eef7' },
|
||||
{ name: 'sprout-verifying.key', hash: '4bd498dae0aacfd8e98dc306338d017d9c08dd0918ead18172bd0aec2fc5df82' },
|
||||
{ name: 'sapling-spend.params', hash: '8e48ffd23abb3a5fd9c5589204f32d9c31285a04b78096ba40a79b75677efc13' },
|
||||
{ name: 'sapling-output.params', hash: '2f0ebbcbb9bb0bcffe95a397e7eba89c29eb4dde6191c339db88570e3f3fb0e4' },
|
||||
{ name: 'sprout-groth16.params', hash: 'b685d700c60328498fbde589c8c7c484c722b788b265b72af448a5bf0ee55b50' },
|
||||
];
|
||||
|
||||
const checkSha256 = (pathToFile: string, expectedHash: string) => new Promise((resolve, reject) => {
|
||||
fs.readFile(pathToFile, (err, file) => {
|
||||
if (err) return reject(new Error(err));
|
||||
|
||||
const sum = crypto.createHash('sha256');
|
||||
sum.update(file);
|
||||
resolve(sum.digest('hex') === expectedHash);
|
||||
});
|
||||
});
|
||||
|
||||
const downloadFile = ({ file, pathToSave }): Promise<*> => new Promise((resolve, reject) => {
|
||||
log(`Downloading ${file.name}...`);
|
||||
|
||||
httpClient
|
||||
.stream(file.name)
|
||||
.on('end', () => {
|
||||
checkSha256(pathToSave, file.hash).then((isValid) => {
|
||||
if (isValid) {
|
||||
log(`SHA256 validation for file ${file.name} succeeded!`);
|
||||
resolve(file.name);
|
||||
} else {
|
||||
reject(new Error(`SHA256 validation failed for file: ${file.name}`));
|
||||
}
|
||||
});
|
||||
})
|
||||
.on('error', err => reject(new Error(err)))
|
||||
.pipe(fs.createWriteStream(pathToSave));
|
||||
});
|
||||
|
||||
let missingDownloadParam = false;
|
||||
|
||||
export default (): Promise<*> => new Promise((resolve, reject) => {
|
||||
const firstRunProcess = cp.spawn(path.join(getBinariesPath(), 'win', 'first-run.bat'));
|
||||
firstRunProcess.stdout.on('data', data => log(data.toString()));
|
||||
firstRunProcess.stderr.on('data', data => reject(data.toString()));
|
||||
|
||||
firstRunProcess.on('exit', async (code, err) => {
|
||||
if (code !== 0 || err) return reject(new Error(err));
|
||||
|
||||
await Promise.all(
|
||||
FILES.map(async (file) => {
|
||||
const pathToSave = path.join(app.getPath('userData'), '..', 'ZcashParams', file.name);
|
||||
|
||||
const [cannotAccess] = await eres(util.promisify(fs.access)(pathToSave, fs.constants.F_OK));
|
||||
|
||||
if (cannotAccess) {
|
||||
missingDownloadParam = true;
|
||||
queue.add(() => downloadFile({ file, pathToSave }).then(() => log(`Download ${file.name} finished!`)));
|
||||
} else {
|
||||
const isValid = await checkSha256(pathToSave, file.hash);
|
||||
if (isValid) {
|
||||
log(`${file.name} already is in ${pathToSave}...`);
|
||||
} else {
|
||||
log(`File: ${file.name} failed in the SHASUM validation, downloading again...`);
|
||||
queue.add(() => {
|
||||
downloadFile({ file, pathToSave }).then(() => log(`Download ${file.name} finished!`));
|
||||
});
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
if (!missingDownloadParam) return resolve();
|
||||
|
||||
queue.onEmpty(resolve);
|
||||
queue.start();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
// @flow
|
||||
|
||||
export default () => Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15)
|
||||
+ Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15);
|
|
@ -0,0 +1,7 @@
|
|||
// @flow
|
||||
import path from 'path';
|
||||
/* eslint-disable-next-line import/no-extraneous-dependencies */
|
||||
import isDev from 'electron-is-dev';
|
||||
|
||||
// $FlowFixMe
|
||||
export default () => (isDev ? path.join(__dirname, '..', '..', './bin') : path.join(process.resourcesPath, 'bin'));
|
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import os from 'os';
|
||||
|
||||
export default () => (os.platform() === 'win32' ? 'zcashd.exe' : 'zcashd');
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
import os from 'os';
|
||||
|
||||
export default () => {
|
||||
if (os.platform() === 'darwin') {
|
||||
return 'mac';
|
||||
}
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
return 'win';
|
||||
}
|
||||
|
||||
return 'linux';
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
// @flow
|
||||
|
||||
/* eslint-disable-next-line no-console */
|
||||
export default (...message: Array<*>) => console.log('[ZCash Daemon]', ...message);
|
|
@ -0,0 +1,12 @@
|
|||
// @flow
|
||||
import os from 'os';
|
||||
|
||||
import log from './logger';
|
||||
import fetchWindowsParams from './fetch-windows-params';
|
||||
import runUnixFetchParams from './fetch-unix-params';
|
||||
|
||||
export default (): Promise<*> => {
|
||||
log('Fetching params');
|
||||
|
||||
return os.platform() === 'win32' ? fetchWindowsParams() : runUnixFetchParams();
|
||||
};
|
|
@ -0,0 +1,104 @@
|
|||
// @flow
|
||||
import cp from 'child_process';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import processExists from 'process-exists';
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import isDev from 'electron-is-dev';
|
||||
import type { ChildProcess } from 'child_process';
|
||||
import eres from 'eres';
|
||||
/* eslint-disable-next-line import/named */
|
||||
import { mainWindow } from '../electron';
|
||||
|
||||
import getBinariesPath from './get-binaries-path';
|
||||
import getOsFolder from './get-os-folder';
|
||||
import getDaemonName from './get-daemon-name';
|
||||
import fetchParams from './run-fetch-params';
|
||||
import log from './logger';
|
||||
import store from '../electron-store';
|
||||
import generateRandomString from './generate-random-string';
|
||||
|
||||
const getDaemonOptions = ({ username, password }) => {
|
||||
/*
|
||||
-showmetrics
|
||||
Show metrics on stdout
|
||||
-metricsui
|
||||
Set to 1 for a persistent metrics screen, 0 for sequential metrics
|
||||
output
|
||||
-metricsrefreshtime
|
||||
Number of seconds between metrics refreshes
|
||||
*/
|
||||
const defaultOptions = [
|
||||
'-showmetrics',
|
||||
'--metricsui=0',
|
||||
'-metricsrefreshtime=3',
|
||||
`-rpcuser=${username}`,
|
||||
`-rpcpassword=${password}`,
|
||||
];
|
||||
return isDev ? defaultOptions.concat('-testnet') : defaultOptions;
|
||||
};
|
||||
|
||||
let resolved = false;
|
||||
|
||||
const runDaemon: () => Promise<?ChildProcess> = () => new Promise(async (resolve, reject) => {
|
||||
const processName = path.join(getBinariesPath(), getOsFolder(), getDaemonName());
|
||||
|
||||
const [err] = await eres(fetchParams());
|
||||
|
||||
if (err) {
|
||||
log('Something went wrong fetching params: ', err);
|
||||
return reject(new Error(err));
|
||||
}
|
||||
|
||||
log('Fetch Params finished!');
|
||||
|
||||
const [, isRunning] = await eres(processExists(processName));
|
||||
|
||||
if (isRunning) {
|
||||
log('Already is running!');
|
||||
return resolve();
|
||||
}
|
||||
|
||||
const hasCredentials = store.has('rpcuser') && store.has('rpcpassword');
|
||||
|
||||
const rpcCredentials = hasCredentials
|
||||
? {
|
||||
username: store.get('rpcuser'),
|
||||
password: store.get('rpcpassword'),
|
||||
}
|
||||
: {
|
||||
username: generateRandomString(),
|
||||
password: generateRandomString(),
|
||||
};
|
||||
|
||||
if (!hasCredentials) {
|
||||
store.set('rpcuser', rpcCredentials.username);
|
||||
store.set('rpcpassword', rpcCredentials.password);
|
||||
}
|
||||
|
||||
const childProcess = cp.spawn(processName, getDaemonOptions(rpcCredentials), {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
childProcess.stdout.on('data', (data) => {
|
||||
if (mainWindow) mainWindow.webContents.send('zcashd-log', data.toString());
|
||||
if (!resolved) {
|
||||
resolve(childProcess);
|
||||
resolved = true;
|
||||
}
|
||||
});
|
||||
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
log(data.toString());
|
||||
reject(new Error(data.toString()));
|
||||
});
|
||||
|
||||
childProcess.on('error', reject);
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
resolved = true;
|
||||
resolve(childProcess);
|
||||
}
|
||||
});
|
||||
|
||||
export default runDaemon;
|
|
@ -0,0 +1,6 @@
|
|||
// @flow
|
||||
import Store from 'electron-store';
|
||||
|
||||
export default new Store({
|
||||
encryptionKey: 'afr58kk5xg6tz5o4kmvmw',
|
||||
});
|
|
@ -1,4 +1,6 @@
|
|||
// @flow
|
||||
import '@babel/polyfill';
|
||||
|
||||
import path from 'path';
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
|
@ -7,10 +9,14 @@ import { autoUpdater } from 'electron-updater';
|
|||
import isDev from 'electron-is-dev';
|
||||
/* eslint-enable import/no-extraneous-dependencies */
|
||||
import type { BrowserWindow as BrowserWindowType } from 'electron';
|
||||
import eres from 'eres';
|
||||
import { registerDebugShortcut } from '../utils/debug-shortcut';
|
||||
import runDaemon from './daemon/zcashd-child-process';
|
||||
import zcashLog from './daemon/logger';
|
||||
|
||||
let mainWindow: BrowserWindowType;
|
||||
let updateAvailable: boolean = false;
|
||||
let zcashDaemon;
|
||||
|
||||
const showStatus = (text) => {
|
||||
if (text === 'Update downloaded') updateAvailable = true;
|
||||
|
@ -55,17 +61,33 @@ const createWindow = () => {
|
|||
mainWindow.setVisibleOnAllWorkspaces(true);
|
||||
registerDebugShortcut(app, mainWindow);
|
||||
|
||||
mainWindow.loadURL(isDev
|
||||
? 'http://0.0.0.0:8080/'
|
||||
: `file://${path.join(__dirname, '../build/index.html')}`);
|
||||
mainWindow.loadURL(isDev ? 'http://0.0.0.0:8080/' : `file://${path.join(__dirname, '../build/index.html')}`);
|
||||
|
||||
exports.app = app;
|
||||
exports.mainWindow = mainWindow;
|
||||
};
|
||||
|
||||
app.on('ready', createWindow);
|
||||
/* eslint-disable-next-line consistent-return */
|
||||
app.on('ready', async () => {
|
||||
createWindow();
|
||||
const [err, proc] = await eres(runDaemon());
|
||||
|
||||
if (err || !proc) return zcashLog(err);
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
zcashLog(`ZCash Daemon running. PID: ${proc.pid}`);
|
||||
|
||||
zcashDaemon = proc;
|
||||
});
|
||||
app.on('activate', () => {
|
||||
if (mainWindow === null) createWindow();
|
||||
});
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
app.on('before-quit', () => {
|
||||
if (zcashDaemon) {
|
||||
zcashLog('Graceful shutdown ZCash Daemon, this may take a few seconds.');
|
||||
zcashDaemon.kill('SIGINT');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,14 +4,13 @@ const autoprefixer = require('autoprefixer');
|
|||
|
||||
module.exports = {
|
||||
entry: {
|
||||
index: './app/index.js',
|
||||
index: ['@babel/polyfill', './app/index.js'],
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new UglifyJSPlugin({ sourceMap: true }),
|
||||
],
|
||||
minimizer: [new UglifyJSPlugin({ sourceMap: true })],
|
||||
},
|
||||
devtool: 'cheap-module-source-map',
|
||||
target: 'electron-renderer',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
@ -23,21 +22,28 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [{
|
||||
loader: 'style-loader',
|
||||
}, {
|
||||
loader: 'css-loader',
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
ident: 'postcss',
|
||||
options: {
|
||||
plugins: () => [autoprefixer({
|
||||
browsers: ['> 1%', 'not ie 11'],
|
||||
})],
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
},
|
||||
}, {
|
||||
loader: 'sass-loader',
|
||||
}],
|
||||
{
|
||||
loader: 'css-loader',
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
ident: 'postcss',
|
||||
options: {
|
||||
plugins: () => [
|
||||
autoprefixer({
|
||||
browsers: ['> 1%', 'not ie 11'],
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'sass-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)$/,
|
||||
|
@ -53,13 +59,15 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'assets/fonts/',
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'assets/fonts/',
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
10
doczrc.js
10
doczrc.js
|
@ -5,4 +5,14 @@ export default {
|
|||
title: 'Zcash Foundation',
|
||||
description: 'Zcash Foundation User Interface Styleguide',
|
||||
plugins: [css()],
|
||||
htmlContext: {
|
||||
head: {
|
||||
links: [
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href: 'https://fonts.googleapis.com/css?family=PT+Sans:400,700',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
291
package.json
291
package.json
|
@ -1,142 +1,149 @@
|
|||
{
|
||||
"name": "zec-react-wallet",
|
||||
"version": "0.1.1",
|
||||
"description": "Zcash Reference Wallet",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "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",
|
||||
"build": "rm -rf build && webpack --config config/webpack-prod.config.js --mode production --env.NODE_ENV=production",
|
||||
"lint:precommit": "eslint ./app/",
|
||||
"flow:precommit": "glow",
|
||||
"flow:coverage": "flow-coverage-report -t html -i 'app/**/*.js' -x 'dist/*.js' --threshold 70",
|
||||
"flow:report": "yarn flow:coverage && cd ./flow-coverage && open index.html",
|
||||
"electron:dev": "electron -r @babel/register .",
|
||||
"electron:prepare": "yarn icon:build && rm -rf dist && mkdir dist",
|
||||
"electron:pack": "yarn electron:prepare && electron-builder --dir",
|
||||
"electron:dist": "yarn electron:prepare && electron-builder",
|
||||
"preelectron:prepare": "yarn build",
|
||||
"icon:build": "./node_modules/.bin/electron-icon-maker --input=build-assets/icon.png --output=./build",
|
||||
"docz:dev": "docz dev",
|
||||
"docz:build": "docz build",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch"
|
||||
},
|
||||
"author": {
|
||||
"name": "André Neves",
|
||||
"email": "andrerfneves@protonmail.com",
|
||||
"url": "https://andrenev.es"
|
||||
},
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0",
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/preset-flow": "^7.0.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"concurrently": "^4.1.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^1.0.1",
|
||||
"docz": "^0.12.13",
|
||||
"docz-plugin-css": "^0.11.0",
|
||||
"electron": "^3.0.10",
|
||||
"electron-builder": "^20.36.2",
|
||||
"electron-icon-maker": "^0.0.4",
|
||||
"electron-is-dev": "^1.0.1",
|
||||
"electron-log": "^2.2.17",
|
||||
"electron-positioner": "^4.1.0",
|
||||
"electron-updater": "^4.0.4",
|
||||
"eslint": "^5.8.0",
|
||||
"eslint-config-airbnb": "^17.1.0",
|
||||
"eslint-plugin-flowtype": "^3.2.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jest": "^22.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"file-loader": "^2.0.0",
|
||||
"flow-bin": "^0.87.0",
|
||||
"flow-coverage-report": "^0.6.0",
|
||||
"flow-typed": "^2.5.1",
|
||||
"glow": "^1.2.2",
|
||||
"html-webpack-plugin": "^3.1.0",
|
||||
"jest": "^23.6.0",
|
||||
"jest-dom": "^2.1.1",
|
||||
"node-sass": "^4.8.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"react-testing-library": "^5.3.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-mock-store": "^1.5.3",
|
||||
"sass-loader": "^7.1.0",
|
||||
"spectron": "^5.0.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"uglifyjs-webpack-plugin": "^2.0.1",
|
||||
"wait-on": "^3.2.0",
|
||||
"webpack": "^4.4.1",
|
||||
"webpack-bundle-analyzer": "^3.0.3",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"webpack-dev-server": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/register": "^7.0.0",
|
||||
"autoprefixer": "^9.3.1",
|
||||
"connected-react-router": "^5.0.1",
|
||||
"got": "^9.3.2",
|
||||
"history": "^4.7.2",
|
||||
"react": "^16.6.0",
|
||||
"react-dom": "^16.6.0",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"redux": "^4.0.1",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"styled-components": "^4.1.1",
|
||||
"styled-theming": "^2.2.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint:precommit",
|
||||
"flow:precommit"
|
||||
],
|
||||
"build": {
|
||||
"appId": "com.zcashfoundation",
|
||||
"productName": "ZEC Wallet",
|
||||
"asar": true,
|
||||
"directories": {
|
||||
"buildResources": "build",
|
||||
"output": "dist"
|
||||
},
|
||||
"files": [
|
||||
"./index.js",
|
||||
"./build/**/*",
|
||||
"./node_modules/**/*"
|
||||
],
|
||||
"linux": {
|
||||
"icon": "./build/icons/png",
|
||||
"target": [
|
||||
"deb"
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"category": "public.app-category.productivity",
|
||||
"type": "distribution",
|
||||
"target": [
|
||||
"pkg",
|
||||
"dmg"
|
||||
]
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/__tests__/setup/jest.js",
|
||||
"testPathIgnorePatterns": [
|
||||
"<rootDir>/__tests__/setup/"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"babel-core": "7.0.0-bridge.0"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "zec-react-wallet",
|
||||
"version": "0.1.1",
|
||||
"description": "Zcash Reference Wallet",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "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",
|
||||
"build": "rm -rf build && webpack --config config/webpack-prod.config.js --mode production --env.NODE_ENV=production",
|
||||
"lint:precommit": "eslint ./app/",
|
||||
"flow:precommit": "glow",
|
||||
"flow:coverage": "flow-coverage-report -t html -i 'app/**/*.js' -x 'dist/*.js' --threshold 70",
|
||||
"flow:report": "yarn flow:coverage && cd ./flow-coverage && open index.html",
|
||||
"electron:dev": "electron -r @babel/register .",
|
||||
"electron:prepare": "yarn icon:build && rm -rf dist && mkdir dist",
|
||||
"electron:pack": "yarn electron:prepare && electron-builder --dir",
|
||||
"electron:dist": "yarn electron:prepare && electron-builder",
|
||||
"preelectron:prepare": "yarn build",
|
||||
"icon:build": "./node_modules/.bin/electron-icon-maker --input=build-assets/icon.png --output=./build",
|
||||
"docz:dev": "docz dev",
|
||||
"docz:build": "docz build",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch"
|
||||
},
|
||||
"author": {
|
||||
"name": "André Neves",
|
||||
"email": "andrerfneves@protonmail.com",
|
||||
"url": "https://andrenev.es"
|
||||
},
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0",
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
|
||||
"@babel/plugin-transform-regenerator": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/preset-flow": "^7.0.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"concurrently": "^4.1.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^1.0.1",
|
||||
"docz": "^0.12.13",
|
||||
"docz-plugin-css": "^0.11.0",
|
||||
"electron": "^3.0.10",
|
||||
"electron-builder": "^20.36.2",
|
||||
"electron-icon-maker": "^0.0.4",
|
||||
"electron-is-dev": "^1.0.1",
|
||||
"electron-log": "^2.2.17",
|
||||
"electron-positioner": "^4.1.0",
|
||||
"electron-updater": "^4.0.4",
|
||||
"eslint": "^5.8.0",
|
||||
"eslint-config-airbnb": "^17.1.0",
|
||||
"eslint-plugin-flowtype": "^3.2.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jest": "^22.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"file-loader": "^2.0.0",
|
||||
"flow-bin": "0.84.0",
|
||||
"flow-coverage-report": "^0.6.0",
|
||||
"flow-typed": "^2.5.1",
|
||||
"glow": "^1.2.2",
|
||||
"html-webpack-plugin": "^3.1.0",
|
||||
"jest": "^23.6.0",
|
||||
"jest-dom": "^2.1.1",
|
||||
"node-sass": "^4.8.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"react-testing-library": "^5.3.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-mock-store": "^1.5.3",
|
||||
"sass-loader": "^7.1.0",
|
||||
"spectron": "^5.0.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"uglifyjs-webpack-plugin": "^2.0.1",
|
||||
"wait-on": "^3.2.0",
|
||||
"webpack": "^4.4.1",
|
||||
"webpack-bundle-analyzer": "^3.0.3",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"webpack-dev-server": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.0.0",
|
||||
"@babel/register": "^7.0.0",
|
||||
"autoprefixer": "^9.3.1",
|
||||
"connected-react-router": "^5.0.1",
|
||||
"electron-store": "^2.0.0",
|
||||
"eres": "^1.0.1",
|
||||
"got": "^9.3.2",
|
||||
"history": "^4.7.2",
|
||||
"p-queue": "^3.0.0",
|
||||
"process-exists": "^3.1.0",
|
||||
"qrcode.react": "^0.8.0",
|
||||
"react": "^16.6.0",
|
||||
"react-dom": "^16.6.0",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"redux": "^4.0.1",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"styled-components": "^4.1.1",
|
||||
"styled-theming": "^2.2.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint:precommit",
|
||||
"flow:precommit"
|
||||
],
|
||||
"build": {
|
||||
"appId": "com.zcashfoundation",
|
||||
"productName": "ZEC Wallet",
|
||||
"asar": true,
|
||||
"directories": {
|
||||
"buildResources": "build",
|
||||
"output": "dist"
|
||||
},
|
||||
"files": [
|
||||
"./index.js",
|
||||
"./build/**/*",
|
||||
"./node_modules/**/*"
|
||||
],
|
||||
"linux": {
|
||||
"icon": "./build/icons/png",
|
||||
"target": [
|
||||
"deb"
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"category": "public.app-category.productivity",
|
||||
"type": "distribution",
|
||||
"target": [
|
||||
"pkg",
|
||||
"dmg"
|
||||
]
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/__tests__/setup/jest.js",
|
||||
"testPathIgnorePatterns": [
|
||||
"<rootDir>/__tests__/setup/"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"babel-core": "7.0.0-bridge.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<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=PT+Sans:400,700" rel="stylesheet" />
|
||||
|
||||
<title>Zcash Reference Wallet</title>
|
||||
</head>
|
||||
|
|
Loading…
Reference in New Issue