aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/redux
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/redux')
-rw-r--r--packages/website/ts/redux/dispatcher.ts244
-rw-r--r--packages/website/ts/redux/reducer.ts363
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..566ab8a01
--- /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;
+ }
+}