Consolidate account state messaging logic
This commit is contained in:
@@ -2,10 +2,12 @@ import { Styles } from '@0xproject/react-shared';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { Blockchain } from 'ts/blockchain';
|
||||||
import { defaultMenuItemEntries, Menu } from 'ts/components/portal/menu';
|
import { defaultMenuItemEntries, Menu } from 'ts/components/portal/menu';
|
||||||
import { Identicon } from 'ts/components/ui/identicon';
|
import { Identicon } from 'ts/components/ui/identicon';
|
||||||
|
import { Text } from 'ts/components/ui/text';
|
||||||
import { colors } from 'ts/style/colors';
|
import { colors } from 'ts/style/colors';
|
||||||
import { WebsitePaths } from 'ts/types';
|
import { ProviderType, WebsitePaths } from 'ts/types';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
const IDENTICON_DIAMETER = 45;
|
const IDENTICON_DIAMETER = 45;
|
||||||
@@ -25,14 +27,15 @@ const styles: Styles = {
|
|||||||
MozBorderRadius: BORDER_RADIUS,
|
MozBorderRadius: BORDER_RADIUS,
|
||||||
WebkitBorderRadius: BORDER_RADIUS,
|
WebkitBorderRadius: BORDER_RADIUS,
|
||||||
},
|
},
|
||||||
userAddress: {
|
|
||||||
color: colors.white,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface DrawerMenuProps {
|
export interface DrawerMenuProps {
|
||||||
selectedPath?: string;
|
selectedPath?: string;
|
||||||
userAddress?: string;
|
userAddress?: string;
|
||||||
|
injectedProviderName: string;
|
||||||
|
providerType: ProviderType;
|
||||||
|
blockchain?: Blockchain;
|
||||||
|
blockchainIsLoaded: boolean;
|
||||||
}
|
}
|
||||||
export const DrawerMenu = (props: DrawerMenuProps) => {
|
export const DrawerMenu = (props: DrawerMenuProps) => {
|
||||||
const relayerItemEntry = {
|
const relayerItemEntry = {
|
||||||
@@ -41,9 +44,15 @@ export const DrawerMenu = (props: DrawerMenuProps) => {
|
|||||||
iconName: 'zmdi-portable-wifi',
|
iconName: 'zmdi-portable-wifi',
|
||||||
};
|
};
|
||||||
const menuItemEntries = _.concat(relayerItemEntry, defaultMenuItemEntries);
|
const menuItemEntries = _.concat(relayerItemEntry, defaultMenuItemEntries);
|
||||||
|
const displayMessage = utils.getReadableAccountState(
|
||||||
|
props.blockchainIsLoaded && !_.isUndefined(props.blockchain),
|
||||||
|
props.providerType,
|
||||||
|
props.injectedProviderName,
|
||||||
|
props.userAddress,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div style={styles.root}>
|
<div style={styles.root}>
|
||||||
<Header userAddress={props.userAddress} />
|
<Header userAddress={props.userAddress} displayMessage={displayMessage} />
|
||||||
<Menu selectedPath={props.selectedPath} menuItemEntries={menuItemEntries} />
|
<Menu selectedPath={props.selectedPath} menuItemEntries={menuItemEntries} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -51,17 +60,16 @@ export const DrawerMenu = (props: DrawerMenuProps) => {
|
|||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
userAddress?: string;
|
userAddress?: string;
|
||||||
|
displayMessage: string;
|
||||||
}
|
}
|
||||||
const Header = (props: HeaderProps) => {
|
const Header = (props: HeaderProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-center py4">
|
<div className="flex flex-center py4">
|
||||||
<div className="flex flex-column mx-auto">
|
<div className="flex flex-column mx-auto">
|
||||||
<Identicon address={props.userAddress} diameter={IDENTICON_DIAMETER} style={styles.identicon} />
|
<Identicon address={props.userAddress} diameter={IDENTICON_DIAMETER} style={styles.identicon} />
|
||||||
{!_.isUndefined(props.userAddress) && (
|
<Text className="pt2" fontColor={colors.white}>
|
||||||
<div className="pt2" style={styles.userAddress}>
|
{props.displayMessage}
|
||||||
{utils.getAddressBeginAndEnd(props.userAddress)}
|
</Text>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import * as React from 'react';
|
|||||||
|
|
||||||
import { Blockchain } from 'ts/blockchain';
|
import { Blockchain } from 'ts/blockchain';
|
||||||
import { ProviderPicker } from 'ts/components/top_bar/provider_picker';
|
import { ProviderPicker } from 'ts/components/top_bar/provider_picker';
|
||||||
|
import { Container } from 'ts/components/ui/container';
|
||||||
import { DropDown } from 'ts/components/ui/drop_down';
|
import { DropDown } from 'ts/components/ui/drop_down';
|
||||||
import { Identicon } from 'ts/components/ui/identicon';
|
import { Identicon } from 'ts/components/ui/identicon';
|
||||||
|
import { Text } from 'ts/components/ui/text';
|
||||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||||
import { colors } from 'ts/style/colors';
|
import { colors } from 'ts/style/colors';
|
||||||
import { ProviderType } from 'ts/types';
|
import { ProviderType } from 'ts/types';
|
||||||
@@ -40,23 +42,16 @@ const styles: Styles = {
|
|||||||
|
|
||||||
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
|
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
|
|
||||||
const isExternallyInjectedProvider = utils.isExternallyInjected(
|
const isExternallyInjectedProvider = utils.isExternallyInjected(
|
||||||
this.props.providerType,
|
this.props.providerType,
|
||||||
this.props.injectedProviderName,
|
this.props.injectedProviderName,
|
||||||
);
|
);
|
||||||
let displayMessage;
|
const displayMessage = utils.getReadableAccountState(
|
||||||
if (!this._isBlockchainReady()) {
|
this._isBlockchainReady(),
|
||||||
displayMessage = 'loading account';
|
this.props.providerType,
|
||||||
} else if (isAddressAvailable) {
|
this.props.injectedProviderName,
|
||||||
displayMessage = utils.getAddressBeginAndEnd(this.props.userAddress);
|
this.props.userAddress,
|
||||||
// tslint:disable-next-line: prefer-conditional-expression
|
);
|
||||||
} else if (isExternallyInjectedProvider) {
|
|
||||||
displayMessage = 'Account locked';
|
|
||||||
} else {
|
|
||||||
displayMessage = '0x0000...0000';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the "injected" provider is our fallback public node, then we want to
|
// If the "injected" provider is our fallback public node, then we want to
|
||||||
// show the "connect a wallet" message instead of the providerName
|
// show the "connect a wallet" message instead of the providerName
|
||||||
const injectedProviderName = isExternallyInjectedProvider
|
const injectedProviderName = isExternallyInjectedProvider
|
||||||
@@ -66,7 +61,7 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
|
|||||||
this.props.providerType === ProviderType.Injected ? injectedProviderName : 'Ledger Nano S';
|
this.props.providerType === ProviderType.Injected ? injectedProviderName : 'Ledger Nano S';
|
||||||
const isProviderMetamask = providerTitle === constants.PROVIDER_NAME_METAMASK;
|
const isProviderMetamask = providerTitle === constants.PROVIDER_NAME_METAMASK;
|
||||||
const hoverActiveNode = (
|
const hoverActiveNode = (
|
||||||
<div className="flex right lg-pr0 md-pr2 sm-pr2 p1" style={styles.root}>
|
<div className="flex items-center p1" style={styles.root}>
|
||||||
<div>
|
<div>
|
||||||
{this._isBlockchainReady() ? (
|
{this._isBlockchainReady() ? (
|
||||||
<Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />
|
<Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />
|
||||||
@@ -74,13 +69,13 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
|
|||||||
<CircularProgress size={ROOT_HEIGHT} thickness={2} />
|
<CircularProgress size={ROOT_HEIGHT} thickness={2} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginLeft: 12, paddingTop: 3 }}>
|
<Container marginLeft="12px" marginRight="12px">
|
||||||
<div style={{ fontSize: 16, color: colors.darkGrey }}>{displayMessage}</div>
|
<Text fontSize="14px" fontColor={colors.darkGrey}>
|
||||||
</div>
|
{displayMessage}
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
{isProviderMetamask && (
|
{isProviderMetamask && (
|
||||||
<div style={{ marginLeft: 16 }}>
|
<img src="/images/metamask_icon.png" style={{ width: ROOT_HEIGHT, height: ROOT_HEIGHT }} />
|
||||||
<img src="/images/metamask_icon.png" style={{ width: ROOT_HEIGHT, height: ROOT_HEIGHT }} />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -297,7 +297,14 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
openSecondary={true}
|
openSecondary={true}
|
||||||
onRequestChange={this._onMenuButtonClick.bind(this)}
|
onRequestChange={this._onMenuButtonClick.bind(this)}
|
||||||
>
|
>
|
||||||
<DrawerMenu selectedPath={this.props.location.pathname} userAddress={this.props.userAddress} />
|
<DrawerMenu
|
||||||
|
selectedPath={this.props.location.pathname}
|
||||||
|
userAddress={this.props.userAddress}
|
||||||
|
injectedProviderName={this.props.injectedProviderName}
|
||||||
|
providerType={this.props.providerType}
|
||||||
|
blockchainIsLoaded={this.props.blockchainIsLoaded}
|
||||||
|
blockchain={this.props.blockchain}
|
||||||
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import blockies = require('blockies');
|
import blockies = require('blockies');
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { constants } from 'ts/utils/constants';
|
|
||||||
|
import { colors } from 'ts/style/colors';
|
||||||
|
|
||||||
interface IdenticonProps {
|
interface IdenticonProps {
|
||||||
address: string;
|
address: string;
|
||||||
@@ -16,14 +17,9 @@ export class Identicon extends React.Component<IdenticonProps, IdenticonState> {
|
|||||||
style: {},
|
style: {},
|
||||||
};
|
};
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let address = this.props.address;
|
const address = this.props.address;
|
||||||
if (_.isEmpty(address)) {
|
|
||||||
address = constants.NULL_ADDRESS;
|
|
||||||
}
|
|
||||||
const diameter = this.props.diameter;
|
const diameter = this.props.diameter;
|
||||||
const icon = blockies({
|
const radius = diameter / 2;
|
||||||
seed: address.toLowerCase(),
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="circle mx-auto relative transitionFix"
|
className="circle mx-auto relative transitionFix"
|
||||||
@@ -34,14 +30,22 @@ export class Identicon extends React.Component<IdenticonProps, IdenticonState> {
|
|||||||
...this.props.style,
|
...this.props.style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
{!_.isEmpty(address) ? (
|
||||||
src={icon.toDataURL()}
|
<img
|
||||||
style={{
|
src={blockies({
|
||||||
width: diameter,
|
seed: address.toLowerCase(),
|
||||||
height: diameter,
|
}).toDataURL()}
|
||||||
imageRendering: 'pixelated',
|
style={{
|
||||||
}}
|
width: diameter,
|
||||||
/>
|
height: diameter,
|
||||||
|
imageRendering: 'pixelated',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<svg height={diameter} width={diameter}>
|
||||||
|
<circle cx={radius} cy={radius} r={radius} fill={colors.grey200} />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,25 @@ export const utils = {
|
|||||||
const truncatedAddress = `${address.substring(0, 6)}...${address.substr(-4)}`; // 0x3d5a...b287
|
const truncatedAddress = `${address.substring(0, 6)}...${address.substr(-4)}`; // 0x3d5a...b287
|
||||||
return truncatedAddress;
|
return truncatedAddress;
|
||||||
},
|
},
|
||||||
|
getReadableAccountState(
|
||||||
|
isBlockchainReady: boolean,
|
||||||
|
providerType: ProviderType,
|
||||||
|
injectedProviderName: string,
|
||||||
|
userAddress?: string,
|
||||||
|
): string {
|
||||||
|
const isAddressAvailable = !_.isUndefined(userAddress) && !_.isEmpty(userAddress);
|
||||||
|
const isExternallyInjectedProvider = utils.isExternallyInjected(providerType, injectedProviderName);
|
||||||
|
if (!isBlockchainReady) {
|
||||||
|
return 'Loading account';
|
||||||
|
} else if (isAddressAvailable) {
|
||||||
|
return utils.getAddressBeginAndEnd(userAddress);
|
||||||
|
// tslint:disable-next-line: prefer-conditional-expression
|
||||||
|
} else if (isExternallyInjectedProvider) {
|
||||||
|
return 'Account locked';
|
||||||
|
} else {
|
||||||
|
return 'No wallet detected';
|
||||||
|
}
|
||||||
|
},
|
||||||
hasUniqueNameAndSymbol(tokens: Token[], token: Token): boolean {
|
hasUniqueNameAndSymbol(tokens: Token[], token: Token): boolean {
|
||||||
if (token.isRegistered) {
|
if (token.isRegistered) {
|
||||||
return true; // Since it's registered, it is the canonical token
|
return true; // Since it's registered, it is the canonical token
|
||||||
|
|||||||
Reference in New Issue
Block a user