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
This commit is contained in:
parent
e8ad2ce958
commit
1aad9d1c21
85
README.md
85
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.
|
||||
|
|
|
@ -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';
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
|
@ -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
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
<div>
|
||||
|
@ -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')}
|
||||
</a>
|
||||
|
@ -95,10 +93,10 @@ export default class DownloadWallet extends Component {
|
|||
<br />
|
||||
<a
|
||||
role="button"
|
||||
className={`btn btn-info ${hasDownloadedWalletFile
|
||||
className={`btn btn-info ${hasDownloadedWallet
|
||||
? ''
|
||||
: 'disabled'}`}
|
||||
onClick={confirmContinueToPaperGenerateWallet}
|
||||
onClick={this._handleContinue}
|
||||
>
|
||||
I understand. Continue.
|
||||
</a>
|
||||
|
|
|
@ -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 (
|
||||
<div>
|
||||
|
@ -54,17 +54,15 @@ class EnterPassword extends Component {
|
|||
<Field
|
||||
validate={[required, minLength9]}
|
||||
component={PasswordInput}
|
||||
showPassword={showPassword}
|
||||
showPasswordGenerateWallet={showPasswordGenerateWallet}
|
||||
isPasswordVisible={isPasswordVisible}
|
||||
togglePassword={this._togglePassword}
|
||||
name="password"
|
||||
type="text"
|
||||
/>
|
||||
<br />
|
||||
<button
|
||||
onClick={this.onClickGenerateFile}
|
||||
disabled={
|
||||
generateWalletPassword ? generateWalletPassword.syncErrors : true
|
||||
}
|
||||
onClick={this._onClickGenerateFile}
|
||||
disabled={walletPasswordForm ? walletPasswordForm.syncErrors : true}
|
||||
className="btn btn-primary btn-block"
|
||||
>
|
||||
{translate('NAV_GenerateWallet')}
|
||||
|
@ -76,5 +74,5 @@ class EnterPassword extends Component {
|
|||
}
|
||||
|
||||
export default reduxForm({
|
||||
form: 'generateWalletPassword' // a unique name for this form
|
||||
form: 'walletPasswordForm' // a unique name for this form
|
||||
})(EnterPassword);
|
||||
|
|
|
@ -1,37 +1,33 @@
|
|||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
type Props = {
|
||||
togglePassword: Function,
|
||||
isPasswordVisible: ?boolean,
|
||||
input: Object,
|
||||
meta: Object
|
||||
};
|
||||
|
||||
export default class PasswordInput extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
showPasswordGenerateWallet: PropTypes.func,
|
||||
showPassword: PropTypes.bool,
|
||||
input: PropTypes.object,
|
||||
meta: PropTypes.object
|
||||
};
|
||||
props: Props;
|
||||
|
||||
render() {
|
||||
const { input, meta, isPasswordVisible, togglePassword } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<div className="input-group" style={{ width: '100%' }}>
|
||||
<input
|
||||
{...this.props.input}
|
||||
{...input}
|
||||
name="password"
|
||||
className={
|
||||
this.props.meta.error
|
||||
? 'form-control is-invalid'
|
||||
: 'form-control'
|
||||
}
|
||||
type={this.props.showPassword ? 'text' : 'password'}
|
||||
className={`form-control ${meta.error ? 'is-invalid' : ''}`}
|
||||
type={isPasswordVisible ? 'text' : 'password'}
|
||||
placeholder="Do NOT forget to save this!"
|
||||
aria-label="Enter a strong password (at least 9 characters)"
|
||||
/>
|
||||
<span
|
||||
onClick={this.props.showPasswordGenerateWallet}
|
||||
onClick={togglePassword}
|
||||
aria-label="make password visible"
|
||||
role="button"
|
||||
className="input-group-addon eye"
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import * as generateWalletActions from 'actions/generateWallet';
|
||||
import PropTypes from 'prop-types';
|
||||
import type {
|
||||
GenerateNewWalletAction,
|
||||
ContinueToPaperAction,
|
||||
ResetGenerateWalletAction
|
||||
} from 'actions/generateWallet';
|
||||
|
||||
import EnterPassword from './components/EnterPassword';
|
||||
import DownloadWallet from './components/DownloadWallet';
|
||||
import PaperWallet from './components/PaperWallet';
|
||||
|
@ -10,28 +15,19 @@ import type PrivKeyWallet from 'libs/wallet/privkey';
|
|||
import type { State } from 'reducers';
|
||||
|
||||
type Props = {
|
||||
// FIXME union actual steps
|
||||
activeStep: string,
|
||||
// Redux state
|
||||
activeStep: string, // FIXME union actual steps
|
||||
password: string,
|
||||
hasDownloadedWalletFile: boolean,
|
||||
wallet: ?PrivKeyWallet
|
||||
} & typeof generateWalletActions;
|
||||
wallet: ?PrivKeyWallet,
|
||||
walletPasswordForm: Object,
|
||||
// Actions
|
||||
generateNewWallet: (pw: string) => GenerateNewWalletAction,
|
||||
continueToPaper: () => ContinueToPaperAction,
|
||||
resetGenerateWallet: () => ResetGenerateWalletAction
|
||||
};
|
||||
|
||||
class GenerateWallet extends Component {
|
||||
props: Props;
|
||||
static propTypes = {
|
||||
// Store state
|
||||
activeStep: PropTypes.string,
|
||||
wallet: PropTypes.object,
|
||||
password: PropTypes.string,
|
||||
hasDownloadedWalletFile: PropTypes.bool,
|
||||
// Actions
|
||||
showPasswordGenerateWallet: PropTypes.func,
|
||||
generateUTCGenerateWallet: PropTypes.func,
|
||||
downloadUTCGenerateWallet: PropTypes.func,
|
||||
confirmContinueToPaperGenerateWallet: PropTypes.func,
|
||||
resetGenerateWallet: PropTypes.func
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.resetGenerateWallet();
|
||||
|
@ -43,20 +39,21 @@ class GenerateWallet extends Component {
|
|||
|
||||
switch (activeStep) {
|
||||
case 'password':
|
||||
content = <EnterPassword {...this.props} />;
|
||||
content = (
|
||||
<EnterPassword
|
||||
walletPasswordForm={this.props.walletPasswordForm}
|
||||
generateNewWallet={this.props.generateNewWallet}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'download':
|
||||
if (wallet) {
|
||||
content = (
|
||||
<DownloadWallet
|
||||
hasDownloadedWalletFile={this.props.hasDownloadedWalletFile}
|
||||
wallet={wallet}
|
||||
password={password}
|
||||
downloadUTCGenerateWallet={this.props.downloadUTCGenerateWallet}
|
||||
confirmContinueToPaperGenerateWallet={
|
||||
this.props.confirmContinueToPaperGenerateWallet
|
||||
}
|
||||
continueToPaper={this.props.continueToPaper}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -91,12 +88,10 @@ class GenerateWallet extends Component {
|
|||
|
||||
function mapStateToProps(state: State) {
|
||||
return {
|
||||
generateWalletPassword: state.form.generateWalletPassword,
|
||||
walletPasswordForm: state.form.walletPasswordForm,
|
||||
activeStep: state.generateWallet.activeStep,
|
||||
password: state.generateWallet.password,
|
||||
hasDownloadedWalletFile: state.generateWallet.hasDownloadedWalletFile,
|
||||
wallet: state.generateWallet.wallet,
|
||||
walletFile: state.generateWallet.walletFile
|
||||
wallet: state.generateWallet.wallet
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
import { combineAndUpper } from 'utils/formatters';
|
||||
import * as swapTypes from 'actions/swapTypes';
|
||||
import SimpleDropDown from 'components/ui/SimpleDropdown';
|
||||
import type {
|
||||
OriginKindSwapAction,
|
||||
DestinationKindSwapAction,
|
||||
OriginAmountSwapAction,
|
||||
DestinationAmountSwapAction,
|
||||
ChangeStepSwapAction
|
||||
} from 'actions/swap';
|
||||
|
||||
export type StateProps = {
|
||||
bityRates: {},
|
||||
|
@ -15,13 +21,11 @@ export type StateProps = {
|
|||
};
|
||||
|
||||
export type ActionProps = {
|
||||
originKindSwap: (value: string) => swapTypes.OriginKindSwapAction,
|
||||
destinationKindSwap: (value: string) => swapTypes.DestinationKindSwapAction,
|
||||
originAmountSwap: (value: ?number) => swapTypes.OriginAmountSwapAction,
|
||||
destinationAmountSwap: (
|
||||
value: ?number
|
||||
) => swapTypes.DestinationAmountSwapAction,
|
||||
changeStepSwap: () => swapTypes.ChangeStepSwapAction
|
||||
originKindSwap: (value: string) => OriginKindSwapAction,
|
||||
destinationKindSwap: (value: string) => DestinationKindSwapAction,
|
||||
originAmountSwap: (value: ?number) => OriginAmountSwapAction,
|
||||
destinationAmountSwap: (value: ?number) => DestinationAmountSwapAction,
|
||||
changeStepSwap: () => ChangeStepSwapAction
|
||||
};
|
||||
|
||||
export default class CurrencySwap extends Component {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
import { toFixedIfLarger } from 'utils/formatters';
|
||||
import { Pairs } from 'actions/swapTypes';
|
||||
import type { Pairs } from 'actions/swap';
|
||||
import { bityReferralURL } from 'config/data';
|
||||
import bityLogoWhite from 'assets/images/logo-bity-white.svg';
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import * as swapTypes from 'actions/swapTypes';
|
||||
import type {
|
||||
DestinationAddressSwapAction,
|
||||
ChangeStepSwapAction,
|
||||
StopLoadBityRatesSwapAction,
|
||||
ReferenceNumberSwapAction
|
||||
} from 'actions/swap';
|
||||
import { donationAddressMap } from 'config/data';
|
||||
import { isValidBTCAddress, isValidETHAddress } from 'libs/validators';
|
||||
import translate from 'translations';
|
||||
|
@ -11,11 +16,10 @@ export type StateProps = {
|
|||
};
|
||||
|
||||
export type ActionProps = {
|
||||
destinationAddressSwap: (
|
||||
value: ?string
|
||||
) => swapTypes.DestinationAddressSwapAction,
|
||||
changeStepSwap: (value: number) => swapTypes.ChangeStepSwapAction,
|
||||
stopLoadBityRatesSwap: () => swapTypes.StopLoadBityRatesSwapAction
|
||||
destinationAddressSwap: (value: ?string) => DestinationAddressSwapAction,
|
||||
changeStepSwap: (value: number) => ChangeStepSwapAction,
|
||||
stopLoadBityRatesSwap: () => StopLoadBityRatesSwapAction,
|
||||
referenceNumberSwap: (value: string) => ReferenceNumberSwapAction
|
||||
};
|
||||
|
||||
export default class ReceivingAddress extends Component {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import { toFixedIfLarger } from 'utils/formatters';
|
||||
import translate from 'translations';
|
||||
import * as swapTypes from 'actions/swapTypes';
|
||||
import type { RestartSwapAction } from 'actions/swap';
|
||||
import bityLogo from 'assets/images/logo-bity.svg';
|
||||
import { bityReferralURL } from 'config/data';
|
||||
|
||||
|
@ -16,7 +16,7 @@ export type StateProps = {
|
|||
};
|
||||
|
||||
export type ActionProps = {
|
||||
restartSwap: () => swapTypes.RestartSwapAction
|
||||
restartSwap: () => RestartSwapAction
|
||||
};
|
||||
|
||||
export default class SwapInfoHeader extends Component {
|
||||
|
@ -126,10 +126,7 @@ export default class SwapInfoHeader extends Component {
|
|||
{/*Your rate*/}
|
||||
<div className={this.computedClass()}>
|
||||
<h4>
|
||||
{` ${toFixedIfLarger(
|
||||
this.computedOriginDestinationRatio(),
|
||||
6
|
||||
)} ${originKind}/${destinationKind} `}
|
||||
{` ${this.computedOriginDestinationRatio()} ${originKind}/${destinationKind} `}
|
||||
</h4>
|
||||
<p>
|
||||
{translate('SWAP_your_rate')}
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import * as swapActions from 'actions/swap';
|
||||
import * as swapTypes from 'actions/swapTypes';
|
||||
import type {
|
||||
ChangeStepSwapAction,
|
||||
OriginKindSwapAction,
|
||||
DestinationKindSwapAction,
|
||||
OriginAmountSwapAction,
|
||||
DestinationAmountSwapAction,
|
||||
LoadBityRatesSwapAction,
|
||||
DestinationAddressSwapAction,
|
||||
RestartSwapAction,
|
||||
StopLoadBityRatesSwapAction
|
||||
} from 'actions/swap';
|
||||
import CurrencySwap from './components/CurrencySwap';
|
||||
import CurrentRates from './components/CurrentRates';
|
||||
import ReceivingAddress from './components/ReceivingAddress';
|
||||
|
@ -18,6 +28,7 @@ type ReduxStateProps = {
|
|||
bityRates: boolean,
|
||||
originAmount: ?number,
|
||||
destinationAmount: ?number,
|
||||
isFetchingRates: boolean,
|
||||
// PART 3
|
||||
referenceNumber: string,
|
||||
timeRemaining: string,
|
||||
|
@ -27,19 +38,15 @@ type ReduxStateProps = {
|
|||
};
|
||||
|
||||
type ReduxActionProps = {
|
||||
changeStepSwap: (value: number) => swapTypes.ChangeStepSwapAction,
|
||||
originKindSwap: (value: string) => swapTypes.OriginKindSwapAction,
|
||||
destinationKindSwap: (value: string) => swapTypes.DestinationKindSwapAction,
|
||||
originAmountSwap: (value: ?number) => swapTypes.OriginAmountSwapAction,
|
||||
destinationAmountSwap: (
|
||||
value: ?number
|
||||
) => swapTypes.DestinationAmountSwapAction,
|
||||
loadBityRatesSwap: () => swapTypes.LoadBityRatesSwapAction,
|
||||
destinationAddressSwap: (
|
||||
value: ?string
|
||||
) => swapTypes.DestinationAddressSwapAction,
|
||||
restartSwap: () => swapTypes.RestartSwapAction,
|
||||
stopLoadBityRatesSwap: () => swapTypes.StopLoadBityRatesSwapAction,
|
||||
changeStepSwap: (value: number) => ChangeStepSwapAction,
|
||||
originKindSwap: (value: string) => OriginKindSwapAction,
|
||||
destinationKindSwap: (value: string) => DestinationKindSwapAction,
|
||||
originAmountSwap: (value: ?number) => OriginAmountSwapAction,
|
||||
destinationAmountSwap: (value: ?number) => DestinationAmountSwapAction,
|
||||
loadBityRatesSwap: () => LoadBityRatesSwapAction,
|
||||
destinationAddressSwap: (value: ?string) => DestinationAddressSwapAction,
|
||||
restartSwap: () => RestartSwapAction,
|
||||
stopLoadBityRatesSwap: () => StopLoadBityRatesSwapAction,
|
||||
// PART 3 (IGNORE FOR NOW)
|
||||
referenceNumberSwap: typeof swapActions.referenceNumberSwap
|
||||
};
|
||||
|
@ -48,6 +55,7 @@ class Swap extends Component {
|
|||
props: ReduxActionProps & ReduxStateProps;
|
||||
|
||||
componentDidMount() {
|
||||
// TODO: Use `isFetchingRates` to show a loader
|
||||
this.props.loadBityRatesSwap();
|
||||
}
|
||||
|
||||
|
@ -158,7 +166,8 @@ function mapStateToProps(state) {
|
|||
timeRemaining: state.swap.timeRemaining,
|
||||
numberOfConfirmations: state.swap.numberOfConfirmations,
|
||||
orderStep: state.swap.orderStep,
|
||||
orderStarted: state.swap.orderStarted
|
||||
orderStarted: state.swap.orderStarted,
|
||||
isFetchingRates: state.swap.isFetchingRates
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export type State = {
|
|||
gasPriceGwei: number
|
||||
};
|
||||
|
||||
export const initialState: State = {
|
||||
export const INITIAL_STATE: State = {
|
||||
languageSelection: languages[0].sign,
|
||||
nodeSelection: Object.keys(NODES)[0],
|
||||
gasPriceGwei: 21
|
||||
|
@ -42,7 +42,7 @@ function changeGasPrice(state: State, action: ChangeGasPriceAction): State {
|
|||
}
|
||||
|
||||
export function config(
|
||||
state: State = initialState,
|
||||
state: State = INITIAL_STATE,
|
||||
action: ConfigAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import type { Token } from 'config/data';
|
|||
|
||||
export type State = Token[];
|
||||
|
||||
const initialState: State = [];
|
||||
export const INITIAL_STATE: State = [];
|
||||
|
||||
function addCustomToken(state: State, action: AddCustomTokenAction): State {
|
||||
if (state.find(token => token.symbol === action.payload.symbol)) {
|
||||
|
@ -25,7 +25,7 @@ function removeCustomToken(
|
|||
}
|
||||
|
||||
export function customTokens(
|
||||
state: State = initialState,
|
||||
state: State = INITIAL_STATE,
|
||||
action: CustomTokenAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
|
|
|
@ -3,14 +3,14 @@ import type { EnsAction, CacheEnsAddressAction } from 'actions/ens';
|
|||
|
||||
export type State = { [string]: string };
|
||||
|
||||
const initialState: State = {};
|
||||
export const INITIAL_STATE: State = {};
|
||||
|
||||
function cacheEnsAddress(state: State, action: CacheEnsAddressAction): State {
|
||||
const { ensName, address } = action.payload;
|
||||
return { ...state, [ensName]: address };
|
||||
}
|
||||
|
||||
export function ens(state: State = initialState, action: EnsAction): State {
|
||||
export function ens(state: State = INITIAL_STATE, action: EnsAction): State {
|
||||
switch (action.type) {
|
||||
case 'ENS_CACHE':
|
||||
return cacheEnsAddress(state, action);
|
||||
|
|
|
@ -1,37 +1,25 @@
|
|||
// @flow
|
||||
import {
|
||||
GENERATE_WALLET_SHOW_PASSWORD,
|
||||
GENERATE_WALLET_FILE,
|
||||
GENERATE_WALLET_DOWNLOAD_FILE,
|
||||
GENERATE_WALLET_CONFIRM_CONTINUE_TO_PAPER,
|
||||
RESET_GENERATE_WALLET
|
||||
} from 'actions/generateWalletConstants';
|
||||
import type PrivateKeyWallet from 'libs/wallet/privkey';
|
||||
import type { GenerateWalletAction } from 'actions/generateWallet';
|
||||
|
||||
export type State = {
|
||||
activeStep: string,
|
||||
hasDownloadedWalletFile: boolean,
|
||||
wallet: ?PrivateKeyWallet,
|
||||
password: ?string
|
||||
};
|
||||
|
||||
const initialState: State = {
|
||||
export const INITIAL_STATE: State = {
|
||||
activeStep: 'password',
|
||||
hasDownloadedWalletFile: false,
|
||||
wallet: null,
|
||||
password: null
|
||||
};
|
||||
|
||||
export function generateWallet(state: State = initialState, action): State {
|
||||
export function generateWallet(
|
||||
state: State = INITIAL_STATE,
|
||||
action: GenerateWalletAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
case GENERATE_WALLET_SHOW_PASSWORD: {
|
||||
return {
|
||||
...state,
|
||||
activeStep: 'password'
|
||||
};
|
||||
}
|
||||
|
||||
case GENERATE_WALLET_FILE: {
|
||||
case 'GENERATE_WALLET_GENERATE_WALLET': {
|
||||
return {
|
||||
...state,
|
||||
wallet: action.wallet,
|
||||
|
@ -40,28 +28,19 @@ export function generateWallet(state: State = initialState, action): State {
|
|||
};
|
||||
}
|
||||
|
||||
case GENERATE_WALLET_DOWNLOAD_FILE: {
|
||||
return {
|
||||
...state,
|
||||
hasDownloadedWalletFile: true
|
||||
};
|
||||
}
|
||||
|
||||
case GENERATE_WALLET_CONFIRM_CONTINUE_TO_PAPER: {
|
||||
case 'GENERATE_WALLET_CONTINUE_TO_PAPER': {
|
||||
return {
|
||||
...state,
|
||||
activeStep: 'paper'
|
||||
};
|
||||
}
|
||||
|
||||
case RESET_GENERATE_WALLET: {
|
||||
return {
|
||||
...state,
|
||||
...initialState
|
||||
};
|
||||
case 'GENERATE_WALLET_RESET': {
|
||||
return INITIAL_STATE;
|
||||
}
|
||||
|
||||
default:
|
||||
(action: empty);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,13 +27,17 @@ import { combineReducers } from 'redux';
|
|||
import { routerReducer } from 'react-router-redux';
|
||||
|
||||
export type State = {
|
||||
// Custom reducers
|
||||
generateWallet: GenerateWalletState,
|
||||
config: ConfigState,
|
||||
notifications: NotificationsState,
|
||||
ens: EnsState,
|
||||
wallet: WalletState,
|
||||
customTokens: CustomTokensState,
|
||||
rates: RatesState
|
||||
rates: RatesState,
|
||||
// Third party reducers (TODO: Fill these out)
|
||||
form: Object,
|
||||
routing: Object
|
||||
};
|
||||
|
||||
export default combineReducers({
|
||||
|
|
|
@ -8,7 +8,7 @@ import type {
|
|||
|
||||
export type State = Notification[];
|
||||
|
||||
const initialState: State = [];
|
||||
export const INITIAL_STATE: State = [];
|
||||
|
||||
function showNotification(state: State, action: ShowNotificationAction): State {
|
||||
return state.concat(action.payload);
|
||||
|
@ -21,7 +21,7 @@ function closeNotification(state, action: CloseNotificationAction): State {
|
|||
}
|
||||
|
||||
export function notifications(
|
||||
state: State = initialState,
|
||||
state: State = INITIAL_STATE,
|
||||
action: NotificationsAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
|
|
|
@ -6,13 +6,16 @@ export type State = {
|
|||
[key: string]: number
|
||||
};
|
||||
|
||||
const initialState: State = {};
|
||||
export const INITIAL_STATE: State = {};
|
||||
|
||||
function setRates(state: State, action: SetRatesAction): State {
|
||||
return action.payload;
|
||||
}
|
||||
|
||||
export function rates(state: State = initialState, action: RatesAction): State {
|
||||
export function rates(
|
||||
state: State = INITIAL_STATE,
|
||||
action: RatesAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
case 'RATES_SET':
|
||||
return setRates(state, action);
|
||||
|
|
|
@ -1,36 +1,45 @@
|
|||
import {
|
||||
SWAP_DESTINATION_AMOUNT,
|
||||
SWAP_DESTINATION_KIND,
|
||||
SWAP_ORIGIN_AMOUNT,
|
||||
SWAP_ORIGIN_KIND,
|
||||
SWAP_UPDATE_BITY_RATES,
|
||||
SWAP_DESTINATION_ADDRESS,
|
||||
SWAP_RESTART,
|
||||
SWAP_STEP,
|
||||
SWAP_REFERENCE_NUMBER
|
||||
} from 'actions/swapConstants';
|
||||
// @flow
|
||||
import { combineAndUpper } from 'utils/formatters';
|
||||
import type { SwapAction } from 'actions/swap';
|
||||
|
||||
export const ALL_CRYPTO_KIND_OPTIONS = ['BTC', 'ETH', 'REP'];
|
||||
|
||||
const initialState = {
|
||||
originAmount: '',
|
||||
destinationAmount: '',
|
||||
type State = {
|
||||
originAmount: number,
|
||||
destinationAmount: number,
|
||||
originKind: string,
|
||||
destinationKind: string,
|
||||
destinationKindOptions: Array<string>,
|
||||
originKindOptions: Array<string>,
|
||||
step: number,
|
||||
bityRates: Object,
|
||||
destinationAddress: string,
|
||||
referenceNumber: string,
|
||||
timeRemaining: string,
|
||||
numberOfConfirmations: ?number,
|
||||
orderStep: ?number,
|
||||
isFetchingRates: boolean
|
||||
};
|
||||
|
||||
export const INITIAL_STATE: State = {
|
||||
originAmount: 0,
|
||||
destinationAmount: 0,
|
||||
originKind: 'BTC',
|
||||
destinationKind: 'ETH',
|
||||
destinationKindOptions: ALL_CRYPTO_KIND_OPTIONS.filter(
|
||||
element => element !== 'BTC'
|
||||
),
|
||||
originKindOptions: ALL_CRYPTO_KIND_OPTIONS.filter(
|
||||
element => element !== 'REP'
|
||||
),
|
||||
destinationKindOptions: ALL_CRYPTO_KIND_OPTIONS.filter(element => {
|
||||
return element !== 'BTC';
|
||||
}),
|
||||
originKindOptions: ALL_CRYPTO_KIND_OPTIONS.filter(element => {
|
||||
return element !== 'REP';
|
||||
}),
|
||||
step: 1,
|
||||
bityRates: {},
|
||||
destinationAddress: '',
|
||||
referenceNumber: '',
|
||||
timeRemaining: '',
|
||||
numberOfConfirmations: null,
|
||||
orderStep: null
|
||||
orderStep: null,
|
||||
isFetchingRates: false
|
||||
};
|
||||
|
||||
const buildDestinationAmount = (
|
||||
|
@ -44,7 +53,10 @@ const buildDestinationAmount = (
|
|||
return originAmount * bityRate;
|
||||
};
|
||||
|
||||
const buildDestinationKind = (originKind, destinationKind) => {
|
||||
const buildDestinationKind = (
|
||||
originKind: string,
|
||||
destinationKind: string
|
||||
): string => {
|
||||
if (originKind === destinationKind) {
|
||||
return ALL_CRYPTO_KIND_OPTIONS.filter(element => element !== originKind)[0];
|
||||
} else {
|
||||
|
@ -52,9 +64,9 @@ const buildDestinationKind = (originKind, destinationKind) => {
|
|||
}
|
||||
};
|
||||
|
||||
export function swap(state = initialState, action) {
|
||||
export function swap(state: State = INITIAL_STATE, action: SwapAction) {
|
||||
switch (action.type) {
|
||||
case SWAP_ORIGIN_KIND: {
|
||||
case 'SWAP_ORIGIN_KIND': {
|
||||
const newDestinationKind = buildDestinationKind(
|
||||
action.value,
|
||||
state.destinationKind
|
||||
|
@ -63,9 +75,10 @@ export function swap(state = initialState, action) {
|
|||
...state,
|
||||
originKind: action.value,
|
||||
destinationKind: newDestinationKind,
|
||||
destinationKindOptions: ALL_CRYPTO_KIND_OPTIONS.filter(
|
||||
element => element !== action.value
|
||||
),
|
||||
destinationKindOptions: ALL_CRYPTO_KIND_OPTIONS.filter(element => {
|
||||
// $FlowFixMe
|
||||
return element !== action.value;
|
||||
}),
|
||||
destinationAmount: buildDestinationAmount(
|
||||
state.originAmount,
|
||||
action.value,
|
||||
|
@ -74,7 +87,7 @@ export function swap(state = initialState, action) {
|
|||
)
|
||||
};
|
||||
}
|
||||
case SWAP_DESTINATION_KIND: {
|
||||
case 'SWAP_DESTINATION_KIND': {
|
||||
return {
|
||||
...state,
|
||||
destinationKind: action.value,
|
||||
|
@ -86,42 +99,42 @@ export function swap(state = initialState, action) {
|
|||
)
|
||||
};
|
||||
}
|
||||
case SWAP_ORIGIN_AMOUNT:
|
||||
case 'SWAP_ORIGIN_AMOUNT':
|
||||
return {
|
||||
...state,
|
||||
originAmount: action.value
|
||||
};
|
||||
case SWAP_DESTINATION_AMOUNT:
|
||||
case 'SWAP_DESTINATION_AMOUNT':
|
||||
return {
|
||||
...state,
|
||||
destinationAmount: action.value
|
||||
};
|
||||
case SWAP_UPDATE_BITY_RATES:
|
||||
case 'SWAP_UPDATE_BITY_RATES':
|
||||
return {
|
||||
...state,
|
||||
bityRates: {
|
||||
...state.bityRates,
|
||||
...action.value
|
||||
}
|
||||
},
|
||||
isFetchingRates: false
|
||||
};
|
||||
case SWAP_STEP: {
|
||||
case 'SWAP_STEP': {
|
||||
return {
|
||||
...state,
|
||||
step: action.value
|
||||
};
|
||||
}
|
||||
case SWAP_DESTINATION_ADDRESS:
|
||||
case 'SWAP_DESTINATION_ADDRESS':
|
||||
return {
|
||||
...state,
|
||||
destinationAddress: action.value
|
||||
};
|
||||
case SWAP_RESTART:
|
||||
case 'SWAP_RESTART':
|
||||
return {
|
||||
...state,
|
||||
...initialState,
|
||||
...INITIAL_STATE,
|
||||
bityRates: state.bityRates
|
||||
};
|
||||
case SWAP_REFERENCE_NUMBER:
|
||||
case 'SWAP_REFERENCE_NUMBER':
|
||||
return {
|
||||
...state,
|
||||
referenceNumber: '2341asdfads',
|
||||
|
@ -129,7 +142,21 @@ export function swap(state = initialState, action) {
|
|||
numberOfConfirmations: 3,
|
||||
orderStep: 2
|
||||
};
|
||||
|
||||
case 'SWAP_LOAD_BITY_RATES':
|
||||
return {
|
||||
...state,
|
||||
isFetchingRates: true
|
||||
};
|
||||
|
||||
case 'SWAP_STOP_LOAD_BITY_RATES':
|
||||
return {
|
||||
...state,
|
||||
isFetchingRates: false
|
||||
};
|
||||
|
||||
default:
|
||||
(action: empty);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ export type State = {
|
|||
}
|
||||
};
|
||||
|
||||
const initialState: State = {
|
||||
export const INITIAL_STATE: State = {
|
||||
inst: null,
|
||||
balance: new Big(0),
|
||||
tokens: {}
|
||||
|
@ -38,7 +38,7 @@ function setTokenBalances(state: State, action: SetTokenBalancesAction): State {
|
|||
}
|
||||
|
||||
export function wallet(
|
||||
state: State = initialState,
|
||||
state: State = INITIAL_STATE,
|
||||
action: WalletAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
// @flow
|
||||
|
||||
import { call, put, fork, take, cancel, cancelled } from 'redux-saga/effects';
|
||||
|
||||
import type { Effect } from 'redux-saga/effects';
|
||||
import { delay } from 'redux-saga';
|
||||
import { updateBityRatesSwap } from 'actions/swap';
|
||||
import {
|
||||
SWAP_LOAD_BITY_RATES,
|
||||
SWAP_STOP_LOAD_BITY_RATES
|
||||
} from 'actions/swapConstants';
|
||||
import { getAllRates } from 'api/bity';
|
||||
|
||||
export function* loadBityRates(_action?: any): Generator<Effect, void, any> {
|
||||
|
@ -31,12 +26,12 @@ export function* loadBityRates(_action?: any): Generator<Effect, void, any> {
|
|||
}
|
||||
|
||||
export default function* bitySaga(): Generator<Effect, void, any> {
|
||||
while (yield take(SWAP_LOAD_BITY_RATES)) {
|
||||
while (yield take('SWAP_LOAD_BITY_RATES')) {
|
||||
// starts the task in the background
|
||||
const loadBityRatesTask = yield fork(loadBityRates);
|
||||
|
||||
// wait for the user to get to point where refresh is no longer needed
|
||||
yield take(SWAP_STOP_LOAD_BITY_RATES);
|
||||
yield take('SWAP_STOP_LOAD_BITY_RATES');
|
||||
// cancel the background task
|
||||
// this will cause the forked loadBityRates task to jump into its finally block
|
||||
yield cancel(loadBityRatesTask);
|
||||
|
|
Loading…
Reference in New Issue