aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/wallet
diff options
context:
space:
mode:
authorHsuan Lee <boczeratul@gmail.com>2019-03-06 17:46:50 +0800
committerHsuan Lee <boczeratul@gmail.com>2019-03-06 17:46:50 +0800
commit35703539d0f2b4ddb3b11d0de8c9634af59ab71f (patch)
treeae3731221dbbb3a6fa40060a8d916cfd3f738289 /packages/website/ts/components/wallet
parent92a1fde5b1ecd81b07cdb5bf0c9c1cd3544799db (diff)
downloaddexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.tar
dexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.tar.gz
dexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.tar.bz2
dexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.tar.lz
dexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.tar.xz
dexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.tar.zst
dexon-0x-contracts-35703539d0f2b4ddb3b11d0de8c9634af59ab71f.zip
Deploy @dexon-foundation/0x.jsstable
Diffstat (limited to 'packages/website/ts/components/wallet')
-rw-r--r--packages/website/ts/components/wallet/body_overlay.tsx136
-rw-r--r--packages/website/ts/components/wallet/null_token_row.tsx41
-rw-r--r--packages/website/ts/components/wallet/placeholder.tsx25
-rw-r--r--packages/website/ts/components/wallet/standard_icon_row.tsx44
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx527
-rw-r--r--packages/website/ts/components/wallet/wrap_ether_item.tsx230
6 files changed, 0 insertions, 1003 deletions
diff --git a/packages/website/ts/components/wallet/body_overlay.tsx b/packages/website/ts/components/wallet/body_overlay.tsx
deleted file mode 100644
index 3795f0eaa..000000000
--- a/packages/website/ts/components/wallet/body_overlay.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Blockchain } from 'ts/blockchain';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Island } from 'ts/components/ui/island';
-import { Text } from 'ts/components/ui/text';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-import { AccountState, ProviderType } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-const METAMASK_IMG_SRC = '/images/metamask_icon.png';
-const COINBASE_WALLET_IMG_SRC = '/images/coinbase_wallet_logo.png';
-
-export interface BodyOverlayProps {
- dispatcher: Dispatcher;
- userAddress: string;
- injectedProviderName: string;
- providerType: ProviderType;
- onToggleLedgerDialog: () => void;
- blockchain?: Blockchain;
- blockchainIsLoaded: boolean;
-}
-
-interface BodyOverlayState {}
-
-export class BodyOverlay extends React.Component<BodyOverlayProps, BodyOverlayState> {
- public render(): React.ReactNode {
- const accountState = this._getAccountState();
- switch (accountState) {
- case AccountState.Locked:
- return <LockedOverlay onUseDifferentWalletClicked={this.props.onToggleLedgerDialog} />;
- case AccountState.Disconnected:
- return <DisconnectedOverlay onUseDifferentWalletClicked={this.props.onToggleLedgerDialog} />;
- case AccountState.Ready:
- case AccountState.Loading:
- default:
- return null;
- }
- }
- private _isBlockchainReady(): boolean {
- return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain);
- }
- private _getAccountState(): AccountState {
- return utils.getAccountState(
- this._isBlockchainReady(),
- this.props.providerType,
- this.props.injectedProviderName,
- this.props.userAddress,
- );
- }
-}
-
-interface LockedOverlayProps {
- className?: string;
- onUseDifferentWalletClicked?: () => void;
-}
-const PlainLockedOverlay: React.StatelessComponent<LockedOverlayProps> = ({
- className,
- onUseDifferentWalletClicked,
-}) => (
- <div className={className}>
- <Container
- className="flex flex-column items-center"
- marginBottom="24px"
- marginTop="24px"
- marginLeft="48px"
- marginRight="48px"
- >
- <Image src={METAMASK_IMG_SRC} height="70px" />
- <Container marginTop="12px">
- <Text fontColor={colors.metaMaskOrange} fontSize="16px" fontWeight="bold">
- Please Unlock MetaMask
- </Text>
- </Container>
- <UseDifferentWallet fontColor={colors.darkGrey} onClick={onUseDifferentWalletClicked} />
- </Container>
- </div>
-);
-const LockedOverlay = styled(PlainLockedOverlay)`
- background: ${colors.metaMaskTransparentOrange};
- border: 1px solid ${colors.metaMaskOrange};
- border-radius: 10px;
-`;
-
-interface DisconnectedOverlayProps {
- onUseDifferentWalletClicked?: () => void;
-}
-const DisconnectedOverlay = (props: DisconnectedOverlayProps) => {
- return (
- <div className="flex flex-column items-center">
- <GetWalletCallToAction />
- {!utils.isMobileOperatingSystem() && (
- <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} />
- )}
- </div>
- );
-};
-
-interface UseDifferentWallet {
- fontColor: string;
- onClick?: () => void;
-}
-const UseDifferentWallet = (props: UseDifferentWallet) => {
- return (
- <Container marginTop="12px">
- <Text fontColor={props.fontColor} fontSize="16px" textDecorationLine="underline" onClick={props.onClick}>
- Use a different wallet
- </Text>
- </Container>
- );
-};
-
-const GetWalletCallToAction = () => {
- const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile();
- const imageUrl = isOnMobile ? COINBASE_WALLET_IMG_SRC : METAMASK_IMG_SRC;
- const text = isOnMobile ? 'Get Coinbase Wallet' : 'Get MetaMask Wallet';
- return (
- <a href={downloadLink} target="_blank" style={{ textDecoration: 'none' }}>
- <Island
- className="flex items-center py1 px2"
- style={{ height: 28, borderRadius: 28, backgroundColor: colors.mediumBlue }}
- >
- <Image src={imageUrl} width="28px" borderRadius="22%" />
- <Container marginLeft="8px" marginRight="12px">
- <Text fontColor={colors.white} fontSize="16px" fontWeight={500}>
- {text}
- </Text>
- </Container>
- </Island>
- </a>
- );
-};
diff --git a/packages/website/ts/components/wallet/null_token_row.tsx b/packages/website/ts/components/wallet/null_token_row.tsx
deleted file mode 100644
index a1ec9871a..000000000
--- a/packages/website/ts/components/wallet/null_token_row.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as React from 'react';
-
-import { Circle } from 'ts/components/ui/circle';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { PlaceHolder } from 'ts/components/wallet/placeholder';
-import { StandardIconRow } from 'ts/components/wallet/standard_icon_row';
-import { colors } from 'ts/style/colors';
-
-export interface NullTokenRowProps {
- iconDimension: number;
- fillColor: string;
-}
-
-export const NullTokenRow: React.StatelessComponent<NullTokenRowProps> = ({ iconDimension, fillColor }) => {
- const icon = <Circle diameter={iconDimension} fillColor={fillColor} />;
- const main = (
- <div className="flex flex-column">
- <PlaceHolder hideChildren={true} fillColor={fillColor}>
- <Text fontSize="16px" fontWeight="bold" lineHeight="1em">
- 0.00 XXX
- </Text>
- </PlaceHolder>
- <Container marginTop="3px">
- <PlaceHolder hideChildren={true} fillColor={fillColor}>
- <Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em">
- $0.00
- </Text>
- </PlaceHolder>
- </Container>
- </div>
- );
- const accessory = (
- <Container marginRight="12px">
- <PlaceHolder hideChildren={true} fillColor={fillColor}>
- <Container width="20px" height="14px" />
- </PlaceHolder>
- </Container>
- );
- return <StandardIconRow icon={icon} main={main} accessory={accessory} />;
-};
diff --git a/packages/website/ts/components/wallet/placeholder.tsx b/packages/website/ts/components/wallet/placeholder.tsx
deleted file mode 100644
index bf40d2ea8..000000000
--- a/packages/website/ts/components/wallet/placeholder.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import * as React from 'react';
-
-import { styled } from 'ts/style/theme';
-
-export interface PlaceHolderProps {
- className?: string;
- hideChildren: React.ReactNode;
- fillColor: string;
-}
-
-const PlainPlaceHolder: React.StatelessComponent<PlaceHolderProps> = ({ className, hideChildren, children }) => {
- const childrenVisibility = hideChildren ? 'hidden' : 'visible';
- const childrenStyle: React.CSSProperties = { visibility: childrenVisibility };
- return (
- <div className={className}>
- <div style={childrenStyle}>{children}</div>
- </div>
- );
-};
-
-export const PlaceHolder = styled(PlainPlaceHolder)`
- background-color: ${props => (props.hideChildren ? props.fillColor : 'transparent')};
- display: inline-block;
- border-radius: 2px;
-`;
diff --git a/packages/website/ts/components/wallet/standard_icon_row.tsx b/packages/website/ts/components/wallet/standard_icon_row.tsx
deleted file mode 100644
index 1a2ec021b..000000000
--- a/packages/website/ts/components/wallet/standard_icon_row.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import * as React from 'react';
-
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-
-export interface StandardIconRowProps {
- className?: string;
- icon: React.ReactNode;
- main: React.ReactNode;
- accessory?: React.ReactNode;
- minHeight?: string;
- borderBottomColor?: string;
- borderBottomStyle?: string;
- borderWidth?: string;
- backgroundColor?: string;
-}
-const PlainStandardIconRow: React.StatelessComponent<StandardIconRowProps> = ({ className, icon, main, accessory }) => {
- return (
- <div className={`flex items-center ${className}`}>
- <div className="flex items-center px2">{icon}</div>
- <div className="flex-none pr2">{main}</div>
- <div className="flex-auto" />
- <div>{accessory}</div>
- </div>
- );
-};
-
-export const StandardIconRow = styled(PlainStandardIconRow)`
- min-height: ${props => props.minHeight};
- border-bottom-color: ${props => props.borderBottomColor};
- border-bottom-style: ${props => props.borderBottomStyle};
- border-width: ${props => props.borderWidth};
- background-color: ${props => props.backgroundColor};
-`;
-
-StandardIconRow.defaultProps = {
- minHeight: '85px',
- borderBottomColor: colors.walletBorder,
- borderBottomStyle: 'solid',
- borderWidth: '1px',
- backgroundColor: colors.walletDefaultItemBackground,
-};
-
-StandardIconRow.displayName = 'StandardIconRow';
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
deleted file mode 100644
index d9da0b9d5..000000000
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ /dev/null
@@ -1,527 +0,0 @@
-import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
-import { BigNumber, errorUtils } from '@0x/utils';
-import * as _ from 'lodash';
-
-import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
-import * as React from 'react';
-import firstBy from 'thenby';
-
-import { Blockchain } from 'ts/blockchain';
-import { AccountConnection } from 'ts/components/ui/account_connection';
-import { Balance } from 'ts/components/ui/balance';
-import { Container } from 'ts/components/ui/container';
-import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down';
-import { IconButton } from 'ts/components/ui/icon_button';
-import { Identicon } from 'ts/components/ui/identicon';
-import { Island } from 'ts/components/ui/island';
-import { PointerDirection } from 'ts/components/ui/pointer';
-import {
- CopyAddressSimpleMenuItem,
- DifferentWalletSimpleMenuItem,
- GoToAccountManagementSimpleMenuItem,
- SimpleMenu,
- SimpleMenuItem,
-} from 'ts/components/ui/simple_menu';
-import { Text } from 'ts/components/ui/text';
-import { TokenIcon } from 'ts/components/ui/token_icon';
-import { BodyOverlay } from 'ts/components/wallet/body_overlay';
-import { NullTokenRow } from 'ts/components/wallet/null_token_row';
-import { PlaceHolder } from 'ts/components/wallet/placeholder';
-import { StandardIconRow } from 'ts/components/wallet/standard_icon_row';
-import { WrapEtherItem } from 'ts/components/wallet/wrap_ether_item';
-import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import {
- AccountState,
- BlockchainErrs,
- ProviderType,
- ScreenWidths,
- Side,
- Token,
- TokenByAddress,
- TokenState,
- TokenStateByAddress,
-} from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-export interface WalletProps {
- userAddress: string;
- networkId: number;
- blockchain: Blockchain;
- blockchainIsLoaded: boolean;
- blockchainErr: BlockchainErrs;
- dispatcher: Dispatcher;
- tokenByAddress: TokenByAddress;
- trackedTokens: Token[];
- userEtherBalanceInWei?: BigNumber;
- lastForceTokenStateRefetch: number;
- injectedProviderName: string;
- providerType: ProviderType;
- screenWidth: ScreenWidths;
- location: Location;
- trackedTokenStateByAddress: TokenStateByAddress;
- onToggleLedgerDialog: () => void;
- onAddToken: () => void;
- onRemoveToken: () => void;
- refetchTokenStateAsync: (tokenAddress: string) => Promise<void>;
- style: React.CSSProperties;
- toggleTooltipDirection?: PointerDirection;
-}
-
-interface WalletState {
- wrappedEtherDirection?: Side;
- isHoveringSidebar: boolean;
-}
-
-interface AllowanceStateToggleConfig {
- token: Token;
- tokenState: TokenState;
-}
-
-interface AccessoryItemConfig {
- wrappedEtherDirection?: Side;
- allowanceStateToggleConfig?: AllowanceStateToggleConfig;
-}
-
-const ETHER_ICON_PATH = '/images/ether.png';
-const ICON_DIMENSION = 28;
-const BODY_ITEM_KEY = 'BODY';
-const HEADER_ITEM_KEY = 'HEADER';
-const ETHER_ITEM_KEY = 'ETHER';
-const WRAP_ROW_ALLOWANCE_TOGGLE_WIDTH = 67;
-const ALLOWANCE_TOGGLE_WIDTH = 56;
-const PLACEHOLDER_COLOR = colors.grey300;
-const LOADING_ROWS_COUNT = 6;
-
-export class Wallet extends React.Component<WalletProps, WalletState> {
- public static defaultProps = {
- style: {},
- };
- constructor(props: WalletProps) {
- super(props);
- this.state = {
- wrappedEtherDirection: undefined,
- isHoveringSidebar: false,
- };
- }
- public componentDidUpdate(prevProps: WalletProps): void {
- const currentTrackedTokens = this.props.trackedTokens;
- const differentTrackedTokens = _.difference(currentTrackedTokens, prevProps.trackedTokens);
- const firstDifferentTrackedToken = _.head(differentTrackedTokens);
- // check if there is only one different token, and if that token is a member of the current tracked tokens
- // this means that the token was added, not removed
- if (
- !_.isUndefined(firstDifferentTrackedToken) &&
- _.size(differentTrackedTokens) === 1 &&
- _.includes(currentTrackedTokens, firstDifferentTrackedToken)
- ) {
- document.getElementById(firstDifferentTrackedToken.address).scrollIntoView();
- }
- }
- public render(): React.ReactNode {
- return (
- <Island className="flex flex-column wallet" style={this.props.style}>
- {this._isBlockchainReady() ? this._renderLoadedRows() : this._renderLoadingRows()}
- </Island>
- );
- }
- private _renderLoadingRows(): React.ReactNode {
- return _.concat(this._renderLoadingHeaderRows(), this._renderLoadingBodyRows());
- }
- private _renderLoadingHeaderRows(): React.ReactElement<{}> {
- return this._renderPlainHeaderRow('Loading...');
- }
- private _renderLoadingBodyRows(): React.ReactElement<{}> {
- const bodyStyle = this._getBodyStyle();
- const loadingRowsRange = _.range(LOADING_ROWS_COUNT);
- return (
- <div key={BODY_ITEM_KEY} className="flex flex-column" style={bodyStyle}>
- {_.map(loadingRowsRange, index => {
- return <NullTokenRow key={index} iconDimension={ICON_DIMENSION} fillColor={PLACEHOLDER_COLOR} />;
- })}
- <Container
- className="flex items-center"
- position="absolute"
- width="100%"
- height="100%"
- maxHeight={bodyStyle.maxHeight}
- >
- <div className="mx-auto">
- <BodyOverlay
- dispatcher={this.props.dispatcher}
- userAddress={this.props.userAddress}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.props.onToggleLedgerDialog}
- blockchain={this.props.blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- />
- </div>
- </Container>
- </div>
- );
- }
- private _renderLoadedRows(): React.ReactNode {
- const isAddressAvailable = !_.isEmpty(this.props.userAddress);
- return isAddressAvailable
- ? _.concat(this._renderConnectedHeaderRows(), this._renderBody())
- : _.concat(this._renderDisconnectedHeaderRows(), this._renderLoadingBodyRows());
- }
- private _renderDisconnectedHeaderRows(): React.ReactElement<{}> {
- const isExternallyInjectedProvider = utils.isExternallyInjected(
- this.props.providerType,
- this.props.injectedProviderName,
- );
- const text = isExternallyInjectedProvider ? 'Please unlock MetaMask...' : 'Please connect a wallet...';
- return this._renderPlainHeaderRow(text);
- }
- private _renderPlainHeaderRow(text: string): React.ReactElement<{}> {
- return (
- <StandardIconRow
- key={HEADER_ITEM_KEY}
- icon={<ActionAccountBalanceWallet color={colors.grey} />}
- main={
- <Text fontSize="16px" fontColor={colors.grey}>
- {text}
- </Text>
- // https://github.com/palantir/tslint-react/issues/140
- // tslint:disable-next-line:jsx-curly-spacing
- }
- minHeight="60px"
- backgroundColor={colors.white}
- />
- );
- }
- private _renderConnectedHeaderRows(): React.ReactElement<{}> {
- const isMobile = this.props.screenWidth === ScreenWidths.Sm;
- const userAddress = this.props.userAddress;
- const accountState = this._getAccountState();
- const main = (
- <div className="flex flex-column">
- <Text fontSize="16px" lineHeight="19px" fontWeight={500}>
- {utils.getAddressBeginAndEnd(userAddress)}
- </Text>
- <AccountConnection accountState={accountState} injectedProviderName={this.props.injectedProviderName} />
- </div>
- );
- const onClick = _.noop.bind(_);
- const accessory = (
- <DropDown
- activeNode={
- // this container gives the menu button more of a hover target for the drop down
- // it prevents accidentally closing the menu by moving off of the button
- <Container paddingLeft="100px" paddingRight="15px">
- <Text
- className="zmdi zmdi-more-horiz"
- Tag="i"
- fontSize="32px"
- fontFamily="Material-Design-Iconic-Font"
- fontColor={colors.darkGrey}
- onClick={onClick}
- hoverColor={colors.mediumBlue}
- />
- </Container>
- }
- popoverContent={
- <SimpleMenu minWidth="150px">
- <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} />
- {!isMobile && <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} />}
- <SimpleMenuItem displayText="Add Tokens..." onClick={this.props.onAddToken} />
- <SimpleMenuItem displayText="Remove Tokens..." onClick={this.props.onRemoveToken} />
- {!isMobile && <GoToAccountManagementSimpleMenuItem />}
- </SimpleMenu>
- }
- anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
- targetOrigin={{ horizontal: 'right', vertical: 'top' }}
- zDepth={1}
- activateEvent={DropdownMouseEvent.Click}
- closeEvent={DropdownMouseEvent.Click}
- />
- );
- return (
- <StandardIconRow
- key={HEADER_ITEM_KEY}
- icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
- main={main}
- accessory={accessory}
- minHeight="60px"
- backgroundColor={colors.white}
- />
- );
- }
- private _renderBody(): React.ReactElement<{}> {
- const bodyStyle = this._getBodyStyle();
- return (
- <div
- style={bodyStyle}
- key={BODY_ITEM_KEY}
- onMouseEnter={this._onSidebarHover.bind(this)}
- onMouseLeave={this._onSidebarHoverOff.bind(this)}
- >
- {this._renderEthRows()}
- {this._renderTokenRows()}
- </div>
- );
- }
- private _getBodyStyle(): React.CSSProperties {
- return {
- overflow: 'auto',
- WebkitOverflowScrolling: 'touch',
- position: 'relative',
- overflowY: this.state.isHoveringSidebar ? 'scroll' : 'hidden',
- marginRight: this.state.isHoveringSidebar ? 0 : 4,
- minHeight: '250px',
- maxHeight: !utils.isMobileWidth(this.props.screenWidth) ? 'calc(90vh - 300px)' : undefined,
- };
- }
- private _onSidebarHover(_event: React.FormEvent<HTMLInputElement>): void {
- this.setState({
- isHoveringSidebar: true,
- });
- }
- private _onSidebarHoverOff(): void {
- this.setState({
- isHoveringSidebar: false,
- });
- }
- private _renderEthRows(): React.ReactNode {
- const icon = <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />;
- const primaryText = this._renderAmount(
- this.props.userEtherBalanceInWei || new BigNumber(0),
- constants.DECIMAL_PLACES_ETH,
- constants.ETHER_SYMBOL,
- _.isUndefined(this.props.userEtherBalanceInWei),
- );
- const etherToken = this._getEthToken();
- const etherTokenState = this.props.trackedTokenStateByAddress[etherToken.address];
- const etherPrice = etherTokenState.price;
- const secondaryText = this._renderValue(
- this.props.userEtherBalanceInWei || new BigNumber(0),
- constants.DECIMAL_PLACES_ETH,
- etherPrice,
- _.isUndefined(this.props.userEtherBalanceInWei) || !etherTokenState.isLoaded,
- );
- const accessoryItemConfig = {
- wrappedEtherDirection: Side.Deposit,
- };
- const key = ETHER_ITEM_KEY;
- return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
- }
- private _renderTokenRows(): React.ReactNode {
- const trackedTokens = this.props.trackedTokens;
- const trackedTokensStartingWithEtherToken = trackedTokens.sort(
- firstBy((t: Token) => t.symbol !== constants.ETHER_TOKEN_SYMBOL)
- .thenBy((t: Token) => t.symbol !== constants.ZRX_TOKEN_SYMBOL)
- .thenBy('trackedTimestamp'),
- );
- return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
- }
- private _renderTokenRow(token: Token): React.ReactNode {
- const tokenState = this.props.trackedTokenStateByAddress[token.address];
- if (_.isUndefined(tokenState)) {
- return null;
- }
- const tokenLink = sharedUtils.getEtherScanLinkIfExists(
- token.address,
- this.props.networkId,
- EtherscanLinkSuffixes.Address,
- );
- const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />;
- const isWeth = token.symbol === constants.ETHER_TOKEN_SYMBOL;
- const wrappedEtherDirection = isWeth ? Side.Receive : undefined;
- const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol, !tokenState.isLoaded);
- const secondaryText = this._renderValue(
- tokenState.balance,
- token.decimals,
- tokenState.price,
- !tokenState.isLoaded,
- );
- const accessoryItemConfig: AccessoryItemConfig = {
- wrappedEtherDirection,
- allowanceStateToggleConfig: {
- token,
- tokenState,
- },
- };
- const key = token.address;
- return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
- }
- private _renderBalanceRow(
- key: string,
- icon: React.ReactNode,
- primaryText: React.ReactNode,
- secondaryText: React.ReactNode,
- accessoryItemConfig: AccessoryItemConfig,
- className?: string,
- ): React.ReactNode {
- const shouldShowWrapEtherItem =
- !_.isUndefined(this.state.wrappedEtherDirection) &&
- this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection &&
- !_.isUndefined(this.props.userEtherBalanceInWei);
- const etherToken = this._getEthToken();
- const wrapEtherItem = shouldShowWrapEtherItem ? (
- <WrapEtherItem
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- direction={accessoryItemConfig.wrappedEtherDirection}
- etherToken={etherToken}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- onConversionSuccessful={this._closeWrappedEtherActionRow.bind(this)}
- // tslint:disable:jsx-no-lambda
- refetchEthTokenStateAsync={async () => this.props.refetchTokenStateAsync(etherToken.address)}
- />
- ) : null;
- return (
- <div id={key} key={key} className={`flex flex-column ${className || ''}`}>
- {this.state.wrappedEtherDirection === Side.Receive && wrapEtherItem}
- <StandardIconRow
- icon={icon}
- main={
- <div className="flex flex-column">
- {primaryText}
- <Container marginTop="3px">{secondaryText}</Container>
- </div>
- }
- accessory={this._renderAccessoryItems(accessoryItemConfig)}
- />
- {this.state.wrappedEtherDirection === Side.Deposit && wrapEtherItem}
- </div>
- );
- }
- private _renderAccessoryItems(config: AccessoryItemConfig): React.ReactElement<{}> {
- const shouldShowWrappedEtherAction = !_.isUndefined(config.wrappedEtherDirection);
- const shouldShowToggle = !_.isUndefined(config.allowanceStateToggleConfig);
- // if we don't have a toggle, we still want some space to the right of the "wrap" button so that it aligns with
- // the "unwrap" button in the row below
- const isWrapEtherRow = shouldShowWrappedEtherAction && config.wrappedEtherDirection === Side.Deposit;
- const width = isWrapEtherRow ? WRAP_ROW_ALLOWANCE_TOGGLE_WIDTH : ALLOWANCE_TOGGLE_WIDTH;
- const toggle = (
- <Container className="flex justify-center" width={width}>
- {shouldShowToggle && this._renderAllowanceToggle(config.allowanceStateToggleConfig)}
- </Container>
- );
- return (
- <div className="flex items-center">
- <div className="flex-auto">
- {shouldShowWrappedEtherAction && this._renderWrappedEtherButton(config.wrappedEtherDirection)}
- </div>
- <div className="flex-last pl2">{toggle}</div>
- </div>
- );
- }
- private _renderAllowanceToggle(config: AllowanceStateToggleConfig): React.ReactNode {
- // TODO: Error handling
- return (
- <AllowanceStateToggle
- blockchain={this.props.blockchain}
- token={config.token}
- tokenState={config.tokenState}
- tooltipDirection={this.props.toggleTooltipDirection}
- refetchTokenStateAsync={async () => this.props.refetchTokenStateAsync(config.token.address)}
- />
- );
- }
- private _renderAmount(
- amount: BigNumber,
- decimals: number,
- symbol: string,
- isLoading: boolean = false,
- ): React.ReactNode {
- if (isLoading) {
- return (
- <PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}>
- <Text fontSize="16px" fontWeight="bold" lineHeight="1em">
- 0.00 XXX
- </Text>
- </PlaceHolder>
- );
- } else {
- return <Balance amount={amount} decimals={decimals} symbol={symbol} />;
- }
- }
- private _renderValue(
- amount: BigNumber,
- decimals: number,
- price?: BigNumber,
- isLoading: boolean = false,
- ): React.ReactNode {
- const result = !isLoading
- ? _.isUndefined(price)
- ? '--'
- : utils.getUsdValueFormattedAmount(amount, decimals, price)
- : '$0.00';
- return (
- <PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}>
- <Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em">
- {result}
- </Text>
- </PlaceHolder>
- );
- }
- private _renderWrappedEtherButton(wrappedEtherDirection: Side): React.ReactNode {
- const isWrappedEtherDirectionOpen = this.state.wrappedEtherDirection === wrappedEtherDirection;
- let buttonLabel;
- let buttonIconName;
- if (isWrappedEtherDirectionOpen) {
- buttonLabel = 'cancel';
- buttonIconName = 'zmdi-close';
- } else {
- switch (wrappedEtherDirection) {
- case Side.Deposit:
- buttonLabel = 'wrap';
- buttonIconName = 'zmdi-long-arrow-down';
- break;
- case Side.Receive:
- buttonLabel = 'unwrap';
- buttonIconName = 'zmdi-long-arrow-up';
- break;
- default:
- throw errorUtils.spawnSwitchErr('wrappedEtherDirection', wrappedEtherDirection);
- }
- }
- const onClick = isWrappedEtherDirectionOpen
- ? this._closeWrappedEtherActionRow.bind(this, wrappedEtherDirection)
- : this._openWrappedEtherActionRow.bind(this, wrappedEtherDirection);
- return (
- <IconButton iconName={buttonIconName} labelText={buttonLabel} onClick={onClick} color={colors.mediumBlue} />
- );
- }
- private _openWrappedEtherActionRow(wrappedEtherDirection: Side): void {
- const action =
- wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Opened' : 'Wallet - Unwrap WETH Opened';
- analytics.track(action);
- this.setState({
- wrappedEtherDirection,
- });
- }
- private _closeWrappedEtherActionRow(wrappedEtherDirection: Side): void {
- const action =
- wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Closed' : 'Wallet - Unwrap WETH Closed';
- analytics.track(action);
- this.setState({
- wrappedEtherDirection: undefined,
- });
- }
- private _getEthToken(): Token {
- return utils.getEthToken(this.props.tokenByAddress);
- }
- private _isBlockchainReady(): boolean {
- return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain);
- }
- private _getAccountState(): AccountState {
- return utils.getAccountState(
- this._isBlockchainReady(),
- this.props.providerType,
- this.props.injectedProviderName,
- this.props.userAddress,
- );
- }
-}
-
-// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/wallet/wrap_ether_item.tsx b/packages/website/ts/components/wallet/wrap_ether_item.tsx
deleted file mode 100644
index 7de3afbf8..000000000
--- a/packages/website/ts/components/wallet/wrap_ether_item.tsx
+++ /dev/null
@@ -1,230 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import { BigNumber, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-
-import { Blockchain } from 'ts/blockchain';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { Container } from 'ts/components/ui/container';
-import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import { BlockchainCallErrs, Side, Token } from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-export interface WrapEtherItemProps {
- userAddress: string;
- networkId: number;
- blockchain: Blockchain;
- dispatcher: Dispatcher;
- userEtherBalanceInWei: BigNumber;
- direction: Side;
- etherToken: Token;
- lastForceTokenStateRefetch: number;
- onConversionSuccessful?: () => void;
- refetchEthTokenStateAsync: () => Promise<void>;
-}
-
-interface WrapEtherItemState {
- currentInputAmount?: BigNumber;
- isEthConversionHappening: boolean;
- errorMsg: React.ReactNode;
-}
-
-const styles: Styles = {
- topLabel: {
- color: colors.black,
- fontSize: 11,
- },
- inputContainer: {
- backgroundColor: colors.white,
- borderBottomRightRadius: 3,
- borderBottomLeftRadius: 3,
- borderTopRightRadius: 3,
- borderTopLeftRadius: 3,
- padding: 4,
- },
- amountInput: {
- height: 34,
- },
- amountInputLabel: {
- paddingTop: 10,
- paddingRight: 10,
- paddingLeft: 5,
- color: colors.grey,
- fontSize: 14,
- },
- amountInputHint: {
- bottom: 18,
- },
- wrapEtherConfirmationButtonLabel: {
- fontSize: 12,
- color: colors.white,
- },
- errorMsg: {
- fontSize: 12,
- marginTop: 4,
- color: colors.red,
- minHeight: 20,
- },
- conversionSpinner: {
- paddingTop: 26,
- },
-};
-
-export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEtherItemState> {
- constructor(props: WrapEtherItemProps) {
- super(props);
- this.state = {
- currentInputAmount: undefined,
- isEthConversionHappening: false,
- errorMsg: null,
- };
- }
- public render(): React.ReactNode {
- const isWrappingEth = this.props.direction === Side.Deposit;
- const topLabelText = isWrappingEth ? 'Convert ETH into WETH 1:1' : 'Convert WETH into ETH 1:1';
- return (
- <Container className="flex" backgroundColor={colors.walletFocusedItemBackground} paddingTop="25px">
- <div>{this._renderIsEthConversionHappeningSpinner()} </div>
- <div className="flex flex-column">
- <div style={styles.topLabel}>{topLabelText}</div>
- <div className="flex items-center">
- <div style={styles.inputContainer}>
- {isWrappingEth ? (
- <EthAmountInput
- amount={this.state.currentInputAmount}
- hintText="0.00"
- onChange={this._onValueChange.bind(this)}
- shouldCheckBalance={true}
- shouldShowIncompleteErrs={false}
- shouldShowErrs={false}
- shouldShowUnderline={false}
- style={styles.amountInput}
- labelStyle={styles.amountInputLabel}
- inputHintStyle={styles.amountInputHint}
- onErrorMsgChange={this._onErrorMsgChange.bind(this)}
- />
- ) : (
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- token={this.props.etherToken}
- shouldShowIncompleteErrs={false}
- shouldCheckBalance={true}
- shouldCheckAllowance={false}
- onChange={this._onValueChange.bind(this)}
- amount={this.state.currentInputAmount}
- hintText="0.00"
- shouldShowErrs={false}
- shouldShowUnderline={false}
- style={styles.amountInput}
- labelStyle={styles.amountInputLabel}
- inputHintStyle={styles.amountInputHint}
- onErrorMsgChange={this._onErrorMsgChange.bind(this)}
- />
- )}
- </div>
- <div>{this._renderWrapEtherConfirmationButton()}</div>
- </div>
-
- {this._renderErrorMsg()}
- </div>
- </Container>
- );
- }
- private _onValueChange(_isValid: boolean, amount?: BigNumber): void {
- this.setState({
- currentInputAmount: amount,
- });
- }
- private _onErrorMsgChange(errorMsg: React.ReactNode): void {
- this.setState({
- errorMsg,
- });
- }
- private _renderIsEthConversionHappeningSpinner(): React.ReactElement<{}> {
- const visibility = this.state.isEthConversionHappening ? 'visible' : 'hidden';
- const style: React.CSSProperties = { ...styles.conversionSpinner, visibility };
- return (
- <div className="pl3 pr2" style={style}>
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- </div>
- );
- }
- private _renderWrapEtherConfirmationButton(): React.ReactElement<{}> {
- const isWrappingEth = this.props.direction === Side.Deposit;
- const labelText = isWrappingEth ? 'wrap' : 'unwrap';
- return (
- <div className="pl1 pr3">
- <FlatButton
- backgroundColor={colors.wrapEtherConfirmationButton}
- label={labelText}
- style={{ zIndex: 0 }}
- labelStyle={styles.wrapEtherConfirmationButtonLabel}
- onClick={this._wrapEtherConfirmationActionAsync.bind(this)}
- disabled={this.state.isEthConversionHappening}
- />
- </div>
- );
- }
- private _renderErrorMsg(): React.ReactNode {
- return <div style={styles.errorMsg}>{this.state.errorMsg}</div>;
- }
- private async _wrapEtherConfirmationActionAsync(): Promise<void> {
- this.setState({
- isEthConversionHappening: true,
- });
- const etherToken = this.props.etherToken;
- const amountToConvert = this.state.currentInputAmount;
- const ethAmount = Web3Wrapper.toUnitAmount(amountToConvert, constants.DECIMAL_PLACES_ETH).toString();
- const tokenAmount = Web3Wrapper.toUnitAmount(amountToConvert, etherToken.decimals).toString();
- try {
- if (this.props.direction === Side.Deposit) {
- await this.props.blockchain.convertEthToWrappedEthTokensAsync(etherToken.address, amountToConvert);
- this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount} ETH to WETH`);
- analytics.track('Wrap ETH Success', {
- amount: ethAmount,
- });
- } else {
- await this.props.blockchain.convertWrappedEthTokensToEthAsync(etherToken.address, amountToConvert);
- this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount} WETH to ETH`);
- analytics.track('Unwrap WETH Success', {
- amount: tokenAmount,
- });
- }
- await this.props.refetchEthTokenStateAsync();
- this.props.onConversionSuccessful();
- } catch (err) {
- const errMsg = `${err}`;
- if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- } else if (!utils.didUserDenyWeb3Request(errMsg)) {
- logUtils.log(`Unexpected error encountered: ${err}`);
- logUtils.log(err.stack);
- if (this.props.direction === Side.Deposit) {
- this.props.dispatcher.showFlashMessage('Failed to wrap your ETH. Please try again.');
- analytics.track('Wrap ETH Failure', {
- amount: ethAmount,
- });
- } else {
- this.props.dispatcher.showFlashMessage('Failed to unwrap your WETH. Please try again.');
- analytics.track('Unwrap WETH Failed', {
- amount: tokenAmount,
- });
- }
- errorReporter.report(err);
- }
- }
- this.setState({
- isEthConversionHappening: false,
- });
- }
-}