aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant/src')
-rw-r--r--packages/instant/src/components/amount_placeholder.tsx2
-rw-r--r--packages/instant/src/components/animations/slide_animation.tsx10
-rw-r--r--packages/instant/src/components/buy_button.tsx16
-rw-r--r--packages/instant/src/components/buy_order_progress.tsx2
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx2
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx2
-rw-r--r--packages/instant/src/components/erc20_token_selector.tsx77
-rw-r--r--packages/instant/src/components/install_wallet_panel_content.tsx2
-rw-r--r--packages/instant/src/components/instant_heading.tsx2
-rw-r--r--packages/instant/src/components/order_details.tsx4
-rw-r--r--packages/instant/src/components/payment_method.tsx2
-rw-r--r--packages/instant/src/components/payment_method_dropdown.tsx2
-rw-r--r--packages/instant/src/components/placing_order_button.tsx2
-rw-r--r--packages/instant/src/components/scaling_amount_input.tsx2
-rw-r--r--packages/instant/src/components/scaling_input.tsx2
-rw-r--r--packages/instant/src/components/secondary_button.tsx1
-rw-r--r--packages/instant/src/components/section_header.tsx1
-rw-r--r--packages/instant/src/components/sliding_error.tsx4
-rw-r--r--packages/instant/src/components/sliding_panel.tsx74
-rw-r--r--packages/instant/src/components/standard_panel_content.tsx2
-rw-r--r--packages/instant/src/components/standard_sliding_panel.tsx2
-rw-r--r--packages/instant/src/components/time_counter.tsx2
-rw-r--r--packages/instant/src/components/timed_progress_bar.tsx2
-rw-r--r--packages/instant/src/components/ui/container.tsx2
-rw-r--r--packages/instant/src/components/ui/dropdown.tsx43
-rw-r--r--packages/instant/src/components/wallet_prompt.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx13
-rw-r--r--packages/instant/src/components/zero_ex_instant_overlay.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx2
-rw-r--r--packages/instant/src/constants.ts1
-rw-r--r--packages/instant/src/containers/latest_error.tsx4
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts3
-rw-r--r--packages/instant/src/types.ts2
-rw-r--r--packages/instant/src/util/analytics.ts6
-rw-r--r--packages/instant/src/util/env.ts2
36 files changed, 201 insertions, 100 deletions
diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx
index 29ce8fafb..290e34a07 100644
--- a/packages/instant/src/components/amount_placeholder.tsx
+++ b/packages/instant/src/components/amount_placeholder.tsx
@@ -30,3 +30,5 @@ export const AmountPlaceholder: React.StatelessComponent<AmountPlaceholderProps>
return <PlainPlaceholder color={props.color} />;
}
};
+
+AmountPlaceholder.displayName = 'AmountPlaceholder';
diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx
index 5992bcba7..6ac47e9a6 100644
--- a/packages/instant/src/components/animations/slide_animation.tsx
+++ b/packages/instant/src/components/animations/slide_animation.tsx
@@ -11,6 +11,7 @@ export interface SlideAnimationProps {
slideOutSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
zIndex?: OptionallyScreenSpecific<number>;
height?: string;
+ onAnimationEnd?: () => void;
}
export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = props => {
@@ -19,8 +20,15 @@ export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = pro
}
const positionSettings = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;
return (
- <PositionAnimation height={props.height} positionSettings={positionSettings} zIndex={props.zIndex}>
+ <PositionAnimation
+ onAnimationEnd={props.onAnimationEnd}
+ height={props.height}
+ positionSettings={positionSettings}
+ zIndex={props.zIndex}
+ >
{props.children}
</PositionAnimation>
);
};
+
+SlideAnimation.displayName = 'SlideAnimation';
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 1489b94d4..551e857a5 100644
--- a/packages/instant/src/components/buy_button.tsx
+++ b/packages/instant/src/components/buy_button.tsx
@@ -10,6 +10,7 @@ import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants'
import { ColorOption } from '../style/theme';
import { AffiliateInfo, Asset, ZeroExInstantError } from '../types';
import { analytics } from '../util/analytics';
+import { errorReporter } from '../util/error_reporter';
import { gasPriceEstimator } from '../util/gas_price_estimator';
import { util } from '../util/util';
@@ -31,7 +32,7 @@ export interface BuyButtonProps {
onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void;
}
-export class BuyButton extends React.Component<BuyButtonProps> {
+export class BuyButton extends React.PureComponent<BuyButtonProps> {
public static defaultProps = {
onClick: util.boundNoop,
onBuySuccess: util.boundNoop,
@@ -82,13 +83,18 @@ export class BuyButton extends React.Component<BuyButtonProps> {
});
} catch (e) {
if (e instanceof Error) {
- if (e.message === AssetBuyerError.SignatureRequestDenied) {
+ if (e.message === AssetBuyerError.TransactionValueTooLow) {
+ analytics.trackBuySimulationFailed(buyQuote);
+ this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow);
+ return;
+ } else if (e.message === AssetBuyerError.SignatureRequestDenied) {
analytics.trackBuySignatureDenied(buyQuote);
this.props.onSignatureDenied(buyQuote);
return;
- } else if (e.message === AssetBuyerError.TransactionValueTooLow) {
- analytics.trackBuySimulationFailed(buyQuote);
- this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow);
+ } else {
+ errorReporter.report(e);
+ analytics.trackBuyUnknownError(buyQuote, e.message);
+ this.props.onValidationFail(buyQuote, ZeroExInstantError.CouldNotSubmitTransaction);
return;
}
}
diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx
index a19f5a4d0..11ac5d5e0 100644
--- a/packages/instant/src/components/buy_order_progress.tsx
+++ b/packages/instant/src/components/buy_order_progress.tsx
@@ -31,3 +31,5 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> =
}
return null;
};
+
+BuyOrderProgress.displayName = 'BuyOrderProgress';
diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx
index 833818900..1214559d1 100644
--- a/packages/instant/src/components/buy_order_state_buttons.tsx
+++ b/packages/instant/src/components/buy_order_state_buttons.tsx
@@ -71,3 +71,5 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
/>
);
};
+
+BuyOrderStateButtons.displayName = 'BuyOrderStateButtons';
diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx
index 4da82eb73..0418f9165 100644
--- a/packages/instant/src/components/erc20_asset_amount_input.tsx
+++ b/packages/instant/src/components/erc20_asset_amount_input.tsx
@@ -31,7 +31,7 @@ export interface ERC20AssetAmountInputState {
currentFontSizePx: number;
}
-export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> {
+export class ERC20AssetAmountInput extends React.PureComponent<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> {
public static defaultProps = {
onChange: util.boundNoop,
isDisabled: false,
diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
index cb8a8c797..a26fb5cf5 100644
--- a/packages/instant/src/components/erc20_token_selector.tsx
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -21,12 +21,12 @@ export interface ERC20TokenSelectorState {
searchQuery: string;
}
-export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> {
+export class ERC20TokenSelector extends React.PureComponent<ERC20TokenSelectorProps> {
public state: ERC20TokenSelectorState = {
searchQuery: '',
};
public render(): React.ReactNode {
- const { tokens, onTokenSelect } = this.props;
+ const { tokens } = this.props;
return (
<Container height="100%">
<Container marginBottom="10px">
@@ -42,12 +42,11 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
tabIndex={-1}
/>
<Container overflow="scroll" height="calc(100% - 90px)" marginTop="10px">
- {_.map(tokens, token => {
- if (!this._isTokenQueryMatch(token)) {
- return null;
- }
- return <TokenSelectorRow key={token.assetData} token={token} onClick={onTokenSelect} />;
- })}
+ <TokenRowFilter
+ tokens={tokens}
+ onClick={this._handleTokenClick}
+ searchQuery={this.state.searchQuery}
+ />
</Container>
</Container>
);
@@ -59,8 +58,32 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
});
analytics.trackTokenSelectorSearched(searchQuery);
};
+ private readonly _handleTokenClick = (token: ERC20Asset): void => {
+ this.props.onTokenSelect(token);
+ };
+}
+
+interface TokenRowFilterProps {
+ tokens: ERC20Asset[];
+ onClick: (token: ERC20Asset) => void;
+ searchQuery: string;
+}
+
+class TokenRowFilter extends React.Component<TokenRowFilterProps> {
+ public render(): React.ReactNode {
+ return _.map(this.props.tokens, token => {
+ if (!this._isTokenQueryMatch(token)) {
+ return null;
+ }
+ return <TokenSelectorRow key={token.assetData} token={token} onClick={this.props.onClick} />;
+ });
+ }
+ public shouldComponentUpdate(nextProps: TokenRowFilterProps): boolean {
+ const arePropsDeeplyEqual = _.isEqual(nextProps, this.props);
+ return !arePropsDeeplyEqual;
+ }
private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => {
- const { searchQuery } = this.state;
+ const { searchQuery } = this.props;
const searchQueryLowerCase = searchQuery.toLowerCase().trim();
if (searchQueryLowerCase === '') {
return true;
@@ -76,7 +99,7 @@ interface TokenSelectorRowProps {
onClick: (token: ERC20Asset) => void;
}
-class TokenSelectorRow extends React.Component<TokenSelectorRowProps> {
+class TokenSelectorRow extends React.PureComponent<TokenSelectorRowProps> {
public render(): React.ReactNode {
const { token } = this.props;
const circleColor = token.metaData.primaryColor || 'black';
@@ -131,21 +154,23 @@ const getTokenIcon = (symbol: string): React.StatelessComponent | undefined => {
}
};
-const TokenSelectorRowIcon: React.StatelessComponent<TokenSelectorRowIconProps> = props => {
- const { token } = props;
- const iconUrlIfExists = token.metaData.iconUrl;
+class TokenSelectorRowIcon extends React.PureComponent<TokenSelectorRowIconProps> {
+ public render(): React.ReactNode {
+ const { token } = this.props;
+ const iconUrlIfExists = token.metaData.iconUrl;
- const TokenIcon = getTokenIcon(token.metaData.symbol);
- const displaySymbol = assetUtils.bestNameForAsset(token);
- if (!_.isUndefined(iconUrlIfExists)) {
- return <img src={iconUrlIfExists} />;
- } else if (!_.isUndefined(TokenIcon)) {
- return <TokenIcon />;
- } else {
- return (
- <Text fontColor={ColorOption.white} fontSize="8px">
- {displaySymbol}
- </Text>
- );
+ const TokenIcon = getTokenIcon(token.metaData.symbol);
+ const displaySymbol = assetUtils.bestNameForAsset(token);
+ if (!_.isUndefined(iconUrlIfExists)) {
+ return <img src={iconUrlIfExists} />;
+ } else if (!_.isUndefined(TokenIcon)) {
+ return <TokenIcon />;
+ } else {
+ return (
+ <Text fontColor={ColorOption.white} fontSize="8px">
+ {displaySymbol}
+ </Text>
+ );
+ }
}
-};
+}
diff --git a/packages/instant/src/components/install_wallet_panel_content.tsx b/packages/instant/src/components/install_wallet_panel_content.tsx
index 481d82da0..1af3dafbb 100644
--- a/packages/instant/src/components/install_wallet_panel_content.tsx
+++ b/packages/instant/src/components/install_wallet_panel_content.tsx
@@ -18,7 +18,7 @@ import { Button } from './ui/button';
export interface InstallWalletPanelContentProps {}
-export class InstallWalletPanelContent extends React.Component<InstallWalletPanelContentProps> {
+export class InstallWalletPanelContent extends React.PureComponent<InstallWalletPanelContentProps> {
public render(): React.ReactNode {
const panelProps = this._getStandardPanelContentProps();
return <StandardPanelContent {...panelProps} />;
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 5b1f9592d..e943f68d7 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -28,7 +28,7 @@ const ICON_WIDTH = 34;
const ICON_HEIGHT = 34;
const ICON_COLOR = ColorOption.white;
-export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
+export class InstantHeading extends React.PureComponent<InstantHeadingProps, {}> {
public render(): React.ReactNode {
const iconOrAmounts = this._renderIcon() || this._renderAmountsSection();
return (
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index 9c10ef9e6..4db20b13e 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -26,7 +26,7 @@ export interface OrderDetailsProps {
onBaseCurrencySwitchEth: () => void;
onBaseCurrencySwitchUsd: () => void;
}
-export class OrderDetails extends React.Component<OrderDetailsProps> {
+export class OrderDetails extends React.PureComponent<OrderDetailsProps> {
public render(): React.ReactNode {
const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice();
return (
@@ -200,7 +200,7 @@ export interface OrderDetailsRowProps {
primaryValue: React.ReactNode;
secondaryValue?: React.ReactNode;
}
-export class OrderDetailsRow extends React.Component<OrderDetailsRowProps, {}> {
+export class OrderDetailsRow extends React.PureComponent<OrderDetailsRowProps, {}> {
public render(): React.ReactNode {
return (
<Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx
index abadf4bd6..ada9f7bab 100644
--- a/packages/instant/src/components/payment_method.tsx
+++ b/packages/instant/src/components/payment_method.tsx
@@ -24,7 +24,7 @@ export interface PaymentMethodProps {
onUnlockWalletClick: () => void;
}
-export class PaymentMethod extends React.Component<PaymentMethodProps> {
+export class PaymentMethod extends React.PureComponent<PaymentMethodProps> {
public render(): React.ReactNode {
return (
<Container width="100%" height="120px" padding="20px 20px 0px 20px">
diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx
index 872ac0831..e463e3eae 100644
--- a/packages/instant/src/components/payment_method_dropdown.tsx
+++ b/packages/instant/src/components/payment_method_dropdown.tsx
@@ -16,7 +16,7 @@ export interface PaymentMethodDropdownProps {
network: Network;
}
-export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdownProps> {
+export class PaymentMethodDropdown extends React.PureComponent<PaymentMethodDropdownProps> {
public render(): React.ReactNode {
const { accountAddress, accountEthBalanceInWei } = this.props;
const value = format.ethAddress(accountAddress);
diff --git a/packages/instant/src/components/placing_order_button.tsx b/packages/instant/src/components/placing_order_button.tsx
index 2516b90b1..528a305dc 100644
--- a/packages/instant/src/components/placing_order_button.tsx
+++ b/packages/instant/src/components/placing_order_button.tsx
@@ -14,3 +14,5 @@ export const PlacingOrderButton: React.StatelessComponent<{}> = props => (
Placing Order&hellip;
</Button>
);
+
+PlacingOrderButton.displayName = 'PlacingOrderButton';
diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx
index 4feb0502d..7dc1fdc0c 100644
--- a/packages/instant/src/components/scaling_amount_input.tsx
+++ b/packages/instant/src/components/scaling_amount_input.tsx
@@ -26,7 +26,7 @@ interface ScalingAmountInputState {
}
const { stringToMaybeBigNumber, areMaybeBigNumbersEqual } = maybeBigNumberUtil;
-export class ScalingAmountInput extends React.Component<ScalingAmountInputProps, ScalingAmountInputState> {
+export class ScalingAmountInput extends React.PureComponent<ScalingAmountInputProps, ScalingAmountInputState> {
public static defaultProps = {
onAmountChange: util.boundNoop,
onFontSizeChange: util.boundNoop,
diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 00aea37da..c31de1fb5 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -51,7 +51,7 @@ const defaultScalingSettings: ScalingSettings = {
additionalInputSpaceInCh: 0.4,
};
-export class ScalingInput extends React.Component<ScalingInputProps> {
+export class ScalingInput extends React.PureComponent<ScalingInputProps> {
public static defaultProps = {
onChange: util.boundNoop,
onFontSizeChange: util.boundNoop,
diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx
index 705390e28..0714ce287 100644
--- a/packages/instant/src/components/secondary_button.tsx
+++ b/packages/instant/src/components/secondary_button.tsx
@@ -24,3 +24,4 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p
SecondaryButton.defaultProps = {
width: '100%',
};
+SecondaryButton.displayName = 'SecondaryButton';
diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx
index d0974ebdc..2185b67ba 100644
--- a/packages/instant/src/components/section_header.tsx
+++ b/packages/instant/src/components/section_header.tsx
@@ -18,3 +18,4 @@ export const SectionHeader: React.StatelessComponent<SectionHeaderProps> = props
</Text>
);
};
+SectionHeader.displayName = 'SectionHeader';
diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx
index b59e2a905..c7c6732cf 100644
--- a/packages/instant/src/components/sliding_error.tsx
+++ b/packages/instant/src/components/sliding_error.tsx
@@ -38,6 +38,8 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
</Container>
);
+Error.displayName = 'Error';
+
export interface SlidingErrorProps extends ErrorProps {
animationState: SlideAnimationState;
}
@@ -94,3 +96,5 @@ export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props =
</SlideAnimation>
);
};
+
+SlidingError.displayName = 'SlidingError';
diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx
index 7f9037049..9b09a0d80 100644
--- a/packages/instant/src/components/sliding_panel.tsx
+++ b/packages/instant/src/components/sliding_panel.tsx
@@ -26,42 +26,48 @@ export const Panel: React.StatelessComponent<PanelProps> = ({ children, onClose
</Container>
);
+Panel.displayName = 'Panel';
+
export interface SlidingPanelProps extends PanelProps {
animationState: SlideAnimationState;
+ onAnimationEnd?: () => void;
}
-export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props => {
- if (props.animationState === 'none') {
- return null;
+export class SlidingPanel extends React.PureComponent<SlidingPanelProps> {
+ public render(): React.ReactNode {
+ if (this.props.animationState === 'none') {
+ return null;
+ }
+ const { animationState, onAnimationEnd, ...rest } = this.props;
+ const slideAmount = '100%';
+ const slideUpSettings: PositionAnimationSettings = {
+ duration: '0.3s',
+ timingFunction: 'ease-in-out',
+ top: {
+ from: slideAmount,
+ to: '0px',
+ },
+ position: 'absolute',
+ };
+ const slideDownSettings: PositionAnimationSettings = {
+ duration: '0.3s',
+ timingFunction: 'ease-out',
+ top: {
+ from: '0px',
+ to: slideAmount,
+ },
+ position: 'absolute',
+ };
+ return (
+ <SlideAnimation
+ slideInSettings={slideUpSettings}
+ slideOutSettings={slideDownSettings}
+ animationState={animationState}
+ height="100%"
+ onAnimationEnd={onAnimationEnd}
+ >
+ <Panel {...rest} />
+ </SlideAnimation>
+ );
}
- const { animationState, ...rest } = props;
- const slideAmount = '100%';
- const slideUpSettings: PositionAnimationSettings = {
- duration: '0.3s',
- timingFunction: 'ease-in-out',
- top: {
- from: slideAmount,
- to: '0px',
- },
- position: 'absolute',
- };
- const slideDownSettings: PositionAnimationSettings = {
- duration: '0.3s',
- timingFunction: 'ease-out',
- top: {
- from: '0px',
- to: slideAmount,
- },
- position: 'absolute',
- };
- return (
- <SlideAnimation
- slideInSettings={slideUpSettings}
- slideOutSettings={slideDownSettings}
- animationState={animationState}
- height="100%"
- >
- <Panel {...rest} />
- </SlideAnimation>
- );
-};
+}
diff --git a/packages/instant/src/components/standard_panel_content.tsx b/packages/instant/src/components/standard_panel_content.tsx
index 79b7bff24..f2987df82 100644
--- a/packages/instant/src/components/standard_panel_content.tsx
+++ b/packages/instant/src/components/standard_panel_content.tsx
@@ -71,3 +71,5 @@ export const StandardPanelContent: React.StatelessComponent<StandardPanelContent
<Container>{action}</Container>
</Container>
);
+
+StandardPanelContent.displayName = 'StandardPanelContent';
diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx
index 9f517d273..bcc9d3dce 100644
--- a/packages/instant/src/components/standard_sliding_panel.tsx
+++ b/packages/instant/src/components/standard_sliding_panel.tsx
@@ -9,7 +9,7 @@ export interface StandardSlidingPanelProps extends StandardSlidingPanelSettings
onClose: () => void;
}
-export class StandardSlidingPanel extends React.Component<StandardSlidingPanelProps> {
+export class StandardSlidingPanel extends React.PureComponent<StandardSlidingPanelProps> {
public render(): React.ReactNode {
const { animationState, content, onClose } = this.props;
return (
diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx
index f9b68163c..93dc497d5 100644
--- a/packages/instant/src/components/time_counter.tsx
+++ b/packages/instant/src/components/time_counter.tsx
@@ -16,7 +16,7 @@ interface TimeCounterState {
elapsedSeconds: number;
}
-export class TimeCounter extends React.Component<TimeCounterProps, TimeCounterState> {
+export class TimeCounter extends React.PureComponent<TimeCounterProps, TimeCounterState> {
public state = {
elapsedSeconds: 0,
};
diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx
index fb3927088..b1644b871 100644
--- a/packages/instant/src/components/timed_progress_bar.tsx
+++ b/packages/instant/src/components/timed_progress_bar.tsx
@@ -17,7 +17,7 @@ export interface TimedProgressBarProps {
* Goes from 0% -> PROGRESS_STALL_AT_WIDTH over time of expectedTimeMs
* When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length of time
*/
-export class TimedProgressBar extends React.Component<TimedProgressBarProps, {}> {
+export class TimedProgressBar extends React.PureComponent<TimedProgressBarProps, {}> {
private readonly _barRef = React.createRef<HTMLDivElement>();
public render(): React.ReactNode {
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
index 636eb8fc9..58d7d5871 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -36,6 +36,7 @@ export interface ContainerProps {
cursor?: string;
overflow?: string;
darkenOnHover?: boolean;
+ rawHoverColor?: string;
boxShadowOnHover?: boolean;
flexGrow?: string | number;
}
@@ -87,6 +88,7 @@ export const Container =
background-color: ${props => getBackgroundColor(props.theme, props.backgroundColor, props.rawBackgroundColor)};
border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
&:hover {
+ ${props => (props.rawHoverColor ? `background-color: ${props.rawHoverColor}` : '')}
${props =>
props.darkenOnHover
? `background-color: ${
diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx
index 02e87d639..8788d3d59 100644
--- a/packages/instant/src/components/ui/dropdown.tsx
+++ b/packages/instant/src/components/ui/dropdown.tsx
@@ -1,7 +1,8 @@
import * as _ from 'lodash';
+import { transparentize } from 'polished';
import * as React from 'react';
-import { ColorOption, completelyTransparent } from '../../style/theme';
+import { ColorOption, completelyTransparent, ThemeConsumer } from '../../style/theme';
import { zIndex } from '../../style/z_index';
import { Container } from './container';
@@ -26,7 +27,7 @@ export interface DropdownState {
isOpen: boolean;
}
-export class Dropdown extends React.Component<DropdownProps, DropdownState> {
+export class Dropdown extends React.PureComponent<DropdownProps, DropdownState> {
public static defaultProps = {
items: [],
};
@@ -121,20 +122,26 @@ export interface DropdownItemProps extends DropdownItemConfig {
}
export const DropdownItem: React.StatelessComponent<DropdownItemProps> = ({ text, onClick, isLast }) => (
- <Container
- onClick={onClick}
- cursor="pointer"
- darkenOnHover={true}
- backgroundColor={ColorOption.white}
- padding="0.8em"
- borderTop="0"
- border="1px solid"
- borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
- width="100%"
- borderColor={ColorOption.feintGrey}
- >
- <Text fontSize="14px" fontColor={ColorOption.darkGrey}>
- {text}
- </Text>
- </Container>
+ <ThemeConsumer>
+ {theme => (
+ <Container
+ onClick={onClick}
+ cursor="pointer"
+ rawHoverColor={transparentize(0.9, theme[ColorOption.primaryColor])}
+ backgroundColor={ColorOption.white}
+ padding="0.8em"
+ borderTop="0"
+ border="1px solid"
+ borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
+ width="100%"
+ borderColor={ColorOption.feintGrey}
+ >
+ <Text fontSize="14px" fontColor={ColorOption.darkGrey}>
+ {text}
+ </Text>
+ </Container>
+ )}
+ </ThemeConsumer>
);
+
+DropdownItem.displayName = 'DropdownItem';
diff --git a/packages/instant/src/components/wallet_prompt.tsx b/packages/instant/src/components/wallet_prompt.tsx
index c07cfe7b5..10433767f 100644
--- a/packages/instant/src/components/wallet_prompt.tsx
+++ b/packages/instant/src/components/wallet_prompt.tsx
@@ -45,3 +45,5 @@ WalletPrompt.defaultProps = {
primaryColor: ColorOption.darkOrange,
secondaryColor: ColorOption.lightOrange,
};
+
+WalletPrompt.displayName = 'WalletPrompt';
diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx
index 2267b4dbf..e9cb48e61 100644
--- a/packages/instant/src/components/zero_ex_instant.tsx
+++ b/packages/instant/src/components/zero_ex_instant.tsx
@@ -17,3 +17,5 @@ export const ZeroExInstant: React.StatelessComponent<ZeroExInstantProps> = props
</div>
);
};
+
+ZeroExInstant.displayName = 'ZeroExInstant';
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index 0337c7714..e8c64d5d1 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -24,7 +24,10 @@ export interface ZeroExInstantContainerState {
tokenSelectionPanelAnimationState: SlideAnimationState;
}
-export class ZeroExInstantContainer extends React.Component<ZeroExInstantContainerProps, ZeroExInstantContainerState> {
+export class ZeroExInstantContainer extends React.PureComponent<
+ ZeroExInstantContainerProps,
+ ZeroExInstantContainerState
+> {
public state = {
tokenSelectionPanelAnimationState: 'none' as SlideAnimationState,
};
@@ -60,6 +63,7 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
<SlidingPanel
animationState={this.state.tokenSelectionPanelAnimationState}
onClose={this._handlePanelCloseClickedX}
+ onAnimationEnd={this._handleSlidingPanelAnimationEnd}
>
<AvailableERC20TokenSelector onTokenSelect={this._handlePanelCloseAfterChose} />
</SlidingPanel>
@@ -98,4 +102,11 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
tokenSelectionPanelAnimationState: 'slidOut',
});
};
+ private readonly _handleSlidingPanelAnimationEnd = (): void => {
+ if (this.state.tokenSelectionPanelAnimationState === 'slidOut') {
+ // When the slidOut animation completes, don't keep the panel mounted.
+ // Performance optimization
+ this.setState({ tokenSelectionPanelAnimationState: 'none' });
+ }
+ };
}
diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx
index 96e560691..38a716091 100644
--- a/packages/instant/src/components/zero_ex_instant_overlay.tsx
+++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx
@@ -49,3 +49,5 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay
</ZeroExInstantProvider>
);
};
+
+ZeroExInstantOverlay.displayName = 'ZeroExInstantOverlay';
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 2de327cd7..ec8e82ee3 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -21,7 +21,7 @@ import { providerStateFactory } from '../util/provider_state_factory';
export type ZeroExInstantProviderProps = ZeroExInstantBaseConfig;
-export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
+export class ZeroExInstantProvider extends React.PureComponent<ZeroExInstantProviderProps> {
private readonly _store: Store;
private _accountUpdateHeartbeat?: Heartbeater;
private _buyQuoteHeartbeat?: Heartbeater;
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index 975dfcbea..22f0cb6a4 100644
--- a/packages/instant/src/constants.ts
+++ b/packages/instant/src/constants.ts
@@ -72,5 +72,6 @@ export const PROVIDER_TYPE_TO_NAME: { [key in ProviderType]: string } = {
[ProviderType.Mist]: 'Mist',
[ProviderType.CoinbaseWallet]: 'Coinbase Wallet',
[ProviderType.Parity]: 'Parity',
+ [ProviderType.TrustWallet]: 'Trust Wallet',
[ProviderType.Fallback]: 'Fallback',
};
diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx
index 0d4349124..6da4558ef 100644
--- a/packages/instant/src/containers/latest_error.tsx
+++ b/packages/instant/src/containers/latest_error.tsx
@@ -14,7 +14,7 @@ import { zIndex } from '../style/z_index';
import { Asset, DisplayStatus, Omit, SlideAnimationState } from '../types';
import { errorFlasher } from '../util/error_flasher';
-export interface LatestErrorComponentProps {
+interface LatestErrorComponentProps {
asset?: Asset;
latestErrorMessage?: string;
animationState: SlideAnimationState;
@@ -22,7 +22,7 @@ export interface LatestErrorComponentProps {
onOverlayClick: () => void;
}
-export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
+const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
if (!props.latestErrorMessage) {
// Render a hidden SlidingError such that instant does not move when a real error is rendered.
return (
diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
index 80943a96f..4da99cf04 100644
--- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
+++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
@@ -95,6 +95,9 @@ const mapDispatchToProps = (
if (error === ZeroExInstantError.InsufficientETH) {
const errorMessage = "You don't have enough ETH";
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
+ } else if (error === ZeroExInstantError.CouldNotSubmitTransaction) {
+ const errorMessage = 'Could not submit transaction';
+ errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
} else {
errorFlasher.flashNewErrorMessage(dispatch);
}
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index e7c920f36..ae672c919 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -96,6 +96,7 @@ export enum Network {
export enum ZeroExInstantError {
AssetMetaDataNotAvailable = 'ASSET_META_DATA_NOT_AVAILABLE',
InsufficientETH = 'INSUFFICIENT_ETH',
+ CouldNotSubmitTransaction = 'COULD_NOT_SUBMIT_TRANSACTION',
}
export type SimpleHandler = () => void;
@@ -181,6 +182,7 @@ export enum ProviderType {
Mist = 'MIST',
CoinbaseWallet = 'COINBASE_WALLET',
Cipher = 'CIPHER',
+ TrustWallet = 'TRUST_WALLET',
Fallback = 'FALLBACK',
}
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index 6c63907dc..4faeaaf5a 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -46,6 +46,7 @@ enum EventNames {
BUY_STARTED = 'Buy - Started',
BUY_SIGNATURE_DENIED = 'Buy - Signature Denied',
BUY_SIMULATION_FAILED = 'Buy - Simulation Failed',
+ BUY_UNKNOWN_ERROR = 'Buy - Unknown Error',
BUY_TX_SUBMITTED = 'Buy - Tx Submitted',
BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded',
BUY_TX_FAILED = 'Buy - Tx Failed',
@@ -189,6 +190,11 @@ export const analytics = {
trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)),
trackBuySimulationFailed: (buyQuote: BuyQuote) =>
trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)),
+ trackBuyUnknownError: (buyQuote: BuyQuote, errorMessage: string) =>
+ trackingEventFnWithPayload(EventNames.BUY_UNKNOWN_ERROR)({
+ ...buyQuoteEventProperties(buyQuote),
+ errorMessage,
+ }),
trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({
...buyQuoteEventProperties(buyQuote),
diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts
index 0fda0cc0e..aedf4f5d6 100644
--- a/packages/instant/src/util/env.ts
+++ b/packages/instant/src/util/env.ts
@@ -44,6 +44,8 @@ export const envUtil = {
getProviderType(provider: Provider): ProviderType | undefined {
if (provider.constructor.name === 'EthereumProvider') {
return ProviderType.Mist;
+ } else if ((provider as any).isTrust) {
+ return ProviderType.TrustWallet;
} else if ((provider as any).isParity) {
return ProviderType.Parity;
} else if ((provider as any).isMetaMask) {