1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-17 05:49:10 +00:00
trezor-wallet/src/actions/SelectedAccountActions.js

204 lines
6.7 KiB
JavaScript
Raw Normal View History

2018-02-20 09:30:36 +00:00
/* @flow */
import { LOCATION_CHANGE } from 'react-router-redux';
import { BLOCKCHAIN } from 'trezor-connect';
import * as WALLET from 'actions/constants/wallet';
2018-08-14 13:18:16 +00:00
import * as ACCOUNT from 'actions/constants/account';
import * as DISCOVERY from 'actions/constants/discovery';
import * as TOKEN from 'actions/constants/token';
import * as PENDING from 'actions/constants/pendingTx';
import * as SEND from 'actions/constants/send';
2018-09-26 12:11:37 +00:00
import * as reducerUtils from 'reducers/utils';
2018-02-20 09:30:36 +00:00
import type {
PayloadAction,
2018-07-30 10:52:13 +00:00
Action,
GetState,
Dispatch,
State,
2018-08-14 12:56:47 +00:00
} from 'flowtype';
2018-09-26 12:11:37 +00:00
type SelectedAccountState = $ElementType<State, 'selectedAccount'>;
2018-05-18 17:26:46 +00:00
export type SelectedAccountAction = {
2018-04-16 21:19:50 +00:00
type: typeof ACCOUNT.DISPOSE,
} | {
type: typeof ACCOUNT.UPDATE_SELECTED_ACCOUNT,
2018-09-26 12:11:37 +00:00
payload: SelectedAccountState,
2018-04-16 21:19:50 +00:00
};
2018-02-20 09:30:36 +00:00
2018-09-26 12:11:37 +00:00
type AccountStatus = {
type: string; // notification type
title: string; // notification title
message?: string; // notification message
shouldRender: boolean; // should render account page
2018-09-26 12:11:37 +00:00
}
2018-09-05 14:17:50 +00:00
export const dispose = (): Action => ({
type: ACCOUNT.DISPOSE,
});
2018-09-26 12:11:37 +00:00
const getAccountStatus = (state: State, selectedAccount: SelectedAccountState): ?AccountStatus => {
const device = state.wallet.selectedDevice;
if (!device || !device.state) {
return {
type: 'loader-progress',
2018-09-26 12:11:37 +00:00
title: 'Loading device...',
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
}
const {
account,
discovery,
network,
} = selectedAccount;
// corner case: accountState didn't finish loading state after LOCATION_CHANGE action
if (!network) {
return {
type: 'loader-progress',
2018-09-26 12:11:37 +00:00
title: 'Loading account state...',
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
}
2018-02-20 09:30:36 +00:00
2018-10-15 13:44:10 +00:00
const blockchain = state.blockchain.find(b => b.shortcut === network.shortcut);
2018-09-26 12:11:37 +00:00
if (blockchain && !blockchain.connected) {
return {
type: 'backend',
title: `${network.name} backend is not connected`,
shouldRender: false,
2018-07-30 10:52:13 +00:00
};
2018-09-26 12:11:37 +00:00
}
2018-09-26 12:11:37 +00:00
// account not found (yet). checking why...
if (!account) {
if (!discovery || (discovery.waitingForDevice || discovery.interrupted)) {
2018-09-26 12:11:37 +00:00
if (device.connected) {
// case 1: device is connected but discovery not started yet (probably waiting for auth)
if (device.available) {
return {
type: 'loader-progress',
title: 'Authenticating device...',
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
}
2018-09-26 12:11:37 +00:00
// case 2: device is unavailable (created with different passphrase settings) account cannot be accessed
return {
type: 'loader-info',
2018-09-26 12:11:37 +00:00
title: `Device ${device.instanceLabel} is unavailable`,
message: 'Change passphrase settings to use this device',
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
2018-07-30 10:52:13 +00:00
}
2018-09-26 12:11:37 +00:00
// case 3: device is disconnected
return {
type: 'loader-info',
2018-09-26 12:11:37 +00:00
title: `Device ${device.instanceLabel} is disconnected`,
message: 'Connect device to load accounts',
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
}
if (discovery.completed) {
// case 4: account not found and discovery is completed
return {
type: 'loader-info',
2018-09-26 12:11:37 +00:00
title: 'Account does not exist',
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
}
}
// Additional status: account does exists and it's visible but shouldn't be active
if (!device.connected) {
return {
type: 'info',
title: `Device ${device.instanceLabel} is disconnected`,
shouldRender: true,
2018-09-26 12:11:37 +00:00
};
}
if (!device.available) {
return {
type: 'info',
title: `Device ${device.instanceLabel} is unavailable`,
message: 'Change passphrase settings to use this device',
shouldRender: true,
2018-09-26 12:11:37 +00:00
};
}
return null;
};
// list of all actions which has influence on "selectedAccount" reducer
// other actions will be ignored
const actions = [
LOCATION_CHANGE,
...Object.values(BLOCKCHAIN).filter(v => typeof v === 'string'),
SEND.TX_COMPLETE,
WALLET.SET_SELECTED_DEVICE,
WALLET.UPDATE_SELECTED_DEVICE,
...Object.values(ACCOUNT).filter(v => typeof v === 'string' && v !== ACCOUNT.UPDATE_SELECTED_ACCOUNT && v !== ACCOUNT.DISPOSE), // exported values got unwanted "__esModule: true" as first element
...Object.values(DISCOVERY).filter(v => typeof v === 'string'),
...Object.values(TOKEN).filter(v => typeof v === 'string'),
...Object.values(PENDING).filter(v => typeof v === 'string'),
];
/*
* Called from WalletService
*/
export const observe = (prevState: State, action: Action): PayloadAction<boolean> => (dispatch: Dispatch, getState: GetState): boolean => {
// ignore not listed actions
if (actions.indexOf(action.type) < 0) return false;
2018-09-26 12:11:37 +00:00
const state: State = getState();
const notification = {
type: null,
message: null,
title: null,
};
2018-09-26 12:11:37 +00:00
const { location } = state.router;
// displayed route is not an account route
if (!location.state.account) return false;
2018-09-26 12:11:37 +00:00
// get new values for selected account
const account = reducerUtils.getSelectedAccount(state);
const network = reducerUtils.getSelectedNetwork(state);
const discovery = reducerUtils.getDiscoveryProcess(state);
const tokens = reducerUtils.getAccountTokens(state, account);
const pending = reducerUtils.getAccountPendingTx(state.pending, account);
// prepare new state for "selectedAccount" reducer
const newState: SelectedAccountState = {
location: state.router.location.pathname,
account,
network,
discovery,
tokens,
pending,
notification,
shouldRender: false,
2018-09-26 12:11:37 +00:00
};
2018-09-26 12:11:37 +00:00
// get "selectedAccount" status from newState
const status = getAccountStatus(state, newState);
newState.notification = status || notification;
newState.shouldRender = status ? status.shouldRender : true;
2018-09-26 12:11:37 +00:00
// check if newState is different than previous state
const stateChanged = reducerUtils.observeChanges(prevState.selectedAccount, newState, {
account: ['balance', 'nonce'],
discovery: ['accountIndex', 'interrupted', 'completed', 'waitingForBlockchain', 'waitingForDevice'],
});
2018-09-26 12:11:37 +00:00
if (stateChanged) {
// update values in reducer
dispatch({
type: ACCOUNT.UPDATE_SELECTED_ACCOUNT,
payload: newState,
});
2018-02-20 09:30:36 +00:00
}
return stateChanged;
2018-07-30 10:52:13 +00:00
};