From 1aad9d1c2150ba84c31afa91056c6e56418ffc87 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Thu, 27 Jul 2017 13:05:09 -0400 Subject: [PATCH] Standardize Redux Actions / Reducers (#95) * Convert Swap to consistent style * Generate wallet reducer cleanup. * Confirm empty action in swap reducer * Union types. Fix gen wallet collision * Fix not using all actions in reducer. Added reducer state for is fetching from bity. Added todo to make that a loader. * Readme instructions. * Remove common action constants. * Bring all actions and reducers inline with readme instructions. * Readme fixes * address comments --- README.md | 85 +++++++++ common/actions/common.js | 4 - common/actions/config.js | 36 ++-- common/actions/customTokens.js | 17 +- common/actions/ens.js | 23 ++- common/actions/generateWallet.js | 43 +++-- common/actions/generateWalletConstants.js | 6 - common/actions/notifications.js | 22 ++- common/actions/rates.js | 6 +- common/actions/swap.js | 173 ++++++++++++------ common/actions/swapConstants.js | 11 -- common/actions/swapTypes.js | 66 ------- common/actions/wallet.js | 51 +++--- .../components/DownloadWallet.jsx | 38 ++-- .../components/EnterPassword.jsx | 48 +++-- .../components/PasswordInput.jsx | 34 ++-- .../containers/Tabs/GenerateWallet/index.js | 53 +++--- .../Tabs/Swap/components/CurrencySwap.js | 20 +- .../Tabs/Swap/components/CurrentRates.js | 2 +- .../Tabs/Swap/components/ReceivingAddress.js | 16 +- .../Tabs/Swap/components/SwapInfoHeader.js | 9 +- common/containers/Tabs/Swap/index.js | 39 ++-- common/reducers/config.js | 4 +- common/reducers/customTokens.js | 4 +- common/reducers/ens.js | 4 +- common/reducers/generateWallet.js | 43 ++--- common/reducers/index.js | 6 +- common/reducers/notifications.js | 4 +- common/reducers/rates.js | 7 +- common/reducers/swap.js | 103 +++++++---- common/reducers/wallet.js | 4 +- common/sagas/bity.js | 9 +- 32 files changed, 542 insertions(+), 448 deletions(-) delete mode 100644 common/actions/common.js delete mode 100644 common/actions/generateWalletConstants.js delete mode 100644 common/actions/swapConstants.js delete mode 100644 common/actions/swapTypes.js diff --git a/README.md b/README.md index 76f6ada6..f67cbc1f 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,91 @@ docker-compose up The following are guides for developers to follow for writing compliant code. + + +### Redux and Actions + +Each reducer has one file in `reducers/[namespace].js` that contains the reducer +and initial state, one file in `actions/[namespace].js` that contains the action +creators and their return types, and optionally one file in +`sagas/[namespace].js` that handles action side effects using +[`redux-saga`](https://github.com/redux-saga/redux-saga). + +The files should be laid out as follows: + +#### Reducer + +* State should be explicitly defined and exported +* Initial state should match state flow typing, define every key +* Reducer function should handle all cases for actions. If state does not change +as a result of an action (Because it merely kicks off side-effects in saga) then +define the case above default, and have it fall through. + +```js +// @flow +import type { NamespaceAction } from "actions/namespace"; + +export type State = { /* Flowtype definition for state object */ }; +export const INITIAL_STATE: State = { /* Initial state shape */ }; + +export function namespace( + state: State = INITIAL_STATE, + action: NamespaceAction +): State { + switch (action.type) { + case 'NAMESPACE_NAME_OF_ACTION': + return { + ...state, + // Alterations to state + }; + + case 'NAMESPACE_NAME_OF_SAGA_ACTION': + default: + // Ensures every action was handled in reducer + // Unhandled actions should just fall into default + (action: empty); + return state; + } +} +``` + +#### Actions + +* Define each action object type beside the action creator +* Export a union of all of the action types for use by the reducer + +```js +/*** Name of action ***/ +export type NameOfActionAction = { + type: 'NAMESPACE_NAME_OF_ACTION', + /* Rest of the action object shape */ +}; + +export function nameOfAction(): NameOfActionAction { + return { + type: 'NAMESPACE_NAME_OF_ACTION', + /* Rest of the action object */ + }; +}; + +/*** Action Union ***/ +export type NamespaceAction = + | ActionOneAction + | ActionTwoAction + | ActionThreeAction; +``` + +#### Action Constants + +Action constants are not used thanks to flow type checking. To avoid typos, we +use `(action: empty)` in the default case which assures every case is accounted +for. If you need to use another reducer's action, import that action type into +your reducer, and create a new action union of your actions, and the other +action types used. + + + + ### Styling Legacy styles are housed under `common/assets/styles` and written with LESS. diff --git a/common/actions/common.js b/common/actions/common.js deleted file mode 100644 index 550cab47..00000000 --- a/common/actions/common.js +++ /dev/null @@ -1,4 +0,0 @@ -export const LOCATION_CHANGE = '@@router/LOCATION_CHANGE'; -// I'm not sure, but I guess that if you use redux-devtools extension your APP_INIT should be look like: -// export const APP_INIT = '@@INIT' -export const APP_INIT = '@@redux/INIT'; diff --git a/common/actions/config.js b/common/actions/config.js index 71ce8a59..3f940abe 100644 --- a/common/actions/config.js +++ b/common/actions/config.js @@ -1,30 +1,25 @@ // @flow -export type ChangeNodeAction = { - type: 'CONFIG_NODE_CHANGE', - // FIXME $keyof? - value: string -}; - +/*** Change Language ***/ export type ChangeLanguageAction = { type: 'CONFIG_LANGUAGE_CHANGE', value: string }; -export type ChangeGasPriceAction = { - type: 'CONFIG_GAS_PRICE', - value: number -} - -export type ConfigAction = ChangeNodeAction | ChangeLanguageAction; - -export function changeLanguage(sign: 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', @@ -32,10 +27,21 @@ export function changeNode(value: string): ChangeNodeAction { }; } +/*** 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; diff --git a/common/actions/customTokens.js b/common/actions/customTokens.js index 215a4376..4512fe85 100644 --- a/common/actions/customTokens.js +++ b/common/actions/customTokens.js @@ -1,18 +1,12 @@ // @flow import type { Token } from 'config/data'; +/*** Add custom token ***/ export type AddCustomTokenAction = { type: 'CUSTOM_TOKEN_ADD', payload: Token }; -export type RemoveCustomTokenAction = { - type: 'CUSTOM_TOKEN_REMOVE', - payload: string -}; - -export type CustomTokenAction = AddCustomTokenAction | RemoveCustomTokenAction; - export function addCustomToken(payload: Token): AddCustomTokenAction { return { type: 'CUSTOM_TOKEN_ADD', @@ -20,9 +14,18 @@ export function addCustomToken(payload: Token): AddCustomTokenAction { }; } +/*** 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; diff --git a/common/actions/ens.js b/common/actions/ens.js index 45f2d3b1..102bfcb3 100644 --- a/common/actions/ens.js +++ b/common/actions/ens.js @@ -1,20 +1,11 @@ // @flow +/*** Resolve ENS name ***/ export type ResolveEnsNameAction = { type: 'ENS_RESOLVE', payload: string }; -export type CacheEnsAddressAction = { - type: 'ENS_CACHE', - payload: { - ensName: string, - address: string - } -}; - -export type EnsAction = ResolveEnsNameAction | CacheEnsAddressAction; - export function resolveEnsName(name: string): ResolveEnsNameAction { return { type: 'ENS_RESOLVE', @@ -22,6 +13,15 @@ export function resolveEnsName(name: string): ResolveEnsNameAction { }; } +/*** Cache ENS address ***/ +export type CacheEnsAddressAction = { + type: 'ENS_CACHE', + payload: { + ensName: string, + address: string + } +}; + export function cacheEnsAddress( ensName: string, address: string @@ -34,3 +34,6 @@ export function cacheEnsAddress( } }; } + +/*** Union Type ***/ +export type EnsAction = ResolveEnsNameAction | CacheEnsAddressAction; diff --git a/common/actions/generateWallet.js b/common/actions/generateWallet.js index 0db1cba0..d441fe16 100644 --- a/common/actions/generateWallet.js +++ b/common/actions/generateWallet.js @@ -1,33 +1,38 @@ // @flow -import { - GENERATE_WALLET_CONFIRM_CONTINUE_TO_PAPER, - GENERATE_WALLET_FILE, - GENERATE_WALLET_DOWNLOAD_FILE, - GENERATE_WALLET_SHOW_PASSWORD, - RESET_GENERATE_WALLET -} from 'actions/generateWalletConstants'; import { PrivKeyWallet } from 'libs/wallet'; -export const showPasswordGenerateWallet = () => { - return { type: GENERATE_WALLET_SHOW_PASSWORD }; +/*** Generate Wallet File ***/ +export type GenerateNewWalletAction = { + type: 'GENERATE_WALLET_GENERATE_WALLET', + wallet: PrivKeyWallet, + password: string }; -export const generateUTCGenerateWallet = (password: string) => { +export function generateNewWallet(password: string): GenerateNewWalletAction { return { - type: GENERATE_WALLET_FILE, + type: 'GENERATE_WALLET_GENERATE_WALLET', wallet: PrivKeyWallet.generate(), password }; +} + +/*** Confirm Continue To Paper ***/ +export type ContinueToPaperAction = { + type: 'GENERATE_WALLET_CONTINUE_TO_PAPER' }; -export const downloadUTCGenerateWallet = () => { - return { type: GENERATE_WALLET_DOWNLOAD_FILE }; +export function continueToPaper(): ContinueToPaperAction { + return { type: 'GENERATE_WALLET_CONTINUE_TO_PAPER' }; +} + +/*** Reset Generate Wallet ***/ +export type ResetGenerateWalletAction = { + type: 'GENERATE_WALLET_RESET' }; -export const confirmContinueToPaperGenerateWallet = () => { - return { type: GENERATE_WALLET_CONFIRM_CONTINUE_TO_PAPER }; -}; +export function resetGenerateWallet(): ResetGenerateWalletAction { + return { type: 'GENERATE_WALLET_RESET' }; +} -export const resetGenerateWallet = () => { - return { type: RESET_GENERATE_WALLET }; -}; +/*** Action Union ***/ +export type GenerateWalletAction = GenerateWalletAction; diff --git a/common/actions/generateWalletConstants.js b/common/actions/generateWalletConstants.js deleted file mode 100644 index e212db52..00000000 --- a/common/actions/generateWalletConstants.js +++ /dev/null @@ -1,6 +0,0 @@ -export const GENERATE_WALLET_SHOW_PASSWORD = 'GENERATE_WALLET_SHOW_PASSWORD'; -export const GENERATE_WALLET_FILE = 'GENERATE_WALLET_FILE'; -export const GENERATE_WALLET_DOWNLOAD_FILE = 'GENERATE_WALLET_DOWNLOAD_FILE'; -export const GENERATE_WALLET_CONFIRM_CONTINUE_TO_PAPER = - 'GENERATE_WALLET_CONFIRM_CONTINUE_TO_PAPER'; -export const RESET_GENERATE_WALLET = 'RESET_GENERATE_WALLET'; diff --git a/common/actions/notifications.js b/common/actions/notifications.js index be8fd623..8f0a8cdc 100644 --- a/common/actions/notifications.js +++ b/common/actions/notifications.js @@ -1,5 +1,6 @@ // @flow +/*** Shared types ***/ export type NOTIFICATION_LEVEL = 'danger' | 'warning' | 'success' | 'info'; export type Notification = { @@ -8,20 +9,12 @@ export type Notification = { duration?: number }; +/*** Show Notification ***/ export type ShowNotificationAction = { type: 'SHOW_NOTIFICATION', payload: Notification }; -export type CloseNotificationAction = { - type: 'CLOSE_NOTIFICATION', - payload: Notification -}; - -export type NotificationsAction = - | ShowNotificationAction - | CloseNotificationAction; - export function showNotification( level: NOTIFICATION_LEVEL = 'info', msg: string, @@ -37,6 +30,12 @@ export function showNotification( }; } +/*** Close notification ***/ +export type CloseNotificationAction = { + type: 'CLOSE_NOTIFICATION', + payload: Notification +}; + export function closeNotification( notification: Notification ): CloseNotificationAction { @@ -45,3 +44,8 @@ export function closeNotification( payload: notification }; } + +/*** Union Type ***/ +export type NotificationsAction = + | ShowNotificationAction + | CloseNotificationAction; diff --git a/common/actions/rates.js b/common/actions/rates.js index 37b1d5b6..fd62b6d0 100644 --- a/common/actions/rates.js +++ b/common/actions/rates.js @@ -1,15 +1,17 @@ // @flow +/*** Set rates ***/ export type SetRatesAction = { type: 'RATES_SET', payload: { [string]: number } }; -export type RatesAction = SetRatesAction; - export function setRates(payload: { [string]: number }): SetRatesAction { return { type: 'RATES_SET', payload }; } + +/*** Union Type ***/ +export type RatesAction = SetRatesAction; diff --git a/common/actions/swap.js b/common/actions/swap.js index dc209571..309a51bd 100644 --- a/common/actions/swap.js +++ b/common/actions/swap.js @@ -1,104 +1,163 @@ // @flow -import { - SWAP_DESTINATION_AMOUNT, - SWAP_DESTINATION_KIND, - SWAP_ORIGIN_AMOUNT, - SWAP_ORIGIN_KIND, - SWAP_UPDATE_BITY_RATES, - SWAP_DESTINATION_ADDRESS, - SWAP_RESTART, - SWAP_LOAD_BITY_RATES, - SWAP_STOP_LOAD_BITY_RATES, - SWAP_STEP, - SWAP_REFERENCE_NUMBER -} from './swapConstants'; -import * as swapTypes from './swapTypes'; +/*** Change Step ***/ +export type ChangeStepSwapAction = { + type: 'SWAP_STEP', + value: number +}; -export function changeStepSwap(value: number): swapTypes.ChangeStepSwapAction { +export function changeStepSwap(value: number): ChangeStepSwapAction { return { - type: SWAP_STEP, + type: 'SWAP_STEP', value }; } -export function referenceNumberSwap( +/*** Change Reference Number ***/ +export type ReferenceNumberSwapAction = { + type: 'SWAP_REFERENCE_NUMBER', value: string -): swapTypes.ReferenceNumberSwapAction { +}; + +export function referenceNumberSwap(value: string): ReferenceNumberSwapAction { return { - type: SWAP_REFERENCE_NUMBER, + type: 'SWAP_REFERENCE_NUMBER', value }; } -export const originKindSwap = ( +/*** Change Origin Kind ***/ +export type OriginKindSwapAction = { + type: 'SWAP_ORIGIN_KIND', value: string -): swapTypes.OriginKindSwapAction => { - return { - type: SWAP_ORIGIN_KIND, - value - }; }; -export const destinationKindSwap = ( +export function originKindSwap(value: string): OriginKindSwapAction { + return { + type: 'SWAP_ORIGIN_KIND', + value + }; +} + +/*** Change Destination Kind ***/ +export type DestinationKindSwapAction = { + type: 'SWAP_DESTINATION_KIND', value: string -): swapTypes.DestinationKindSwapAction => { - return { - type: SWAP_DESTINATION_KIND, - value - }; }; -export const originAmountSwap = ( +export function destinationKindSwap(value: string): DestinationKindSwapAction { + return { + type: 'SWAP_DESTINATION_KIND', + value + }; +} + +/*** Change Origin Amount ***/ +export type OriginAmountSwapAction = { + type: 'SWAP_ORIGIN_AMOUNT', value: ?number -): swapTypes.OriginAmountSwapAction => { - return { - type: SWAP_ORIGIN_AMOUNT, - value - }; }; -export const destinationAmountSwap = ( +export function originAmountSwap(value: ?number): OriginAmountSwapAction { + return { + type: 'SWAP_ORIGIN_AMOUNT', + value + }; +} + +/*** Change Destination Amount ***/ +export type DestinationAmountSwapAction = { + type: 'SWAP_DESTINATION_AMOUNT', value: ?number -): swapTypes.DestinationAmountSwapAction => { - return { - type: SWAP_DESTINATION_AMOUNT, - value - }; }; -export const updateBityRatesSwap = ( - value: swapTypes.Pairs -): swapTypes.BityRatesSwapAction => { +export function destinationAmountSwap( + value: ?number +): DestinationAmountSwapAction { return { - type: SWAP_UPDATE_BITY_RATES, + type: 'SWAP_DESTINATION_AMOUNT', value }; +} + +/*** Update Bity Rates ***/ +export type Pairs = { + ETHBTC: number, + ETHREP: number, + BTCETH: number, + BTCREP: number }; -export const destinationAddressSwap = ( +export type BityRatesSwapAction = { + type: 'SWAP_UPDATE_BITY_RATES', + value: Pairs +}; + +export function updateBityRatesSwap(value: Pairs): BityRatesSwapAction { + return { + type: 'SWAP_UPDATE_BITY_RATES', + value + }; +} + +/*** Change Destination Address ***/ +export type DestinationAddressSwapAction = { + type: 'SWAP_DESTINATION_ADDRESS', value: ?string -): swapTypes.DestinationAddressSwapAction => { +}; + +export function destinationAddressSwap( + value: ?string +): DestinationAddressSwapAction { return { - type: SWAP_DESTINATION_ADDRESS, + type: 'SWAP_DESTINATION_ADDRESS', value }; +} + +/*** Restart ***/ +export type RestartSwapAction = { + type: 'SWAP_RESTART' }; -export const restartSwap = (): swapTypes.RestartSwapAction => { +export function restartSwap(): RestartSwapAction { return { - type: SWAP_RESTART + type: 'SWAP_RESTART' }; +} + +/*** Load Bity Rates ***/ +export type LoadBityRatesSwapAction = { + type: 'SWAP_LOAD_BITY_RATES' }; -export const loadBityRatesSwap = (): swapTypes.LoadBityRatesSwapAction => { +export function loadBityRatesSwap(): LoadBityRatesSwapAction { return { - type: SWAP_LOAD_BITY_RATES + type: 'SWAP_LOAD_BITY_RATES' }; +} + +/*** Stop Loading Bity Rates ***/ +export type StopLoadBityRatesSwapAction = { + type: 'SWAP_STOP_LOAD_BITY_RATES' }; -export const stopLoadBityRatesSwap = (): swapTypes.StopLoadBityRatesSwapAction => { +export function stopLoadBityRatesSwap(): StopLoadBityRatesSwapAction { return { - type: SWAP_STOP_LOAD_BITY_RATES + type: 'SWAP_STOP_LOAD_BITY_RATES' }; -}; +} + +/*** Action Type Union ***/ +export type SwapAction = + | ChangeStepSwapAction + | ReferenceNumberSwapAction + | OriginKindSwapAction + | DestinationKindSwapAction + | OriginAmountSwapAction + | DestinationAmountSwapAction + | BityRatesSwapAction + | DestinationAddressSwapAction + | RestartSwapAction + | LoadBityRatesSwapAction + | StopLoadBityRatesSwapAction; diff --git a/common/actions/swapConstants.js b/common/actions/swapConstants.js deleted file mode 100644 index 9360a14e..00000000 --- a/common/actions/swapConstants.js +++ /dev/null @@ -1,11 +0,0 @@ -export const SWAP_ORIGIN_KIND = 'SWAP_ORIGIN_KIND'; -export const SWAP_DESTINATION_KIND = 'SWAP_DESTINATION_KIND'; -export const SWAP_ORIGIN_AMOUNT = 'SWAP_ORIGIN_AMOUNT'; -export const SWAP_DESTINATION_AMOUNT = 'SWAP_DESTINATION_AMOUNT'; -export const SWAP_UPDATE_BITY_RATES = 'SWAP_UPDATE_BITY_RATES'; -export const SWAP_DESTINATION_ADDRESS = 'SWAP_DESTINATION_ADDRESS'; -export const SWAP_RESTART = 'SWAP_RESTART'; -export const SWAP_LOAD_BITY_RATES = 'SWAP_LOAD_BITY_RATES'; -export const SWAP_STOP_LOAD_BITY_RATES = 'SWAP_STOP_LOAD_BITY_RATES'; -export const SWAP_STEP = 'SWAP_STEP'; -export const SWAP_REFERENCE_NUMBER = 'SWAP_REFERENCE_NUMBER'; diff --git a/common/actions/swapTypes.js b/common/actions/swapTypes.js deleted file mode 100644 index 457289a2..00000000 --- a/common/actions/swapTypes.js +++ /dev/null @@ -1,66 +0,0 @@ -import { - SWAP_DESTINATION_AMOUNT, - SWAP_DESTINATION_KIND, - SWAP_ORIGIN_AMOUNT, - SWAP_ORIGIN_KIND, - SWAP_UPDATE_BITY_RATES, - SWAP_DESTINATION_ADDRESS, - SWAP_RESTART, - SWAP_LOAD_BITY_RATES, - SWAP_STOP_LOAD_BITY_RATES, - SWAP_STEP, - SWAP_REFERENCE_NUMBER -} from './swapConstants'; - -export type Pairs = { - ETHBTC: number, - ETHREP: number, - BTCETH: number, - BTCREP: number -}; - -export type ReferenceNumberSwapAction = { - type: SWAP_REFERENCE_NUMBER, - value: string -}; -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 BityRatesSwapAction = { - type: SWAP_UPDATE_BITY_RATES, - value: Pairs -}; -export type DestinationAddressSwapAction = { - type: SWAP_DESTINATION_ADDRESS, - value: ?number -}; - -export type RestartSwapAction = { - type: SWAP_RESTART -}; - -export type LoadBityRatesSwapAction = { - type: SWAP_LOAD_BITY_RATES -}; - -export type ChangeStepSwapAction = { - type: SWAP_STEP, - value: number -}; - -export type StopLoadBityRatesSwapAction = { - type: SWAP_STOP_LOAD_BITY_RATES -}; diff --git a/common/actions/wallet.js b/common/actions/wallet.js index b4539695..b79ba0b3 100644 --- a/common/actions/wallet.js +++ b/common/actions/wallet.js @@ -2,6 +2,7 @@ import BaseWallet from 'libs/wallet/base'; import Big from 'big.js'; +/*** Unlock Private Key ***/ export type PrivateKeyUnlockParams = { key: string, password: string @@ -12,29 +13,6 @@ export type UnlockPrivateKeyAction = { payload: PrivateKeyUnlockParams }; -export type SetWalletAction = { - type: 'WALLET_SET', - payload: BaseWallet -}; - -export type SetBalanceAction = { - type: 'WALLET_SET_BALANCE', - payload: Big -}; - -export type SetTokenBalancesAction = { - type: 'WALLET_SET_TOKEN_BALANCES', - payload: { - [string]: Big - } -}; - -export type WalletAction = - | UnlockPrivateKeyAction - | SetWalletAction - | SetBalanceAction - | SetTokenBalancesAction; - export function unlockPrivateKey( value: PrivateKeyUnlockParams ): UnlockPrivateKeyAction { @@ -44,6 +22,12 @@ export function unlockPrivateKey( }; } +/*** Set Wallet ***/ +export type SetWalletAction = { + type: 'WALLET_SET', + payload: BaseWallet +}; + export function setWallet(value: BaseWallet): SetWalletAction { return { type: 'WALLET_SET', @@ -51,6 +35,12 @@ export function setWallet(value: BaseWallet): SetWalletAction { }; } +/*** Set Balance ***/ +export type SetBalanceAction = { + type: 'WALLET_SET_BALANCE', + payload: Big +}; + export function setBalance(value: Big): SetBalanceAction { return { type: 'WALLET_SET_BALANCE', @@ -58,6 +48,14 @@ export function setBalance(value: Big): SetBalanceAction { }; } +/*** Set Token Balance ***/ +export type SetTokenBalancesAction = { + type: 'WALLET_SET_TOKEN_BALANCES', + payload: { + [string]: Big + } +}; + export function setTokenBalances(payload: { [string]: Big }): SetTokenBalancesAction { @@ -66,3 +64,10 @@ export function setTokenBalances(payload: { payload }; } + +/*** Union Type ***/ +export type WalletAction = + | UnlockPrivateKeyAction + | SetWalletAction + | SetBalanceAction + | SetTokenBalancesAction; diff --git a/common/containers/Tabs/GenerateWallet/components/DownloadWallet.jsx b/common/containers/Tabs/GenerateWallet/components/DownloadWallet.jsx index e1415fa3..a6e034fe 100644 --- a/common/containers/Tabs/GenerateWallet/components/DownloadWallet.jsx +++ b/common/containers/Tabs/GenerateWallet/components/DownloadWallet.jsx @@ -1,6 +1,5 @@ // @flow import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import translate from 'translations'; import type PrivKeyWallet from 'libs/wallet/privkey'; import { makeBlob } from 'utils/blob'; @@ -9,23 +8,16 @@ import { getV3Filename } from 'libs/keystore'; type Props = { wallet: PrivKeyWallet, password: string, - hasDownloadedWalletFile: boolean, - downloadUTCGenerateWallet: () => any, - confirmContinueToPaperGenerateWallet: () => any + continueToPaper: Function }; export default class DownloadWallet extends Component { props: Props; keystore: Object; - static propTypes = { - // Store state - wallet: PropTypes.object.isRequired, - password: PropTypes.string.isRequired, - hasDownloadedWalletFile: PropTypes.bool, - // Actions - downloadUTCGenerateWallet: PropTypes.func, - confirmContinueToPaperGenerateWallet: PropTypes.func + state = { + hasDownloadedWallet: false }; + componentWillMount() { this.keystore = this.props.wallet.toKeystore(this.props.password); } @@ -35,12 +27,18 @@ export default class DownloadWallet extends Component { } } + _markDownloaded = () => { + this.setState({ hasDownloadedWallet: true }); + }; + + _handleContinue = () => { + if (this.state.hasDownloadedWallet) { + this.props.continueToPaper(); + } + }; + render() { - const { - hasDownloadedWalletFile, - downloadUTCGenerateWallet, - confirmContinueToPaperGenerateWallet - } = this.props; + const { hasDownloadedWallet } = this.state; return (
@@ -68,7 +66,7 @@ export default class DownloadWallet extends Component { aria-describedby="x_KeystoreDesc" download={this.getFilename()} href={this.getBlob()} - onClick={downloadUTCGenerateWallet} + onClick={this._markDownloaded} > {translate('x_Download')} @@ -95,10 +93,10 @@ export default class DownloadWallet extends Component {
I understand. Continue. diff --git a/common/containers/Tabs/GenerateWallet/components/EnterPassword.jsx b/common/containers/Tabs/GenerateWallet/components/EnterPassword.jsx index 134763a2..39806f68 100644 --- a/common/containers/Tabs/GenerateWallet/components/EnterPassword.jsx +++ b/common/containers/Tabs/GenerateWallet/components/EnterPassword.jsx @@ -1,6 +1,5 @@ // @flow import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { Field, reduxForm } from 'redux-form'; import translate from 'translations'; import PasswordInput from './PasswordInput'; @@ -14,32 +13,33 @@ const minLength = min => value => { const minLength9 = minLength(9); const required = value => (value ? undefined : 'Required'); +type Props = { + walletPasswordForm: Object, + showWalletPassword: Function, + generateNewWallet: Function +}; + class EnterPassword extends Component { - static propTypes = { - // Store state - generateWalletPassword: PropTypes.object, - showPassword: PropTypes.bool, - // Actions - showPasswordGenerateWallet: PropTypes.func, - generateUTCGenerateWallet: PropTypes.func - }; + props: Props; state = { fileName: null, - blobURI: null + blobURI: null, + isPasswordVisible: false }; - onClickGenerateFile = () => { - const form = this.props.generateWalletPassword; - this.props.generateUTCGenerateWallet(form.values.password); + _onClickGenerateFile = () => { + const form = this.props.walletPasswordForm; + this.props.generateNewWallet(form.values.password); + }; + + _togglePassword = () => { + this.setState({ isPasswordVisible: !this.state.isPasswordVisible }); }; render() { - const { - generateWalletPassword, - showPassword, - showPasswordGenerateWallet - } = this.props; + const { walletPasswordForm } = this.props; + const { isPasswordVisible } = this.state; return (
@@ -54,17 +54,15 @@ class EnterPassword extends Component {