diff options
Diffstat (limited to 'packages/website/ts/redux')
-rw-r--r-- | packages/website/ts/redux/dispatcher.ts | 244 | ||||
-rw-r--r-- | packages/website/ts/redux/reducer.ts | 363 |
2 files changed, 607 insertions, 0 deletions
diff --git a/packages/website/ts/redux/dispatcher.ts b/packages/website/ts/redux/dispatcher.ts new file mode 100644 index 000000000..6badf95bd --- /dev/null +++ b/packages/website/ts/redux/dispatcher.ts @@ -0,0 +1,244 @@ +import {Dispatch} from 'redux'; +import {State} from 'ts/redux/reducer'; +import { + Direction, + Side, + AssetToken, + BlockchainErrs, + Token, + SignatureData, + Fill, + Order, + ActionTypes, + ScreenWidths, + ProviderType, + TokenStateByAddress, +} from 'ts/types'; +import BigNumber from 'bignumber.js'; + +export class Dispatcher { + private dispatch: Dispatch<State>; + constructor(dispatch: Dispatch<State>) { + this.dispatch = dispatch; + } + // Portal + public resetState() { + this.dispatch({ + type: ActionTypes.RESET_STATE, + }); + } + public updateNodeVersion(nodeVersion: string) { + this.dispatch({ + data: nodeVersion, + type: ActionTypes.UPDATE_NODE_VERSION, + }); + } + public updateScreenWidth(screenWidth: ScreenWidths) { + this.dispatch({ + data: screenWidth, + type: ActionTypes.UPDATE_SCREEN_WIDTH, + }); + } + public swapAssetTokenSymbols() { + this.dispatch({ + type: ActionTypes.SWAP_ASSET_TOKENS, + }); + } + public updateGenerateOrderStep(direction: Direction) { + this.dispatch({ + data: direction, + type: ActionTypes.UPDATE_GENERATE_ORDER_STEP, + }); + } + public updateOrderSalt(salt: BigNumber) { + this.dispatch({ + data: salt, + type: ActionTypes.UPDATE_ORDER_SALT, + }); + } + public updateUserSuppliedOrderCache(order: Order) { + this.dispatch({ + data: order, + type: ActionTypes.UPDATE_USER_SUPPLIED_ORDER_CACHE, + }); + } + public updateShouldBlockchainErrDialogBeOpen(shouldBeOpen: boolean) { + this.dispatch({ + data: shouldBeOpen, + type: ActionTypes.UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN, + }); + } + public updateChosenAssetToken(side: Side, token: AssetToken) { + this.dispatch({ + data: { + side, + token, + }, + type: ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN, + }); + } + public updateChosenAssetTokenAddress(side: Side, address: string) { + this.dispatch({ + data: { + address, + side, + }, + type: ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS, + }); + } + public updateOrderTakerAddress(address: string) { + this.dispatch({ + data: address, + type: ActionTypes.UPDATE_ORDER_TAKER_ADDRESS, + }); + } + public updateUserAddress(address: string) { + this.dispatch({ + data: address, + type: ActionTypes.UPDATE_USER_ADDRESS, + }); + } + public updateOrderExpiry(unixTimestampSec: BigNumber) { + this.dispatch({ + data: unixTimestampSec, + type: ActionTypes.UPDATE_ORDER_EXPIRY, + }); + } + public encounteredBlockchainError(err: BlockchainErrs) { + this.dispatch({ + data: err, + type: ActionTypes.BLOCKCHAIN_ERR_ENCOUNTERED, + }); + } + public updateBlockchainIsLoaded(isLoaded: boolean) { + this.dispatch({ + data: isLoaded, + type: ActionTypes.UPDATE_BLOCKCHAIN_IS_LOADED, + }); + } + public addTokenToTokenByAddress(token: Token) { + this.dispatch({ + data: token, + type: ActionTypes.ADD_TOKEN_TO_TOKEN_BY_ADDRESS, + }); + } + public removeTokenToTokenByAddress(token: Token) { + this.dispatch({ + data: token, + type: ActionTypes.REMOVE_TOKEN_TO_TOKEN_BY_ADDRESS, + }); + } + public clearTokenByAddress() { + this.dispatch({ + type: ActionTypes.CLEAR_TOKEN_BY_ADDRESS, + }); + } + public updateTokenByAddress(tokens: Token[]) { + this.dispatch({ + data: tokens, + type: ActionTypes.UPDATE_TOKEN_BY_ADDRESS, + }); + } + public updateTokenStateByAddress(tokenStateByAddress: TokenStateByAddress) { + this.dispatch({ + data: tokenStateByAddress, + type: ActionTypes.UPDATE_TOKEN_STATE_BY_ADDRESS, + }); + } + public removeFromTokenStateByAddress(tokenAddress: string) { + this.dispatch({ + data: tokenAddress, + type: ActionTypes.REMOVE_FROM_TOKEN_STATE_BY_ADDRESS, + }); + } + public replaceTokenAllowanceByAddress(address: string, allowance: BigNumber) { + this.dispatch({ + data: { + address, + allowance, + }, + type: ActionTypes.REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS, + }); + } + public replaceTokenBalanceByAddress(address: string, balance: BigNumber) { + this.dispatch({ + data: { + address, + balance, + }, + type: ActionTypes.REPLACE_TOKEN_BALANCE_BY_ADDRESS, + }); + } + public updateTokenBalanceByAddress(address: string, balanceDelta: BigNumber) { + this.dispatch({ + data: { + address, + balanceDelta, + }, + type: ActionTypes.UPDATE_TOKEN_BALANCE_BY_ADDRESS, + }); + } + public updateSignatureData(signatureData: SignatureData) { + this.dispatch({ + data: signatureData, + type: ActionTypes.UPDATE_ORDER_SIGNATURE_DATA, + }); + } + public updateUserEtherBalance(balance: BigNumber) { + this.dispatch({ + data: balance, + type: ActionTypes.UPDATE_USER_ETHER_BALANCE, + }); + } + public updateNetworkId(networkId: number) { + this.dispatch({ + data: networkId, + type: ActionTypes.UPDATE_NETWORK_ID, + }); + } + public updateOrderFillAmount(amount: BigNumber) { + this.dispatch({ + data: amount, + type: ActionTypes.UPDATE_ORDER_FILL_AMOUNT, + }); + } + + // Docs + public updateCurrentDocsVersion(version: string) { + this.dispatch({ + data: version, + type: ActionTypes.UPDATE_LIBRARY_VERSION, + }); + } + public updateAvailableDocVersions(versions: string[]) { + this.dispatch({ + data: versions, + type: ActionTypes.UPDATE_AVAILABLE_LIBRARY_VERSIONS, + }); + } + + // Shared + public showFlashMessage(msg: string|React.ReactNode) { + this.dispatch({ + data: msg, + type: ActionTypes.SHOW_FLASH_MESSAGE, + }); + } + public hideFlashMessage() { + this.dispatch({ + type: ActionTypes.HIDE_FLASH_MESSAGE, + }); + } + public updateProviderType(providerType: ProviderType) { + this.dispatch({ + type: ActionTypes.UPDATE_PROVIDER_TYPE, + data: providerType, + }); + } + public updateInjectedProviderName(injectedProviderName: string) { + this.dispatch({ + type: ActionTypes.UPDATE_INJECTED_PROVIDER_NAME, + data: injectedProviderName, + }); + } +} diff --git a/packages/website/ts/redux/reducer.ts b/packages/website/ts/redux/reducer.ts new file mode 100644 index 000000000..7723597cd --- /dev/null +++ b/packages/website/ts/redux/reducer.ts @@ -0,0 +1,363 @@ +import * as _ from 'lodash'; +import {ZeroEx} from '0x.js'; +import BigNumber from 'bignumber.js'; +import {utils} from 'ts/utils/utils'; +import { + GenerateOrderSteps, + Side, + SideToAssetToken, + Direction, + BlockchainErrs, + SignatureData, + TokenByAddress, + TokenStateByAddress, + Order, + Action, + ActionTypes, + ScreenWidths, + ProviderType, + TokenState, +} from 'ts/types'; + +// Instead of defaulting the docs version to an empty string, we pre-populate it with +// a valid version value. This does not need to be updated however, since onLoad, it +// is always replaced with a value retrieved from our S3 bucket. +const DEFAULT_DOCS_VERSION = '0.0.0'; + +export interface State { + // Portal + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + generateOrderStep: GenerateOrderSteps; + networkId: number; + orderExpiryTimestamp: BigNumber; + orderFillAmount: BigNumber; + orderTakerAddress: string; + orderSignatureData: SignatureData; + orderSalt: BigNumber; + nodeVersion: string; + screenWidth: ScreenWidths; + shouldBlockchainErrDialogBeOpen: boolean; + sideToAssetToken: SideToAssetToken; + tokenByAddress: TokenByAddress; + tokenStateByAddress: TokenStateByAddress; + userAddress: string; + userEtherBalance: BigNumber; + // Note: cache of supplied orderJSON in fill order step. Do not use for anything else. + userSuppliedOrderCache: Order; + + // Docs + docsVersion: string; + availableDocVersions: string[]; + + // Shared + flashMessage: string|React.ReactNode; + providerType: ProviderType; + injectedProviderName: string; +}; + +const INITIAL_STATE: State = { + // Portal + blockchainErr: '', + blockchainIsLoaded: false, + generateOrderStep: GenerateOrderSteps.ChooseAssets, + networkId: undefined, + orderExpiryTimestamp: utils.initialOrderExpiryUnixTimestampSec(), + orderFillAmount: undefined, + orderSignatureData: { + hash: '', + r: '', + s: '', + v: 27, + }, + orderTakerAddress: '', + orderSalt: ZeroEx.generatePseudoRandomSalt(), + nodeVersion: undefined, + screenWidth: utils.getScreenWidth(), + shouldBlockchainErrDialogBeOpen: false, + sideToAssetToken: { + [Side.deposit]: {}, + [Side.receive]: {}, + }, + tokenByAddress: {}, + tokenStateByAddress: {}, + userAddress: '', + userEtherBalance: new BigNumber(0), + userSuppliedOrderCache: undefined, + + // Docs + docsVersion: DEFAULT_DOCS_VERSION, + availableDocVersions: [DEFAULT_DOCS_VERSION], + + // Shared + flashMessage: undefined, + providerType: ProviderType.INJECTED, + injectedProviderName: '', +}; + +export function reducer(state: State = INITIAL_STATE, action: Action) { + switch (action.type) { + // Portal + case ActionTypes.RESET_STATE: + return INITIAL_STATE; + + case ActionTypes.UPDATE_ORDER_SALT: { + return _.assign({}, state, { + orderSalt: action.data, + }); + } + + case ActionTypes.UPDATE_NODE_VERSION: { + return _.assign({}, state, { + nodeVersion: action.data, + }); + } + + case ActionTypes.UPDATE_ORDER_FILL_AMOUNT: { + return _.assign({}, state, { + orderFillAmount: action.data, + }); + } + + case ActionTypes.UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN: { + return _.assign({}, state, { + shouldBlockchainErrDialogBeOpen: action.data, + }); + } + + case ActionTypes.UPDATE_USER_ETHER_BALANCE: { + return _.assign({}, state, { + userEtherBalance: action.data, + }); + } + + case ActionTypes.UPDATE_USER_SUPPLIED_ORDER_CACHE: { + return _.assign({}, state, { + userSuppliedOrderCache: action.data, + }); + } + + case ActionTypes.CLEAR_TOKEN_BY_ADDRESS: { + return _.assign({}, state, { + tokenByAddress: {}, + }); + } + + case ActionTypes.ADD_TOKEN_TO_TOKEN_BY_ADDRESS: { + const newTokenByAddress = state.tokenByAddress; + newTokenByAddress[action.data.address] = action.data; + return _.assign({}, state, { + tokenByAddress: newTokenByAddress, + }); + } + + case ActionTypes.REMOVE_TOKEN_TO_TOKEN_BY_ADDRESS: { + const newTokenByAddress = state.tokenByAddress; + delete newTokenByAddress[action.data.address]; + return _.assign({}, state, { + tokenByAddress: newTokenByAddress, + }); + } + + case ActionTypes.UPDATE_TOKEN_BY_ADDRESS: { + const tokenByAddress = state.tokenByAddress; + const tokens = action.data; + _.each(tokens, token => { + const updatedToken = _.assign({}, tokenByAddress[token.address], token); + tokenByAddress[token.address] = updatedToken; + }); + return _.assign({}, state, { + tokenByAddress, + }); + } + + case ActionTypes.UPDATE_TOKEN_STATE_BY_ADDRESS: { + const tokenStateByAddress = state.tokenStateByAddress; + const updatedTokenStateByAddress = action.data; + _.each(updatedTokenStateByAddress, (tokenState: TokenState, address: string) => { + const updatedTokenState = _.assign({}, tokenStateByAddress[address], tokenState); + tokenStateByAddress[address] = updatedTokenState; + }); + return _.assign({}, state, { + tokenStateByAddress, + }); + } + + case ActionTypes.REMOVE_FROM_TOKEN_STATE_BY_ADDRESS: { + const tokenStateByAddress = state.tokenStateByAddress; + const tokenAddress = action.data; + delete tokenStateByAddress[tokenAddress]; + return _.assign({}, state, { + tokenStateByAddress, + }); + } + + case ActionTypes.REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS: { + const tokenStateByAddress = state.tokenStateByAddress; + const allowance = action.data.allowance; + const tokenAddress = action.data.address; + tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], { + allowance, + }); + return _.assign({}, state, { + tokenStateByAddress, + }); + } + + case ActionTypes.REPLACE_TOKEN_BALANCE_BY_ADDRESS: { + const tokenStateByAddress = state.tokenStateByAddress; + const balance = action.data.balance; + const tokenAddress = action.data.address; + tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], { + balance, + }); + return _.assign({}, state, { + tokenStateByAddress, + }); + } + + case ActionTypes.UPDATE_TOKEN_BALANCE_BY_ADDRESS: { + const tokenStateByAddress = state.tokenStateByAddress; + const balanceDelta = action.data.balanceDelta; + const tokenAddress = action.data.address; + const currBalance = tokenStateByAddress[tokenAddress].balance; + tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], { + balance: currBalance.plus(balanceDelta), + }); + return _.assign({}, state, { + tokenStateByAddress, + }); + } + + case ActionTypes.UPDATE_ORDER_SIGNATURE_DATA: { + return _.assign({}, state, { + orderSignatureData: action.data, + }); + } + + case ActionTypes.UPDATE_SCREEN_WIDTH: { + return _.assign({}, state, { + screenWidth: action.data, + }); + } + + case ActionTypes.UPDATE_BLOCKCHAIN_IS_LOADED: { + return _.assign({}, state, { + blockchainIsLoaded: action.data, + }); + } + + case ActionTypes.BLOCKCHAIN_ERR_ENCOUNTERED: { + return _.assign({}, state, { + blockchainErr: action.data, + }); + } + + case ActionTypes.UPDATE_NETWORK_ID: { + return _.assign({}, state, { + networkId: action.data, + }); + } + + case ActionTypes.UPDATE_GENERATE_ORDER_STEP: { + const direction = action.data; + let nextGenerateOrderStep = state.generateOrderStep; + if (direction === Direction.forward) { + nextGenerateOrderStep += 1; + } else if (state.generateOrderStep !== 0) { + nextGenerateOrderStep -= 1; + } + return _.assign({}, state, { + generateOrderStep: nextGenerateOrderStep, + }); + } + + case ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN: { + const newSideToAssetToken = _.assign({}, state.sideToAssetToken, { + [action.data.side]: action.data.token, + }); + return _.assign({}, state, { + sideToAssetToken: newSideToAssetToken, + }); + } + + case ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS: { + const newAssetToken = state.sideToAssetToken[action.data.side]; + newAssetToken.address = action.data.address; + const newSideToAssetToken = _.assign({}, state.sideToAssetToken, { + [action.data.side]: newAssetToken, + }); + return _.assign({}, state, { + sideToAssetToken: newSideToAssetToken, + }); + } + + case ActionTypes.SWAP_ASSET_TOKENS: { + const newSideToAssetToken = _.assign({}, state.sideToAssetToken, { + [Side.deposit]: state.sideToAssetToken[Side.receive], + [Side.receive]: state.sideToAssetToken[Side.deposit], + }); + return _.assign({}, state, { + sideToAssetToken: newSideToAssetToken, + }); + } + + case ActionTypes.UPDATE_ORDER_EXPIRY: { + return _.assign({}, state, { + orderExpiryTimestamp: action.data, + }); + } + + case ActionTypes.UPDATE_ORDER_TAKER_ADDRESS: { + return _.assign({}, state, { + orderTakerAddress: action.data, + }); + } + + case ActionTypes.UPDATE_USER_ADDRESS: { + return _.assign({}, state, { + userAddress: action.data, + }); + } + + // Docs + case ActionTypes.UPDATE_LIBRARY_VERSION: { + return _.assign({}, state, { + docsVersion: action.data, + }); + } + case ActionTypes.UPDATE_AVAILABLE_LIBRARY_VERSIONS: { + return _.assign({}, state, { + availableDocVersions: action.data, + }); + } + + // Shared + case ActionTypes.SHOW_FLASH_MESSAGE: { + return _.assign({}, state, { + flashMessage: action.data, + }); + } + + case ActionTypes.HIDE_FLASH_MESSAGE: { + return _.assign({}, state, { + flashMessage: undefined, + }); + } + + case ActionTypes.UPDATE_PROVIDER_TYPE: { + return _.assign({}, state, { + providerType: action.data, + }); + } + + case ActionTypes.UPDATE_INJECTED_PROVIDER_NAME: { + return _.assign({}, state, { + injectedProviderName: action.data, + }); + } + + default: + return state; + } +} |