mirror of
https://github.com/trezor/trezor-wallet
synced 2025-01-12 09:00:58 +00:00
Merge pull request #197 from trezor/fix/beta-disclaimer
added beta-wallet disclaimer
This commit is contained in:
commit
89cc455536
@ -7,11 +7,23 @@ import * as TOKEN from 'actions/constants/token';
|
|||||||
import * as DISCOVERY from 'actions/constants/discovery';
|
import * as DISCOVERY from 'actions/constants/discovery';
|
||||||
import * as STORAGE from 'actions/constants/localStorage';
|
import * as STORAGE from 'actions/constants/localStorage';
|
||||||
import * as PENDING from 'actions/constants/pendingTx';
|
import * as PENDING from 'actions/constants/pendingTx';
|
||||||
|
import * as WALLET from 'actions/constants/wallet';
|
||||||
import { httpRequest } from 'utils/networkUtils';
|
import { httpRequest } from 'utils/networkUtils';
|
||||||
import * as buildUtils from 'utils/build';
|
import * as buildUtils from 'utils/build';
|
||||||
|
|
||||||
|
import { findAccountTokens } from 'reducers/TokensReducer';
|
||||||
|
import type { Account } from 'reducers/AccountsReducer';
|
||||||
|
import type { Token } from 'reducers/TokensReducer';
|
||||||
|
import type { PendingTx } from 'reducers/PendingTxReducer';
|
||||||
|
import type { Discovery } from 'reducers/DiscoveryReducer';
|
||||||
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ThunkAction, AsyncAction, /* GetState, */ Dispatch,
|
TrezorDevice,
|
||||||
|
ThunkAction,
|
||||||
|
AsyncAction,
|
||||||
|
GetState,
|
||||||
|
Dispatch,
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
import type { Config, Network, TokensCollection } from 'reducers/LocalStorageReducer';
|
import type { Config, Network, TokensCollection } from 'reducers/LocalStorageReducer';
|
||||||
|
|
||||||
@ -31,7 +43,7 @@ export type StorageAction = {
|
|||||||
error: string,
|
error: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const get = (key: string): ?string => {
|
const get = (key: string): ?string => {
|
||||||
try {
|
try {
|
||||||
return window.localStorage.getItem(key);
|
return window.localStorage.getItem(key);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -40,168 +52,212 @@ export const get = (key: string): ?string => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function update(event: StorageEvent): AsyncAction {
|
const set = (key: string, value: string | boolean): void => {
|
||||||
return async (dispatch: Dispatch/* , getState: GetState */): Promise<void> => {
|
try {
|
||||||
if (!event.newValue) return;
|
window.localStorage.setItem(key, value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Local Storage ERROR: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (event.key === 'devices') {
|
// https://github.com/STRML/react-localstorage/blob/master/react-localstorage.js
|
||||||
// check if device was added/ removed
|
// or
|
||||||
// const newDevices: Array<TrezorDevice> = JSON.parse(event.newValue);
|
// https://www.npmjs.com/package/redux-react-session
|
||||||
// const myDevices: Array<TrezorDevice> = getState().connect.devices.filter(d => d.features);
|
|
||||||
|
|
||||||
// if (newDevices.length !== myDevices.length) {
|
const findAccounts = (devices: Array<TrezorDevice>, accounts: Array<Account>): Array<Account> => devices.reduce((arr, dev) => arr.concat(accounts.filter(a => a.deviceState === dev.state)), []);
|
||||||
// const diff = myDevices.filter(d => newDevices.indexOf(d) < 0)
|
|
||||||
// console.warn("DEV LIST CHANGED!", newDevices.length, myDevices.length, diff)
|
|
||||||
// // check if difference is caused by local device which is not saved
|
|
||||||
// // or device which was saved in other tab
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const diff = oldDevices.filter(d => newDevices.indexOf())
|
const findTokens = (accounts: Array<Account>, tokens: Array<Token>): Array<Token> => accounts.reduce((arr, account) => arr.concat(findAccountTokens(tokens, account)), []);
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'accounts') {
|
const findDiscovery = (devices: Array<TrezorDevice>, discovery: Array<Discovery>): Array<Discovery> => devices.reduce((arr, dev) => arr.concat(discovery.filter(a => a.deviceState === dev.state && a.publicKey.length > 0)), []);
|
||||||
dispatch({
|
|
||||||
type: ACCOUNT.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(event.newValue),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'tokens') {
|
const findPendingTxs = (accounts: Array<Account>, pending: Array<PendingTx>): Array<PendingTx> => accounts.reduce((result, account) => result.concat(pending.filter(p => p.address === account.address && p.network === account.network)), []);
|
||||||
dispatch({
|
|
||||||
type: TOKEN.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(event.newValue),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'pending') {
|
export const save = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||||
dispatch({
|
const devices: Array<TrezorDevice> = getState().devices.filter(d => d.features && d.remember === true);
|
||||||
type: PENDING.FROM_STORAGE,
|
const accounts: Array<Account> = findAccounts(devices, getState().accounts);
|
||||||
payload: JSON.parse(event.newValue),
|
const tokens: Array<Token> = findTokens(accounts, getState().tokens);
|
||||||
});
|
const pending: Array<PendingTx> = findPendingTxs(accounts, getState().pending);
|
||||||
}
|
const discovery: Array<Discovery> = findDiscovery(devices, getState().discovery);
|
||||||
|
|
||||||
if (event.key === 'discovery') {
|
// save devices
|
||||||
dispatch({
|
set('devices', JSON.stringify(devices));
|
||||||
type: DISCOVERY.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(event.newValue),
|
// save already preloaded accounts
|
||||||
});
|
set('accounts', JSON.stringify(accounts));
|
||||||
}
|
|
||||||
};
|
// save discovery state
|
||||||
}
|
set('discovery', JSON.stringify(discovery));
|
||||||
|
|
||||||
|
// tokens
|
||||||
|
set('tokens', JSON.stringify(tokens));
|
||||||
|
|
||||||
|
// pending transactions
|
||||||
|
set('pending', JSON.stringify(pending));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const update = (event: StorageEvent): ThunkAction => (dispatch: Dispatch): void => {
|
||||||
|
if (!event.newValue) return;
|
||||||
|
|
||||||
|
if (event.key === 'devices') {
|
||||||
|
// check if device was added/ removed
|
||||||
|
// const newDevices: Array<TrezorDevice> = JSON.parse(event.newValue);
|
||||||
|
// const myDevices: Array<TrezorDevice> = getState().connect.devices.filter(d => d.features);
|
||||||
|
|
||||||
|
// if (newDevices.length !== myDevices.length) {
|
||||||
|
// const diff = myDevices.filter(d => newDevices.indexOf(d) < 0)
|
||||||
|
// console.warn("DEV LIST CHANGED!", newDevices.length, myDevices.length, diff)
|
||||||
|
// // check if difference is caused by local device which is not saved
|
||||||
|
// // or device which was saved in other tab
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const diff = oldDevices.filter(d => newDevices.indexOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'accounts') {
|
||||||
|
dispatch({
|
||||||
|
type: ACCOUNT.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(event.newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'tokens') {
|
||||||
|
dispatch({
|
||||||
|
type: TOKEN.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(event.newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'pending') {
|
||||||
|
dispatch({
|
||||||
|
type: PENDING.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(event.newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'discovery') {
|
||||||
|
dispatch({
|
||||||
|
type: DISCOVERY.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(event.newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VERSION: string = '1';
|
const VERSION: string = '1';
|
||||||
|
|
||||||
export function loadTokensFromJSON(): AsyncAction {
|
const loadJSON = (): AsyncAction => async (dispatch: Dispatch): Promise<void> => {
|
||||||
return async (dispatch: Dispatch): Promise<void> => {
|
if (typeof window.localStorage === 'undefined') return;
|
||||||
if (typeof window.localStorage === 'undefined') return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const config: Config = await httpRequest(AppConfigJSON, 'json');
|
const config: Config = await httpRequest(AppConfigJSON, 'json');
|
||||||
|
|
||||||
if (!buildUtils.isDev()) {
|
if (!buildUtils.isDev()) {
|
||||||
const index = config.networks.findIndex(c => c.shortcut === 'trop');
|
const index = config.networks.findIndex(c => c.shortcut === 'trop');
|
||||||
delete config.networks[index];
|
delete config.networks[index];
|
||||||
}
|
|
||||||
|
|
||||||
const ERC20Abi = await httpRequest(Erc20AbiJSON, 'json');
|
|
||||||
|
|
||||||
window.addEventListener('storage', (event) => {
|
|
||||||
dispatch(update(event));
|
|
||||||
});
|
|
||||||
|
|
||||||
// validate version
|
|
||||||
const version: ?string = get('version');
|
|
||||||
if (version !== VERSION) {
|
|
||||||
window.localStorage.clear();
|
|
||||||
dispatch(save('version', VERSION));
|
|
||||||
}
|
|
||||||
|
|
||||||
// load tokens
|
|
||||||
const tokens = await config.networks.reduce(async (promise: Promise<TokensCollection>, network: Network): Promise<TokensCollection> => {
|
|
||||||
const collection: TokensCollection = await promise;
|
|
||||||
const json = await httpRequest(network.tokens, 'json');
|
|
||||||
collection[network.shortcut] = json;
|
|
||||||
return collection;
|
|
||||||
}, Promise.resolve({}));
|
|
||||||
|
|
||||||
const devices: ?string = get('devices');
|
|
||||||
if (devices) {
|
|
||||||
dispatch({
|
|
||||||
type: CONNECT.DEVICE_FROM_STORAGE,
|
|
||||||
payload: JSON.parse(devices),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const accounts: ?string = get('accounts');
|
|
||||||
if (accounts) {
|
|
||||||
dispatch({
|
|
||||||
type: ACCOUNT.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(accounts),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const userTokens: ?string = get('tokens');
|
|
||||||
if (userTokens) {
|
|
||||||
dispatch({
|
|
||||||
type: TOKEN.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(userTokens),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const pending: ?string = get('pending');
|
|
||||||
if (pending) {
|
|
||||||
dispatch({
|
|
||||||
type: PENDING.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(pending),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const discovery: ?string = get('discovery');
|
|
||||||
if (discovery) {
|
|
||||||
dispatch({
|
|
||||||
type: DISCOVERY.FROM_STORAGE,
|
|
||||||
payload: JSON.parse(discovery),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: STORAGE.READY,
|
|
||||||
config,
|
|
||||||
tokens,
|
|
||||||
ERC20Abi,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
dispatch({
|
|
||||||
type: STORAGE.ERROR,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadData = (): ThunkAction => (dispatch: Dispatch): void => {
|
const ERC20Abi = await httpRequest(Erc20AbiJSON, 'json');
|
||||||
// check if local storage is available
|
|
||||||
// let available: boolean = true;
|
|
||||||
// if (typeof window.localStorage === 'undefined') {
|
|
||||||
// available = false;
|
|
||||||
// } else {
|
|
||||||
// try {
|
|
||||||
// window.localStorage.setItem('ethereum_wallet', true);
|
|
||||||
// } catch (error) {
|
|
||||||
// available = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
dispatch(loadTokensFromJSON());
|
window.addEventListener('storage', (event) => {
|
||||||
|
dispatch(update(event));
|
||||||
|
});
|
||||||
|
|
||||||
|
// validate version
|
||||||
|
const version: ?string = get('version');
|
||||||
|
if (version !== VERSION) {
|
||||||
|
try {
|
||||||
|
window.localStorage.clear();
|
||||||
|
window.sessionStorage.clear();
|
||||||
|
} catch (error) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
set('version', VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load tokens
|
||||||
|
const tokens = await config.networks.reduce(async (promise: Promise<TokensCollection>, network: Network): Promise<TokensCollection> => {
|
||||||
|
const collection: TokensCollection = await promise;
|
||||||
|
const json = await httpRequest(network.tokens, 'json');
|
||||||
|
collection[network.shortcut] = json;
|
||||||
|
return collection;
|
||||||
|
}, Promise.resolve({}));
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: STORAGE.READY,
|
||||||
|
config,
|
||||||
|
tokens,
|
||||||
|
ERC20Abi,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
dispatch({
|
||||||
|
type: STORAGE.ERROR,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const save = (key: string, value: string): ThunkAction => (): void => {
|
|
||||||
if (typeof window.localStorage !== 'undefined') {
|
const loadStorageData = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||||
try {
|
const devices: ?string = get('devices');
|
||||||
window.localStorage.setItem(key, value);
|
if (devices) {
|
||||||
} catch (error) {
|
dispatch({
|
||||||
// available = false;
|
type: CONNECT.DEVICE_FROM_STORAGE,
|
||||||
console.error(`Local Storage ERROR: ${error}`);
|
payload: JSON.parse(devices),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const accounts: ?string = get('accounts');
|
||||||
|
if (accounts) {
|
||||||
|
dispatch({
|
||||||
|
type: ACCOUNT.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(accounts),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const userTokens: ?string = get('tokens');
|
||||||
|
if (userTokens) {
|
||||||
|
dispatch({
|
||||||
|
type: TOKEN.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(userTokens),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const pending: ?string = get('pending');
|
||||||
|
if (pending) {
|
||||||
|
dispatch({
|
||||||
|
type: PENDING.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(pending),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const discovery: ?string = get('discovery');
|
||||||
|
if (discovery) {
|
||||||
|
dispatch({
|
||||||
|
type: DISCOVERY.FROM_STORAGE,
|
||||||
|
payload: JSON.parse(discovery),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildUtils.isDev() || buildUtils.isBeta()) {
|
||||||
|
const betaModal = get('/betaModalPrivacy');
|
||||||
|
if (!betaModal) {
|
||||||
|
dispatch({
|
||||||
|
type: WALLET.SHOW_BETA_DISCLAIMER,
|
||||||
|
show: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const loadData = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
dispatch(loadStorageData());
|
||||||
|
|
||||||
|
// stop loading resources and wait for user action
|
||||||
|
if (!getState().wallet.showBetaDisclaimer) {
|
||||||
|
dispatch(loadJSON());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hideBetaDisclaimer = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||||
|
set('/betaModalPrivacy', true);
|
||||||
|
dispatch(loadJSON());
|
||||||
|
};
|
||||||
|
@ -119,7 +119,6 @@ export const onWalletTypeRequest = (device: TrezorDevice, hidden: boolean, state
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const gotoExternalWallet = (id: string, url: string): ThunkAction => (dispatch: Dispatch): void => {
|
export const gotoExternalWallet = (id: string, url: string): ThunkAction => (dispatch: Dispatch): void => {
|
||||||
console.warn('OPEN', id, url);
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: MODAL.OPEN_EXTERNAL_WALLET,
|
type: MODAL.OPEN_EXTERNAL_WALLET,
|
||||||
id,
|
id,
|
||||||
@ -127,7 +126,6 @@ export const gotoExternalWallet = (id: string, url: string): ThunkAction => (dis
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onPinSubmit,
|
onPinSubmit,
|
||||||
onPassphraseSubmit,
|
onPassphraseSubmit,
|
||||||
|
@ -153,7 +153,7 @@ export const getValidUrl = (action: RouterAction): PayloadAction<string> => (dis
|
|||||||
const shouldBeLandingPage = getState().devices.length < 1 || !getState().wallet.ready || getState().connect.error !== null;
|
const shouldBeLandingPage = getState().devices.length < 1 || !getState().wallet.ready || getState().connect.error !== null;
|
||||||
const landingPageUrl = dispatch(isLandingPageUrl(requestedUrl));
|
const landingPageUrl = dispatch(isLandingPageUrl(requestedUrl));
|
||||||
if (shouldBeLandingPage) {
|
if (shouldBeLandingPage) {
|
||||||
const landingPageRoute = dispatch(isLandingPageUrl(requestedUrl, true));
|
const landingPageRoute = dispatch(isLandingPageUrl(requestedUrl, getState().wallet.ready));
|
||||||
return !landingPageRoute ? '/' : requestedUrl;
|
return !landingPageRoute ? '/' : requestedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ export type WalletAction = {
|
|||||||
} | {
|
} | {
|
||||||
type: typeof WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA,
|
type: typeof WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA,
|
||||||
devices: Array<TrezorDevice>
|
devices: Array<TrezorDevice>
|
||||||
|
} | {
|
||||||
|
type: typeof WALLET.SHOW_BETA_DISCLAIMER | typeof WALLET.HIDE_BETA_DISCLAIMER,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||||
@ -51,6 +53,10 @@ export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
|||||||
window.addEventListener('offline', updateOnlineStatus);
|
window.addEventListener('offline', updateOnlineStatus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const hideBetaDisclaimer = (): WalletAction => ({
|
||||||
|
type: WALLET.HIDE_BETA_DISCLAIMER,
|
||||||
|
});
|
||||||
|
|
||||||
export const toggleDeviceDropdown = (opened: boolean): WalletAction => ({
|
export const toggleDeviceDropdown = (opened: boolean): WalletAction => ({
|
||||||
type: WALLET.TOGGLE_DEVICE_DROPDOWN,
|
type: WALLET.TOGGLE_DEVICE_DROPDOWN,
|
||||||
opened,
|
opened,
|
||||||
|
@ -6,5 +6,7 @@ export const ONLINE_STATUS: 'wallet__online_status' = 'wallet__online_status';
|
|||||||
|
|
||||||
export const SET_SELECTED_DEVICE: 'wallet__set_selected_device' = 'wallet__set_selected_device';
|
export const SET_SELECTED_DEVICE: 'wallet__set_selected_device' = 'wallet__set_selected_device';
|
||||||
export const UPDATE_SELECTED_DEVICE: 'wallet__update_selected_device' = 'wallet__update_selected_device';
|
export const UPDATE_SELECTED_DEVICE: 'wallet__update_selected_device' = 'wallet__update_selected_device';
|
||||||
|
export const SHOW_BETA_DISCLAIMER: 'wallet__show_beta_disclaimer' = 'wallet__show_beta_disclaimer';
|
||||||
|
export const HIDE_BETA_DISCLAIMER: 'wallet__hide_beta_disclaimer' = 'wallet__hide_beta_disclaimer';
|
||||||
|
|
||||||
export const CLEAR_UNAVAILABLE_DEVICE_DATA: 'wallet__clear_unavailable_device_data' = 'wallet__clear_unavailable_device_data';
|
export const CLEAR_UNAVAILABLE_DEVICE_DATA: 'wallet__clear_unavailable_device_data' = 'wallet__clear_unavailable_device_data';
|
@ -7,13 +7,13 @@ import * as MODAL from 'actions/constants/modal';
|
|||||||
import * as WALLET from 'actions/constants/wallet';
|
import * as WALLET from 'actions/constants/wallet';
|
||||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||||
|
|
||||||
|
|
||||||
import type { Action, RouterLocationState, TrezorDevice } from 'flowtype';
|
import type { Action, RouterLocationState, TrezorDevice } from 'flowtype';
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
ready: boolean;
|
ready: boolean;
|
||||||
online: boolean;
|
online: boolean;
|
||||||
dropdownOpened: boolean;
|
dropdownOpened: boolean;
|
||||||
|
showBetaDisclaimer: boolean;
|
||||||
initialParams: ?RouterLocationState;
|
initialParams: ?RouterLocationState;
|
||||||
initialPathname: ?string;
|
initialPathname: ?string;
|
||||||
disconnectRequest: ?TrezorDevice;
|
disconnectRequest: ?TrezorDevice;
|
||||||
@ -24,6 +24,7 @@ const initialState: State = {
|
|||||||
ready: false,
|
ready: false,
|
||||||
online: navigator.onLine,
|
online: navigator.onLine,
|
||||||
dropdownOpened: false,
|
dropdownOpened: false,
|
||||||
|
showBetaDisclaimer: false,
|
||||||
initialParams: null,
|
initialParams: null,
|
||||||
initialPathname: null,
|
initialPathname: null,
|
||||||
disconnectRequest: null,
|
disconnectRequest: null,
|
||||||
@ -86,6 +87,17 @@ export default function wallet(state: State = initialState, action: Action): Sta
|
|||||||
selectedDevice: action.device,
|
selectedDevice: action.device,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case WALLET.SHOW_BETA_DISCLAIMER:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
showBetaDisclaimer: true,
|
||||||
|
};
|
||||||
|
case WALLET.HIDE_BETA_DISCLAIMER:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
showBetaDisclaimer: false,
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
import { DEVICE } from 'trezor-connect';
|
import { DEVICE } from 'trezor-connect';
|
||||||
import * as LocalStorageActions from 'actions/LocalStorageActions';
|
import * as LocalStorageActions from 'actions/LocalStorageActions';
|
||||||
// import * as WalletActions from 'actions/WalletActions';
|
|
||||||
|
|
||||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||||
import * as TOKEN from 'actions/constants/token';
|
import * as TOKEN from 'actions/constants/token';
|
||||||
@ -9,95 +8,45 @@ import * as ACCOUNT from 'actions/constants/account';
|
|||||||
import * as DISCOVERY from 'actions/constants/discovery';
|
import * as DISCOVERY from 'actions/constants/discovery';
|
||||||
import * as SEND from 'actions/constants/send';
|
import * as SEND from 'actions/constants/send';
|
||||||
import * as PENDING from 'actions/constants/pendingTx';
|
import * as PENDING from 'actions/constants/pendingTx';
|
||||||
import { findAccountTokens } from 'reducers/TokensReducer';
|
import * as WALLET from 'actions/constants/wallet';
|
||||||
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
Middleware,
|
Middleware,
|
||||||
MiddlewareAPI,
|
MiddlewareAPI,
|
||||||
MiddlewareDispatch,
|
MiddlewareDispatch,
|
||||||
Dispatch,
|
|
||||||
Action,
|
Action,
|
||||||
GetState,
|
|
||||||
TrezorDevice,
|
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
|
|
||||||
import type { Account } from 'reducers/AccountsReducer';
|
|
||||||
import type { Token } from 'reducers/TokensReducer';
|
|
||||||
import type { PendingTx } from 'reducers/PendingTxReducer';
|
|
||||||
import type { Discovery } from 'reducers/DiscoveryReducer';
|
|
||||||
|
|
||||||
|
|
||||||
// https://github.com/STRML/react-localstorage/blob/master/react-localstorage.js
|
|
||||||
// or
|
|
||||||
// https://www.npmjs.com/package/redux-react-session
|
|
||||||
|
|
||||||
const findAccounts = (devices: Array<TrezorDevice>, accounts: Array<Account>): Array<Account> => devices.reduce((arr, dev) => arr.concat(accounts.filter(a => a.deviceState === dev.state)), []);
|
|
||||||
|
|
||||||
const findTokens = (accounts: Array<Account>, tokens: Array<Token>): Array<Token> => accounts.reduce((arr, account) => arr.concat(findAccountTokens(tokens, account)), []);
|
|
||||||
|
|
||||||
const findDiscovery = (devices: Array<TrezorDevice>, discovery: Array<Discovery>): Array<Discovery> => devices.reduce((arr, dev) => arr.concat(discovery.filter(a => a.deviceState === dev.state && a.publicKey.length > 0)), []);
|
|
||||||
|
|
||||||
const findPendingTxs = (accounts: Array<Account>, pending: Array<PendingTx>): Array<PendingTx> => accounts.reduce((result, account) => result.concat(pending.filter(p => p.address === account.address && p.network === account.network)), []);
|
|
||||||
|
|
||||||
const save = (dispatch: Dispatch, getState: GetState): void => {
|
|
||||||
const devices: Array<TrezorDevice> = getState().devices.filter(d => d.features && d.remember === true);
|
|
||||||
const accounts: Array<Account> = findAccounts(devices, getState().accounts);
|
|
||||||
const tokens: Array<Token> = findTokens(accounts, getState().tokens);
|
|
||||||
const pending: Array<PendingTx> = findPendingTxs(accounts, getState().pending);
|
|
||||||
const discovery: Array<Discovery> = findDiscovery(devices, getState().discovery);
|
|
||||||
|
|
||||||
// save devices
|
|
||||||
dispatch(LocalStorageActions.save('devices', JSON.stringify(devices)));
|
|
||||||
|
|
||||||
// save already preloaded accounts
|
|
||||||
dispatch(LocalStorageActions.save('accounts', JSON.stringify(accounts)));
|
|
||||||
|
|
||||||
// save discovery state
|
|
||||||
dispatch(LocalStorageActions.save('discovery', JSON.stringify(discovery)));
|
|
||||||
|
|
||||||
// tokens
|
|
||||||
dispatch(LocalStorageActions.save('tokens', JSON.stringify(tokens)));
|
|
||||||
|
|
||||||
// pending transactions
|
|
||||||
dispatch(LocalStorageActions.save('pending', JSON.stringify(pending)));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
|
const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
|
||||||
// Application live cycle starts here
|
// pass action
|
||||||
// if (action.type === LOCATION_CHANGE) {
|
|
||||||
// const { location } = api.getState().router;
|
|
||||||
// if (!location) {
|
|
||||||
// api.dispatch( WalletActions.init() );
|
|
||||||
// // load data from config.json and local storage
|
|
||||||
// api.dispatch( LocalStorageActions.loadData() );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
next(action);
|
next(action);
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case WALLET.HIDE_BETA_DISCLAIMER:
|
||||||
|
api.dispatch(LocalStorageActions.hideBetaDisclaimer());
|
||||||
|
break;
|
||||||
// first time saving
|
// first time saving
|
||||||
case CONNECT.REMEMBER:
|
case CONNECT.REMEMBER:
|
||||||
save(api.dispatch, api.getState);
|
api.dispatch(LocalStorageActions.save());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN.ADD:
|
case TOKEN.ADD:
|
||||||
case TOKEN.REMOVE:
|
case TOKEN.REMOVE:
|
||||||
case TOKEN.SET_BALANCE:
|
case TOKEN.SET_BALANCE:
|
||||||
save(api.dispatch, api.getState);
|
api.dispatch(LocalStorageActions.save());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACCOUNT.CREATE:
|
case ACCOUNT.CREATE:
|
||||||
case ACCOUNT.SET_BALANCE:
|
case ACCOUNT.SET_BALANCE:
|
||||||
case ACCOUNT.SET_NONCE:
|
case ACCOUNT.SET_NONCE:
|
||||||
save(api.dispatch, api.getState);
|
api.dispatch(LocalStorageActions.save());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DISCOVERY.START:
|
case DISCOVERY.START:
|
||||||
case DISCOVERY.STOP:
|
case DISCOVERY.STOP:
|
||||||
case DISCOVERY.COMPLETE:
|
case DISCOVERY.COMPLETE:
|
||||||
save(api.dispatch, api.getState);
|
api.dispatch(LocalStorageActions.save());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONNECT.FORGET:
|
case CONNECT.FORGET:
|
||||||
@ -107,13 +56,13 @@ const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: Middlewar
|
|||||||
case DEVICE.CHANGED:
|
case DEVICE.CHANGED:
|
||||||
case DEVICE.DISCONNECT:
|
case DEVICE.DISCONNECT:
|
||||||
case CONNECT.AUTH_DEVICE:
|
case CONNECT.AUTH_DEVICE:
|
||||||
save(api.dispatch, api.getState);
|
api.dispatch(LocalStorageActions.save());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEND.TX_COMPLETE:
|
case SEND.TX_COMPLETE:
|
||||||
case PENDING.TX_RESOLVED:
|
case PENDING.TX_RESOLVED:
|
||||||
case PENDING.TX_REJECTED:
|
case PENDING.TX_REJECTED:
|
||||||
save(api.dispatch, api.getState);
|
api.dispatch(LocalStorageActions.save());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
80
src/views/Landing/components/BetaDisclaimer/index.js
Normal file
80
src/views/Landing/components/BetaDisclaimer/index.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/* @flow */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
|
import colors from 'config/colors';
|
||||||
|
import icons from 'config/icons';
|
||||||
|
|
||||||
|
import Icon from 'components/Icon';
|
||||||
|
import Button from 'components/Button';
|
||||||
|
import P from 'components/Paragraph';
|
||||||
|
import { H2 } from 'components/Heading';
|
||||||
|
import * as WalletActions from 'actions/WalletActions';
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
background: rgba(0, 0, 0, 0.35);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ModalWindow = styled.div`
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: ${colors.WHITE};
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 620px;
|
||||||
|
padding: 24px 48px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledP = styled(P)`
|
||||||
|
padding: 10px 0px;
|
||||||
|
font-size: 14px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledButton = styled(Button)`
|
||||||
|
margin: 10px 0px;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledIcon = styled(Icon)`
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const BetaDisclaimer = (props: { close: () => void }) => (
|
||||||
|
<Wrapper>
|
||||||
|
<ModalWindow>
|
||||||
|
<H2>You are opening Trezor Beta Wallet</H2>
|
||||||
|
<StyledP><i>Trezor Beta Wallet</i> is a public feature-testing version of the <i>Trezor Wallet</i>, offering the newest features before they are available to the general public.</StyledP>
|
||||||
|
<StyledP>In contrast, <i>Trezor Wallet</i> is feature-conservative, making sure that its functionality is maximally reliable and dependable for the general public.</StyledP>
|
||||||
|
<StyledP>
|
||||||
|
<StyledIcon
|
||||||
|
size={24}
|
||||||
|
color={colors.WARNING_PRIMARY}
|
||||||
|
icon={icons.WARNING}
|
||||||
|
/>
|
||||||
|
Please note that the <i>Trezor Beta Wallet</i> might be collecting anonymized usage data, especially error logs, for development purposes. The <i>Trezor Wallet</i> does not log any data.
|
||||||
|
</StyledP>
|
||||||
|
<StyledButton onClick={props.close}>OK, I understand</StyledButton>
|
||||||
|
</ModalWindow>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
(dispatch: Dispatch) => ({
|
||||||
|
close: bindActionCreators(WalletActions.hideBetaDisclaimer, dispatch),
|
||||||
|
}),
|
||||||
|
)(BetaDisclaimer);
|
@ -4,6 +4,7 @@ import React from 'react';
|
|||||||
import { isWebUSB } from 'utils/device';
|
import { isWebUSB } from 'utils/device';
|
||||||
|
|
||||||
import LandingWrapper from 'views/Landing/components/LandingWrapper';
|
import LandingWrapper from 'views/Landing/components/LandingWrapper';
|
||||||
|
import BetaDisclaimer from 'views/Landing/components/BetaDisclaimer';
|
||||||
import BrowserNotSupported from 'views/Landing/components/BrowserNotSupported';
|
import BrowserNotSupported from 'views/Landing/components/BrowserNotSupported';
|
||||||
import ConnectDevice from 'views/Landing/components/ConnectDevice';
|
import ConnectDevice from 'views/Landing/components/ConnectDevice';
|
||||||
import InstallBridge from 'views/Landing/views/InstallBridge/Container';
|
import InstallBridge from 'views/Landing/views/InstallBridge/Container';
|
||||||
@ -16,6 +17,8 @@ const Root = (props: Props) => {
|
|||||||
const localStorageError = props.localStorage.error;
|
const localStorageError = props.localStorage.error;
|
||||||
const connectError = props.connect.error;
|
const connectError = props.connect.error;
|
||||||
|
|
||||||
|
if (props.wallet.showBetaDisclaimer) return <BetaDisclaimer />;
|
||||||
|
|
||||||
const error = !initialized ? (localStorageError || connectError) : null;
|
const error = !initialized ? (localStorageError || connectError) : null;
|
||||||
const shouldShowUnsupportedBrowser = browserState.supported === false;
|
const shouldShowUnsupportedBrowser = browserState.supported === false;
|
||||||
const shouldShowInstallBridge = initialized && connectError;
|
const shouldShowInstallBridge = initialized && connectError;
|
||||||
|
Loading…
Reference in New Issue
Block a user