added new wallet and fixed loading

This commit is contained in:
Zlatko Fedor
2020-10-19 21:02:02 +02:00
parent f05002e30f
commit 222efac642
14 changed files with 282 additions and 125 deletions
+16
View File
@@ -0,0 +1,16 @@
{
"eslintConfig": {
"extends": ["react-app", "shared-config"],
"rules": {
"additional-rule": "warn"
},
"overrides": [
{
"files": ["**/*.ts?(x)"],
"rules": {
"additional-typescript-only-rule": "warn"
}
}
]
}
}
+1
View File
@@ -29,6 +29,7 @@
"react-redux": "^7.2.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-use": "^15.3.4",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"stringify": "^5.2.0",
+1 -1
View File
@@ -3,7 +3,7 @@ import { CssBaseline } from "@material-ui/core";
import { Provider } from "react-redux";
import { ModalDialog, Spinner } from '../pages/ModalDialog';
import Router from './Router';
import theme from '../theme/default';
import theme from '../theme/light';
import WebSocketConnection from "../hocs/WebsocketConnection";
import { daemon_rpc_ws } from "../util/config";
import store from "../modules/store";
+5 -2
View File
@@ -1,7 +1,7 @@
import React from 'react';
import { HashRouter, Switch, Route } from 'react-router-dom';
import SelectKey from "./selectKey/SelectKey";
import NewWallet from "../pages/NewWallet";
import NewWallet from "./newWallet/NewWallet";
import OldWallet from "../pages/OldWallet";
import Dashboard from "../pages/Dashboard";
import { RestoreBackup } from "../pages/backup/restoreBackup";
@@ -41,9 +41,12 @@ export default function Router() {
return (
<HashRouter>
<Switch>
<Route path="/">
<Route path="/" exact>
<SelectKey />
</Route>
<Route path="/wallet">
<NewWallet />
</Route>
</Switch>
</HashRouter>
);
@@ -0,0 +1,53 @@
import styled from "styled-components";
import { TextField } from "@material-ui/core";
export default styled(TextField)`
color: #ffffff;
& .MuiFormLabel-root {
color: #e3f2fd;
}
& .MuiInputLabel-root {
color: #e3f2fd;
}
& label.Mui-focused {
color: #e3f2fd;
}
& label.Mui-required {
color: #e3f2fd;
}
& label.Mui-disabled {
color: #e3f2fd;
}
& label.Mui-root {
color: #e3f2fd;
}
& .MuiInput-underline:after {
border-bottom-color: #e3f2fd;
}
& .MuiOutlinedInput-root {
& fieldset {
border-color: #e3f2fd;
}
&:hover fieldset {
border-color: #e3f2fd;
}
&.Mui-focused fieldset {
border-color: #e3f2fd;
}
&.Mui-disabled fieldset {
border-color: #e3f2fd;
}
}
& .MuiOutlinedInput-input {
color: #ffffff;
}
`;
@@ -0,0 +1,6 @@
import { CircularProgress } from '@material-ui/core';
import styled from 'styled-components';
export default styled(CircularProgress)`
color: white;
`;
@@ -1,11 +1,8 @@
import React, { ReactNode } from 'react';
import { CircularProgress, Typography } from '@material-ui/core';
import { Typography } from '@material-ui/core';
import styled from 'styled-components';
import LayoutHero from '../layout/LayoutHero';
const StyledCircularProgress = styled(CircularProgress)`
color: white;
`;
import Loading from './Loading';
const StyledTypography = styled(Typography)`
color: white;
@@ -23,7 +20,7 @@ export default function LoadingScreen(props: Props) {
<StyledTypography variant="h6">
{children}
</StyledTypography>
<StyledCircularProgress />
<Loading />
</LayoutHero>
);
}
@@ -0,0 +1,8 @@
import React from 'react';
import logo from "../../assets/img/chia_logo.svg";
export default function Logo() {
return (
<img src={logo} alt="Logo" />
);
}
@@ -0,0 +1,91 @@
import React from "react";
import { Typography, Button, Grid, Container } from "@material-ui/core";
import { ArrowBackIos as ArrowBackIosIcon } from "@material-ui/icons";
import { useSelector, useDispatch } from "react-redux";
import { useEffectOnce } from 'react-use';
import { genereate_mnemonics, add_new_key_action } from "../../modules/message";
import TextField from "../form/TextField";
import type { RootState } from "../../modules/rootReducer";
import Logo from '../logo/Logo';
import Flex from '../flex/Flex';
import Loading from '../loading/Loading';
import Link from '../router/Link';
import LayoutHero from "../layout/LayoutHero";
const MnemonicField = (props: any) => {
return (
<Grid item xs={2}>
<TextField
variant="outlined"
margin="normal"
disabled
fullWidth
color="primary"
id={props.id}
label={props.index}
name="email"
autoComplete="email"
autoFocus
value={props.word}
/>
</Grid>
);
};
export default function NewWallet() {
const dispatch = useDispatch();
const words = useSelector((state: RootState) => state.wallet_state.mnemonic);
useEffectOnce(() => {
const get_mnemonics = genereate_mnemonics();
dispatch(get_mnemonics);
});
function handleNext() {
dispatch(add_new_key_action(words));
}
return (
<LayoutHero>
<Container maxWidth="xl">
<Link to="/">
<ArrowBackIosIcon fontSize="large" color="secondary" />
</Link>
</Container>
<Container maxWidth="lg">
<Flex flexDirection="column" gap={3} alignItems="center">
<Logo />
<Typography variant="h4" component="h1" gutterBottom>
New Wallet
</Typography>
<Typography variant="subtitle1" align="center">
Welcome! The following words are used for your wallet backup.
Without them, you will lose access to your wallet, keep them safe!
Write down each word along with the order number next to them.
(Order is important)
</Typography>
{!!words.length ? (
<Grid container spacing={2}>
{words.map((word, i) => (
<MnemonicField key={i} word={word} id={"id_" + (i + 1)} index={i + 1} />
))}
</Grid>
) : (
<Loading />
)}
<Container maxWidth="xs">
<Button
onClick={handleNext}
type="submit"
variant="contained"
color="primary"
fullWidth
>
Next
</Button>
</Container>
</Flex>
</Container>
</LayoutHero>
);
}
@@ -1,12 +1,13 @@
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Container, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Tooltip, List, ListItem, ListItemText, IconButton } from "@material-ui/core";
import { Card, Typography, Container, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Tooltip, List, ListItem, ListItemText, IconButton } from "@material-ui/core";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import { Delete as DeleteIcon, Visibility as VisibilityIcon } from "@material-ui/icons";
import Button from '../button/Button';
import { makeStyles } from "@material-ui/core/styles";
import logo from "../../assets/img/chia_logo.svg";
import LayoutHero from '../layout/LayoutHero';
import Flex from '../flex/Flex';
import Logo from '../logo/Logo';
import {
login_action,
delete_key,
@@ -21,15 +22,9 @@ import {
presentNewWallet
} from "../../modules/entranceMenu";
import { resetMnemonic } from "../../modules/mnemonic";
import { RootState } from "../../modules/rootReducer";
import type { RootState } from "../../modules/rootReducer";
const useStyles = makeStyles(theme => ({
paper: {
display: "flex",
flexDirection: "column",
alignItems: "center",
height: "100%"
},
centeredSpan: {
display: "flex",
flexDirection: "column",
@@ -38,29 +33,6 @@ const useStyles = makeStyles(theme => ({
textField: {
borderColor: "#ffffff"
},
topButton: {
width: 400,
height: 45,
marginTop: theme.spacing(4),
marginBottom: theme.spacing(1)
},
bottomButton: {
width: 400,
height: 45,
marginTop: theme.spacing(2),
marginBottom: theme.spacing(1)
},
bottomButtonRed: {
width: 400,
height: 45,
marginTop: theme.spacing(2),
marginBottom: theme.spacing(1),
color: "red"
},
logo: {
marginTop: theme.spacing(8),
marginBottom: theme.spacing(3)
},
whiteText: {
color: "white"
},
@@ -79,7 +51,7 @@ const useStyles = makeStyles(theme => ({
export default function SelectKey() {
const dispatch = useDispatch();
const classes = useStyles();
const public_key_fingerprints = useSelector(
const publicKeyFingerprints = useSelector(
(state: RootState) => state.wallet_state.public_key_fingerprints
);
@@ -122,92 +94,100 @@ export default function SelectKey() {
dispatch(changeEntranceMenu(presentNewWallet));
};
const list_items = public_key_fingerprints.map(fingerprint => {
return (
<ListItem
button
onClick={handleClick(fingerprint)}
key={fingerprint.toString()}
>
<ListItemText
className={classes.rightPadding}
primary={`Private key with public fingerprint ${fingerprint.toString()}`}
secondary="Can be backed up to mnemonic seed"
/>
<ListItemSecondaryAction>
<Tooltip title="See private key">
<IconButton
edge="end"
aria-label="delete"
onClick={showKey(fingerprint)}
>
<VisibilityIcon />
</IconButton>
</Tooltip>
<Tooltip title="DANGER: permanantly delete private key">
<IconButton
edge="end"
aria-label="delete"
onClick={handleDelete(fingerprint)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
);
});
const hasFingerprints = publicKeyFingerprints && !!publicKeyFingerprints.length;
return (
<LayoutHero>
<Container component="main" maxWidth="xs">
<div className={classes.paper}>
<img className={classes.logo} src={logo} alt="Logo" />
{public_key_fingerprints && public_key_fingerprints.length > 0 ? (
<Container maxWidth="xs">
<Flex flexDirection="column" alignItems="center" gap={3}>
<Logo />
{hasFingerprints ? (
<h1 className={classes.whiteText}>Select Key</h1>
) : (
<span className={classes.centeredSpan}>
<h2 className={classes.whiteText}>Sign In</h2>
<p className={classes.whiteP}>
<>
<Typography variant="h5" component="h1" color="primary" gutterBottom>
Sign In
</Typography>
<Typography variant="subtitle1">
Welcome to Chia. Please log in with an existing key, or create a
a new key.
</p>
</span>
</Typography>
</>
)}
<div className={classes.demo}>
<List>{list_items}</List>
</div>
<Link onClick={goToMnemonics} to="/mnemonics" fullWidth>
<Flex flexDirection="column" gap={3} alignItems="stretch" alignSelf="stretch">
{hasFingerprints && (
<Card>
<List>
{publicKeyFingerprints.map((fingerprint) => (
<ListItem
button
onClick={handleClick(fingerprint)}
key={fingerprint.toString()}
>
<ListItemText
className={classes.rightPadding}
primary={`Private key with public fingerprint ${fingerprint.toString()}`}
secondary="Can be backed up to mnemonic seed"
/>
<ListItemSecondaryAction>
<Tooltip title="See private key">
<IconButton
edge="end"
aria-label="delete"
onClick={showKey(fingerprint)}
>
<VisibilityIcon />
</IconButton>
</Tooltip>
<Tooltip title="DANGER: permanantly delete private key">
<IconButton
edge="end"
aria-label="delete"
onClick={handleDelete(fingerprint)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
))}
</List>
</Card>
)}
<Link onClick={goToMnemonics} to="/mnemonics">
<Button
type="submit"
variant="contained"
color="primary"
size="large"
fullWidth
>
Import from Mnemonics (24 words)
</Button>
</Link>
<Link to="/wallet">
<Button
type="submit"
variant="contained"
color="primary"
size="large"
fullWidth
>
Create a new private key
</Button>
</Link>
<Button
onClick={handleClickOpen}
type="submit"
variant="contained"
color="primary"
color="danger"
size="large"
fullWidth
>
Import from Mnemonics (24 words)
Delete all keys
</Button>
</Link>
<Link onClick={goToNewWallet} to="/wallet" fullWidth>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
>
Create a new private key
</Button>
</Link>
<Button
onClick={handleClickOpen}
type="submit"
variant="contained"
color="danger"
fullWidth
>
Delete all keys
</Button>
</div>
</Flex>
</Flex>
</Container>
<Dialog
open={open}
+10 -6
View File
@@ -92,7 +92,11 @@ export default function incomingReducer(state = { ...initialState }, action: any
const command = message.command;
let success, wallets;
if (command === "generate_mnemonic") {
return { ...state, mnemonic: message.data.mnemonic };
const mnemonic = typeof message.data.mnemonic === 'string'
? message.data.mnemonic.split(' ')
: message.data.mnemonic;
return { ...state, mnemonic };
} else if (command === "add_key") {
success = data.success;
return { ...state, logged_in: success };
@@ -165,7 +169,7 @@ export default function incomingReducer(state = { ...initialState }, action: any
id = data.wallet_id;
var transactions = data.transactions;
wallets = state.wallets;
wallet = wallets[parseInt(id)];
wallet = wallets[Number(id)];
if (!wallet) {
return state;
}
@@ -176,7 +180,7 @@ export default function incomingReducer(state = { ...initialState }, action: any
id = data.wallet_id;
var address = data.address;
wallets = state.wallets;
wallet = wallets[parseInt(id)];
wallet = wallets[Number(id)];
if (!wallet) {
return state;
}
@@ -212,7 +216,7 @@ export default function incomingReducer(state = { ...initialState }, action: any
id = data.wallet_id;
const colour = data.colour;
wallets = state.wallets;
wallet = wallets[parseInt(id)];
wallet = wallets[Number(id)];
if (!wallet) {
return state;
}
@@ -222,7 +226,7 @@ export default function incomingReducer(state = { ...initialState }, action: any
const id = data.wallet_id;
const name = data.name;
wallets = state.wallets;
wallet = wallets[parseInt(id)];
wallet = wallets[Number(id)];
if (!wallet) {
return state;
}
@@ -232,7 +236,7 @@ export default function incomingReducer(state = { ...initialState }, action: any
if (command === "state_changed" && data.state === "tx_update") {
const id = data.wallet_id;
wallets = state.wallets;
wallet = wallets[parseInt(id)];
wallet = wallets[Number(id)];
wallet.sending_transaction = false;
wallet.send_transaction_result = message.data.additional_data;
return { ...state };
-2
View File
@@ -6,8 +6,6 @@ export default {
palette: {
primary: {
main: "#5DA962",
light: 'white',
dark: 'orange',
contrastText: "#ffffff",
},
secondary: {
+1 -2
View File
@@ -1,5 +1,4 @@
type Program = {
}
};
export default Program;
+3 -2
View File
@@ -1,4 +1,5 @@
import WalletType from "./WalletType";
import type Transaction from "./Transaction";
import type WalletType from "./WalletType";
interface Wallet {
id: number,
@@ -10,7 +11,7 @@ interface Wallet {
balance_spendable: number,
balance_frozen: number,
balance_change: number,
transactions: [],
transactions: Transaction[],
address: string,
colour: string,
sending_transaction: boolean,