commit
a459042acd
25
.babelrc
25
.babelrc
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"plugins": [
|
||||
[
|
||||
"transform-runtime", {
|
||||
"helpers": false,
|
||||
"polyfill": false,
|
||||
"regenerator": true,
|
||||
"moduleName": "babel-runtime"
|
||||
}
|
||||
],
|
||||
["module-resolver", {
|
||||
"root": ["./common"],
|
||||
"alias": {
|
||||
"underscore": "lodash"
|
||||
},
|
||||
"cwd": "babelrc"
|
||||
}],
|
||||
"react-hot-loader/babel"],
|
||||
"presets": ["es2015", "react", "stage-0", "flow"],
|
||||
"env": {
|
||||
"production": {
|
||||
"presets": ["react-optimize"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||
"parser": "babel-eslint",
|
||||
"plugins": ["react"],
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"modules": true
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"amd": true,
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"jest": true
|
||||
},
|
||||
"rules": {
|
||||
"comma-dangle": 1,
|
||||
"quotes": [1, "single"],
|
||||
"no-undef": 1,
|
||||
"global-strict": 0,
|
||||
"no-extra-semi": 1,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-console": 0,
|
||||
"no-unused-vars": 0,
|
||||
"no-constant-condition": 0,
|
||||
"no-trailing-spaces": [1, { "skipBlankLines": true }],
|
||||
"no-unreachable": 1,
|
||||
"no-alert": 0,
|
||||
"react/jsx-uses-react": 1,
|
||||
"no-unused-vars": [1, { "argsIgnorePattern": "^_" }],
|
||||
"no-restricted-globals": ["error", "event"]
|
||||
},
|
||||
"globals": {
|
||||
"SyntheticInputEvent": false,
|
||||
"SyntheticKeyboardEvent": false,
|
||||
"Generator": false,
|
||||
"$Keys": false,
|
||||
"SyntheticMouseEvent": false
|
||||
}
|
||||
}
|
|
@ -45,4 +45,13 @@ jspm_packages
|
|||
# VScode workspace settings
|
||||
.vscode/
|
||||
static/dll.vendor.js
|
||||
dll
|
||||
dll
|
||||
.cache-loader
|
||||
|
||||
# SSL cert stuff
|
||||
webpack_config/server.key
|
||||
webpack_config/server.crt
|
||||
webpack_config/server.csr
|
||||
|
||||
|
||||
v8-compile-cache-0/
|
||||
|
|
|
@ -15,4 +15,5 @@ notifications:
|
|||
|
||||
script:
|
||||
- npm run test
|
||||
- npm run flow
|
||||
- npm run tslint
|
||||
- tsc --noEmit
|
||||
|
|
22
README.md
22
README.md
|
@ -20,6 +20,16 @@ It generates app in `dist` folder.
|
|||
npm run test # run tests with Jest
|
||||
```
|
||||
|
||||
#### Dev (HTTPS):
|
||||
|
||||
1. Create your own SSL Certificate (Heroku has a [nice guide here](https://devcenter.heroku.com/articles/ssl-certificate-self))
|
||||
2. Move the `.key` and `.crt` files into `webpack_config/server.*`
|
||||
3. Run the following command:
|
||||
|
||||
```bash
|
||||
npm run dev:https
|
||||
```
|
||||
|
||||
#### Derivation Check:
|
||||
##### The derivation checker utility assumes that you have:
|
||||
1. Docker installed/available
|
||||
|
@ -28,7 +38,7 @@ npm run test # run tests with Jest
|
|||
##### Docker setup instructions:
|
||||
1. Install docker (on macOS, I suggest [Docker for Mac](https://docs.docker.com/docker-for-mac/))
|
||||
2. `docker pull dternyak/eth-priv-to-addr`
|
||||
|
||||
|
||||
##### Run Derivation Checker
|
||||
```bash
|
||||
npm run derivation-checker
|
||||
|
@ -212,3 +222,13 @@ When working on a module that has styling in Less, try to do the following:
|
|||
* Convert as many element selectors to class name selectors as possible
|
||||
* Convert as many `<br/>` tags or ` `s to margins
|
||||
* Ensure that there has been little to no deviation from screenshot
|
||||
|
||||
|
||||
|
||||
## Thanks & Support
|
||||
|
||||
<a href="https://browserstack.com/">
|
||||
<img src="https://i.imgur.com/Rib9y9E.png" align="left" />
|
||||
</a>
|
||||
|
||||
Cross browser testing and debugging provided by the very lovely team at BrowserStack.
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
// @flow
|
||||
|
||||
/*** Change Language ***/
|
||||
export type ChangeLanguageAction = {
|
||||
type: 'CONFIG_LANGUAGE_CHANGE',
|
||||
value: string
|
||||
};
|
||||
|
||||
export function changeLanguage(sign: string): ChangeLanguageAction {
|
||||
return {
|
||||
type: 'CONFIG_LANGUAGE_CHANGE',
|
||||
value: sign
|
||||
};
|
||||
}
|
||||
|
||||
/*** Change Node ***/
|
||||
export type ChangeNodeAction = {
|
||||
type: 'CONFIG_NODE_CHANGE',
|
||||
// FIXME $keyof?
|
||||
value: string
|
||||
};
|
||||
|
||||
export function changeNode(value: string): ChangeNodeAction {
|
||||
return {
|
||||
type: 'CONFIG_NODE_CHANGE',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Change gas price ***/
|
||||
export type ChangeGasPriceAction = {
|
||||
type: 'CONFIG_GAS_PRICE',
|
||||
value: number
|
||||
};
|
||||
|
||||
export function changeGasPrice(value: number): ChangeGasPriceAction {
|
||||
return {
|
||||
type: 'CONFIG_GAS_PRICE',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type ConfigAction =
|
||||
| ChangeNodeAction
|
||||
| ChangeLanguageAction
|
||||
| ChangeGasPriceAction;
|
|
@ -0,0 +1,57 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export type TForceOfflineConfig = typeof forceOfflineConfig;
|
||||
export function forceOfflineConfig(): interfaces.ForceOfflineAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_FORCE_OFFLINE
|
||||
};
|
||||
}
|
||||
|
||||
export type TToggleOfflineConfig = typeof toggleOfflineConfig;
|
||||
export function toggleOfflineConfig(): interfaces.ToggleOfflineAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_TOGGLE_OFFLINE
|
||||
};
|
||||
}
|
||||
|
||||
export type TChangeLanguage = typeof changeLanguage;
|
||||
export function changeLanguage(sign: string): interfaces.ChangeLanguageAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_LANGUAGE_CHANGE,
|
||||
payload: sign
|
||||
};
|
||||
}
|
||||
|
||||
export type TChangeNode = typeof changeNode;
|
||||
export function changeNode(value: string): interfaces.ChangeNodeAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_NODE_CHANGE,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TChangeGasPrice = typeof changeGasPrice;
|
||||
export function changeGasPrice(value: number): interfaces.ChangeGasPriceAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_GAS_PRICE,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TPollOfflineStatus = typeof pollOfflineStatus;
|
||||
export function pollOfflineStatus(): interfaces.PollOfflineStatus {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_POLL_OFFLINE_STATUS
|
||||
};
|
||||
}
|
||||
|
||||
export type TChangeNodeIntent = typeof changeNodeIntent;
|
||||
export function changeNodeIntent(
|
||||
payload: string
|
||||
): interfaces.ChangeNodeIntentAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_NODE_CHANGE_INTENT,
|
||||
payload
|
||||
};
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import { TypeKeys } from './constants';
|
||||
|
||||
/*** Toggle Offline ***/
|
||||
export interface ToggleOfflineAction {
|
||||
type: TypeKeys.CONFIG_TOGGLE_OFFLINE;
|
||||
}
|
||||
|
||||
/*** Force Offline ***/
|
||||
export interface ForceOfflineAction {
|
||||
type: TypeKeys.CONFIG_FORCE_OFFLINE;
|
||||
}
|
||||
|
||||
/*** Change Language ***/
|
||||
export interface ChangeLanguageAction {
|
||||
type: TypeKeys.CONFIG_LANGUAGE_CHANGE;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
/*** Change Node ***/
|
||||
export interface ChangeNodeAction {
|
||||
type: TypeKeys.CONFIG_NODE_CHANGE;
|
||||
// FIXME $keyof?
|
||||
payload: string;
|
||||
}
|
||||
|
||||
/*** Change gas price ***/
|
||||
export interface ChangeGasPriceAction {
|
||||
type: TypeKeys.CONFIG_GAS_PRICE;
|
||||
payload: number;
|
||||
}
|
||||
|
||||
/*** Poll offline status ***/
|
||||
export interface PollOfflineStatus {
|
||||
type: TypeKeys.CONFIG_POLL_OFFLINE_STATUS;
|
||||
}
|
||||
|
||||
/*** Change Node ***/
|
||||
export interface ChangeNodeIntentAction {
|
||||
type: TypeKeys.CONFIG_NODE_CHANGE_INTENT;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type ConfigAction =
|
||||
| ChangeNodeAction
|
||||
| ChangeLanguageAction
|
||||
| ChangeGasPriceAction
|
||||
| ToggleOfflineAction
|
||||
| PollOfflineStatus
|
||||
| ForceOfflineAction
|
||||
| ChangeNodeIntentAction;
|
|
@ -0,0 +1,9 @@
|
|||
export enum TypeKeys {
|
||||
CONFIG_LANGUAGE_CHANGE = 'CONFIG_LANGUAGE_CHANGE',
|
||||
CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE',
|
||||
CONFIG_NODE_CHANGE_INTENT = 'CONFIG_NODE_CHANGE_INTENT',
|
||||
CONFIG_GAS_PRICE = 'CONFIG_GAS_PRICE',
|
||||
CONFIG_TOGGLE_OFFLINE = 'CONFIG_TOGGLE_OFFLINE',
|
||||
CONFIG_FORCE_OFFLINE = 'CONFIG_FORCE_OFFLINE',
|
||||
CONFIG_POLL_OFFLINE_STATUS = 'CONFIG_POLL_OFFLINE_STATUS'
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './actionCreators';
|
||||
export * from './actionTypes';
|
|
@ -1,47 +0,0 @@
|
|||
// @flow
|
||||
|
||||
/***** Access Contract *****/
|
||||
export type AccessContractAction = {
|
||||
type: 'ACCESS_CONTRACT',
|
||||
address: string,
|
||||
abiJson: string
|
||||
};
|
||||
|
||||
export function accessContract(
|
||||
address: string,
|
||||
abiJson: string
|
||||
): AccessContractAction {
|
||||
return {
|
||||
type: 'ACCESS_CONTRACT',
|
||||
address,
|
||||
abiJson
|
||||
};
|
||||
}
|
||||
|
||||
/***** Set Interactive Contract *****/
|
||||
export type ABIFunctionField = {
|
||||
name: string,
|
||||
type: string
|
||||
};
|
||||
|
||||
export type ABIFunction = {
|
||||
name: string,
|
||||
type: string,
|
||||
constant: boolean,
|
||||
inputs: Array<ABIFunctionField>,
|
||||
outputs: Array<ABIFunctionField>
|
||||
};
|
||||
|
||||
export type SetInteractiveContractAction = {
|
||||
type: 'SET_INTERACTIVE_CONTRACT',
|
||||
functions: Array<ABIFunction>
|
||||
};
|
||||
|
||||
export function setInteractiveContract(
|
||||
functions: Array<ABIFunction>
|
||||
): SetInteractiveContractAction {
|
||||
return {
|
||||
type: 'SET_INTERACTIVE_CONTRACT',
|
||||
functions
|
||||
};
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export function accessContract(
|
||||
address: string,
|
||||
abiJson: string
|
||||
): interfaces.AccessContractAction {
|
||||
return {
|
||||
type: TypeKeys.ACCESS_CONTRACT,
|
||||
address,
|
||||
abiJson
|
||||
};
|
||||
}
|
||||
|
||||
export function setInteractiveContract(
|
||||
functions: interfaces.ABIFunction[]
|
||||
): interfaces.SetInteractiveContractAction {
|
||||
return {
|
||||
type: TypeKeys.SET_INTERACTIVE_CONTRACT,
|
||||
functions
|
||||
};
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
import { TypeKeys } from './constants';
|
||||
/***** Set Interactive Contract *****/
|
||||
export interface ABIFunctionField {
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface ABIFunction {
|
||||
name: string;
|
||||
type: string;
|
||||
constant: boolean;
|
||||
inputs: ABIFunctionField[];
|
||||
outputs: ABIFunctionField[];
|
||||
}
|
||||
|
||||
export interface SetInteractiveContractAction {
|
||||
type: TypeKeys.SET_INTERACTIVE_CONTRACT;
|
||||
functions: ABIFunction[];
|
||||
}
|
||||
|
||||
/***** Access Contract *****/
|
||||
export interface AccessContractAction {
|
||||
type: TypeKeys.ACCESS_CONTRACT;
|
||||
address: string;
|
||||
abiJson: string;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type ContractsAction =
|
||||
| SetInteractiveContractAction
|
||||
| AccessContractAction;
|
|
@ -0,0 +1,4 @@
|
|||
export enum TypeKeys {
|
||||
ACCESS_CONTRACT = 'ACCESS_CONTRACT',
|
||||
SET_INTERACTIVE_CONTRACT = 'SET_INTERACTIVE_CONTRACT'
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from './constants';
|
||||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,31 +0,0 @@
|
|||
// @flow
|
||||
import type { Token } from 'config/data';
|
||||
|
||||
/*** Add custom token ***/
|
||||
export type AddCustomTokenAction = {
|
||||
type: 'CUSTOM_TOKEN_ADD',
|
||||
payload: Token
|
||||
};
|
||||
|
||||
export function addCustomToken(payload: Token): AddCustomTokenAction {
|
||||
return {
|
||||
type: 'CUSTOM_TOKEN_ADD',
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
/*** Remove Custom Token ***/
|
||||
export type RemoveCustomTokenAction = {
|
||||
type: 'CUSTOM_TOKEN_REMOVE',
|
||||
payload: string
|
||||
};
|
||||
|
||||
export function removeCustomToken(payload: string): RemoveCustomTokenAction {
|
||||
return {
|
||||
type: 'CUSTOM_TOKEN_REMOVE',
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type CustomTokenAction = AddCustomTokenAction | RemoveCustomTokenAction;
|
|
@ -0,0 +1,24 @@
|
|||
import { Token } from 'config/data';
|
||||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export type TAddCustomToken = typeof addCustomToken;
|
||||
export function addCustomToken(
|
||||
payload: Token
|
||||
): interfaces.AddCustomTokenAction {
|
||||
return {
|
||||
type: TypeKeys.CUSTOM_TOKEN_ADD,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TRemoveCustomToken = typeof removeCustomToken;
|
||||
|
||||
export function removeCustomToken(
|
||||
payload: string
|
||||
): interfaces.RemoveCustomTokenAction {
|
||||
return {
|
||||
type: TypeKeys.CUSTOM_TOKEN_REMOVE,
|
||||
payload
|
||||
};
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { Token } from 'config/data';
|
||||
import { TypeKeys } from './constants';
|
||||
/*** Add custom token ***/
|
||||
export interface AddCustomTokenAction {
|
||||
type: TypeKeys.CUSTOM_TOKEN_ADD;
|
||||
payload: Token;
|
||||
}
|
||||
|
||||
/*** Remove Custom Token ***/
|
||||
export interface RemoveCustomTokenAction {
|
||||
type: TypeKeys.CUSTOM_TOKEN_REMOVE;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
export type CustomTokenAction = AddCustomTokenAction | RemoveCustomTokenAction;
|
|
@ -0,0 +1,4 @@
|
|||
export enum TypeKeys {
|
||||
CUSTOM_TOKEN_ADD = 'CUSTOM_TOKEN_ADD',
|
||||
CUSTOM_TOKEN_REMOVE = 'CUSTOM_TOKEN_REMOVE'
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './actionCreators';
|
||||
export * from './actionTypes';
|
|
@ -1,105 +0,0 @@
|
|||
// @flow
|
||||
import type Big from 'bignumber.js';
|
||||
|
||||
export type TokenValues = { [string]: ?Big };
|
||||
|
||||
export type DeterministicWalletData = {
|
||||
index: number,
|
||||
address: string,
|
||||
value?: Big,
|
||||
tokenValues: TokenValues
|
||||
};
|
||||
|
||||
/*** Get determinstic wallets ***/
|
||||
export type GetDeterministicWalletsAction = {
|
||||
type: 'DW_GET_WALLETS',
|
||||
payload: {
|
||||
seed: ?string,
|
||||
dPath: string,
|
||||
publicKey: ?string,
|
||||
chainCode: ?string,
|
||||
limit: number,
|
||||
offset: number
|
||||
}
|
||||
};
|
||||
|
||||
export type GetDeterministicWalletsArgs = {
|
||||
seed: ?string,
|
||||
dPath: string,
|
||||
publicKey: ?string,
|
||||
chainCode: ?string,
|
||||
limit?: number,
|
||||
offset?: number
|
||||
};
|
||||
|
||||
export function getDeterministicWallets(
|
||||
args: GetDeterministicWalletsArgs
|
||||
): GetDeterministicWalletsAction {
|
||||
const { seed, dPath, publicKey, chainCode, limit, offset } = args;
|
||||
return {
|
||||
type: 'DW_GET_WALLETS',
|
||||
payload: {
|
||||
seed,
|
||||
dPath,
|
||||
publicKey,
|
||||
chainCode,
|
||||
limit: limit || 5,
|
||||
offset: offset || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set deterministic wallets ***/
|
||||
export type SetDeterministicWalletsAction = {
|
||||
type: 'DW_SET_WALLETS',
|
||||
payload: DeterministicWalletData[]
|
||||
};
|
||||
|
||||
export function setDeterministicWallets(
|
||||
wallets: DeterministicWalletData[]
|
||||
): SetDeterministicWalletsAction {
|
||||
return {
|
||||
type: 'DW_SET_WALLETS',
|
||||
payload: wallets
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set desired token ***/
|
||||
export type SetDesiredTokenAction = {
|
||||
type: 'DW_SET_DESIRED_TOKEN',
|
||||
payload: ?string
|
||||
};
|
||||
|
||||
export function setDesiredToken(token: ?string): SetDesiredTokenAction {
|
||||
return {
|
||||
type: 'DW_SET_DESIRED_TOKEN',
|
||||
payload: token
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set wallet values ***/
|
||||
export type UpdateDeterministicWalletArgs = {
|
||||
address: string,
|
||||
value: ?Big,
|
||||
tokenValues: ?TokenValues
|
||||
};
|
||||
|
||||
export type UpdateDeterministicWalletAction = {
|
||||
type: 'DW_UPDATE_WALLET',
|
||||
payload: UpdateDeterministicWalletArgs
|
||||
};
|
||||
|
||||
export function updateDeterministicWallet(
|
||||
args: UpdateDeterministicWalletArgs
|
||||
): UpdateDeterministicWalletAction {
|
||||
return {
|
||||
type: 'DW_UPDATE_WALLET',
|
||||
payload: args
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type DeterministicWalletAction =
|
||||
| GetDeterministicWalletsAction
|
||||
| UpdateDeterministicWalletAction
|
||||
| SetDesiredTokenAction;
|
|
@ -0,0 +1,45 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
export function getDeterministicWallets(
|
||||
args: interfaces.GetDeterministicWalletsArgs
|
||||
): interfaces.GetDeterministicWalletsAction {
|
||||
const { seed, dPath, publicKey, chainCode, limit, offset } = args;
|
||||
return {
|
||||
type: TypeKeys.DW_GET_WALLETS,
|
||||
payload: {
|
||||
seed,
|
||||
dPath,
|
||||
publicKey,
|
||||
chainCode,
|
||||
limit: limit || 5,
|
||||
offset: offset || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setDeterministicWallets(
|
||||
wallets: interfaces.DeterministicWalletData[]
|
||||
): interfaces.SetDeterministicWalletsAction {
|
||||
return {
|
||||
type: TypeKeys.DW_SET_WALLETS,
|
||||
payload: wallets
|
||||
};
|
||||
}
|
||||
|
||||
export function setDesiredToken(
|
||||
token: string | undefined
|
||||
): interfaces.SetDesiredTokenAction {
|
||||
return {
|
||||
type: TypeKeys.DW_SET_DESIRED_TOKEN,
|
||||
payload: token
|
||||
};
|
||||
}
|
||||
|
||||
export function updateDeterministicWallet(
|
||||
args: interfaces.UpdateDeterministicWalletArgs
|
||||
): interfaces.UpdateDeterministicWalletAction {
|
||||
return {
|
||||
type: TypeKeys.DW_UPDATE_WALLET,
|
||||
payload: args
|
||||
};
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import { BigNumber } from 'bignumber.js';
|
||||
|
||||
export interface TokenValues {
|
||||
[key: string]: BigNumber;
|
||||
}
|
||||
|
||||
export interface DeterministicWalletData {
|
||||
index: number;
|
||||
address: string;
|
||||
value?: BigNumber;
|
||||
tokenValues: TokenValues;
|
||||
}
|
||||
|
||||
/*** Get determinstic wallets ***/
|
||||
export interface GetDeterministicWalletsAction {
|
||||
type: 'DW_GET_WALLETS';
|
||||
payload: {
|
||||
seed?: string;
|
||||
dPath: string;
|
||||
publicKey?: string;
|
||||
chainCode?: string;
|
||||
limit: number;
|
||||
offset: number;
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set deterministic wallets ***/
|
||||
export interface SetDeterministicWalletsAction {
|
||||
type: 'DW_SET_WALLETS';
|
||||
payload: DeterministicWalletData[];
|
||||
}
|
||||
|
||||
/*** Set desired token ***/
|
||||
export interface SetDesiredTokenAction {
|
||||
type: 'DW_SET_DESIRED_TOKEN';
|
||||
payload: string | undefined;
|
||||
}
|
||||
|
||||
/*** Set wallet values ***/
|
||||
export interface UpdateDeterministicWalletArgs {
|
||||
address: string;
|
||||
value?: BigNumber;
|
||||
tokenValues?: TokenValues;
|
||||
index?: any;
|
||||
}
|
||||
|
||||
export interface UpdateDeterministicWalletAction {
|
||||
type: 'DW_UPDATE_WALLET';
|
||||
payload: UpdateDeterministicWalletArgs;
|
||||
}
|
||||
|
||||
export interface GetDeterministicWalletsArgs {
|
||||
seed?: string;
|
||||
dPath: string;
|
||||
publicKey?: string;
|
||||
chainCode?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type DeterministicWalletAction =
|
||||
| SetDeterministicWalletsAction
|
||||
| GetDeterministicWalletsAction
|
||||
| UpdateDeterministicWalletAction
|
||||
| SetDesiredTokenAction;
|
|
@ -0,0 +1,6 @@
|
|||
export enum TypeKeys {
|
||||
DW_GET_WALLETS = 'DW_GET_WALLETS',
|
||||
DW_SET_WALLETS = 'DW_SET_WALLETS',
|
||||
DW_SET_DESIRED_TOKEN = 'DW_SET_DESIRED_TOKEN',
|
||||
DW_UPDATE_WALLET = 'DW_UPDATE_WALLET'
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,39 +0,0 @@
|
|||
// @flow
|
||||
|
||||
/*** Resolve ENS name ***/
|
||||
export type ResolveEnsNameAction = {
|
||||
type: 'ENS_RESOLVE',
|
||||
payload: string
|
||||
};
|
||||
|
||||
export function resolveEnsName(name: string): ResolveEnsNameAction {
|
||||
return {
|
||||
type: 'ENS_RESOLVE',
|
||||
payload: name
|
||||
};
|
||||
}
|
||||
|
||||
/*** Cache ENS address ***/
|
||||
export type CacheEnsAddressAction = {
|
||||
type: 'ENS_CACHE',
|
||||
payload: {
|
||||
ensName: string,
|
||||
address: string
|
||||
}
|
||||
};
|
||||
|
||||
export function cacheEnsAddress(
|
||||
ensName: string,
|
||||
address: string
|
||||
): CacheEnsAddressAction {
|
||||
return {
|
||||
type: 'ENS_CACHE',
|
||||
payload: {
|
||||
ensName,
|
||||
address
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type EnsAction = ResolveEnsNameAction | CacheEnsAddressAction;
|
|
@ -0,0 +1,22 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import * as constants from './constants';
|
||||
|
||||
export function resolveEnsName(name: string): interfaces.ResolveEnsNameAction {
|
||||
return {
|
||||
type: constants.ENS_RESOLVE,
|
||||
payload: name
|
||||
};
|
||||
}
|
||||
|
||||
export function cacheEnsAddress(
|
||||
ensName: string,
|
||||
address: string
|
||||
): interfaces.CacheEnsAddressAction {
|
||||
return {
|
||||
type: constants.ENS_CACHE,
|
||||
payload: {
|
||||
ensName,
|
||||
address
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import * as constants from './constants';
|
||||
|
||||
/*** Resolve ENS name ***/
|
||||
export interface ResolveEnsNameAction {
|
||||
type: 'ENS_RESOLVE';
|
||||
payload: string;
|
||||
}
|
||||
|
||||
/*** Cache ENS address ***/
|
||||
export interface CacheEnsAddressAction {
|
||||
type: 'ENS_CACHE';
|
||||
payload: {
|
||||
ensName: string;
|
||||
address: string;
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type EnsAction = ResolveEnsNameAction | CacheEnsAddressAction;
|
|
@ -0,0 +1,2 @@
|
|||
export const ENS_RESOLVE = 'ENS_RESOLVE';
|
||||
export const ENS_CACHE = 'ENS_CACHE';
|
|
@ -0,0 +1,3 @@
|
|||
export * from './constants';
|
||||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,38 +0,0 @@
|
|||
// @flow
|
||||
import { PrivKeyWallet } from 'libs/wallet';
|
||||
|
||||
/*** Generate Wallet File ***/
|
||||
export type GenerateNewWalletAction = {
|
||||
type: 'GENERATE_WALLET_GENERATE_WALLET',
|
||||
wallet: PrivKeyWallet,
|
||||
password: string
|
||||
};
|
||||
|
||||
export function generateNewWallet(password: string): GenerateNewWalletAction {
|
||||
return {
|
||||
type: 'GENERATE_WALLET_GENERATE_WALLET',
|
||||
wallet: PrivKeyWallet.generate(),
|
||||
password
|
||||
};
|
||||
}
|
||||
|
||||
/*** Confirm Continue To Paper ***/
|
||||
export type ContinueToPaperAction = {
|
||||
type: 'GENERATE_WALLET_CONTINUE_TO_PAPER'
|
||||
};
|
||||
|
||||
export function continueToPaper(): ContinueToPaperAction {
|
||||
return { type: 'GENERATE_WALLET_CONTINUE_TO_PAPER' };
|
||||
}
|
||||
|
||||
/*** Reset Generate Wallet ***/
|
||||
export type ResetGenerateWalletAction = {
|
||||
type: 'GENERATE_WALLET_RESET'
|
||||
};
|
||||
|
||||
export function resetGenerateWallet(): ResetGenerateWalletAction {
|
||||
return { type: 'GENERATE_WALLET_RESET' };
|
||||
}
|
||||
|
||||
/*** Action Union ***/
|
||||
export type GenerateWalletAction = GenerateWalletAction;
|
|
@ -0,0 +1,24 @@
|
|||
import { PrivKeyWallet } from 'libs/wallet';
|
||||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export type TGenerateNewWallet = typeof generateNewWallet;
|
||||
export function generateNewWallet(
|
||||
password: string
|
||||
): interfaces.GenerateNewWalletAction {
|
||||
return {
|
||||
type: TypeKeys.GENERATE_WALLET_GENERATE_WALLET,
|
||||
wallet: PrivKeyWallet.generate(),
|
||||
password
|
||||
};
|
||||
}
|
||||
|
||||
export type TContinueToPaper = typeof continueToPaper;
|
||||
export function continueToPaper(): interfaces.ContinueToPaperAction {
|
||||
return { type: TypeKeys.GENERATE_WALLET_CONTINUE_TO_PAPER };
|
||||
}
|
||||
|
||||
export type TResetGenerateWallet = typeof resetGenerateWallet;
|
||||
export function resetGenerateWallet(): interfaces.ResetGenerateWalletAction {
|
||||
return { type: TypeKeys.GENERATE_WALLET_RESET };
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { PrivKeyWallet } from 'libs/wallet';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
/*** Generate Wallet File ***/
|
||||
export interface GenerateNewWalletAction {
|
||||
type: TypeKeys.GENERATE_WALLET_GENERATE_WALLET;
|
||||
wallet: PrivKeyWallet;
|
||||
password: string;
|
||||
}
|
||||
|
||||
/*** Reset Generate Wallet ***/
|
||||
export interface ResetGenerateWalletAction {
|
||||
type: TypeKeys.GENERATE_WALLET_RESET;
|
||||
}
|
||||
|
||||
/*** Confirm Continue To Paper ***/
|
||||
export interface ContinueToPaperAction {
|
||||
type: TypeKeys.GENERATE_WALLET_CONTINUE_TO_PAPER;
|
||||
}
|
||||
|
||||
/*** Action Union ***/
|
||||
export type GenerateWalletAction =
|
||||
| GenerateNewWalletAction
|
||||
| ContinueToPaperAction
|
||||
| ResetGenerateWalletAction;
|
|
@ -0,0 +1,5 @@
|
|||
export enum TypeKeys {
|
||||
GENERATE_WALLET_GENERATE_WALLET = 'GENERATE_WALLET_GENERATE_WALLET',
|
||||
GENERATE_WALLET_CONTINUE_TO_PAPER = 'GENERATE_WALLET_CONTINUE_TO_PAPER',
|
||||
GENERATE_WALLET_RESET = 'GENERATE_WALLET_RESET'
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from './constants';
|
||||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,53 +0,0 @@
|
|||
// @flow
|
||||
import type { Element } from 'react';
|
||||
|
||||
/*** Shared types ***/
|
||||
export type NOTIFICATION_LEVEL = 'danger' | 'warning' | 'success' | 'info';
|
||||
export type INFINITY = 'infinity';
|
||||
|
||||
export type Notification = {
|
||||
level: NOTIFICATION_LEVEL,
|
||||
msg: Element<*> | string,
|
||||
duration?: number | INFINITY
|
||||
};
|
||||
|
||||
/*** Show Notification ***/
|
||||
export type ShowNotificationAction = {
|
||||
type: 'SHOW_NOTIFICATION',
|
||||
payload: Notification
|
||||
};
|
||||
|
||||
export function showNotification(
|
||||
level: NOTIFICATION_LEVEL = 'info',
|
||||
msg: Element<*> | string,
|
||||
duration?: number | INFINITY
|
||||
): ShowNotificationAction {
|
||||
return {
|
||||
type: 'SHOW_NOTIFICATION',
|
||||
payload: {
|
||||
level,
|
||||
msg,
|
||||
duration
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*** Close notification ***/
|
||||
export type CloseNotificationAction = {
|
||||
type: 'CLOSE_NOTIFICATION',
|
||||
payload: Notification
|
||||
};
|
||||
|
||||
export function closeNotification(
|
||||
notification: Notification
|
||||
): CloseNotificationAction {
|
||||
return {
|
||||
type: 'CLOSE_NOTIFICATION',
|
||||
payload: notification
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type NotificationsAction =
|
||||
| ShowNotificationAction
|
||||
| CloseNotificationAction;
|
|
@ -0,0 +1,29 @@
|
|||
import { ReactElement } from 'react';
|
||||
import * as types from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export type TShowNotification = typeof showNotification;
|
||||
export function showNotification(
|
||||
level: types.NOTIFICATION_LEVEL = 'info',
|
||||
msg: ReactElement<any> | string,
|
||||
duration?: number | types.INFINITY
|
||||
): types.ShowNotificationAction {
|
||||
return {
|
||||
type: TypeKeys.SHOW_NOTIFICATION,
|
||||
payload: {
|
||||
level,
|
||||
msg,
|
||||
duration
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type TCloseNotification = typeof closeNotification;
|
||||
export function closeNotification(
|
||||
notification: types.Notification
|
||||
): types.CloseNotificationAction {
|
||||
return {
|
||||
type: TypeKeys.CLOSE_NOTIFICATION,
|
||||
payload: notification
|
||||
};
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { ReactElement } from 'react';
|
||||
import { TypeKeys } from './constants';
|
||||
/*** Shared types ***/
|
||||
export type NOTIFICATION_LEVEL = 'danger' | 'warning' | 'success' | 'info';
|
||||
export type INFINITY = 'infinity';
|
||||
|
||||
export interface Notification {
|
||||
level: NOTIFICATION_LEVEL;
|
||||
msg: ReactElement<any> | string;
|
||||
duration?: number | INFINITY;
|
||||
}
|
||||
|
||||
/*** Close notification ***/
|
||||
export interface CloseNotificationAction {
|
||||
type: TypeKeys.CLOSE_NOTIFICATION;
|
||||
payload: Notification;
|
||||
}
|
||||
|
||||
/*** Show Notification ***/
|
||||
export interface ShowNotificationAction {
|
||||
type: TypeKeys.SHOW_NOTIFICATION;
|
||||
payload: Notification;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type NotificationsAction =
|
||||
| ShowNotificationAction
|
||||
| CloseNotificationAction;
|
|
@ -0,0 +1,4 @@
|
|||
export enum TypeKeys {
|
||||
SHOW_NOTIFICATION = 'SHOW_NOTIFICATION',
|
||||
CLOSE_NOTIFICATION = 'CLOSE_NOTIFICATION'
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,29 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export type FiatRequestedRatesAction = {
|
||||
type: 'RATES_FIAT_REQUESTED'
|
||||
};
|
||||
|
||||
export function fiatRequestedRates() {
|
||||
return {
|
||||
type: 'RATES_FIAT_REQUESTED'
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set rates ***/
|
||||
export type FiatSucceededRatesAction = {
|
||||
type: 'RATES_FIAT_SUCCEEDED',
|
||||
payload: { [string]: number }
|
||||
};
|
||||
|
||||
export function fiatSucceededRates(payload: {
|
||||
[string]: number
|
||||
}): FiatSucceededRatesAction {
|
||||
return {
|
||||
type: 'RATES_FIAT_SUCCEEDED',
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type RatesAction = FiatSucceededRatesAction | FiatRequestedRatesAction;
|
|
@ -0,0 +1,11 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
import { fetchRates, CCResponse } from './actionPayloads';
|
||||
|
||||
export type TFetchCCRates = typeof fetchCCRates;
|
||||
export function fetchCCRates(): interfaces.FetchCCRates {
|
||||
return {
|
||||
type: TypeKeys.RATES_FETCH_CC,
|
||||
payload: fetchRates()
|
||||
};
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { handleJSONResponse } from 'api/utils';
|
||||
|
||||
export const symbols = ['USD', 'EUR', 'GBP', 'BTC', 'CHF', 'REP'];
|
||||
const symbolsURL = symbols.join(',');
|
||||
// TODO - internationalize
|
||||
const ERROR_MESSAGE = 'Could not fetch rate data.';
|
||||
const CCApi = 'https://min-api.cryptocompare.com';
|
||||
|
||||
const CCRates = CCSymbols => `${CCApi}/data/price?fsym=ETH&tsyms=${CCSymbols}`;
|
||||
|
||||
export interface CCResponse {
|
||||
BTC: number;
|
||||
EUR: number;
|
||||
GBP: number;
|
||||
CHF: number;
|
||||
REP: number;
|
||||
}
|
||||
|
||||
export const fetchRates = (): Promise<CCResponse> =>
|
||||
fetch(CCRates(symbolsURL)).then(response =>
|
||||
handleJSONResponse(response, ERROR_MESSAGE)
|
||||
);
|
|
@ -0,0 +1,23 @@
|
|||
import { TypeKeys } from './constants';
|
||||
import { CCResponse } from './actionPayloads';
|
||||
|
||||
export interface FetchCCRates {
|
||||
type: TypeKeys.RATES_FETCH_CC;
|
||||
payload: Promise<CCResponse>;
|
||||
}
|
||||
|
||||
/*** Set rates ***/
|
||||
export interface FetchCCRatesSucceeded {
|
||||
type: TypeKeys.RATES_FETCH_CC_SUCCEEDED;
|
||||
payload: CCResponse;
|
||||
}
|
||||
|
||||
export interface FetchCCRatesFailed {
|
||||
type: TypeKeys.RATES_FETCH_CC_FAILED;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type RatesAction =
|
||||
| FetchCCRatesSucceeded
|
||||
| FetchCCRates
|
||||
| FetchCCRatesFailed;
|
|
@ -0,0 +1,5 @@
|
|||
export enum TypeKeys {
|
||||
RATES_FETCH_CC = 'RATES_FETCH_CC',
|
||||
RATES_FETCH_CC_FAILED = 'RATES_FETCH_CC_FAILED',
|
||||
RATES_FETCH_CC_SUCCEEDED = 'RATES_FETCH_CC_SUCCEEDED'
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from './actionCreators';
|
||||
export * from './actionTypes';
|
||||
export * from './actionPayloads';
|
|
@ -1,169 +0,0 @@
|
|||
// @flow
|
||||
import type {
|
||||
OriginKindSwapAction,
|
||||
DestinationKindSwapAction,
|
||||
OriginAmountSwapAction,
|
||||
DestinationAmountSwapAction,
|
||||
LoadBityRatesSucceededSwapAction,
|
||||
DestinationAddressSwapAction,
|
||||
BityOrderCreateSucceededSwapAction,
|
||||
BityOrderCreateRequestedSwapAction,
|
||||
OrderStatusSucceededSwapAction,
|
||||
ChangeStepSwapAction,
|
||||
Pairs,
|
||||
RestartSwapAction,
|
||||
LoadBityRatesRequestedSwapAction,
|
||||
StopLoadBityRatesSwapAction,
|
||||
BityOrderResponse,
|
||||
BityOrderPostResponse,
|
||||
OrderStatusRequestedSwapAction,
|
||||
StopOrderTimerSwapAction,
|
||||
StartOrderTimerSwapAction,
|
||||
StartPollBityOrderStatusAction,
|
||||
StopPollBityOrderStatusAction
|
||||
} from './swapTypes';
|
||||
|
||||
export function changeStepSwap(value: number): ChangeStepSwapAction {
|
||||
return {
|
||||
type: 'SWAP_STEP',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function originKindSwap(value: string): OriginKindSwapAction {
|
||||
return {
|
||||
type: 'SWAP_ORIGIN_KIND',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function destinationKindSwap(value: string): DestinationKindSwapAction {
|
||||
return {
|
||||
type: 'SWAP_DESTINATION_KIND',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function originAmountSwap(value: ?number): OriginAmountSwapAction {
|
||||
return {
|
||||
type: 'SWAP_ORIGIN_AMOUNT',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function destinationAmountSwap(
|
||||
value: ?number
|
||||
): DestinationAmountSwapAction {
|
||||
return {
|
||||
type: 'SWAP_DESTINATION_AMOUNT',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function loadBityRatesSucceededSwap(
|
||||
value: Pairs
|
||||
): LoadBityRatesSucceededSwapAction {
|
||||
return {
|
||||
type: 'SWAP_LOAD_BITY_RATES_SUCCEEDED',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function destinationAddressSwap(
|
||||
value: ?string
|
||||
): DestinationAddressSwapAction {
|
||||
return {
|
||||
type: 'SWAP_DESTINATION_ADDRESS',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function restartSwap(): RestartSwapAction {
|
||||
return {
|
||||
type: 'SWAP_RESTART'
|
||||
};
|
||||
}
|
||||
|
||||
export function loadBityRatesRequestedSwap(): LoadBityRatesRequestedSwapAction {
|
||||
return {
|
||||
type: 'SWAP_LOAD_BITY_RATES_REQUESTED'
|
||||
};
|
||||
}
|
||||
|
||||
export function stopLoadBityRatesSwap(): StopLoadBityRatesSwapAction {
|
||||
return {
|
||||
type: 'SWAP_STOP_LOAD_BITY_RATES'
|
||||
};
|
||||
}
|
||||
|
||||
export function orderTimeSwap(value: number) {
|
||||
return {
|
||||
type: 'SWAP_ORDER_TIME',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function bityOrderCreateSucceededSwap(
|
||||
payload: BityOrderPostResponse
|
||||
): BityOrderCreateSucceededSwapAction {
|
||||
return {
|
||||
type: 'SWAP_BITY_ORDER_CREATE_SUCCEEDED',
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export function bityOrderCreateRequestedSwap(
|
||||
amount: number,
|
||||
destinationAddress: string,
|
||||
pair: string,
|
||||
mode: number = 0
|
||||
): BityOrderCreateRequestedSwapAction {
|
||||
return {
|
||||
type: 'SWAP_ORDER_CREATE_REQUESTED',
|
||||
payload: {
|
||||
amount,
|
||||
destinationAddress,
|
||||
pair,
|
||||
mode
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function orderStatusSucceededSwap(
|
||||
payload: BityOrderResponse
|
||||
): OrderStatusSucceededSwapAction {
|
||||
return {
|
||||
type: 'SWAP_BITY_ORDER_STATUS_SUCCEEDED',
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export function orderStatusRequestedSwap(): OrderStatusRequestedSwapAction {
|
||||
return {
|
||||
type: 'SWAP_BITY_ORDER_STATUS_REQUESTED'
|
||||
};
|
||||
}
|
||||
|
||||
export function startOrderTimerSwap(): StartOrderTimerSwapAction {
|
||||
return {
|
||||
type: 'SWAP_ORDER_START_TIMER'
|
||||
};
|
||||
}
|
||||
|
||||
export function stopOrderTimerSwap(): StopOrderTimerSwapAction {
|
||||
return {
|
||||
type: 'SWAP_ORDER_STOP_TIMER'
|
||||
};
|
||||
}
|
||||
|
||||
export function startPollBityOrderStatus(): StartPollBityOrderStatusAction {
|
||||
return {
|
||||
type: 'SWAP_START_POLL_BITY_ORDER_STATUS'
|
||||
};
|
||||
}
|
||||
|
||||
export function stopPollBityOrderStatus(): StopPollBityOrderStatusAction {
|
||||
return {
|
||||
type: 'SWAP_STOP_POLL_BITY_ORDER_STATUS'
|
||||
};
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export type TChangeStepSwap = typeof changeStepSwap;
|
||||
export function changeStepSwap(
|
||||
payload: number
|
||||
): interfaces.ChangeStepSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_STEP,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TOriginKindSwap = typeof originKindSwap;
|
||||
export function originKindSwap(
|
||||
payload: string
|
||||
): interfaces.OriginKindSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORIGIN_KIND,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TDestinationKindSwap = typeof destinationKindSwap;
|
||||
export function destinationKindSwap(
|
||||
payload: string
|
||||
): interfaces.DestinationKindSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_DESTINATION_KIND,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TOriginAmountSwap = typeof originAmountSwap;
|
||||
export function originAmountSwap(
|
||||
payload?: number | null
|
||||
): interfaces.OriginAmountSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORIGIN_AMOUNT,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TDestinationAmountSwap = typeof destinationAmountSwap;
|
||||
export function destinationAmountSwap(
|
||||
payload?: number | null
|
||||
): interfaces.DestinationAmountSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_DESTINATION_AMOUNT,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TLoadBityRatesSucceededSwap = typeof loadBityRatesSucceededSwap;
|
||||
export function loadBityRatesSucceededSwap(
|
||||
payload: interfaces.Pairs
|
||||
): interfaces.LoadBityRatesSucceededSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_LOAD_BITY_RATES_SUCCEEDED,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TDestinationAddressSwap = typeof destinationAddressSwap;
|
||||
export function destinationAddressSwap(
|
||||
payload?: string
|
||||
): interfaces.DestinationAddressSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_DESTINATION_ADDRESS,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TRestartSwap = typeof restartSwap;
|
||||
export function restartSwap(): interfaces.RestartSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_RESTART
|
||||
};
|
||||
}
|
||||
|
||||
export type TLoadBityRatesRequestedSwap = typeof loadBityRatesRequestedSwap;
|
||||
export function loadBityRatesRequestedSwap(): interfaces.LoadBityRatesRequestedSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_LOAD_BITY_RATES_REQUESTED
|
||||
};
|
||||
}
|
||||
|
||||
export type TStopLoadBityRatesSwap = typeof stopLoadBityRatesSwap;
|
||||
export function stopLoadBityRatesSwap(): interfaces.StopLoadBityRatesSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_STOP_LOAD_BITY_RATES
|
||||
};
|
||||
}
|
||||
|
||||
export type TOrderTimeSwap = typeof orderTimeSwap;
|
||||
export function orderTimeSwap(
|
||||
payload: number
|
||||
): interfaces.OrderSwapTimeSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORDER_TIME,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TBityOrderCreateSucceededSwap = typeof bityOrderCreateSucceededSwap;
|
||||
export function bityOrderCreateSucceededSwap(
|
||||
payload: interfaces.BityOrderPostResponse
|
||||
): interfaces.BityOrderCreateSucceededSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_BITY_ORDER_CREATE_SUCCEEDED,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TBityOrderCreateRequestedSwap = typeof bityOrderCreateRequestedSwap;
|
||||
export function bityOrderCreateRequestedSwap(
|
||||
amount: number,
|
||||
destinationAddress: string,
|
||||
pair: string,
|
||||
mode: number = 0
|
||||
): interfaces.BityOrderCreateRequestedSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORDER_CREATE_REQUESTED,
|
||||
payload: {
|
||||
amount,
|
||||
destinationAddress,
|
||||
pair,
|
||||
mode
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function bityOrderCreateFailedSwap(): interfaces.BityOrderCreateFailedSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORDER_CREATE_FAILED
|
||||
};
|
||||
}
|
||||
|
||||
export type TOrderStatusSucceededSwap = typeof orderStatusSucceededSwap;
|
||||
export function orderStatusSucceededSwap(
|
||||
payload: interfaces.BityOrderResponse
|
||||
): interfaces.OrderStatusSucceededSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_BITY_ORDER_STATUS_SUCCEEDED,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TOrderStatusRequestedSwap = typeof orderStatusRequestedSwap;
|
||||
export function orderStatusRequestedSwap(): interfaces.OrderStatusRequestedSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_BITY_ORDER_STATUS_REQUESTED
|
||||
};
|
||||
}
|
||||
|
||||
export type TStartOrderTimerSwap = typeof startOrderTimerSwap;
|
||||
export function startOrderTimerSwap(): interfaces.StartOrderTimerSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORDER_START_TIMER
|
||||
};
|
||||
}
|
||||
|
||||
export type TStopOrderTimerSwap = typeof stopOrderTimerSwap;
|
||||
export function stopOrderTimerSwap(): interfaces.StopOrderTimerSwapAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_ORDER_STOP_TIMER
|
||||
};
|
||||
}
|
||||
|
||||
export type TStartPollBityOrderStatus = typeof startPollBityOrderStatus;
|
||||
export function startPollBityOrderStatus(): interfaces.StartPollBityOrderStatusAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_START_POLL_BITY_ORDER_STATUS
|
||||
};
|
||||
}
|
||||
|
||||
export type TStopPollBityOrderStatus = typeof stopPollBityOrderStatus;
|
||||
export function stopPollBityOrderStatus(): interfaces.StopPollBityOrderStatusAction {
|
||||
return {
|
||||
type: TypeKeys.SWAP_STOP_POLL_BITY_ORDER_STATUS
|
||||
};
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
import { TypeKeys } from './constants';
|
||||
export interface Pairs {
|
||||
ETHBTC: number;
|
||||
ETHREP: number;
|
||||
BTCETH: number;
|
||||
BTCREP: number;
|
||||
}
|
||||
|
||||
export interface OriginKindSwapAction {
|
||||
type: TypeKeys.SWAP_ORIGIN_KIND;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
export interface DestinationKindSwapAction {
|
||||
type: TypeKeys.SWAP_DESTINATION_KIND;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
export interface OriginAmountSwapAction {
|
||||
type: TypeKeys.SWAP_ORIGIN_AMOUNT;
|
||||
payload?: number | null;
|
||||
}
|
||||
|
||||
export interface DestinationAmountSwapAction {
|
||||
type: TypeKeys.SWAP_DESTINATION_AMOUNT;
|
||||
payload?: number | null;
|
||||
}
|
||||
|
||||
export interface LoadBityRatesSucceededSwapAction {
|
||||
type: TypeKeys.SWAP_LOAD_BITY_RATES_SUCCEEDED;
|
||||
payload: Pairs;
|
||||
}
|
||||
|
||||
export interface DestinationAddressSwapAction {
|
||||
type: TypeKeys.SWAP_DESTINATION_ADDRESS;
|
||||
payload?: string;
|
||||
}
|
||||
|
||||
export interface RestartSwapAction {
|
||||
type: TypeKeys.SWAP_RESTART;
|
||||
}
|
||||
|
||||
export interface LoadBityRatesRequestedSwapAction {
|
||||
type: TypeKeys.SWAP_LOAD_BITY_RATES_REQUESTED;
|
||||
payload?: null;
|
||||
}
|
||||
|
||||
export interface ChangeStepSwapAction {
|
||||
type: TypeKeys.SWAP_STEP;
|
||||
payload: number;
|
||||
}
|
||||
|
||||
export interface StopLoadBityRatesSwapAction {
|
||||
type: TypeKeys.SWAP_STOP_LOAD_BITY_RATES;
|
||||
}
|
||||
|
||||
export interface OrderSwapTimeSwapAction {
|
||||
type: TypeKeys.SWAP_ORDER_TIME;
|
||||
payload: number;
|
||||
}
|
||||
|
||||
export interface BityOrderCreateRequestedSwapAction {
|
||||
type: TypeKeys.SWAP_ORDER_CREATE_REQUESTED;
|
||||
payload: {
|
||||
amount: number;
|
||||
destinationAddress: string;
|
||||
pair: string;
|
||||
mode: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface BityOrderInput {
|
||||
amount: string;
|
||||
currency: string;
|
||||
reference: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
interface BityOrderOutput {
|
||||
amount: string;
|
||||
currency: string;
|
||||
reference: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface BityOrderResponse {
|
||||
input: BityOrderInput;
|
||||
output: BityOrderOutput;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export type BityOrderPostResponse = BityOrderResponse & {
|
||||
payment_address: string;
|
||||
status: string;
|
||||
input: BityOrderInput;
|
||||
output: BityOrderOutput;
|
||||
timestamp_created: string;
|
||||
validFor: number;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export interface BityOrderCreateSucceededSwapAction {
|
||||
type: TypeKeys.SWAP_BITY_ORDER_CREATE_SUCCEEDED;
|
||||
payload: BityOrderPostResponse;
|
||||
}
|
||||
|
||||
export interface BityOrderCreateFailedSwapAction {
|
||||
type: TypeKeys.SWAP_ORDER_CREATE_FAILED;
|
||||
}
|
||||
export interface OrderStatusRequestedSwapAction {
|
||||
type: TypeKeys.SWAP_BITY_ORDER_STATUS_REQUESTED;
|
||||
}
|
||||
|
||||
export interface OrderStatusSucceededSwapAction {
|
||||
type: TypeKeys.SWAP_BITY_ORDER_STATUS_SUCCEEDED;
|
||||
payload: BityOrderResponse;
|
||||
}
|
||||
|
||||
export interface StartOrderTimerSwapAction {
|
||||
type: TypeKeys.SWAP_ORDER_START_TIMER;
|
||||
}
|
||||
|
||||
export interface StopOrderTimerSwapAction {
|
||||
type: TypeKeys.SWAP_ORDER_STOP_TIMER;
|
||||
}
|
||||
|
||||
export interface StartPollBityOrderStatusAction {
|
||||
type: TypeKeys.SWAP_START_POLL_BITY_ORDER_STATUS;
|
||||
}
|
||||
|
||||
export interface StopPollBityOrderStatusAction {
|
||||
type: TypeKeys.SWAP_STOP_POLL_BITY_ORDER_STATUS;
|
||||
}
|
||||
|
||||
/*** Action Type Union ***/
|
||||
export type SwapAction =
|
||||
| ChangeStepSwapAction
|
||||
| OriginKindSwapAction
|
||||
| DestinationKindSwapAction
|
||||
| OriginAmountSwapAction
|
||||
| DestinationAmountSwapAction
|
||||
| LoadBityRatesSucceededSwapAction
|
||||
| DestinationAddressSwapAction
|
||||
| RestartSwapAction
|
||||
| LoadBityRatesRequestedSwapAction
|
||||
| StopLoadBityRatesSwapAction
|
||||
| BityOrderCreateRequestedSwapAction
|
||||
| BityOrderCreateSucceededSwapAction
|
||||
| OrderStatusSucceededSwapAction
|
||||
| StartPollBityOrderStatusAction
|
||||
| BityOrderCreateFailedSwapAction
|
||||
| OrderSwapTimeSwapAction;
|
|
@ -0,0 +1,22 @@
|
|||
export enum TypeKeys {
|
||||
SWAP_STEP = 'SWAP_STEP',
|
||||
SWAP_ORIGIN_KIND = 'SWAP_ORIGIN_KIND',
|
||||
SWAP_DESTINATION_KIND = 'SWAP_DESTINATION_KIND',
|
||||
SWAP_ORIGIN_AMOUNT = 'SWAP_ORIGIN_AMOUNT',
|
||||
SWAP_DESTINATION_AMOUNT = 'SWAP_DESTINATION_AMOUNT',
|
||||
SWAP_LOAD_BITY_RATES_SUCCEEDED = 'SWAP_LOAD_BITY_RATES_SUCCEEDED',
|
||||
SWAP_DESTINATION_ADDRESS = 'SWAP_DESTINATION_ADDRESS',
|
||||
SWAP_RESTART = 'SWAP_RESTART',
|
||||
SWAP_LOAD_BITY_RATES_REQUESTED = 'SWAP_LOAD_BITY_RATES_REQUESTED',
|
||||
SWAP_STOP_LOAD_BITY_RATES = 'SWAP_STOP_LOAD_BITY_RATES',
|
||||
SWAP_ORDER_TIME = 'SWAP_ORDER_TIME',
|
||||
SWAP_BITY_ORDER_CREATE_SUCCEEDED = 'SWAP_BITY_ORDER_CREATE_SUCCEEDED',
|
||||
SWAP_BITY_ORDER_STATUS_SUCCEEDED = 'SWAP_BITY_ORDER_STATUS_SUCCEEDED',
|
||||
SWAP_BITY_ORDER_STATUS_REQUESTED = 'SWAP_BITY_ORDER_STATUS_REQUESTED',
|
||||
SWAP_ORDER_START_TIMER = 'SWAP_ORDER_START_TIMER',
|
||||
SWAP_ORDER_STOP_TIMER = 'SWAP_ORDER_STOP_TIMER',
|
||||
SWAP_START_POLL_BITY_ORDER_STATUS = 'SWAP_START_POLL_BITY_ORDER_STATUS',
|
||||
SWAP_STOP_POLL_BITY_ORDER_STATUS = 'SWAP_STOP_POLL_BITY_ORDER_STATUS',
|
||||
SWAP_ORDER_CREATE_REQUESTED = 'SWAP_ORDER_CREATE_REQUESTED',
|
||||
SWAP_ORDER_CREATE_FAILED = 'SWAP_ORDER_CREATE_FAILED'
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,128 +0,0 @@
|
|||
export type Pairs = {
|
||||
ETHBTC: number,
|
||||
ETHREP: number,
|
||||
BTCETH: number,
|
||||
BTCREP: number
|
||||
};
|
||||
|
||||
export type OriginKindSwapAction = {
|
||||
type: 'SWAP_ORIGIN_KIND',
|
||||
value: string
|
||||
};
|
||||
export type DestinationKindSwapAction = {
|
||||
type: 'SWAP_DESTINATION_KIND',
|
||||
value: string
|
||||
};
|
||||
export type OriginAmountSwapAction = {
|
||||
type: 'SWAP_ORIGIN_AMOUNT',
|
||||
value: ?number
|
||||
};
|
||||
export type DestinationAmountSwapAction = {
|
||||
type: 'SWAP_DESTINATION_AMOUNT',
|
||||
value: ?number
|
||||
};
|
||||
export type LoadBityRatesSucceededSwapAction = {
|
||||
type: 'SWAP_LOAD_BITY_RATES_SUCCEEDED',
|
||||
value: Pairs
|
||||
};
|
||||
export type DestinationAddressSwapAction = {
|
||||
type: 'SWAP_DESTINATION_ADDRESS',
|
||||
value: ?number
|
||||
};
|
||||
|
||||
export type RestartSwapAction = {
|
||||
type: 'SWAP_RESTART'
|
||||
};
|
||||
|
||||
export type LoadBityRatesRequestedSwapAction = {
|
||||
type: 'SWAP_LOAD_BITY_RATES_REQUESTED'
|
||||
};
|
||||
|
||||
export type ChangeStepSwapAction = {
|
||||
type: 'SWAP_STEP',
|
||||
value: number
|
||||
};
|
||||
|
||||
export type StopLoadBityRatesSwapAction = {
|
||||
type: 'SWAP_STOP_LOAD_BITY_RATES'
|
||||
};
|
||||
|
||||
export type BityOrderCreateRequestedSwapAction = {
|
||||
type: 'SWAP_ORDER_CREATE_REQUESTED',
|
||||
payload: {
|
||||
amount: number,
|
||||
destinationAddress: string,
|
||||
pair: string,
|
||||
mode: number
|
||||
}
|
||||
};
|
||||
|
||||
type BityOrderInput = {
|
||||
amount: string
|
||||
};
|
||||
|
||||
type BityOrderOutput = {
|
||||
amount: string
|
||||
};
|
||||
|
||||
export type BityOrderResponse = {
|
||||
status: string
|
||||
};
|
||||
|
||||
export type BityOrderPostResponse = BityOrderResponse & {
|
||||
payment_address: string,
|
||||
status: string,
|
||||
input: BityOrderInput,
|
||||
output: BityOrderOutput,
|
||||
timestamp_created: string,
|
||||
validFor: number
|
||||
};
|
||||
|
||||
export type BityOrderCreateSucceededSwapAction = {
|
||||
type: 'SWAP_BITY_ORDER_CREATE_SUCCEEDED',
|
||||
payload: BityOrderPostResponse
|
||||
};
|
||||
|
||||
export type OrderStatusRequestedSwapAction = {
|
||||
type: 'SWAP_BITY_ORDER_STATUS_REQUESTED',
|
||||
payload: BityOrderResponse
|
||||
};
|
||||
|
||||
export type OrderStatusSucceededSwapAction = {
|
||||
type: 'SWAP_BITY_ORDER_STATUS_SUCCEEDED',
|
||||
payload: BityOrderResponse
|
||||
};
|
||||
|
||||
export type StartOrderTimerSwapAction = {
|
||||
type: 'SWAP_ORDER_START_TIMER'
|
||||
};
|
||||
|
||||
export type StopOrderTimerSwapAction = {
|
||||
type: 'SWAP_ORDER_STOP_TIMER'
|
||||
};
|
||||
|
||||
export type StartPollBityOrderStatusAction = {
|
||||
type: 'SWAP_START_POLL_BITY_ORDER_STATUS'
|
||||
};
|
||||
|
||||
export type StopPollBityOrderStatusAction = {
|
||||
type: 'SWAP_STOP_POLL_BITY_ORDER_STATUS'
|
||||
};
|
||||
|
||||
/*** Action Type Union ***/
|
||||
export type SwapAction =
|
||||
| ChangeStepSwapAction
|
||||
| OriginKindSwapAction
|
||||
| DestinationKindSwapAction
|
||||
| OriginAmountSwapAction
|
||||
| DestinationAmountSwapAction
|
||||
| LoadBityRatesSucceededSwapAction
|
||||
| DestinationAddressSwapAction
|
||||
| RestartSwapAction
|
||||
| LoadBityRatesRequestedSwapAction
|
||||
| StopLoadBityRatesSwapAction
|
||||
| BityOrderCreateRequestedSwapAction
|
||||
| BityOrderCreateSucceededSwapAction
|
||||
| BityOrderResponse
|
||||
| OrderStatusSucceededSwapAction
|
||||
| StartPollBityOrderStatusAction;
|
|
@ -1,134 +0,0 @@
|
|||
// @flow
|
||||
import type { IWallet } from 'libs/wallet/IWallet';
|
||||
import Big from 'bignumber.js';
|
||||
import { Wei } from 'libs/units';
|
||||
|
||||
/*** Unlock Private Key ***/
|
||||
export type PrivateKeyUnlockParams = {
|
||||
key: string,
|
||||
password: string
|
||||
};
|
||||
|
||||
export type UnlockPrivateKeyAction = {
|
||||
type: 'WALLET_UNLOCK_PRIVATE_KEY',
|
||||
payload: PrivateKeyUnlockParams
|
||||
};
|
||||
|
||||
export function unlockPrivateKey(
|
||||
value: PrivateKeyUnlockParams
|
||||
): UnlockPrivateKeyAction {
|
||||
return {
|
||||
type: 'WALLET_UNLOCK_PRIVATE_KEY',
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Unlock Keystore File ***/
|
||||
export type KeystoreUnlockParams = {
|
||||
file: string,
|
||||
password: string
|
||||
};
|
||||
|
||||
export type UnlockKeystoreAction = {
|
||||
type: 'WALLET_UNLOCK_KEYSTORE',
|
||||
payload: KeystoreUnlockParams
|
||||
};
|
||||
|
||||
export function unlockKeystore(
|
||||
value: KeystoreUnlockParams
|
||||
): UnlockKeystoreAction {
|
||||
return {
|
||||
type: 'WALLET_UNLOCK_KEYSTORE',
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Unlock Mnemonic ***/
|
||||
export type MnemonicUnlockParams = {
|
||||
phrase: string,
|
||||
pass: string,
|
||||
path: string,
|
||||
address: string
|
||||
};
|
||||
|
||||
export type UnlockMnemonicAction = {
|
||||
type: 'WALLET_UNLOCK_MNEMONIC',
|
||||
payload: MnemonicUnlockParams
|
||||
};
|
||||
|
||||
export function unlockMnemonic(
|
||||
value: MnemonicUnlockParams
|
||||
): UnlockMnemonicAction {
|
||||
return {
|
||||
type: 'WALLET_UNLOCK_MNEMONIC',
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set Wallet ***/
|
||||
export type SetWalletAction = {
|
||||
type: 'WALLET_SET',
|
||||
payload: IWallet
|
||||
};
|
||||
|
||||
export function setWallet(value: IWallet): SetWalletAction {
|
||||
return {
|
||||
type: 'WALLET_SET',
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set Balance ***/
|
||||
export type SetBalanceAction = {
|
||||
type: 'WALLET_SET_BALANCE',
|
||||
payload: Wei
|
||||
};
|
||||
|
||||
export function setBalance(value: Wei): SetBalanceAction {
|
||||
return {
|
||||
type: 'WALLET_SET_BALANCE',
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
/*** Set Token Balance ***/
|
||||
export type SetTokenBalancesAction = {
|
||||
type: 'WALLET_SET_TOKEN_BALANCES',
|
||||
payload: {
|
||||
[string]: Big
|
||||
}
|
||||
};
|
||||
|
||||
export function setTokenBalances(payload: {
|
||||
[string]: Big
|
||||
}): SetTokenBalancesAction {
|
||||
return {
|
||||
type: 'WALLET_SET_TOKEN_BALANCES',
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
/*** Broadcast Tx ***/
|
||||
export type BroadcastTxRequestedAction = {
|
||||
type: 'WALLET_BROADCAST_TX_REQUESTED',
|
||||
payload: {
|
||||
signedTx: string
|
||||
}
|
||||
};
|
||||
|
||||
export function broadcastTx(signedTx: string): BroadcastTxRequestedAction {
|
||||
return {
|
||||
type: 'WALLET_BROADCAST_TX_REQUESTED',
|
||||
payload: {
|
||||
signedTx
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type WalletAction =
|
||||
| UnlockPrivateKeyAction
|
||||
| SetWalletAction
|
||||
| SetBalanceAction
|
||||
| SetTokenBalancesAction
|
||||
| BroadcastTxRequestedAction;
|
|
@ -0,0 +1,108 @@
|
|||
import { BigNumber } from 'bignumber.js';
|
||||
import { Wei } from 'libs/units';
|
||||
import { IWallet } from 'libs/wallet/IWallet';
|
||||
import * as types from './actionTypes';
|
||||
import * as constants from './constants';
|
||||
|
||||
export type TUnlockPrivateKey = typeof unlockPrivateKey;
|
||||
export function unlockPrivateKey(
|
||||
value: types.PrivateKeyUnlockParams
|
||||
): types.UnlockPrivateKeyAction {
|
||||
return {
|
||||
type: constants.WALLET_UNLOCK_PRIVATE_KEY,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TUnlockKeystore = typeof unlockKeystore;
|
||||
export function unlockKeystore(
|
||||
value: types.KeystoreUnlockParams
|
||||
): types.UnlockKeystoreAction {
|
||||
return {
|
||||
type: constants.WALLET_UNLOCK_KEYSTORE,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TUnlockMnemonic = typeof unlockMnemonic;
|
||||
export function unlockMnemonic(
|
||||
value: types.MnemonicUnlockParams
|
||||
): types.UnlockMnemonicAction {
|
||||
return {
|
||||
type: constants.WALLET_UNLOCK_MNEMONIC,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TSetWallet = typeof setWallet;
|
||||
export function setWallet(value: IWallet): types.SetWalletAction {
|
||||
return {
|
||||
type: constants.WALLET_SET,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TSetBalance = typeof setBalance;
|
||||
export function setBalance(value: Wei): types.SetBalanceAction {
|
||||
return {
|
||||
type: constants.WALLET_SET_BALANCE,
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export type TSetTokenBalances = typeof setTokenBalances;
|
||||
export function setTokenBalances(payload: {
|
||||
[key: string]: BigNumber;
|
||||
}): types.SetTokenBalancesAction {
|
||||
return {
|
||||
type: constants.WALLET_SET_TOKEN_BALANCES,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TBroadcastTx = typeof broadcastTx;
|
||||
export function broadcastTx(
|
||||
signedTx: string
|
||||
): types.BroadcastTxRequestedAction {
|
||||
return {
|
||||
type: constants.WALLET_BROADCAST_TX_REQUESTED,
|
||||
payload: {
|
||||
signedTx
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type TBroadcastTxSucceded = typeof broadcastTxSucceded;
|
||||
export function broadcastTxSucceded(
|
||||
txHash: string,
|
||||
signedTx: string
|
||||
): types.BroadcastTxSuccededAction {
|
||||
return {
|
||||
type: constants.WALLET_BROADCAST_TX_SUCCEEDED,
|
||||
payload: {
|
||||
txHash,
|
||||
signedTx
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type TBroadCastTxFailed = typeof broadCastTxFailed;
|
||||
export function broadCastTxFailed(
|
||||
signedTx: string,
|
||||
errorMsg: string
|
||||
): types.BroadcastTxFailedAction {
|
||||
return {
|
||||
type: constants.WALLET_BROADCAST_TX_FAILED,
|
||||
payload: {
|
||||
signedTx,
|
||||
error: errorMsg
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type TResetWallet = typeof resetWallet;
|
||||
export function resetWallet() {
|
||||
return {
|
||||
type: constants.WALLET_RESET
|
||||
};
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
import { BigNumber } from 'bignumber.js';
|
||||
import { Wei } from 'libs/units';
|
||||
import { IWallet } from 'libs/wallet/IWallet';
|
||||
|
||||
/*** Unlock Private Key ***/
|
||||
export interface PrivateKeyUnlockParams {
|
||||
key: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface UnlockPrivateKeyAction {
|
||||
type: 'WALLET_UNLOCK_PRIVATE_KEY';
|
||||
payload: PrivateKeyUnlockParams;
|
||||
}
|
||||
export interface UnlockMnemonicAction {
|
||||
type: 'WALLET_UNLOCK_MNEMONIC';
|
||||
payload: MnemonicUnlockParams;
|
||||
}
|
||||
|
||||
/*** Set Wallet ***/
|
||||
export interface SetWalletAction {
|
||||
type: 'WALLET_SET';
|
||||
payload: IWallet;
|
||||
}
|
||||
|
||||
/*** Reset Wallet ***/
|
||||
export interface ResetWalletAction {
|
||||
type: 'WALLET_RESET';
|
||||
}
|
||||
|
||||
/*** Set Balance ***/
|
||||
export interface SetBalanceAction {
|
||||
type: 'WALLET_SET_BALANCE';
|
||||
payload: Wei;
|
||||
}
|
||||
|
||||
/*** Set Token Balance ***/
|
||||
export interface SetTokenBalancesAction {
|
||||
type: 'WALLET_SET_TOKEN_BALANCES';
|
||||
payload: {
|
||||
[key: string]: BigNumber;
|
||||
};
|
||||
}
|
||||
|
||||
/*** Broadcast Tx ***/
|
||||
export interface BroadcastTxRequestedAction {
|
||||
type: 'WALLET_BROADCAST_TX_REQUESTED';
|
||||
payload: {
|
||||
signedTx: string;
|
||||
};
|
||||
}
|
||||
|
||||
/*** Unlock Mnemonic ***/
|
||||
export interface MnemonicUnlockParams {
|
||||
phrase: string;
|
||||
pass: string;
|
||||
path: string;
|
||||
address: string;
|
||||
}
|
||||
|
||||
/*** Unlock Keystore File ***/
|
||||
export interface KeystoreUnlockParams {
|
||||
file: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface UnlockKeystoreAction {
|
||||
type: 'WALLET_UNLOCK_KEYSTORE';
|
||||
payload: KeystoreUnlockParams;
|
||||
}
|
||||
|
||||
export interface BroadcastTxSuccededAction {
|
||||
type: 'WALLET_BROADCAST_TX_SUCCEEDED';
|
||||
payload: {
|
||||
txHash: string;
|
||||
signedTx: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface BroadcastTxFailedAction {
|
||||
type: 'WALLET_BROADCAST_TX_FAILED';
|
||||
payload: {
|
||||
signedTx: string;
|
||||
error: string;
|
||||
};
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type WalletAction =
|
||||
| UnlockPrivateKeyAction
|
||||
| SetWalletAction
|
||||
| ResetWalletAction
|
||||
| SetBalanceAction
|
||||
| SetTokenBalancesAction
|
||||
| BroadcastTxRequestedAction
|
||||
| BroadcastTxFailedAction
|
||||
| BroadcastTxSuccededAction;
|
|
@ -0,0 +1,10 @@
|
|||
export const WALLET_UNLOCK_PRIVATE_KEY = 'WALLET_UNLOCK_PRIVATE_KEY';
|
||||
export const WALLET_UNLOCK_KEYSTORE = 'WALLET_UNLOCK_KEYSTORE';
|
||||
export const WALLET_UNLOCK_MNEMONIC = 'WALLET_UNLOCK_MNEMONIC';
|
||||
export const WALLET_SET = 'WALLET_SET';
|
||||
export const WALLET_SET_BALANCE = 'WALLET_SET_BALANCE';
|
||||
export const WALLET_SET_TOKEN_BALANCES = 'WALLET_SET_TOKEN_BALANCES';
|
||||
export const WALLET_BROADCAST_TX_REQUESTED = 'WALLET_BROADCAST_TX_REQUESTED';
|
||||
export const WALLET_BROADCAST_TX_FAILED = 'WALLET_BROADCAST_TX_FAILED';
|
||||
export const WALLET_BROADCAST_TX_SUCCEEDED = 'WALLET_BROADCAST_TX_SUCCEEDED';
|
||||
export const WALLET_RESET = 'WALLET_RESET';
|
|
@ -0,0 +1,3 @@
|
|||
export * from './constants';
|
||||
export * from './actionTypes';
|
||||
export * from './actionCreators';
|
|
@ -1,22 +1,10 @@
|
|||
// @flow
|
||||
import bityConfig from 'config/bity';
|
||||
import { checkHttpStatus, parseJSON } from './utils';
|
||||
// import { combineAndUpper } from 'utils/formatters';
|
||||
|
||||
// function findRateFromBityRateList(rateObjects, pairName: string) {
|
||||
// return rateObjects.find(x => x.pair === pairName);
|
||||
// }
|
||||
|
||||
// function _getRate(bityRates, originKind: string, destinationKind: string) {
|
||||
// const pairName = combineAndUpper(originKind, destinationKind);
|
||||
// const rateObjects = bityRates.objects;
|
||||
// return findRateFromBityRateList(rateObjects, pairName);
|
||||
// }
|
||||
|
||||
export function getAllRates() {
|
||||
const mappedRates = {};
|
||||
return _getAllRates().then(bityRates => {
|
||||
bityRates.objects.forEach(each => {
|
||||
return _getAllRates().then((bityRates) => {
|
||||
bityRates.objects.forEach((each) => {
|
||||
const pairName = each.pair;
|
||||
mappedRates[pairName] = parseFloat(each.rate_we_sell);
|
||||
});
|
||||
|
@ -44,11 +32,11 @@ export function postOrder(
|
|||
.then(parseJSON);
|
||||
}
|
||||
|
||||
export function getOrderStatus(orderid: string) {
|
||||
export function getOrderStatus(orderId: string) {
|
||||
return fetch(`${bityConfig.serverURL}/status`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
orderid
|
||||
orderid: orderId
|
||||
}),
|
||||
headers: bityConfig.postConfig.headers
|
||||
})
|
||||
|
@ -60,6 +48,4 @@ function _getAllRates() {
|
|||
return fetch(`${bityConfig.bityURL}/v1/rate2/`)
|
||||
.then(checkHttpStatus)
|
||||
.then(parseJSON);
|
||||
}
|
||||
|
||||
// function requestOrderStatus() {}
|
||||
}
|
|
@ -2,9 +2,7 @@ export function checkHttpStatus(response) {
|
|||
if (response.status >= 200 && response.status < 300) {
|
||||
return response;
|
||||
} else {
|
||||
let error = new Error(response.statusText);
|
||||
error.response = response;
|
||||
throw error;
|
||||
return new Error(response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,8 +12,7 @@ export function parseJSON(response) {
|
|||
|
||||
export async function handleJSONResponse(response, errorMessage) {
|
||||
if (response.ok) {
|
||||
const json = await response.json();
|
||||
return json;
|
||||
return await response.json();
|
||||
}
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage);
|
|
@ -0,0 +1,33 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="15.5 15.5 224.5 224.5">
|
||||
<defs>
|
||||
<radialGradient cy="0" cx="0.5" id="r">
|
||||
<stop stop-color="#f06b59"/>
|
||||
<stop offset="1" stop-color="#df2227"/>
|
||||
</radialGradient>
|
||||
<radialGradient r="0.76" cy="0.3" cx="0.65" id="g">
|
||||
<stop offset="0.65" stop-color="#4cb749"/>
|
||||
<stop offset="1" stop-color="#388b41"/>
|
||||
</radialGradient>
|
||||
<radialGradient r="0.8" cy="0.25" cx="0.36" id="y">
|
||||
<stop offset="0.6" stop-color="#FCD209"/>
|
||||
<stop offset="0.7" stop-color="#f7c616"/>
|
||||
<stop offset="1" stop-color="#bc821e"/>
|
||||
</radialGradient>
|
||||
<radialGradient r="1" cy="0" cx="0.5" spreadMethod="pad" id="cf">
|
||||
<stop offset="0.1" stop-color="#7FB3DF"/>
|
||||
<stop offset="0.9" stop-color="#0F5B94"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="cb" r="1" cy="0" cx="0.5">
|
||||
<stop offset="0" stop-color="#F6F0EE"/>
|
||||
<stop offset="1" stop-color="#ddd"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<path d="m198,148a70,70 0 0 0 -140,0l20,0a50,50 0 0 1 100,0" fill-opacity="0.1"/>
|
||||
<circle r="45" cx="127.5" cy="127.6" fill="url(#cf)" stroke="url(#cb)" stroke-width="9" />
|
||||
<path d="m228,78a112,112 0 0 0 -193,-13l45,78a50,50 0 0 1 47,-65" fill="url(#r)"/>
|
||||
<path d="m35,65a112,112 0 0 0 84,174l47,-80a50,50 0 0 1 -86,-16" fill="url(#g)"/>
|
||||
<path d="m119,239a112,112 0 0 0 109,-161l-101,0a50,50 0 0 1 39,81" fill="url(#y)"/>
|
||||
<path d="m35,65l45,78a50,50 0 0 1 2,-34l-45,-47" opacity="0.075"/>
|
||||
<path d="m119,239l47,-80a50,50 0 0 1 -29,17l-20,63" opacity="0.05"/>
|
||||
<path d="m228,78l-101,0a50,50 0 0 1 39,19l64,-16" opacity="0.05"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 140 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="9.75 9.75 100.5 100.5"><linearGradient id="a" gradientTransform="matrix(0 97.396584 -97.396584 0 51.620814 11.389501)" gradientUnits="userSpaceOnUse" spreadMethod="pad" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#ff1b2d"/><stop offset=".3" stop-color="#ff1b2d"/><stop offset=".61" stop-color="#ff1b2d"/><stop offset="1" stop-color="#a70014"/></linearGradient><linearGradient id="b" gradientTransform="matrix(0 86.142511 -86.142511 0 76.85435 17.130095)" gradientUnits="userSpaceOnUse" spreadMethod="pad" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#9c0000"/><stop offset=".7" stop-color="#ff4b4b"/><stop offset="1" stop-color="#ff4b4b"/></linearGradient><path d="m60 9.75c-27.75 0-50.25 22.5-50.25 50.25l0 0c0 26.95 21.22 48.94 47.86 50.19l0 0c .8.04 1.59.06 2.39.06l0 0c12.87 0 24.6-4.84 33.49-12.79l0 0c-5.89 3.91-12.78 6.15-20.14 6.15l0 0c-11.97 0-22.68-5.94-29.89-15.3l0 0c-5.56-6.56-9.15-16.25-9.4-27.13l0 0c0-.03 0-2.34 0-2.37l0 0c .25-10.88 3.84-20.58 9.4-27.13l0 0c7.21-9.36 17.93-15.3 29.89-15.3l0 0c7.36 0 14.25 2.25 20.14 6.16l0 0c-8.84-7.91-20.51-12.74-33.3-12.79l0 0c-.06 0-.13 0-.19 0z" fill="url(#a)"/><path d="m43.46 31.68c4.61-5.44 10.57-8.73 17.07-8.73l0 0c14.63 0 26.49 16.59 26.49 37.04l0 0c0 20.46-11.86 37.04-26.49 37.04l0 0c-6.51 0-12.46-3.28-17.07-8.72l0 0c7.21 9.36 17.92 15.3 29.89 15.3l0 0c7.36 0 14.25-2.25 20.14-6.15l0 0c10.29-9.2 16.76-22.57 16.76-37.46l0 0c0-14.88-6.47-28.26-16.76-37.46l0 0c-5.89-3.91-12.78-6.15-20.14-6.15l0 0c-11.97 0-22.68 5.94-29.89 15.3" fill="url(#b)"/></svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496.16 496.16"><defs><style>.cls-1{fill:#04778d}.cls-2{fill:#fff}.cls-3{fill:#f34002}</style></defs><title>Offline Icon</title><path class="cls-1" d="M496.16 248.09C496.16 111.06 385.09 0 248.08 0S0 111.06 0 248.09s111.07 248.07 248.08 248.07 248.08-111.07 248.08-248.07z"/><circle class="cls-2" cx="248.08" cy="332.81" r="49.15"/><path class="cls-2" d="M172.13 289.13c20.29-23.3 47.26-36.13 76-36.13s55.66 12.83 76 36.13l16-18.34c-24.55-28.2-57.2-43.73-91.93-43.73s-67.37 15.53-91.92 43.73l16 18.34z"/><path class="cls-2" d="M138.56 248.41c29.26-33.6 68.15-52.1 109.52-52.1s80.27 18.5 109.52 52.1l16-18.34c-33.52-38.49-78.09-59.7-125.49-59.7s-92 21.2-125.49 59.7l16 18.34z"/><path class="cls-2" d="M105.31 208.06c38.14-43.8 88.84-67.92 142.77-67.92s104.64 24.12 142.77 67.92l16-18.34C364.42 141 308 114.21 248.08 114.21S131.74 141 89.34 189.72l16 18.34zM248.08 376.37h.01v.01h-.01z"/><circle class="cls-3" cx="340.29" cy="343.74" r="63.78"/><path class="cls-2" d="M315 365.51l16.82-21.59-14.12-19.21a36.92 36.92 0 0 1-3-4.8 8.64 8.64 0 0 1-1-3.86 4.31 4.31 0 0 1 1.92-3.4 7.36 7.36 0 0 1 4.69-1.51 7 7 0 0 1 4.95 1.65 42.15 42.15 0 0 1 4.9 6.11l11.28 16 12.05-16 2.54-3.47a18.66 18.66 0 0 1 2-2.39 6.53 6.53 0 0 1 2.18-1.42 7.61 7.61 0 0 1 2.79-.47 7.11 7.11 0 0 1 4.69 1.51 4.53 4.53 0 0 1 1.82 3.58q0 3-3.95 8.21l-14.82 19.48 16 21.59a35.31 35.31 0 0 1 3.13 4.71 7.7 7.7 0 0 1 1 3.54 5.09 5.09 0 0 1-.87 2.89 6 6 0 0 1-2.46 2.07 8.17 8.17 0 0 1-3.59.77 7.7 7.7 0 0 1-3.64-.79 7.44 7.44 0 0 1-2.41-2q-.92-1.17-3.44-4.55l-13.23-18.3-14.05 18.84q-1.64 2.26-2.33 3.16a12.43 12.43 0 0 1-1.67 1.76 7.32 7.32 0 0 1-2.31 1.35 9 9 0 0 1-3.13.5 7 7 0 0 1-4.59-1.49 5.27 5.27 0 0 1-1.82-4.33q-.04-3.32 3.67-8.14z"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496.16 496.16"><defs><style>.cls-1{fill:#04778d}.cls-2{fill:#fff}.cls-3{fill:#00e65f}</style></defs><title>Online Icon</title><path class="cls-1" d="M496.16 248.09C496.16 111.06 385.09 0 248.08 0S0 111.06 0 248.09s111.07 248.07 248.08 248.07 248.08-111.07 248.08-248.07z"/><circle class="cls-2" cx="248.08" cy="332.81" r="49.15"/><path class="cls-2" d="M172.13 289.13c20.29-23.3 47.26-36.13 76-36.13s55.66 12.83 76 36.13l16-18.34c-24.55-28.2-57.2-43.73-91.93-43.73s-67.37 15.53-91.92 43.73l16 18.34z"/><path class="cls-2" d="M138.56 248.41c29.26-33.6 68.15-52.1 109.52-52.1s80.27 18.5 109.52 52.1l16-18.34c-33.52-38.49-78.09-59.7-125.49-59.7s-92 21.2-125.49 59.7l16 18.34z"/><path class="cls-2" d="M105.31 208.06c38.14-43.8 88.84-67.92 142.77-67.92s104.64 24.12 142.77 67.92l16-18.34C364.42 141 308 114.21 248.08 114.21S131.74 141 89.34 189.72l16 18.34zM248.08 376.37h.01v.01h-.01z"/><circle class="cls-3" cx="340.29" cy="343.74" r="63.78"/><path class="cls-2" d="M383.53 317.43c-1.85-4.77-5.61-4-9.7-3.21-2.44.51-13.28 3.68-30.44 21.77a144.85 144.85 0 0 0-14.91 18.06c-1.89-2.32-4.05-4.8-6.33-7.08a91.5 91.5 0 0 0-15.11-12 6.95 6.95 0 0 0-7.26 11.85 78.31 78.31 0 0 1 12.54 10 107.89 107.89 0 0 1 11.29 14 6.95 6.95 0 0 0 12.52-2.17c0-.06 2.77-7.68 17.32-23 11.72-12.36 19.54-16.29 22.25-17.38h.08l.25-.12a7.69 7.69 0 0 1 .73-.24h-.2l3.65-1.58c3.55-1.54 4.7-5.33 3.32-8.9z"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -1,33 +1,11 @@
|
|||
@import "common/sass/variables";
|
||||
@import "common/sass/mixins";
|
||||
|
||||
.AlphaAgreement {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
@include cover-message;
|
||||
background: $brand-warning;
|
||||
overflow: auto;
|
||||
z-index: 10000;
|
||||
|
||||
&-content {
|
||||
max-width: 520px;
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
color: #fff;
|
||||
text-shadow: 1px 1px 1px rgba(#000, 0.12);
|
||||
overflow: auto;
|
||||
|
||||
h2 {
|
||||
font-size: 42px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
padding-top: 20px;
|
||||
|
||||
|
|
|
@ -3,35 +3,17 @@ import './index.scss';
|
|||
|
||||
const LS_KEY = 'acknowledged-alpha';
|
||||
|
||||
export default class AlphaAgreement extends React.Component {
|
||||
state = {
|
||||
isFading: false,
|
||||
hasAcknowledged: false
|
||||
interface State {
|
||||
isFading: boolean;
|
||||
hasAcknowledged: boolean;
|
||||
}
|
||||
export default class AlphaAgreement extends React.Component<{}, State> {
|
||||
public state = {
|
||||
hasAcknowledged: !!localStorage.getItem(LS_KEY),
|
||||
isFading: false
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
hasAcknowledged: localStorage.getItem(LS_KEY),
|
||||
isFading: false
|
||||
};
|
||||
}
|
||||
|
||||
_continue = () => {
|
||||
localStorage.setItem(LS_KEY, true);
|
||||
this.setState({ isFading: true });
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({ hasAcknowledged: true });
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
_reject = () => {
|
||||
window.location = 'https://myetherwallet.com';
|
||||
};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
if (this.state.hasAcknowledged) {
|
||||
return null;
|
||||
}
|
||||
|
@ -58,13 +40,13 @@ export default class AlphaAgreement extends React.Component {
|
|||
<div className="AlphaAgreement-content-buttons">
|
||||
<button
|
||||
className="AlphaAgreement-content-buttons-btn is-reject"
|
||||
onClick={this._reject}
|
||||
onClick={this.reject}
|
||||
>
|
||||
No, Take Me to v3
|
||||
</button>
|
||||
<button
|
||||
className="AlphaAgreement-content-buttons-btn is-continue"
|
||||
onClick={this._continue}
|
||||
onClick={this.doContinue}
|
||||
>
|
||||
Yes, Continue to v4
|
||||
</button>
|
||||
|
@ -73,4 +55,17 @@ export default class AlphaAgreement extends React.Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private doContinue = () => {
|
||||
localStorage.setItem(LS_KEY, 'true');
|
||||
this.setState({ isFading: true });
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({ hasAcknowledged: true });
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
private reject = () => {
|
||||
window.location.assign('https://myetherwallet.com');
|
||||
};
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
// @flow
|
||||
import './AccountInfo.scss';
|
||||
import React from 'react';
|
||||
import translate from 'translations';
|
||||
import { Identicon } from 'components/ui';
|
||||
import { formatNumber } from 'utils/formatters';
|
||||
import type { IWallet } from 'libs/wallet';
|
||||
import type { NetworkConfig } from 'config/data';
|
||||
import { Ether } from 'libs/units';
|
||||
import type { FiatRequestedRatesAction } from 'actions/rates';
|
||||
|
||||
type Props = {
|
||||
balance: Ether,
|
||||
wallet: IWallet,
|
||||
network: NetworkConfig,
|
||||
fiatRequestedRates: () => FiatRequestedRatesAction
|
||||
};
|
||||
|
||||
export default class AccountInfo extends React.Component {
|
||||
props: Props;
|
||||
|
||||
state = {
|
||||
showLongBalance: false,
|
||||
address: ''
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fiatRequestedRates();
|
||||
this.props.wallet.getAddress().then(addr => {
|
||||
this.setState({ address: addr });
|
||||
});
|
||||
}
|
||||
|
||||
toggleShowLongBalance = (e: SyntheticMouseEvent) => {
|
||||
e.preventDefault();
|
||||
this.setState(state => {
|
||||
return {
|
||||
showLongBalance: !state.showLongBalance
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { network, balance } = this.props;
|
||||
const { blockExplorer, tokenExplorer } = network;
|
||||
const { address } = this.state;
|
||||
|
||||
return (
|
||||
<div className="AccountInfo">
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_AccountAddr')}
|
||||
</h5>
|
||||
<div className="AccountInfo-address">
|
||||
<div className="AccountInfo-address-icon">
|
||||
<Identicon address={address} size="100%" />
|
||||
</div>
|
||||
<div className="AccountInfo-address-addr">
|
||||
{address}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_AccountBal')}
|
||||
</h5>
|
||||
<ul className="AccountInfo-list">
|
||||
<li className="AccountInfo-list-item">
|
||||
<span
|
||||
className="AccountInfo-list-item-clickable mono wrap"
|
||||
onClick={this.toggleShowLongBalance}
|
||||
>
|
||||
{this.state.showLongBalance
|
||||
? balance ? balance.toString() : '???'
|
||||
: balance ? formatNumber(balance.amount) : '???'}
|
||||
</span>
|
||||
{` ${network.name}`}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{(!!blockExplorer || !!tokenExplorer) &&
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_TransHistory')}
|
||||
</h5>
|
||||
<ul className="AccountInfo-list">
|
||||
{!!blockExplorer &&
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={blockExplorer.address(address)} target="_blank">
|
||||
{`${network.name} (${blockExplorer.name})`}
|
||||
</a>
|
||||
</li>}
|
||||
{!!tokenExplorer &&
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={tokenExplorer.address(address)} target="_blank">
|
||||
{`Tokens (${tokenExplorer.name})`}
|
||||
</a>
|
||||
</li>}
|
||||
</ul>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
import { TFetchCCRates } from 'actions/rates';
|
||||
import { Identicon } from 'components/ui';
|
||||
import { NetworkConfig } from 'config/data';
|
||||
import { Ether } from 'libs/units';
|
||||
import { IWallet } from 'libs/wallet';
|
||||
import React from 'react';
|
||||
import translate from 'translations';
|
||||
import { formatNumber } from 'utils/formatters';
|
||||
import './AccountInfo.scss';
|
||||
|
||||
interface Props {
|
||||
balance: Ether;
|
||||
wallet: IWallet;
|
||||
network: NetworkConfig;
|
||||
fetchCCRates: TFetchCCRates;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showLongBalance: boolean;
|
||||
address: string;
|
||||
}
|
||||
export default class AccountInfo extends React.Component<Props, State> {
|
||||
public state = {
|
||||
showLongBalance: false,
|
||||
address: ''
|
||||
};
|
||||
|
||||
public async setAddressFromWallet() {
|
||||
const address = await this.props.wallet.getAddress();
|
||||
if (address !== this.state.address) {
|
||||
this.setState({ address });
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.fetchCCRates();
|
||||
this.setAddressFromWallet();
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
this.setAddressFromWallet();
|
||||
}
|
||||
|
||||
// TODO: don't use any;
|
||||
public toggleShowLongBalance = (e: any) => {
|
||||
e.preventDefault();
|
||||
this.setState(state => {
|
||||
return {
|
||||
showLongBalance: !state.showLongBalance
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
public render() {
|
||||
const { network, balance } = this.props;
|
||||
const { blockExplorer, tokenExplorer } = network;
|
||||
const { address } = this.state;
|
||||
|
||||
return (
|
||||
<div className="AccountInfo">
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_AccountAddr')}
|
||||
</h5>
|
||||
<div className="AccountInfo-address">
|
||||
<div className="AccountInfo-address-icon">
|
||||
<Identicon address={address} size="100%" />
|
||||
</div>
|
||||
<div className="AccountInfo-address-addr">{address}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_AccountBal')}
|
||||
</h5>
|
||||
<ul className="AccountInfo-list">
|
||||
<li className="AccountInfo-list-item">
|
||||
<span
|
||||
className="AccountInfo-list-item-clickable mono wrap"
|
||||
onClick={this.toggleShowLongBalance}
|
||||
>
|
||||
{this.state.showLongBalance
|
||||
? balance ? balance.toString() : '???'
|
||||
: balance ? formatNumber(balance.amount) : '???'}
|
||||
</span>
|
||||
{` ${network.name}`}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{(!!blockExplorer || !!tokenExplorer) && (
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_TransHistory')}
|
||||
</h5>
|
||||
<ul className="AccountInfo-list">
|
||||
{!!blockExplorer && (
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={blockExplorer.address(address)} target="_blank">
|
||||
{`${network.name} (${blockExplorer.name})`}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{!!tokenExplorer && (
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={tokenExplorer.address(address)} target="_blank">
|
||||
{`Tokens (${tokenExplorer.name})`}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,47 +1,46 @@
|
|||
// @flow
|
||||
import './EquivalentValues.scss';
|
||||
import { Ether } from 'libs/units';
|
||||
import React from 'react';
|
||||
import translate from 'translations';
|
||||
import { formatNumber } from 'utils/formatters';
|
||||
import { Ether } from 'libs/units';
|
||||
import './EquivalentValues.scss';
|
||||
import { State } from 'reducers/rates';
|
||||
import { symbols } from 'actions/rates';
|
||||
|
||||
const ratesKeys = ['BTC', 'REP', 'EUR', 'USD', 'GBP', 'CHF'];
|
||||
interface Props {
|
||||
balance?: Ether;
|
||||
rates?: State['rates'];
|
||||
ratesError?: State['ratesError'];
|
||||
}
|
||||
|
||||
type Props = {
|
||||
balance: ?Ether,
|
||||
rates: ?{ [string]: number }
|
||||
};
|
||||
|
||||
export default class EquivalentValues extends React.Component {
|
||||
props: Props;
|
||||
|
||||
render() {
|
||||
const { balance, rates } = this.props;
|
||||
export default class EquivalentValues extends React.Component<Props, {}> {
|
||||
public render() {
|
||||
const { balance, rates, ratesError } = this.props;
|
||||
|
||||
return (
|
||||
<div className="EquivalentValues">
|
||||
<h5 className="EquivalentValues-title">
|
||||
{translate('sidebar_Equiv')}
|
||||
</h5>
|
||||
<h5 className="EquivalentValues-title">{translate('sidebar_Equiv')}</h5>
|
||||
|
||||
<ul className="EquivalentValues-values">
|
||||
{rates
|
||||
? ratesKeys.map(key => {
|
||||
if (!rates[key]) return null;
|
||||
? symbols.map(key => {
|
||||
if (!rates[key]) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<li className="EquivalentValues-values-currency" key={key}>
|
||||
<span className="EquivalentValues-values-currency-label">
|
||||
{key}:
|
||||
</span>
|
||||
<span className="EquivalentValues-values-currency-value">
|
||||
{' '}{balance
|
||||
{' '}
|
||||
{balance
|
||||
? formatNumber(balance.amount.times(rates[key]))
|
||||
: '???'}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
: <h5>No rates were loaded.</h5>}
|
||||
: ratesError && <h5>{ratesError}</h5>}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
|
@ -0,0 +1,55 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
forceOfflineConfig as dForceOfflineConfig,
|
||||
TForceOfflineConfig
|
||||
} from 'actions/config';
|
||||
import OfflineSymbol from 'components/ui/OfflineSymbol';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from 'reducers';
|
||||
|
||||
type sizeType = 'small' | 'medium' | 'large';
|
||||
|
||||
interface OfflineToggleProps {
|
||||
offline: boolean;
|
||||
forceOffline: boolean;
|
||||
forceOfflineConfig: TForceOfflineConfig;
|
||||
size?: sizeType;
|
||||
}
|
||||
|
||||
class OfflineToggle extends React.Component<OfflineToggleProps, {}> {
|
||||
public render() {
|
||||
const { forceOfflineConfig, offline, forceOffline, size } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!offline ? (
|
||||
<div className="row text-center">
|
||||
<div className="col-md-3">
|
||||
<OfflineSymbol offline={offline || forceOffline} size={size} />
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<button className="btn-xs btn-info" onClick={forceOfflineConfig}>
|
||||
{forceOffline ? 'Go Online' : 'Go Offline'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center">
|
||||
<h5>You are currently offline.</h5>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: AppState) {
|
||||
return {
|
||||
offline: state.config.offline,
|
||||
forceOffline: state.config.forceOffline
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
forceOfflineConfig: dForceOfflineConfig
|
||||
})(OfflineToggle);
|
|
@ -1,14 +1,14 @@
|
|||
// @flow
|
||||
import './Promos.scss';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import './Promos.scss';
|
||||
|
||||
const promos = [
|
||||
{
|
||||
isExternal: true,
|
||||
color: '#6e9a3e',
|
||||
href:
|
||||
'https://myetherwallet.groovehq.com/knowledge_base/topics/protecting-yourself-and-your-funds',
|
||||
isExternal: true,
|
||||
|
||||
texts: [<h6 key="1">Learn more about protecting your funds.</h6>],
|
||||
images: [
|
||||
require('assets/images/logo-ledger.svg'),
|
||||
|
@ -16,10 +16,10 @@ const promos = [
|
|||
]
|
||||
},
|
||||
{
|
||||
isExternal: true,
|
||||
color: '#2b71b1',
|
||||
href:
|
||||
'https://buy.coinbase.com?code=a6e1bd98-6464-5552-84dd-b27f0388ac7d&address=0xA7DeFf12461661212734dB35AdE9aE7d987D648c&crypto_currency=ETH¤cy=USD',
|
||||
isExternal: true,
|
||||
texts: [
|
||||
<p key="1">It’s now easier to get more ETH</p>,
|
||||
<h5 key="2">Buy ETH with USD</h5>
|
||||
|
@ -27,6 +27,7 @@ const promos = [
|
|||
images: [require('assets/images/logo-coinbase.svg')]
|
||||
},
|
||||
{
|
||||
isExternal: false,
|
||||
color: '#006e79',
|
||||
href: '/swap',
|
||||
texts: [
|
||||
|
@ -37,64 +38,60 @@ const promos = [
|
|||
}
|
||||
];
|
||||
|
||||
export default class Promos extends React.Component {
|
||||
state: { activePromo: number };
|
||||
interface State {
|
||||
activePromo: number;
|
||||
}
|
||||
|
||||
state = {
|
||||
activePromo: parseInt(Math.random() * promos.length)
|
||||
export default class Promos extends React.Component<{}, State> {
|
||||
public state = {
|
||||
activePromo: parseInt(String(Math.random() * promos.length), 10)
|
||||
};
|
||||
|
||||
_navigateToPromo = (idx: number) => {
|
||||
this.setState({ activePromo: Math.max(0, Math.min(promos.length, idx)) });
|
||||
};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const { activePromo } = this.state;
|
||||
const promo = promos[activePromo];
|
||||
|
||||
const promoContent = (
|
||||
<div className="Promos-promo-inner">
|
||||
<div className="Promos-promo-text">
|
||||
{promo.texts}
|
||||
</div>
|
||||
<div className="Promos-promo-text">{promo.texts}</div>
|
||||
<div className="Promos-promo-images">
|
||||
{promo.images.map((img, idx) => <img src={img} key={idx} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const promoEl = promo.isExternal
|
||||
? <a
|
||||
className="Promos-promo"
|
||||
key={promo.href}
|
||||
target="_blank"
|
||||
href={promo.href}
|
||||
style={{ backgroundColor: promo.color }}
|
||||
>
|
||||
{promoContent}
|
||||
</a>
|
||||
: <Link
|
||||
className="Promos-promo"
|
||||
key={promo.href}
|
||||
to={promo.href}
|
||||
style={{ backgroundColor: promo.color }}
|
||||
>
|
||||
<div className="Promos-promo-inner">
|
||||
{promoContent}
|
||||
</div>
|
||||
</Link>;
|
||||
const promoEl = promo.isExternal ? (
|
||||
<a
|
||||
className="Promos-promo"
|
||||
key={promo.href}
|
||||
target="_blank"
|
||||
href={promo.href}
|
||||
style={{ backgroundColor: promo.color }}
|
||||
>
|
||||
{promoContent}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
className="Promos-promo"
|
||||
key={promo.href}
|
||||
to={promo.href}
|
||||
style={{ backgroundColor: promo.color }}
|
||||
>
|
||||
<div className="Promos-promo-inner">{promoContent}</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="Promos">
|
||||
{promoEl}
|
||||
<div className="Promos-nav">
|
||||
{promos.map((promo, idx) => {
|
||||
{promos.map((_, index) => {
|
||||
return (
|
||||
<button
|
||||
className={`Promos-nav-btn ${idx === activePromo
|
||||
className={`Promos-nav-btn ${index === activePromo
|
||||
? 'is-active'
|
||||
: ''}`}
|
||||
key={idx}
|
||||
onClick={() => this._navigateToPromo(idx)}
|
||||
key={index}
|
||||
onClick={this.navigateToPromo(index)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -102,4 +99,8 @@ export default class Promos extends React.Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private navigateToPromo = (idx: number) => () => {
|
||||
this.setState({ activePromo: Math.max(0, Math.min(promos.length, idx)) });
|
||||
};
|
||||
}
|
|
@ -1,20 +1,27 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { isValidETHAddress, isPositiveIntegerOrZero } from 'libs/validators';
|
||||
import { Token } from 'config/data';
|
||||
import { isPositiveIntegerOrZero, isValidETHAddress } from 'libs/validators';
|
||||
import React from 'react';
|
||||
import translate from 'translations';
|
||||
|
||||
export default class AddCustomTokenForm extends React.Component {
|
||||
props: {
|
||||
onSave: ({ address: string, symbol: string, decimal: number }) => void
|
||||
};
|
||||
state = {
|
||||
interface Props {
|
||||
onSave(params: Token): void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
address: string;
|
||||
symbol: string;
|
||||
decimal: string;
|
||||
}
|
||||
|
||||
export default class AddCustomTokenForm extends React.Component<Props, State> {
|
||||
public state = {
|
||||
address: '',
|
||||
symbol: '',
|
||||
decimal: ''
|
||||
};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const { address, symbol, decimal } = this.state;
|
||||
const inputClasses = 'AddCustom-field-input form-control input-sm';
|
||||
const errors = this.getErrors();
|
||||
|
@ -42,9 +49,7 @@ export default class AddCustomTokenForm extends React.Component {
|
|||
{fields.map(field => {
|
||||
return (
|
||||
<label className="AddCustom-field form-group" key={field.name}>
|
||||
<span className="AddCustom-field-label">
|
||||
{field.label}
|
||||
</span>
|
||||
<span className="AddCustom-field-label">{field.label}</span>
|
||||
<input
|
||||
className={classnames(
|
||||
inputClasses,
|
||||
|
@ -69,9 +74,13 @@ export default class AddCustomTokenForm extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
getErrors() {
|
||||
public getErrors() {
|
||||
const { address, symbol, decimal } = this.state;
|
||||
const errors = {};
|
||||
const errors = {
|
||||
decimal: false,
|
||||
address: false,
|
||||
symbol: false
|
||||
};
|
||||
|
||||
if (!isPositiveIntegerOrZero(parseInt(decimal, 10))) {
|
||||
errors.decimal = true;
|
||||
|
@ -86,17 +95,18 @@ export default class AddCustomTokenForm extends React.Component {
|
|||
return errors;
|
||||
}
|
||||
|
||||
isValid() {
|
||||
public isValid() {
|
||||
return !Object.keys(this.getErrors()).length;
|
||||
}
|
||||
|
||||
onFieldChange = (e: SyntheticInputEvent) => {
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
public onFieldChange = (e: React.SyntheticEvent<HTMLInputElement>) => {
|
||||
// TODO: typescript bug: https://github.com/Microsoft/TypeScript/issues/13948
|
||||
const name: any = (e.target as HTMLInputElement).name;
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
this.setState({ [name]: value });
|
||||
};
|
||||
|
||||
onSave = (ev: SyntheticInputEvent) => {
|
||||
public onSave = (ev: React.SyntheticEvent<HTMLFormElement>) => {
|
||||
ev.preventDefault();
|
||||
if (!this.isValid()) {
|
||||
return;
|
|
@ -1,22 +1,24 @@
|
|||
// @flow
|
||||
import './TokenRow.scss';
|
||||
import React from 'react';
|
||||
import Big from 'bignumber.js';
|
||||
import { formatNumber } from 'utils/formatters';
|
||||
import removeIcon from 'assets/images/icon-remove.svg';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import React from 'react';
|
||||
import { formatNumber } from 'utils/formatters';
|
||||
import './TokenRow.scss';
|
||||
|
||||
export default class TokenRow extends React.Component {
|
||||
props: {
|
||||
balance: Big,
|
||||
symbol: string,
|
||||
custom?: boolean,
|
||||
onRemove: (symbol: string) => void
|
||||
};
|
||||
interface Props {
|
||||
balance: BigNumber;
|
||||
symbol: string;
|
||||
custom?: boolean;
|
||||
onRemove(symbol: string): void;
|
||||
}
|
||||
interface State {
|
||||
showLongBalance: boolean;
|
||||
}
|
||||
|
||||
state = {
|
||||
export default class TokenRow extends React.Component<Props, State> {
|
||||
public state = {
|
||||
showLongBalance: false
|
||||
};
|
||||
render() {
|
||||
public render() {
|
||||
const { balance, symbol, custom } = this.props;
|
||||
const { showLongBalance } = this.state;
|
||||
return (
|
||||
|
@ -32,7 +34,7 @@ export default class TokenRow extends React.Component {
|
|||
className="TokenRow-balance-remove"
|
||||
title="Remove Token"
|
||||
onClick={this.onRemove}
|
||||
tabIndex="0"
|
||||
tabIndex={0}
|
||||
/>}
|
||||
<span>
|
||||
{showLongBalance ? balance.toString() : formatNumber(balance)}
|
||||
|
@ -45,7 +47,10 @@ export default class TokenRow extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
toggleShowLongBalance = (e: SyntheticInputEvent) => {
|
||||
public toggleShowLongBalance = (
|
||||
// TODO: don't use any
|
||||
e: any
|
||||
) => {
|
||||
e.preventDefault();
|
||||
this.setState(state => {
|
||||
return {
|
||||
|
@ -54,7 +59,7 @@ export default class TokenRow extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
onRemove = () => {
|
||||
public onRemove = () => {
|
||||
this.props.onRemove(this.props.symbol);
|
||||
};
|
||||
}
|
|
@ -1,26 +1,28 @@
|
|||
// @flow
|
||||
import './index.scss';
|
||||
import { Token } from 'config/data';
|
||||
import React from 'react';
|
||||
import { TokenBalance } from 'selectors/wallet';
|
||||
import translate from 'translations';
|
||||
import TokenRow from './TokenRow';
|
||||
import AddCustomTokenForm from './AddCustomTokenForm';
|
||||
import type { TokenBalance } from 'selectors/wallet';
|
||||
import type { Token } from 'config/data';
|
||||
import './index.scss';
|
||||
import TokenRow from './TokenRow';
|
||||
|
||||
type Props = {
|
||||
tokens: TokenBalance[],
|
||||
onAddCustomToken: (token: Token) => any,
|
||||
onRemoveCustomToken: (symbol: string) => any
|
||||
};
|
||||
interface Props {
|
||||
tokens: TokenBalance[];
|
||||
onAddCustomToken(token: Token): any;
|
||||
onRemoveCustomToken(symbol: string): any;
|
||||
}
|
||||
|
||||
export default class TokenBalances extends React.Component {
|
||||
props: Props;
|
||||
state = {
|
||||
interface State {
|
||||
showAllTokens: boolean;
|
||||
showCustomTokenForm: boolean;
|
||||
}
|
||||
export default class TokenBalances extends React.Component<Props, State> {
|
||||
public state = {
|
||||
showAllTokens: false,
|
||||
showCustomTokenForm: false
|
||||
};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const { tokens } = this.props;
|
||||
const shownTokens = tokens.filter(
|
||||
token => !token.balance.eq(0) || token.custom || this.state.showAllTokens
|
||||
|
@ -70,7 +72,7 @@ export default class TokenBalances extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
toggleShowAllTokens = () => {
|
||||
public toggleShowAllTokens = () => {
|
||||
this.setState(state => {
|
||||
return {
|
||||
showAllTokens: !state.showAllTokens
|
||||
|
@ -78,7 +80,7 @@ export default class TokenBalances extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
toggleShowCustomTokenForm = () => {
|
||||
public toggleShowCustomTokenForm = () => {
|
||||
this.setState(state => {
|
||||
return {
|
||||
showCustomTokenForm: !state.showCustomTokenForm
|
||||
|
@ -86,7 +88,7 @@ export default class TokenBalances extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
addCustomToken = (token: Token) => {
|
||||
public addCustomToken = (token: Token) => {
|
||||
this.props.onAddCustomToken(token);
|
||||
this.setState({ showCustomTokenForm: false });
|
||||
};
|
|
@ -1,111 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { IWallet } from 'libs/wallet';
|
||||
import type { NetworkConfig } from 'config/data';
|
||||
import type { State } from 'reducers';
|
||||
import { connect } from 'react-redux';
|
||||
import { getWalletInst, getTokenBalances } from 'selectors/wallet';
|
||||
import type { TokenBalance } from 'selectors/wallet';
|
||||
import { getNetworkConfig } from 'selectors/config';
|
||||
import * as customTokenActions from 'actions/customTokens';
|
||||
import { showNotification } from 'actions/notifications';
|
||||
import { fiatRequestedRates } from 'actions/rates';
|
||||
import type { FiatRequestedRatesAction } from 'actions/rates';
|
||||
|
||||
import AccountInfo from './AccountInfo';
|
||||
import Promos from './Promos';
|
||||
import TokenBalances from './TokenBalances';
|
||||
import EquivalentValues from './EquivalentValues';
|
||||
import { Ether } from 'libs/units';
|
||||
|
||||
type Props = {
|
||||
wallet: IWallet,
|
||||
balance: Ether,
|
||||
network: NetworkConfig,
|
||||
tokenBalances: TokenBalance[],
|
||||
rates: { [string]: number },
|
||||
showNotification: Function,
|
||||
addCustomToken: typeof customTokenActions.addCustomToken,
|
||||
removeCustomToken: typeof customTokenActions.removeCustomToken,
|
||||
fiatRequestedRates: () => FiatRequestedRatesAction
|
||||
};
|
||||
|
||||
export class BalanceSidebar extends React.Component {
|
||||
props: Props;
|
||||
|
||||
render() {
|
||||
const {
|
||||
wallet,
|
||||
balance,
|
||||
network,
|
||||
tokenBalances,
|
||||
rates,
|
||||
fiatRequestedRates
|
||||
} = this.props;
|
||||
if (!wallet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blocks = [
|
||||
{
|
||||
name: 'Account Info',
|
||||
content: (
|
||||
<AccountInfo
|
||||
wallet={wallet}
|
||||
balance={balance}
|
||||
network={network}
|
||||
fiatRequestedRates={fiatRequestedRates}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'Promos',
|
||||
isFullWidth: true,
|
||||
content: <Promos />
|
||||
},
|
||||
{
|
||||
name: 'Token Balances',
|
||||
content: (
|
||||
<TokenBalances
|
||||
tokens={tokenBalances}
|
||||
onAddCustomToken={this.props.addCustomToken}
|
||||
onRemoveCustomToken={this.props.removeCustomToken}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'Equivalent Values',
|
||||
content: <EquivalentValues balance={balance} rates={rates} />
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<aside>
|
||||
{blocks.map(block =>
|
||||
<section
|
||||
className={`Block ${block.isFullWidth ? 'is-full-width' : ''}`}
|
||||
key={block.name}
|
||||
>
|
||||
{block.content}
|
||||
</section>
|
||||
)}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: State) {
|
||||
return {
|
||||
wallet: getWalletInst(state),
|
||||
balance: state.wallet.balance,
|
||||
tokenBalances: getTokenBalances(state),
|
||||
network: getNetworkConfig(state),
|
||||
rates: state.rates
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
...customTokenActions,
|
||||
showNotification,
|
||||
fiatRequestedRates
|
||||
})(BalanceSidebar);
|
|
@ -0,0 +1,136 @@
|
|||
import {
|
||||
addCustomToken,
|
||||
removeCustomToken,
|
||||
TAddCustomToken,
|
||||
TRemoveCustomToken
|
||||
} from 'actions/customTokens';
|
||||
import { showNotification, TShowNotification } from 'actions/notifications';
|
||||
import { fetchCCRates as dFetchCCRates, TFetchCCRates } from 'actions/rates';
|
||||
import { NetworkConfig } from 'config/data';
|
||||
import { Ether } from 'libs/units';
|
||||
import { IWallet } from 'libs/wallet/IWallet';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from 'reducers';
|
||||
import { getNetworkConfig } from 'selectors/config';
|
||||
import {
|
||||
getTokenBalances,
|
||||
getWalletInst,
|
||||
TokenBalance
|
||||
} from 'selectors/wallet';
|
||||
import AccountInfo from './AccountInfo';
|
||||
import EquivalentValues from './EquivalentValues';
|
||||
import Promos from './Promos';
|
||||
import TokenBalances from './TokenBalances';
|
||||
import { State } from 'reducers/rates';
|
||||
import OfflineToggle from './OfflineToggle';
|
||||
|
||||
interface Props {
|
||||
wallet: IWallet;
|
||||
balance: Ether;
|
||||
network: NetworkConfig;
|
||||
tokenBalances: TokenBalance[];
|
||||
rates: State['rates'];
|
||||
ratesError: State['ratesError'];
|
||||
showNotification: TShowNotification;
|
||||
addCustomToken: TAddCustomToken;
|
||||
removeCustomToken: TRemoveCustomToken;
|
||||
fetchCCRates: TFetchCCRates;
|
||||
}
|
||||
|
||||
interface Block {
|
||||
name: string;
|
||||
content: React.ReactElement<any>;
|
||||
isFullWidth?: boolean;
|
||||
}
|
||||
|
||||
export class BalanceSidebar extends React.Component<Props, {}> {
|
||||
public render() {
|
||||
const {
|
||||
wallet,
|
||||
balance,
|
||||
network,
|
||||
tokenBalances,
|
||||
rates,
|
||||
ratesError,
|
||||
fetchCCRates
|
||||
} = this.props;
|
||||
if (!wallet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blocks: Block[] = [
|
||||
{
|
||||
name: 'Go Offline',
|
||||
content: <OfflineToggle />
|
||||
},
|
||||
{
|
||||
name: 'Account Info',
|
||||
content: (
|
||||
<AccountInfo
|
||||
wallet={wallet}
|
||||
balance={balance}
|
||||
network={network}
|
||||
fetchCCRates={fetchCCRates}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'Promos',
|
||||
isFullWidth: true,
|
||||
content: <Promos />
|
||||
},
|
||||
{
|
||||
name: 'Token Balances',
|
||||
content: (
|
||||
<TokenBalances
|
||||
tokens={tokenBalances}
|
||||
onAddCustomToken={this.props.addCustomToken}
|
||||
onRemoveCustomToken={this.props.removeCustomToken}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'Equivalent Values',
|
||||
content: (
|
||||
<EquivalentValues
|
||||
balance={balance}
|
||||
rates={rates}
|
||||
ratesError={ratesError}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<aside>
|
||||
{blocks.map(block => (
|
||||
<section
|
||||
className={`Block ${block.isFullWidth ? 'is-full-width' : ''}`}
|
||||
key={block.name}
|
||||
>
|
||||
{block.content}
|
||||
</section>
|
||||
))}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: AppState) {
|
||||
return {
|
||||
wallet: getWalletInst(state),
|
||||
balance: state.wallet.balance,
|
||||
tokenBalances: getTokenBalances(state),
|
||||
network: getNetworkConfig(state),
|
||||
rates: state.rates.rates,
|
||||
ratesError: state.rates.ratesError
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
addCustomToken,
|
||||
removeCustomToken,
|
||||
showNotification,
|
||||
fetchCCRates: dFetchCCRates
|
||||
})(BalanceSidebar);
|
|
@ -1,18 +1,23 @@
|
|||
import { BlockExplorerConfig } from 'config/data';
|
||||
import React from 'react';
|
||||
import { ETHTxExplorer } from 'config/data';
|
||||
import translate from 'translations';
|
||||
export type TransactionSucceededProps = {
|
||||
txHash: string
|
||||
};
|
||||
import {translateRaw} from 'translations';
|
||||
|
||||
const TransactionSucceeded = ({ txHash }: TransactionSucceededProps) => {
|
||||
export interface TransactionSucceededProps {
|
||||
txHash: string;
|
||||
blockExplorer: BlockExplorerConfig;
|
||||
}
|
||||
|
||||
const TransactionSucceeded = ({
|
||||
txHash,
|
||||
blockExplorer
|
||||
}: TransactionSucceededProps) => {
|
||||
// const checkTxLink = `https://www.myetherwallet.com?txHash=${txHash}/#check-tx-status`;
|
||||
const txHashLink = ETHTxExplorer(txHash);
|
||||
const txHashLink = blockExplorer.tx(txHash);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
{translate('SUCCESS_3', true) + txHash}
|
||||
{translateRaw('SUCCESS_3') + txHash}
|
||||
</p>
|
||||
<a
|
||||
className="btn btn-xs btn-info string"
|
|
@ -1,199 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
import { donationAddressMap } from 'config/data';
|
||||
import logo from 'assets/images/logo-myetherwallet.svg';
|
||||
import { bityReferralURL } from 'config/data';
|
||||
import PreFooter from './PreFooter';
|
||||
import './index.scss';
|
||||
|
||||
const LINKS_LEFT = [
|
||||
{
|
||||
text: 'Knowledge Base',
|
||||
href: 'https://myetherwallet.groovehq.com/help_center'
|
||||
},
|
||||
{
|
||||
text: 'Helpers & ENS Debugging',
|
||||
href: 'https://www.myetherwallet.com/helpers.html'
|
||||
},
|
||||
{
|
||||
text: 'Sign Message',
|
||||
href: 'https://www.myetherwallet.com/signmsg.html'
|
||||
}
|
||||
];
|
||||
|
||||
const LINKS_SUPPORT = [
|
||||
{
|
||||
href: bityReferralURL,
|
||||
text: 'Swap ETH/BTC/EUR/CHF via Bity.com'
|
||||
},
|
||||
{
|
||||
href: 'https://www.ledgerwallet.com/r/fa4b?path=/products/',
|
||||
text: 'Buy a Ledger Nano S'
|
||||
},
|
||||
{
|
||||
href: 'https://trezor.io/?a=myetherwallet.com',
|
||||
text: 'Buy a TREZOR'
|
||||
},
|
||||
{
|
||||
href: 'https://digitalbitbox.com/?ref=mew',
|
||||
text: 'Buy a Digital Bitbox'
|
||||
}
|
||||
];
|
||||
|
||||
const LINKS_RIGHT = [
|
||||
{
|
||||
href: 'https://www.MyEtherWallet.com',
|
||||
text: 'MyEtherWallet.com'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/MyEtherWallet/MyEtherWallet',
|
||||
text: 'Github: Current Site'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/MyEtherWallet',
|
||||
text: 'Github: MEW Org'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/MyEtherWallet/MyEtherWallet/releases/latest',
|
||||
text: 'Github: Latest Release'
|
||||
},
|
||||
{
|
||||
href:
|
||||
'https://chrome.google.com/webstore/detail/myetherwallet-cx/nlbmnnijcnlegkjjpcfjclmcfggfefdm?hl=en',
|
||||
text: 'MyEtherWallet CX'
|
||||
},
|
||||
{
|
||||
href:
|
||||
'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn',
|
||||
text: 'Anti-Phishing CX'
|
||||
}
|
||||
];
|
||||
|
||||
const LINKS_SOCIAL = [
|
||||
{
|
||||
href: 'https://myetherwallet.herokuapp.com/',
|
||||
text: 'Slack'
|
||||
},
|
||||
{
|
||||
href: 'https://www.reddit.com/r/MyEtherWallet/',
|
||||
text: 'Reddit'
|
||||
},
|
||||
{
|
||||
href: 'https://twitter.com/myetherwallet',
|
||||
text: 'Twitter'
|
||||
},
|
||||
{
|
||||
href: 'https://www.facebook.com/MyEtherWallet/',
|
||||
text: 'Facebook'
|
||||
},
|
||||
{
|
||||
href: 'https://medium.com/@myetherwallet',
|
||||
text: 'Medium'
|
||||
}
|
||||
];
|
||||
|
||||
export default class Footer extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<PreFooter />
|
||||
<footer className="Footer" role="contentinfo" aria-label="footer">
|
||||
<div className="Footer-column Footer-about">
|
||||
<p aria-hidden="true">
|
||||
<a href="/">
|
||||
<img
|
||||
className="Footer-about-logo"
|
||||
src={logo}
|
||||
height="55px"
|
||||
width="auto"
|
||||
alt="MyEtherWallet"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
<p className="Footer-about-text">
|
||||
<span>
|
||||
{translate('FOOTER_1')}
|
||||
</span>
|
||||
<span>
|
||||
{translate('FOOTER_1b')}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
{LINKS_LEFT.map(link => {
|
||||
return (
|
||||
<p key={link.href}>
|
||||
<a href={link.href} target="_blank" rel="noopener">
|
||||
{link.text}
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
|
||||
<p>© 2017 MyEtherWallet, LLC</p>
|
||||
</div>
|
||||
|
||||
<div className="Footer-column Footer-info">
|
||||
<h5>
|
||||
<i aria-hidden="true">👫</i>
|
||||
You can support us by supporting our blockchain-family.
|
||||
</h5>
|
||||
<p>Consider using our affiliate links to...</p>
|
||||
<ul>
|
||||
{LINKS_SUPPORT.map(link => {
|
||||
return (
|
||||
<li key={link.href}>
|
||||
<a href={link.href} target="_blank">
|
||||
{link.text}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
||||
<h5>
|
||||
<i aria-hidden="true">💝</i>
|
||||
{translate('FOOTER_2')}
|
||||
</h5>
|
||||
<ul>
|
||||
<li>
|
||||
{' '}ETH:{' '}
|
||||
<span className="mono wrap">{donationAddressMap.ETH}</span>
|
||||
</li>
|
||||
<li>
|
||||
{' '}BTC:{' '}
|
||||
<span className="mono wrap">{donationAddressMap.BTC}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="Footer-column Footer-links">
|
||||
{LINKS_RIGHT.map(link => {
|
||||
return (
|
||||
<p key={link.href}>
|
||||
<a href={link.href} target="_blank">
|
||||
{link.text}
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
<p>
|
||||
{LINKS_SOCIAL.map((link, i) => {
|
||||
return (
|
||||
<span key={link.href}>
|
||||
<a key={link.href} href={link.href} target="_blank">
|
||||
{link.text}
|
||||
</a>
|
||||
{i !== LINKS_SOCIAL.length - 1 && ' · '}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</p>
|
||||
|
||||
{/* TODO: Fix me */}
|
||||
<p>Latest Block#: ?????</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
@import "common/sass/variables";
|
||||
@import 'common/sass/variables';
|
||||
|
||||
// footer
|
||||
.Footer {
|
||||
|
@ -40,6 +40,20 @@
|
|||
max-width: 28rem;
|
||||
}
|
||||
|
||||
&-modal-button {
|
||||
color: #4ac8ed;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: none;
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
transition: 500ms all ease-in-out;
|
||||
&:hover {
|
||||
color: #0e97c0;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: $space-xs 0 $space-sm;
|
||||
}
|
||||
|
@ -57,7 +71,7 @@
|
|||
margin: $font-size-small 0 0;
|
||||
|
||||
i {
|
||||
margin-right: .25em;
|
||||
margin-right: 0.25em;
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
margin-left: -1.5em;
|
||||
|
@ -79,8 +93,12 @@
|
|||
|
||||
@media screen and (max-width: $grid-float-breakpoint) {
|
||||
.row {
|
||||
margin-left: -.5rem;
|
||||
margin-right: -.5rem;
|
||||
margin-left: -0.5rem;
|
||||
margin-right: -0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Modal {
|
||||
color: #000;
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
import logo from 'assets/images/logo-myetherwallet.svg';
|
||||
import { bityReferralURL, donationAddressMap } from 'config/data';
|
||||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
import './index.scss';
|
||||
import PreFooter from './PreFooter';
|
||||
import Modal, { IButton } from 'components/ui/Modal';
|
||||
|
||||
const LINKS_LEFT = [
|
||||
{
|
||||
text: 'Knowledge Base',
|
||||
href: 'https://myetherwallet.groovehq.com/help_center'
|
||||
},
|
||||
{
|
||||
text: 'Helpers & ENS Debugging',
|
||||
href: 'https://www.myetherwallet.com/helpers.html'
|
||||
},
|
||||
{
|
||||
text: 'Sign Message',
|
||||
href: 'https://www.myetherwallet.com/signmsg.html'
|
||||
}
|
||||
];
|
||||
|
||||
const LINKS_SUPPORT = [
|
||||
{
|
||||
href: bityReferralURL,
|
||||
text: 'Swap ETH/BTC/EUR/CHF via Bity.com'
|
||||
},
|
||||
{
|
||||
href: 'https://www.ledgerwallet.com/r/fa4b?path=/products/',
|
||||
text: 'Buy a Ledger Nano S'
|
||||
},
|
||||
{
|
||||
href: 'https://trezor.io/?a=myetherwallet.com',
|
||||
text: 'Buy a TREZOR'
|
||||
},
|
||||
{
|
||||
href: 'https://digitalbitbox.com/?ref=mew',
|
||||
text: 'Buy a Digital Bitbox'
|
||||
}
|
||||
];
|
||||
|
||||
const LINKS_RIGHT = [
|
||||
{
|
||||
href: 'https://www.MyEtherWallet.com',
|
||||
text: 'MyEtherWallet.com'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/MyEtherWallet/MyEtherWallet',
|
||||
text: 'Github: Current Site'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/MyEtherWallet',
|
||||
text: 'Github: MEW Org'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/MyEtherWallet/MyEtherWallet/releases/latest',
|
||||
text: 'Github: Latest Release'
|
||||
},
|
||||
{
|
||||
href:
|
||||
'https://chrome.google.com/webstore/detail/myetherwallet-cx/nlbmnnijcnlegkjjpcfjclmcfggfefdm?hl=en',
|
||||
text: 'MyEtherWallet CX'
|
||||
},
|
||||
{
|
||||
href:
|
||||
'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn',
|
||||
text: 'Anti-Phishing CX'
|
||||
}
|
||||
];
|
||||
|
||||
const LINKS_SOCIAL = [
|
||||
{
|
||||
href: 'https://myetherwallet.herokuapp.com/',
|
||||
text: 'Slack'
|
||||
},
|
||||
{
|
||||
href: 'https://www.reddit.com/r/MyEtherWallet/',
|
||||
text: 'Reddit'
|
||||
},
|
||||
{
|
||||
href: 'https://twitter.com/myetherwallet',
|
||||
text: 'Twitter'
|
||||
},
|
||||
{
|
||||
href: 'https://www.facebook.com/MyEtherWallet/',
|
||||
text: 'Facebook'
|
||||
},
|
||||
{
|
||||
href: 'https://medium.com/@myetherwallet',
|
||||
text: 'Medium'
|
||||
}
|
||||
];
|
||||
|
||||
interface ComponentState {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default class Footer extends React.Component<{}, ComponentState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { isOpen: false };
|
||||
}
|
||||
|
||||
public openModal = () => {
|
||||
this.setState({ isOpen: true });
|
||||
};
|
||||
|
||||
public closeModal = () => {
|
||||
this.setState({ isOpen: false });
|
||||
};
|
||||
|
||||
public render() {
|
||||
const buttons: IButton[] = [
|
||||
{ text: 'Okay', type: 'default', onClick: this.closeModal }
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<PreFooter />
|
||||
<footer className="Footer" role="contentinfo" aria-label="footer">
|
||||
<div className="Footer-column Footer-about">
|
||||
<p aria-hidden="true">
|
||||
<a href="/">
|
||||
<img
|
||||
className="Footer-about-logo"
|
||||
src={logo}
|
||||
height="55px"
|
||||
width="auto"
|
||||
alt="MyEtherWallet"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
<p className="Footer-about-text">
|
||||
<span>{translate('FOOTER_1')}</span>
|
||||
<span>{translate('FOOTER_1b')}</span>
|
||||
</p>
|
||||
|
||||
{LINKS_LEFT.map(link => {
|
||||
return (
|
||||
<p key={link.href}>
|
||||
<a href={link.href} target="_blank" rel="noopener">
|
||||
{link.text}
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
|
||||
<button className="Footer-modal-button" onClick={this.openModal}>
|
||||
Disclaimer
|
||||
</button>
|
||||
<Modal
|
||||
isOpen={this.state.isOpen}
|
||||
title="Disclaimer"
|
||||
buttons={buttons}
|
||||
handleClose={this.closeModal}
|
||||
>
|
||||
<p>
|
||||
<b>Be safe & secure: </b>
|
||||
<a href="https://myetherwallet.groovehq.com/knowledge_base/topics/protecting-yourself-and-your-funds">
|
||||
We highly recommend that you read our guide on How to Prevent
|
||||
Loss & Theft for some recommendations on how to be proactive
|
||||
about your security.
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<b>Always backup your keys: </b>
|
||||
MyEtherWallet.com & MyEtherWallet CX are not "web wallets". You
|
||||
do not create an account or give us your funds to hold onto. No
|
||||
data leaves your computer / your browser. We make it easy for
|
||||
you to create, save, and access your information and interact
|
||||
with the blockchain.
|
||||
</p>
|
||||
<p>
|
||||
<b>We are not responsible for any loss: </b>
|
||||
Ethereum, MyEtherWallet.com & MyEtherWallet CX, and some of the
|
||||
underlying Javascript libraries we use are under active
|
||||
development. While we have thoroughly tested & tens of thousands
|
||||
of wallets have been successfully created by people all over the
|
||||
globe, there is always the possibility something unexpected
|
||||
happens that causes your funds to be lost. Please do not invest
|
||||
more than you are willing to lose, and please be careful.
|
||||
</p>
|
||||
<p>
|
||||
<b>Translations of MyEtherWallet: </b>
|
||||
The community has done an amazing job translating MyEtherWallet
|
||||
into a variety of languages. However, MyEtherWallet can only
|
||||
verify the validity and accuracy of the information provided in
|
||||
English and, because of this, the English version of our website
|
||||
is the official text.
|
||||
</p>
|
||||
<p>
|
||||
<b>MIT License</b> Copyright © 2015-2017 MyEtherWallet LLC
|
||||
</p>
|
||||
<p>
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
</p>
|
||||
<p>
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
</p>
|
||||
<b>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
</b>
|
||||
</Modal>
|
||||
|
||||
<p>© 2017 MyEtherWallet, LLC</p>
|
||||
</div>
|
||||
|
||||
<div className="Footer-column Footer-info">
|
||||
<h5>
|
||||
<i aria-hidden="true">👫</i>
|
||||
You can support us by supporting our blockchain-family.
|
||||
</h5>
|
||||
<p>Consider using our affiliate links to...</p>
|
||||
<ul>
|
||||
{LINKS_SUPPORT.map(link => {
|
||||
return (
|
||||
<li key={link.href}>
|
||||
<a href={link.href} target="_blank">
|
||||
{link.text}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
||||
<h5>
|
||||
<i aria-hidden="true">💝</i>
|
||||
{translate('FOOTER_2')}
|
||||
</h5>
|
||||
<ul>
|
||||
<li>
|
||||
{' '}
|
||||
ETH: <span className="mono wrap">{donationAddressMap.ETH}</span>
|
||||
</li>
|
||||
<li>
|
||||
{' '}
|
||||
BTC: <span className="mono wrap">{donationAddressMap.BTC}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="Footer-column Footer-links">
|
||||
{LINKS_RIGHT.map(link => {
|
||||
return (
|
||||
<p key={link.href}>
|
||||
<a href={link.href} target="_blank">
|
||||
{link.text}
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
<p>
|
||||
{LINKS_SOCIAL.map((link, i) => {
|
||||
return (
|
||||
<span key={link.href}>
|
||||
<a key={link.href} href={link.href} target="_blank">
|
||||
{link.text}
|
||||
</a>
|
||||
{i !== LINKS_SOCIAL.length - 1 && ' · '}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</p>
|
||||
|
||||
{/* TODO: Fix me */}
|
||||
<p>Latest Block#: ?????</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import throttle from 'lodash/throttle';
|
||||
|
||||
import './GasPriceDropdown.scss';
|
||||
import { gasPriceDefaults } from 'config/data';
|
||||
|
||||
type Props = {
|
||||
value: number,
|
||||
onChange: (gasPrice: number) => void
|
||||
};
|
||||
|
||||
export default class GasPriceDropdown extends Component {
|
||||
state = { expanded: false };
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.number,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.updateGasPrice = throttle(this.updateGasPrice, 50);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { expanded } = this.state;
|
||||
return (
|
||||
<span className={`dropdown ${expanded ? 'open' : ''}`}>
|
||||
<a
|
||||
aria-haspopup="true"
|
||||
aria-label="adjust gas price"
|
||||
className="dropdown-toggle"
|
||||
onClick={this.toggleExpanded}
|
||||
>
|
||||
<span>Gas Price</span>: {this.props.value} Gwei
|
||||
<i className="caret" />
|
||||
</a>
|
||||
{expanded &&
|
||||
<ul className="dropdown-menu GasPrice-dropdown-menu">
|
||||
<div className="GasPrice-header">
|
||||
<span>Gas Price</span>: {this.props.value} Gwei
|
||||
<input
|
||||
type="range"
|
||||
value={this.props.value}
|
||||
min={gasPriceDefaults.gasPriceMinGwei}
|
||||
max={gasPriceDefaults.gasPriceMaxGwei}
|
||||
onChange={this.handleGasPriceChange}
|
||||
/>
|
||||
<p className="small col-xs-4 text-left GasPrice-padding-reset">
|
||||
Not So Fast
|
||||
</p>
|
||||
<p className="small col-xs-4 text-center GasPrice-padding-reset">
|
||||
Fast
|
||||
</p>
|
||||
<p className="small col-xs-4 text-right GasPrice-padding-reset">
|
||||
Fast AF
|
||||
</p>
|
||||
<p className="small GasPrice-description">
|
||||
Gas Price is the amount you pay per unit of gas.{' '}
|
||||
<code>TX fee = gas price * gas limit</code> & is paid to miners
|
||||
for including your TX in a block. Higher the gas price = faster
|
||||
transaction, but more expensive. Default is <code>21 GWEI</code>.
|
||||
</p>
|
||||
<p>
|
||||
{/* TODO: maybe not hardcode a link? :) */}
|
||||
<a
|
||||
href="https://myetherwallet.groovehq.com/knowledge_base/topics/what-is-gas"
|
||||
target="_blank"
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</ul>}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
toggleExpanded = () => {
|
||||
this.setState(state => {
|
||||
return {
|
||||
expanded: !state.expanded
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
updateGasPrice = (value: string) => {
|
||||
this.props.onChange(parseInt(value, 10));
|
||||
};
|
||||
|
||||
handleGasPriceChange = (e: SyntheticInputEvent) => {
|
||||
this.updateGasPrice(e.target.value);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
import { gasPriceDefaults } from 'config/data';
|
||||
import throttle from 'lodash/throttle';
|
||||
import React, { Component } from 'react';
|
||||
import DropdownShell from 'components/ui/DropdownShell';
|
||||
import './GasPriceDropdown.scss';
|
||||
|
||||
interface Props {
|
||||
value: number;
|
||||
onChange(gasPrice: number): void;
|
||||
}
|
||||
|
||||
export default class GasPriceDropdown extends Component<Props, {}> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.updateGasPrice = throttle(this.updateGasPrice, 50);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { value } = this.props;
|
||||
return (
|
||||
<DropdownShell
|
||||
color="white"
|
||||
size="smr"
|
||||
ariaLabel={`adjust gas price. current price is ${value} gwei`}
|
||||
renderLabel={this.renderLabel}
|
||||
renderOptions={this.renderOptions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderLabel = () => {
|
||||
return `Gas Price: ${this.props.value} Gwei`;
|
||||
};
|
||||
|
||||
private renderOptions = () => {
|
||||
const { value } = this.props;
|
||||
return (
|
||||
<div className="GasPrice-dropdown-menu dropdown-menu dropdown-menu-right">
|
||||
<div className="GasPrice-header">
|
||||
<span>Gas Price</span>: {value} Gwei
|
||||
<input
|
||||
type="range"
|
||||
value={value}
|
||||
min={gasPriceDefaults.gasPriceMinGwei}
|
||||
max={gasPriceDefaults.gasPriceMaxGwei}
|
||||
onChange={this.handleGasPriceChange}
|
||||
/>
|
||||
<p className="small col-xs-4 text-left GasPrice-padding-reset">
|
||||
Not So Fast
|
||||
</p>
|
||||
<p className="small col-xs-4 text-center GasPrice-padding-reset">
|
||||
Fast
|
||||
</p>
|
||||
<p className="small col-xs-4 text-right GasPrice-padding-reset">
|
||||
Fast AF
|
||||
</p>
|
||||
<p className="small GasPrice-description">
|
||||
Gas Price is the amount you pay per unit of gas.{' '}
|
||||
<code>TX fee = gas price * gas limit</code> & is paid to miners for
|
||||
including your TX in a block. Higher the gas price = faster
|
||||
transaction, but more expensive. Default is <code>21 GWEI</code>.
|
||||
</p>
|
||||
<p>
|
||||
{/* TODO: maybe not hardcode a link? :) */}
|
||||
<a
|
||||
href="https://myetherwallet.groovehq.com/knowledge_base/topics/what-is-gas"
|
||||
target="_blank"
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
private updateGasPrice = (value: string) => {
|
||||
this.props.onChange(parseInt(value, 10));
|
||||
};
|
||||
|
||||
private handleGasPriceChange = (
|
||||
e: React.SyntheticEvent<HTMLInputElement>
|
||||
) => {
|
||||
this.updateGasPrice((e.target as HTMLInputElement).value);
|
||||
};
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
position: relative;
|
||||
overflow-y: hidden;
|
||||
border-top: .25rem solid $brand-primary;
|
||||
transition: border 300ms ease;
|
||||
|
||||
&-scroll {
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import NavigationLink from './NavigationLink';
|
||||
|
||||
import './Navigation.scss';
|
||||
|
@ -17,13 +17,6 @@ const tabs = [
|
|||
name: 'NAV_Swap',
|
||||
to: 'swap'
|
||||
},
|
||||
{
|
||||
name: 'NAV_Offline'
|
||||
},
|
||||
{
|
||||
name: 'NAV_Contracts',
|
||||
to: 'contracts'
|
||||
},
|
||||
{
|
||||
name: 'NAV_ViewWallet'
|
||||
// to: 'view-wallet'
|
||||
|
@ -39,62 +32,71 @@ const tabs = [
|
|||
}
|
||||
];
|
||||
|
||||
export default class TabsOptions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showLeftArrow: false,
|
||||
showRightArrow: false
|
||||
};
|
||||
}
|
||||
interface Props {
|
||||
color?: string;
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
location: PropTypes.object
|
||||
interface State {
|
||||
showLeftArrow: boolean;
|
||||
showRightArrow: boolean;
|
||||
}
|
||||
|
||||
interface BorderStyle {
|
||||
borderTopColor?: string;
|
||||
}
|
||||
|
||||
export default class Navigation extends Component<Props, State> {
|
||||
public state = {
|
||||
showLeftArrow: false,
|
||||
showRightArrow: false
|
||||
};
|
||||
|
||||
scrollLeft() {}
|
||||
/*
|
||||
* public scrollLeft() {}
|
||||
public scrollRight() {}
|
||||
*
|
||||
*/
|
||||
|
||||
scrollRight() {}
|
||||
public render() {
|
||||
const { color } = this.props;
|
||||
const borderStyle: BorderStyle = {};
|
||||
|
||||
if (color) {
|
||||
borderStyle.borderTopColor = color;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { location } = this.props;
|
||||
return (
|
||||
<nav
|
||||
role="navigation"
|
||||
aria-label="main navigation"
|
||||
className="Navigation"
|
||||
style={borderStyle}
|
||||
>
|
||||
{this.state.showLeftArrow &&
|
||||
{this.state.showLeftArrow && (
|
||||
<a
|
||||
aria-hidden="true"
|
||||
className="Navigation-arrow Navigation-arrow--left"
|
||||
onClick={() => this.scrollLeft(100)}
|
||||
>
|
||||
«
|
||||
</a>}
|
||||
</a>
|
||||
)}
|
||||
|
||||
<div className="Navigation-scroll container">
|
||||
<ul className="Navigation-links">
|
||||
{tabs.map(link => {
|
||||
return (
|
||||
<NavigationLink
|
||||
key={link.name}
|
||||
link={link}
|
||||
location={location}
|
||||
/>
|
||||
);
|
||||
return <NavigationLink key={link.name} link={link} />;
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{this.state.showRightArrow &&
|
||||
{this.state.showRightArrow && (
|
||||
<a
|
||||
aria-hidden="true"
|
||||
className="Navigation-arrow Navigation-arrow-right"
|
||||
onClick={() => this.scrollRight(100)}
|
||||
>
|
||||
»
|
||||
</a>}
|
||||
</a>
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import translate from 'translations';
|
||||
import { Link } from 'react-router';
|
||||
import './NavigationLink.scss';
|
||||
|
||||
type Props = {
|
||||
link: {
|
||||
name: string,
|
||||
to?: string,
|
||||
external?: boolean
|
||||
},
|
||||
location: Object
|
||||
};
|
||||
|
||||
export default class NavigationLink extends React.Component {
|
||||
props: Props;
|
||||
|
||||
render() {
|
||||
const { link, location } = this.props;
|
||||
const linkClasses = classnames({
|
||||
'NavigationLink-link': true,
|
||||
'is-disabled': !link.to,
|
||||
'is-active':
|
||||
location.pathname === link.to ||
|
||||
location.pathname.substring(1) === link.to
|
||||
});
|
||||
// $FlowFixMe flow is wrong, this isn't an element
|
||||
const linkLabel = `nav item: ${translate(link.name, true)}`;
|
||||
|
||||
const linkEl = link.external
|
||||
? <a
|
||||
className={linkClasses}
|
||||
href={link.to}
|
||||
aria-label={linkLabel}
|
||||
target="_blank"
|
||||
>
|
||||
{translate(link.name)}
|
||||
</a>
|
||||
: <Link className={linkClasses} to={link.to} aria-label={linkLabel}>
|
||||
{translate(link.name)}
|
||||
</Link>;
|
||||
|
||||
return (
|
||||
<li className="NavigationLink">
|
||||
{linkEl}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import translate, { translateRaw } from 'translations';
|
||||
import './NavigationLink.scss';
|
||||
|
||||
interface Props {
|
||||
link: {
|
||||
name: string;
|
||||
to?: string;
|
||||
external?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface InjectedLocation extends Props {
|
||||
location: { pathname: string };
|
||||
}
|
||||
|
||||
class NavigationLink extends React.Component<Props, {}> {
|
||||
get injected() {
|
||||
return this.props as InjectedLocation;
|
||||
}
|
||||
public render() {
|
||||
const { link } = this.props;
|
||||
const { location } = this.injected;
|
||||
const linkClasses = classnames({
|
||||
'NavigationLink-link': true,
|
||||
'is-disabled': !link.to,
|
||||
'is-active':
|
||||
location.pathname === link.to ||
|
||||
location.pathname.substring(1) === link.to
|
||||
});
|
||||
const linkLabel = `nav item: ${translateRaw(link.name)}`;
|
||||
|
||||
const linkEl =
|
||||
link.external || !link.to ? (
|
||||
<a
|
||||
className={linkClasses}
|
||||
href={link.to}
|
||||
aria-label={linkLabel}
|
||||
target="_blank"
|
||||
>
|
||||
{translate(link.name)}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
className={linkClasses}
|
||||
to={(link as any).to}
|
||||
aria-label={linkLabel}
|
||||
>
|
||||
{translate(link.name)}
|
||||
</Link>
|
||||
);
|
||||
|
||||
return <li className="NavigationLink">{linkEl}</li>;
|
||||
}
|
||||
}
|
||||
|
||||
// withRouter is a HOC which provides NavigationLink with a react-router location prop
|
||||
export default withRouter(NavigationLink);
|
|
@ -1,118 +0,0 @@
|
|||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import Navigation from './components/Navigation';
|
||||
import GasPriceDropdown from './components/GasPriceDropdown';
|
||||
import { Link } from 'react-router';
|
||||
import { Dropdown } from 'components/ui';
|
||||
import {
|
||||
languages,
|
||||
NODES,
|
||||
VERSION,
|
||||
ANNOUNCEMENT_TYPE,
|
||||
ANNOUNCEMENT_MESSAGE
|
||||
} from '../../config/data';
|
||||
import logo from 'assets/images/logo-myetherwallet.svg';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export default class Header extends Component {
|
||||
props: {
|
||||
location: {},
|
||||
languageSelection: string,
|
||||
nodeSelection: string,
|
||||
gasPriceGwei: number,
|
||||
|
||||
changeLanguage: (sign: string) => any,
|
||||
changeNode: (key: string) => any,
|
||||
changeGasPrice: (price: number) => any
|
||||
};
|
||||
|
||||
render() {
|
||||
const { languageSelection, changeNode, nodeSelection } = this.props;
|
||||
const selectedLanguage =
|
||||
languages.find(l => l.sign === languageSelection) || languages[0];
|
||||
const selectedNode = NODES[nodeSelection];
|
||||
|
||||
return (
|
||||
<div className="Header">
|
||||
{ANNOUNCEMENT_MESSAGE &&
|
||||
<div
|
||||
className={`Header-announcement is-${ANNOUNCEMENT_TYPE}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: ANNOUNCEMENT_MESSAGE
|
||||
}}
|
||||
/>}
|
||||
|
||||
<section className="Header-branding">
|
||||
<section className="Header-branding-inner container">
|
||||
<Link
|
||||
to={'/'}
|
||||
className="Header-branding-title"
|
||||
aria-label="Go to homepage"
|
||||
>
|
||||
{/* TODO - don't hardcode image path*/}
|
||||
<img
|
||||
className="Header-branding-title-logo"
|
||||
src={logo}
|
||||
height="64px"
|
||||
width="245px"
|
||||
alt="MyEtherWallet"
|
||||
/>
|
||||
</Link>
|
||||
<div className="Header-branding-title-tagline">
|
||||
<span className="Header-branding-title-tagline-version">
|
||||
v{VERSION}
|
||||
</span>
|
||||
|
||||
<GasPriceDropdown
|
||||
value={this.props.gasPriceGwei}
|
||||
onChange={this.props.changeGasPrice}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
ariaLabel={`change language. current language ${selectedLanguage.name}`}
|
||||
options={languages}
|
||||
formatTitle={o => o.name}
|
||||
value={selectedLanguage}
|
||||
extra={[
|
||||
<li key={'separator'} role="separator" className="divider" />,
|
||||
<li key={'disclaimer'}>
|
||||
<a data-toggle="modal" data-target="#disclaimerModal">
|
||||
Disclaimer
|
||||
</a>
|
||||
</li>
|
||||
]}
|
||||
onChange={this.changeLanguage}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
ariaLabel={`change node. current node ${selectedNode.network} node by ${selectedNode.service}`}
|
||||
options={Object.keys(NODES)}
|
||||
formatTitle={o => [
|
||||
NODES[o].network,
|
||||
' ',
|
||||
<small key="service">
|
||||
({NODES[o].service})
|
||||
</small>
|
||||
]}
|
||||
value={nodeSelection}
|
||||
extra={
|
||||
<li>
|
||||
<a onClick={() => {}}>Add Custom Node</a>
|
||||
</li>
|
||||
}
|
||||
onChange={changeNode}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<Navigation location={this.props.location} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
changeLanguage = (value: { sign: string }) => {
|
||||
this.props.changeLanguage(value.sign);
|
||||
};
|
||||
}
|
|
@ -92,66 +92,37 @@ $small-size: 900px;
|
|||
padding: 5px 0;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
&-tagline {
|
||||
font-size: 18px;
|
||||
font-weight: 200;
|
||||
color: white;
|
||||
flex: 1 auto;
|
||||
text-align: right;
|
||||
padding: 5px 0;
|
||||
@include small-query {
|
||||
text-align: center;
|
||||
}
|
||||
> * {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&-version {
|
||||
max-width: 395px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
&-right {
|
||||
font-size: 18px;
|
||||
font-weight: 200;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-weight: 400;
|
||||
transition: 250ms all ease;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
opacity: .8;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
transition: 250ms all ease;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - Move to dropdown component?
|
||||
.dropdown {
|
||||
margin-left: 15px;
|
||||
padding: 0;
|
||||
flex: 1 auto;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
padding: 0 0 5px;
|
||||
@include small-query {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
right: -10px;
|
||||
left: auto;
|
||||
min-width: auto;
|
||||
left: auto;
|
||||
> * {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
& > li > a {
|
||||
font-size: 15px;
|
||||
padding: 5px 30px 5px 15px;
|
||||
position: relative;
|
||||
&-version {
|
||||
max-width: 395px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
text-decoration: none;
|
||||
color: $brand-primary;
|
||||
background-color: $gray-lightest;
|
||||
}
|
||||
&-dropdown {
|
||||
margin-left: 6px;
|
||||
|
||||
&-add {
|
||||
text-align: center;
|
||||
padding-top: $space-sm !important;
|
||||
padding-bottom: $space-sm !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
import {
|
||||
TChangeGasPrice,
|
||||
TChangeLanguage,
|
||||
TChangeNodeIntent
|
||||
} from 'actions/config';
|
||||
import logo from 'assets/images/logo-myetherwallet.svg';
|
||||
import { Dropdown, ColorDropdown } from 'components/ui';
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
ANNOUNCEMENT_MESSAGE,
|
||||
ANNOUNCEMENT_TYPE,
|
||||
languages,
|
||||
NETWORKS,
|
||||
NODES,
|
||||
VERSION
|
||||
} from '../../config/data';
|
||||
import GasPriceDropdown from './components/GasPriceDropdown';
|
||||
import Navigation from './components/Navigation';
|
||||
import { getKeyByValue } from 'utils/helpers';
|
||||
import './index.scss';
|
||||
|
||||
interface Props {
|
||||
languageSelection: string;
|
||||
nodeSelection: string;
|
||||
gasPriceGwei: number;
|
||||
|
||||
changeLanguage: TChangeLanguage;
|
||||
changeNodeIntent: TChangeNodeIntent;
|
||||
changeGasPrice: TChangeGasPrice;
|
||||
}
|
||||
|
||||
export default class Header extends Component<Props, {}> {
|
||||
public render() {
|
||||
const { languageSelection, changeNodeIntent, nodeSelection } = this.props;
|
||||
const selectedLanguage = languageSelection;
|
||||
const selectedNode = NODES[nodeSelection];
|
||||
const selectedNetwork = NETWORKS[selectedNode.network];
|
||||
const LanguageDropDown = Dropdown as new () => Dropdown<
|
||||
typeof selectedLanguage
|
||||
>;
|
||||
const nodeOptions = Object.keys(NODES).map(key => {
|
||||
return {
|
||||
value: key,
|
||||
name: (
|
||||
<span>
|
||||
{NODES[key].network} <small>({NODES[key].service})</small>
|
||||
</span>
|
||||
),
|
||||
color: NETWORKS[NODES[key].network].color
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="Header">
|
||||
{ANNOUNCEMENT_MESSAGE && (
|
||||
<div
|
||||
className={`Header-announcement is-${ANNOUNCEMENT_TYPE}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: ANNOUNCEMENT_MESSAGE
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<section className="Header-branding">
|
||||
<section className="Header-branding-inner container">
|
||||
<Link
|
||||
to={'/'}
|
||||
className="Header-branding-title"
|
||||
aria-label="Go to homepage"
|
||||
>
|
||||
{/* TODO - don't hardcode image path*/}
|
||||
<img
|
||||
className="Header-branding-title-logo"
|
||||
src={logo}
|
||||
height="64px"
|
||||
width="245px"
|
||||
alt="MyEtherWallet"
|
||||
/>
|
||||
</Link>
|
||||
<div className="Header-branding-right">
|
||||
<span className="Header-branding-right-version">v{VERSION}</span>
|
||||
|
||||
<div className="Header-branding-right-dropdown">
|
||||
<GasPriceDropdown
|
||||
value={this.props.gasPriceGwei}
|
||||
onChange={this.props.changeGasPrice}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="Header-branding-right-dropdown">
|
||||
<LanguageDropDown
|
||||
ariaLabel={`change language. current language ${languages[
|
||||
selectedLanguage
|
||||
]}`}
|
||||
options={Object.values(languages)}
|
||||
value={languages[selectedLanguage]}
|
||||
extra={
|
||||
<li key="disclaimer">
|
||||
<a data-toggle="modal" data-target="#disclaimerModal">
|
||||
Disclaimer
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
onChange={this.changeLanguage}
|
||||
size="smr"
|
||||
color="white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="Header-branding-right-dropdown">
|
||||
<ColorDropdown
|
||||
ariaLabel={`change node. current node ${selectedNode.network} node by ${selectedNode.service}`}
|
||||
options={nodeOptions}
|
||||
value={nodeSelection}
|
||||
extra={
|
||||
<li>
|
||||
<a>Add Custom Node</a>
|
||||
</li>
|
||||
}
|
||||
onChange={changeNodeIntent}
|
||||
size="smr"
|
||||
color="white"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<Navigation color={selectedNetwork.color} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public changeLanguage = (value: string) => {
|
||||
const key = getKeyByValue(languages, value);
|
||||
if (key) {
|
||||
this.props.changeLanguage(key);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,16 +1,15 @@
|
|||
// @flow
|
||||
import { Identicon, QRCode } from 'components/ui';
|
||||
import PrivKeyWallet from 'libs/wallet/privkey';
|
||||
import React from 'react';
|
||||
import { QRCode, Identicon } from 'components/ui';
|
||||
import type PrivKeyWallet from 'libs/wallet/privkey';
|
||||
|
||||
import ethLogo from 'assets/images/logo-ethereum-1.png';
|
||||
import sidebarImg from 'assets/images/print-sidebar.png';
|
||||
import notesBg from 'assets/images/notes-bg.png';
|
||||
import sidebarImg from 'assets/images/print-sidebar.png';
|
||||
|
||||
const walletWidth = 680;
|
||||
const walletHeight = 280;
|
||||
|
||||
const styles = {
|
||||
const styles: any = {
|
||||
container: {
|
||||
position: 'relative',
|
||||
margin: '0 auto',
|
||||
|
@ -91,22 +90,26 @@ const styles = {
|
|||
}
|
||||
};
|
||||
|
||||
type Props = {
|
||||
wallet: PrivKeyWallet
|
||||
};
|
||||
interface Props {
|
||||
wallet: PrivKeyWallet;
|
||||
}
|
||||
|
||||
export default class PaperWallet extends React.Component {
|
||||
props: Props;
|
||||
state = { address: '' };
|
||||
interface State {
|
||||
address: string;
|
||||
}
|
||||
export default class PaperWallet extends React.Component<Props, State> {
|
||||
public state = { address: '' };
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.wallet) return;
|
||||
this.props.wallet.getAddress().then(addr => {
|
||||
this.setState({ address: addr });
|
||||
public componentDidMount() {
|
||||
if (!this.props.wallet) {
|
||||
return;
|
||||
}
|
||||
this.props.wallet.getAddress().then(address => {
|
||||
this.setState({ address });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const privateKey = this.props.wallet.getPrivateKey();
|
||||
|
||||
return (
|
|
@ -1,22 +1,15 @@
|
|||
// @flow
|
||||
import { PaperWallet } from 'components';
|
||||
import PrivKeyWallet from 'libs/wallet/privkey';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import translate from 'translations';
|
||||
import printElement from 'utils/printElement';
|
||||
import { PaperWallet } from 'components';
|
||||
import type PrivKeyWallet from 'libs/wallet/privkey';
|
||||
|
||||
type Props = {
|
||||
wallet: PrivKeyWallet
|
||||
};
|
||||
interface Props {
|
||||
wallet: PrivKeyWallet;
|
||||
}
|
||||
|
||||
export default class PrintableWallet extends Component {
|
||||
props: Props;
|
||||
static propTypes = {
|
||||
wallet: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
print = () => {
|
||||
export default class PrintableWallet extends Component<Props, {}> {
|
||||
public print = () => {
|
||||
printElement(<PaperWallet wallet={this.props.wallet} />, {
|
||||
popupFeatures: {
|
||||
scrollbars: 'no'
|
||||
|
@ -36,7 +29,7 @@ export default class PrintableWallet extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
return (
|
||||
<div>
|
||||
<PaperWallet wallet={this.props.wallet} />
|
|
@ -1,24 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class Root extends Component {
|
||||
static propTypes = {
|
||||
store: PropTypes.object,
|
||||
history: PropTypes.object,
|
||||
routes: PropTypes.func
|
||||
};
|
||||
|
||||
render() {
|
||||
const { store, history, routes } = this.props;
|
||||
// key={Math.random()} = hack for HMR from https://github.com/webpack/webpack-dev-server/issues/395
|
||||
return (
|
||||
<Provider store={store} key={Math.random()}>
|
||||
<Router history={history} key={Math.random()}>
|
||||
{routes()}
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router, Route } from 'react-router-dom';
|
||||
// Components
|
||||
import ENS from 'containers/Tabs/ENS';
|
||||
import GenerateWallet from 'containers/Tabs/GenerateWallet';
|
||||
import Help from 'containers/Tabs/Help';
|
||||
import SendTransaction from 'containers/Tabs/SendTransaction';
|
||||
import Swap from 'containers/Tabs/Swap';
|
||||
import ViewWallet from 'containers/Tabs/ViewWallet';
|
||||
|
||||
// TODO: fix this
|
||||
interface Props {
|
||||
store: any;
|
||||
history: any;
|
||||
}
|
||||
|
||||
export default class Root extends Component<Props, {}> {
|
||||
public render() {
|
||||
const { store, history } = this.props;
|
||||
// key={Math.random()} = hack for HMR from https://github.com/webpack/webpack-dev-server/issues/395
|
||||
return (
|
||||
<Provider store={store} key={Math.random()}>
|
||||
<Router history={history} key={Math.random()}>
|
||||
<div>
|
||||
<Route exact={true} path="/" component={GenerateWallet} />
|
||||
<Route path="/view-wallet" component={ViewWallet} />
|
||||
<Route path="/help" component={Help} />
|
||||
<Route path="/swap" component={Swap} />
|
||||
<Route path="/send-transaction" component={SendTransaction} />
|
||||
<Route path="/ens" component={ENS} />
|
||||
</div>
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Markdown from 'react-markdown';
|
||||
import { translateRaw } from 'translations';
|
||||
|
||||
type Props = {
|
||||
translationKey: string
|
||||
};
|
||||
interface Props {
|
||||
translationKey: string;
|
||||
}
|
||||
|
||||
const Translate = ({ translationKey }: Props) => {
|
||||
const source = translateRaw(translationKey);
|
|
@ -1,60 +1,59 @@
|
|||
// @flow
|
||||
import './DeterministicWalletsModal.scss';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Modal from 'components/ui/Modal';
|
||||
import {
|
||||
getDeterministicWallets,
|
||||
setDesiredToken
|
||||
} from 'actions/deterministicWallets';
|
||||
import { getNetworkConfig } from 'selectors/config';
|
||||
import { getTokens } from 'selectors/wallet';
|
||||
import { isValidPath } from 'libs/validators';
|
||||
import type {
|
||||
DeterministicWalletData,
|
||||
GetDeterministicWalletsArgs,
|
||||
getDeterministicWallets,
|
||||
GetDeterministicWalletsAction,
|
||||
GetDeterministicWalletsArgs,
|
||||
setDesiredToken,
|
||||
SetDesiredTokenAction
|
||||
} from 'actions/deterministicWallets';
|
||||
import type { NetworkConfig, Token } from 'config/data';
|
||||
import Modal, { IButton } from 'components/ui/Modal';
|
||||
import { NetworkConfig, Token } from 'config/data';
|
||||
import { isValidPath } from 'libs/validators';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { getNetworkConfig } from 'selectors/config';
|
||||
import { getTokens, MergedToken } from 'selectors/wallet';
|
||||
import './DeterministicWalletsModal.scss';
|
||||
|
||||
const WALLETS_PER_PAGE = 5;
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
// Passed props
|
||||
isOpen?: boolean;
|
||||
walletType?: string;
|
||||
dPath: string;
|
||||
dPaths: { label: string; value: string }[];
|
||||
publicKey?: string;
|
||||
chainCode?: string;
|
||||
seed?: string;
|
||||
|
||||
// Redux state
|
||||
wallets: DeterministicWalletData[],
|
||||
desiredToken: string,
|
||||
network: NetworkConfig,
|
||||
tokens: Token[],
|
||||
wallets: DeterministicWalletData[];
|
||||
desiredToken: string;
|
||||
network: NetworkConfig;
|
||||
tokens: MergedToken[];
|
||||
|
||||
// Redux actions
|
||||
getDeterministicWallets: GetDeterministicWalletsArgs => GetDeterministicWalletsAction,
|
||||
setDesiredToken: (tkn: ?string) => SetDesiredTokenAction,
|
||||
getDeterministicWallets(
|
||||
args: GetDeterministicWalletsArgs
|
||||
): GetDeterministicWalletsAction;
|
||||
setDesiredToken(tkn: string | undefined): SetDesiredTokenAction;
|
||||
|
||||
// Passed props
|
||||
isOpen?: boolean,
|
||||
walletType: ?string,
|
||||
dPath: string,
|
||||
dPaths: { label: string, value: string }[],
|
||||
publicKey: ?string,
|
||||
chainCode: ?string,
|
||||
seed: ?string,
|
||||
onCancel: () => void,
|
||||
onConfirmAddress: (string, number) => void,
|
||||
onPathChange: string => void
|
||||
};
|
||||
onCancel(): void;
|
||||
onConfirmAddress(address: string, addressIndex: number): void;
|
||||
onPathChange(path: string): void;
|
||||
}
|
||||
|
||||
type State = {
|
||||
selectedAddress: string,
|
||||
selectedAddrIndex: number,
|
||||
isCustomPath: boolean,
|
||||
customPath: string,
|
||||
page: number
|
||||
};
|
||||
interface State {
|
||||
selectedAddress: string;
|
||||
selectedAddrIndex: number;
|
||||
isCustomPath: boolean;
|
||||
customPath: string;
|
||||
page: number;
|
||||
}
|
||||
|
||||
class DeterministicWalletsModal extends React.Component {
|
||||
props: Props;
|
||||
state: State = {
|
||||
class DeterministicWalletsModal extends React.Component<Props, State> {
|
||||
public state = {
|
||||
selectedAddress: '',
|
||||
selectedAddrIndex: 0,
|
||||
isCustomPath: false,
|
||||
|
@ -62,11 +61,11 @@ class DeterministicWalletsModal extends React.Component {
|
|||
page: 0
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this._getAddresses();
|
||||
public componentDidMount() {
|
||||
this.getAddresses();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
public componentWillReceiveProps(nextProps) {
|
||||
const { publicKey, chainCode, seed, dPath } = this.props;
|
||||
if (
|
||||
nextProps.publicKey !== publicKey ||
|
||||
|
@ -74,11 +73,125 @@ class DeterministicWalletsModal extends React.Component {
|
|||
nextProps.dPath !== dPath ||
|
||||
nextProps.seed !== seed
|
||||
) {
|
||||
this._getAddresses(nextProps);
|
||||
this.getAddresses(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
_getAddresses(props: Props = this.props) {
|
||||
public render() {
|
||||
const {
|
||||
wallets,
|
||||
desiredToken,
|
||||
network,
|
||||
tokens,
|
||||
dPath,
|
||||
dPaths,
|
||||
onCancel,
|
||||
walletType
|
||||
} = this.props;
|
||||
const { selectedAddress, isCustomPath, customPath, page } = this.state;
|
||||
const validPathClass = isValidPath(customPath) ? 'is-valid' : 'is-invalid';
|
||||
|
||||
const buttons: IButton[] = [
|
||||
{
|
||||
text: 'Unlock this Address',
|
||||
type: 'primary',
|
||||
onClick: this.handleConfirmAddress,
|
||||
disabled: !selectedAddress
|
||||
},
|
||||
{
|
||||
text: 'Cancel',
|
||||
type: 'default',
|
||||
onClick: onCancel
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={`Unlock your ${walletType || ''} Wallet`}
|
||||
isOpen={this.props.isOpen}
|
||||
buttons={buttons}
|
||||
handleClose={onCancel}
|
||||
>
|
||||
<div className="DWModal">
|
||||
<form
|
||||
className="DWModal-path form-group-sm"
|
||||
onSubmit={this.handleSubmitCustomPath}
|
||||
>
|
||||
<span className="DWModal-path-label">Addresses for</span>
|
||||
<select
|
||||
className="form-control"
|
||||
onChange={this.handleChangePath}
|
||||
value={isCustomPath ? 'custom' : dPath}
|
||||
>
|
||||
{dPaths.map(dp =>
|
||||
<option key={dp.value} value={dp.value}>
|
||||
{dp.label}
|
||||
</option>
|
||||
)}
|
||||
<option value="custom">Custom path...</option>
|
||||
</select>
|
||||
{isCustomPath &&
|
||||
<input
|
||||
className={`form-control ${validPathClass}`}
|
||||
value={customPath}
|
||||
placeholder="m/44'/60'/0'/0"
|
||||
onChange={this.handleChangeCustomPath}
|
||||
/>}
|
||||
</form>
|
||||
|
||||
<div className="DWModal-addresses">
|
||||
<table className="DWModal-addresses-table table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>Address</td>
|
||||
<td>
|
||||
{network.unit}
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
className="DWModal-addresses-table-token"
|
||||
value={desiredToken}
|
||||
onChange={this.handleChangeToken}
|
||||
>
|
||||
<option value="">-Token-</option>
|
||||
{tokens.map(t =>
|
||||
<option key={t.symbol} value={t.symbol}>
|
||||
{t.symbol}
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
</td>
|
||||
<td>More</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{wallets.map(wallet => this.renderWalletRow(wallet))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className="DWModal-addresses-nav">
|
||||
<button
|
||||
className="DWModal-addresses-nav-btn btn btn-sm btn-default"
|
||||
disabled={page === 0}
|
||||
onClick={this.prevPage}
|
||||
>
|
||||
← Back
|
||||
</button>
|
||||
<button
|
||||
className="DWModal-addresses-nav-btn btn btn-sm btn-default"
|
||||
onClick={this.nextPage}
|
||||
>
|
||||
More →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
private getAddresses(props: Props = this.props) {
|
||||
const { dPath, publicKey, chainCode, seed } = props;
|
||||
|
||||
if (dPath && ((publicKey && chainCode) || seed) && isValidPath(dPath)) {
|
||||
|
@ -93,8 +206,8 @@ class DeterministicWalletsModal extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_handleChangePath = (ev: SyntheticInputEvent) => {
|
||||
const { value } = ev.target;
|
||||
private handleChangePath = (ev: React.SyntheticEvent<HTMLSelectElement>) => {
|
||||
const { value } = ev.target as HTMLSelectElement;
|
||||
|
||||
if (value === 'custom') {
|
||||
this.setState({ isCustomPath: true });
|
||||
|
@ -106,21 +219,29 @@ class DeterministicWalletsModal extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
_handleChangeCustomPath = (ev: SyntheticInputEvent) => {
|
||||
this.setState({ customPath: ev.target.value });
|
||||
private handleChangeCustomPath = (
|
||||
ev: React.SyntheticEvent<HTMLInputElement>
|
||||
) => {
|
||||
this.setState({ customPath: (ev.target as HTMLInputElement).value });
|
||||
};
|
||||
|
||||
_handleSubmitCustomPath = (ev: SyntheticInputEvent) => {
|
||||
private handleSubmitCustomPath = (
|
||||
ev: React.SyntheticEvent<HTMLFormElement>
|
||||
) => {
|
||||
ev.preventDefault();
|
||||
if (!isValidPath(this.state.customPath)) return;
|
||||
if (!isValidPath(this.state.customPath)) {
|
||||
return;
|
||||
}
|
||||
this.props.onPathChange(this.state.customPath);
|
||||
};
|
||||
|
||||
_handleChangeToken = (ev: SyntheticInputEvent) => {
|
||||
this.props.setDesiredToken(ev.target.value || null);
|
||||
private handleChangeToken = (ev: React.SyntheticEvent<HTMLSelectElement>) => {
|
||||
this.props.setDesiredToken(
|
||||
(ev.target as HTMLSelectElement).value || undefined
|
||||
);
|
||||
};
|
||||
|
||||
_handleConfirmAddress = () => {
|
||||
private handleConfirmAddress = () => {
|
||||
if (this.state.selectedAddress) {
|
||||
this.props.onConfirmAddress(
|
||||
this.state.selectedAddress,
|
||||
|
@ -129,22 +250,22 @@ class DeterministicWalletsModal extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
_selectAddress(selectedAddress, selectedAddrIndex) {
|
||||
private selectAddress(selectedAddress, selectedAddrIndex) {
|
||||
this.setState({ selectedAddress, selectedAddrIndex });
|
||||
}
|
||||
|
||||
_nextPage = () => {
|
||||
this.setState({ page: this.state.page + 1 }, this._getAddresses);
|
||||
private nextPage = () => {
|
||||
this.setState({ page: this.state.page + 1 }, this.getAddresses);
|
||||
};
|
||||
|
||||
_prevPage = () => {
|
||||
private prevPage = () => {
|
||||
this.setState(
|
||||
{ page: Math.max(this.state.page - 1, 0) },
|
||||
this._getAddresses
|
||||
this.getAddresses
|
||||
);
|
||||
};
|
||||
|
||||
_renderWalletRow(wallet) {
|
||||
private renderWalletRow(wallet) {
|
||||
const { desiredToken, network } = this.props;
|
||||
const { selectedAddress } = this.state;
|
||||
|
||||
|
@ -157,7 +278,7 @@ class DeterministicWalletsModal extends React.Component {
|
|||
return (
|
||||
<tr
|
||||
key={wallet.address}
|
||||
onClick={this._selectAddress.bind(this, wallet.address, wallet.index)}
|
||||
onClick={this.selectAddress.bind(this, wallet.address, wallet.index)}
|
||||
>
|
||||
<td>
|
||||
{wallet.index + 1}
|
||||
|
@ -188,120 +309,6 @@ class DeterministicWalletsModal extends React.Component {
|
|||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
wallets,
|
||||
desiredToken,
|
||||
network,
|
||||
tokens,
|
||||
dPath,
|
||||
dPaths,
|
||||
onCancel,
|
||||
walletType
|
||||
} = this.props;
|
||||
const { selectedAddress, isCustomPath, customPath, page } = this.state;
|
||||
const validPathClass = isValidPath(customPath) ? 'is-valid' : 'is-invalid';
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
text: 'Unlock this Address',
|
||||
type: 'primary',
|
||||
onClick: this._handleConfirmAddress,
|
||||
disabled: !selectedAddress
|
||||
},
|
||||
{
|
||||
text: 'Cancel',
|
||||
type: 'default',
|
||||
onClick: onCancel
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={`Unlock your ${walletType || ''} Wallet`}
|
||||
isOpen={this.props.isOpen}
|
||||
buttons={buttons}
|
||||
handleClose={onCancel}
|
||||
>
|
||||
<div className="DWModal">
|
||||
<form
|
||||
className="DWModal-path form-group-sm"
|
||||
onSubmit={this._handleSubmitCustomPath}
|
||||
>
|
||||
<span className="DWModal-path-label">Addresses for</span>
|
||||
<select
|
||||
className="form-control"
|
||||
onChange={this._handleChangePath}
|
||||
value={isCustomPath ? 'custom' : dPath}
|
||||
>
|
||||
{dPaths.map(dp =>
|
||||
<option key={dp.value} value={dp.value}>
|
||||
{dp.label}
|
||||
</option>
|
||||
)}
|
||||
<option value="custom">Custom path...</option>
|
||||
</select>
|
||||
{isCustomPath &&
|
||||
<input
|
||||
className={`form-control ${validPathClass}`}
|
||||
value={customPath}
|
||||
placeholder="m/44'/60'/0'/0"
|
||||
onChange={this._handleChangeCustomPath}
|
||||
/>}
|
||||
</form>
|
||||
|
||||
<div className="DWModal-addresses">
|
||||
<table className="DWModal-addresses-table table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>Address</td>
|
||||
<td>
|
||||
{network.unit}
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
className="DWModal-addresses-table-token"
|
||||
value={desiredToken}
|
||||
onChange={this._handleChangeToken}
|
||||
>
|
||||
<option value="">-Token-</option>
|
||||
{tokens.map(t =>
|
||||
<option key={t.symbol} value={t.symbol}>
|
||||
{t.symbol}
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
</td>
|
||||
<td>More</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{wallets.map(wallet => this._renderWalletRow(wallet))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className="DWModal-addresses-nav">
|
||||
<button
|
||||
className="DWModal-addresses-nav-btn btn btn-sm btn-default"
|
||||
disabled={page === 0}
|
||||
onClick={this._prevPage}
|
||||
>
|
||||
← Back
|
||||
</button>
|
||||
<button
|
||||
className="DWModal-addresses-nav-btn btn btn-sm btn-default"
|
||||
onClick={this._nextPage}
|
||||
>
|
||||
More →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
|
@ -1,33 +1,33 @@
|
|||
import { isKeystorePassRequired } from 'libs/keystore';
|
||||
import React, { Component } from 'react';
|
||||
import translate, { translateRaw } from 'translations';
|
||||
import { isKeystorePassRequired } from 'libs/keystore';
|
||||
|
||||
export type KeystoreValue = {
|
||||
file: string,
|
||||
password: string,
|
||||
valid: boolean
|
||||
};
|
||||
export interface KeystoreValue {
|
||||
file: string;
|
||||
password: string;
|
||||
valid: boolean;
|
||||
}
|
||||
|
||||
function isPassRequired(file: string): boolean {
|
||||
let passReq = false;
|
||||
try {
|
||||
passReq = isKeystorePassRequired(file);
|
||||
} catch (e) {
|
||||
//TODO: communicate invalid file to user
|
||||
// TODO: communicate invalid file to user
|
||||
}
|
||||
return passReq;
|
||||
}
|
||||
|
||||
export default class KeystoreDecrypt extends Component {
|
||||
props: {
|
||||
value: KeystoreValue,
|
||||
onChange: (value: KeystoreValue) => void,
|
||||
onUnlock: () => void
|
||||
public props: {
|
||||
value: KeystoreValue;
|
||||
onChange(value: KeystoreValue): void;
|
||||
onUnlock(): void;
|
||||
};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const { file, password } = this.props.value;
|
||||
let passReq = isPassRequired(file);
|
||||
const passReq = isPassRequired(file);
|
||||
|
||||
return (
|
||||
<section className="col-md-4 col-sm-6">
|
||||
|
@ -47,7 +47,7 @@ export default class KeystoreDecrypt extends Component {
|
|||
<a
|
||||
className="btn btn-default btn-block"
|
||||
id="aria1"
|
||||
tabIndex="0"
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
{translate('ADD_Radio_2_short')}
|
||||
|
@ -74,7 +74,7 @@ export default class KeystoreDecrypt extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
onKeyDown = (e: SyntheticKeyboardEvent) => {
|
||||
public onKeyDown = (e: any) => {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -82,7 +82,7 @@ export default class KeystoreDecrypt extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
onPasswordChange = (e: SyntheticInputEvent) => {
|
||||
public onPasswordChange = (e: any) => {
|
||||
const valid = this.props.value.file.length && e.target.value.length;
|
||||
this.props.onChange({
|
||||
...this.props.value,
|
||||
|
@ -91,13 +91,14 @@ export default class KeystoreDecrypt extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
handleFileSelection = (e: SyntheticInputEvent) => {
|
||||
public handleFileSelection = (e: any) => {
|
||||
const fileReader = new FileReader();
|
||||
const inputFile = e.target.files[0];
|
||||
const target = e.target;
|
||||
const inputFile = target.files[0];
|
||||
|
||||
fileReader.onload = () => {
|
||||
const keystore = fileReader.result;
|
||||
let passReq = isPassRequired(keystore);
|
||||
const passReq = isPassRequired(keystore);
|
||||
|
||||
this.props.onChange({
|
||||
...this.props.value,
|
|
@ -1,27 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
|
||||
export default class LedgerNanoSDecrypt extends Component {
|
||||
render() {
|
||||
return (
|
||||
<section className="col-md-4 col-sm-6">
|
||||
<div id="selectedUploadKey">
|
||||
<h4>{translate('ADD_Radio_2_alt')}</h4>
|
||||
|
||||
<div className="form-group">
|
||||
<input type="file" id="fselector" />
|
||||
|
||||
<a
|
||||
className="btn-file marg-v-sm"
|
||||
id="aria1"
|
||||
tabIndex="0"
|
||||
role="button"
|
||||
>
|
||||
{translate('ADD_Radio_2_short')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
.LedgerDecrypt {
|
||||
text-align: center;
|
||||
padding-top: 30px;
|
||||
|
||||
&-decrypt {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-help {
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&-error {
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
|
||||
&.is-showing {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-buy {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
import './LedgerNano.scss';
|
||||
import React, { Component } from 'react';
|
||||
import translate, { translateRaw } from 'translations';
|
||||
import DeterministicWalletsModal from './DeterministicWalletsModal';
|
||||
import LedgerWallet from 'libs/wallet/ledger';
|
||||
import Ledger3 from 'vendor/ledger3';
|
||||
import LedgerEth from 'vendor/ledger-eth';
|
||||
import DPATHS from 'config/dpaths';
|
||||
|
||||
const DEFAULT_PATH = DPATHS.LEDGER[0].value;
|
||||
|
||||
interface Props {
|
||||
onUnlock(param: any): void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
publicKey: string;
|
||||
chainCode: string;
|
||||
dPath: string;
|
||||
error: string | null;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export default class LedgerNanoSDecrypt extends Component<Props, State> {
|
||||
public state: State = {
|
||||
publicKey: '',
|
||||
chainCode: '',
|
||||
dPath: DEFAULT_PATH,
|
||||
error: null,
|
||||
isLoading: false
|
||||
};
|
||||
|
||||
public render() {
|
||||
const { dPath, publicKey, chainCode, error, isLoading } = this.state;
|
||||
const showErr = error ? 'is-showing' : '';
|
||||
|
||||
return (
|
||||
<section className="LedgerDecrypt col-md-4 col-sm-6">
|
||||
<button
|
||||
className="LedgerDecrypt-decrypt btn btn-primary btn-lg"
|
||||
onClick={this.handleNullConnect}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Unlocking...' : translate('ADD_Ledger_scan')}
|
||||
</button>
|
||||
|
||||
<div className="LedgerDecrypt-help">
|
||||
Guides:
|
||||
<div>
|
||||
<a
|
||||
href="http://support.ledgerwallet.com/knowledge_base/topics/how-to-use-myetherwallet-with-ledger"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
How to use MyEtherWallet with your Nano S
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href="https://ledger.groovehq.com/knowledge_base/topics/how-to-secure-your-eth-tokens-augur-rep-dot-dot-dot-with-your-nano-s"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
How to secure your tokens with your Nano S
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={`LedgerDecrypt-error alert alert-danger ${showErr}`}>
|
||||
{error || '-'}
|
||||
</div>
|
||||
|
||||
<a
|
||||
className="LedgerDecrypt-buy btn btn-sm btn-default"
|
||||
href="https://www.ledgerwallet.com/r/fa4b?path=/products/"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{translate('Don’t have a Ledger? Order one now!')}
|
||||
</a>
|
||||
|
||||
<DeterministicWalletsModal
|
||||
isOpen={!!publicKey && !!chainCode}
|
||||
publicKey={publicKey}
|
||||
chainCode={chainCode}
|
||||
dPath={dPath}
|
||||
dPaths={DPATHS.LEDGER}
|
||||
onCancel={this.handleCancel}
|
||||
onConfirmAddress={this.handleUnlock}
|
||||
onPathChange={this.handlePathChange}
|
||||
walletType={translateRaw('x_Ledger')}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
private handlePathChange = (dPath: string) => {
|
||||
this.handleConnect(dPath);
|
||||
};
|
||||
|
||||
private handleConnect = (dPath: string = this.state.dPath) => {
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
error: null
|
||||
});
|
||||
|
||||
const ledger = new Ledger3('w0w');
|
||||
const ethApp = new LedgerEth(ledger);
|
||||
|
||||
ethApp.getAddress(
|
||||
dPath,
|
||||
(res, err) => {
|
||||
if (err) {
|
||||
err = ethApp.getError(err);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
this.setState({
|
||||
publicKey: res.publicKey,
|
||||
chainCode: res.chainCode,
|
||||
isLoading: false
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
error: err,
|
||||
isLoading: false
|
||||
});
|
||||
}
|
||||
},
|
||||
false,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
private handleCancel = () => {
|
||||
this.setState({
|
||||
publicKey: '',
|
||||
chainCode: '',
|
||||
dPath: DEFAULT_PATH
|
||||
});
|
||||
};
|
||||
|
||||
private handleUnlock = (address: string, index: number) => {
|
||||
this.props.onUnlock(new LedgerWallet(address, this.state.dPath, index));
|
||||
};
|
||||
|
||||
private handleNullConnect = (): void => {
|
||||
return this.handleConnect();
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue