aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/components
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-12-21 07:21:28 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-12-21 07:21:28 +0800
commit56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0 (patch)
tree54ed033d1d080bcf6212ce697dffa6f427b1b020 /packages/instant/src/components
parentb399aa25aa9386d388d31edb463e803c7c31a2db (diff)
parent0a84ee748823e5099b0767eedc5de95c71cb8f4e (diff)
downloaddexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.tar
dexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.tar.gz
dexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.tar.bz2
dexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.tar.lz
dexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.tar.xz
dexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.tar.zst
dexon-sol-tools-56af9b2aab26fd6a774d0b345ce8e1441bb1a9e0.zip
Merge branch 'development' into fix/instant/signature-denied
* development: (914 commits) Unfix compiler version except for top level contracts Move OrderValidator to extensions Update CHANGELOG Remove assembly version of matchOrders Add getOrderInfo check before calling fillOrder Update comments and hard code function selector constants Fix build after rebase update comments Fix build and add back tests Update dependency paths Add OrderMatcher tests feat: Add OrderMatcher contract that takes spread in multiple assets by calling `matchOrders` followed by `fillOrder` Update CHANGELOG Use more efficient equality checks Add note about input validation Use more efficient check for overflow Check if amount == 0 before doing division Reapply prettier New relayers feat(sra_client.py): Test deployed pkg via tox ...
Diffstat (limited to 'packages/instant/src/components')
-rw-r--r--packages/instant/src/components/instant_heading.tsx15
-rw-r--r--packages/instant/src/components/order_details.tsx265
-rw-r--r--packages/instant/src/components/payment_method.tsx11
-rw-r--r--packages/instant/src/components/section_header.tsx20
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx1
5 files changed, 216 insertions, 96 deletions
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 816cc5c33..5b1f9592d 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -113,20 +113,23 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
}
private readonly _renderEthAmount = (): React.ReactNode => {
+ const ethAmount = format.ethBaseUnitAmount(
+ this.props.totalEthBaseUnitAmount,
+ 4,
+ <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />,
+ );
+
+ const fontSize = _.isString(ethAmount) && ethAmount.length >= 13 ? '14px' : '16px';
return (
<Text
- fontSize="16px"
+ fontSize={fontSize}
textAlign="right"
width="100%"
fontColor={ColorOption.white}
fontWeight={500}
noWrap={true}
>
- {format.ethBaseUnitAmount(
- this.props.totalEthBaseUnitAmount,
- 4,
- <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />,
- )}
+ {ethAmount}
</Text>
);
};
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index a8e0e2513..9c10ef9e6 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -4,124 +4,227 @@ import * as _ from 'lodash';
import * as React from 'react';
import { oc } from 'ts-optchain';
-import { BIG_NUMBER_ZERO } from '../constants';
+import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants';
import { ColorOption } from '../style/theme';
+import { BaseCurrency } from '../types';
import { format } from '../util/format';
import { AmountPlaceholder } from './amount_placeholder';
+import { SectionHeader } from './section_header';
import { Container } from './ui/container';
import { Flex } from './ui/flex';
-import { Text } from './ui/text';
+import { Text, TextProps } from './ui/text';
export interface OrderDetailsProps {
buyQuoteInfo?: BuyQuoteInfo;
selectedAssetUnitAmount?: BigNumber;
ethUsdPrice?: BigNumber;
isLoading: boolean;
+ assetName?: string;
+ baseCurrency: BaseCurrency;
+ onBaseCurrencySwitchEth: () => void;
+ onBaseCurrencySwitchUsd: () => void;
}
export class OrderDetails extends React.Component<OrderDetailsProps> {
public render(): React.ReactNode {
- const { buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props;
- const buyQuoteAccessor = oc(buyQuoteInfo);
- const assetEthBaseUnitAmount = buyQuoteAccessor.assetEthAmount();
- const feeEthBaseUnitAmount = buyQuoteAccessor.feeEthAmount();
- const totalEthBaseUnitAmount = buyQuoteAccessor.totalEthAmount();
- const pricePerTokenEth =
- !_.isUndefined(assetEthBaseUnitAmount) &&
- !_.isUndefined(selectedAssetUnitAmount) &&
- !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO)
- ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil()
- : undefined;
+ const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice();
return (
<Container width="100%" flexGrow={1} padding="20px 20px 0px 20px">
- <Container marginBottom="10px">
- <Text
- letterSpacing="1px"
- fontColor={ColorOption.primaryColor}
- fontWeight={600}
- textTransform="uppercase"
- fontSize="14px"
- >
- Order Details
- </Text>
- </Container>
- <EthAmountRow
- rowLabel="Token Price"
- ethAmount={pricePerTokenEth}
- ethUsdPrice={ethUsdPrice}
- isLoading={this.props.isLoading}
+ <Container marginBottom="10px">{this._renderHeader()}</Container>
+ {shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()}
+ </Container>
+ );
+ }
+
+ private _renderRows(): React.ReactNode {
+ const { buyQuoteInfo } = this.props;
+ return (
+ <React.Fragment>
+ <OrderDetailsRow
+ labelText={this._assetAmountLabel()}
+ primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.assetEthAmount)}
/>
- <EthAmountRow
- rowLabel="Fee"
- ethAmount={feeEthBaseUnitAmount}
- ethUsdPrice={ethUsdPrice}
- isLoading={this.props.isLoading}
+ <OrderDetailsRow
+ labelText="Fee"
+ primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.feeEthAmount)}
/>
- <EthAmountRow
- rowLabel="Total Cost"
- ethAmount={totalEthBaseUnitAmount}
- ethUsdPrice={ethUsdPrice}
- shouldEmphasize={true}
- isLoading={this.props.isLoading}
+ <OrderDetailsRow
+ labelText="Total Cost"
+ isLabelBold={true}
+ primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.totalEthAmount)}
+ isPrimaryValueBold={true}
+ secondaryValue={this._totalCostSecondaryValue()}
/>
- </Container>
+ </React.Fragment>
);
}
-}
-export interface EthAmountRowProps {
- rowLabel: string;
- ethAmount?: BigNumber;
- isEthAmountInBaseUnits?: boolean;
- ethUsdPrice?: BigNumber;
- shouldEmphasize?: boolean;
- isLoading: boolean;
+ private _renderErrorFetchingUsdPrice(): React.ReactNode {
+ return (
+ <Text>
+ There was an error fetching the USD price.
+ <Text
+ onClick={this.props.onBaseCurrencySwitchEth}
+ fontWeight={700}
+ fontColor={ColorOption.primaryColor}
+ >
+ Click here
+ </Text>
+ {' to view ETH prices'}
+ </Text>
+ );
+ }
+
+ private _hadErrorFetchingUsdPrice(): boolean {
+ return this.props.ethUsdPrice ? this.props.ethUsdPrice.equals(BIG_NUMBER_ZERO) : false;
+ }
+
+ private _totalCostSecondaryValue(): React.ReactNode {
+ const secondaryCurrency = this.props.baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD;
+
+ const canDisplayCurrency =
+ secondaryCurrency === BaseCurrency.ETH ||
+ (secondaryCurrency === BaseCurrency.USD && this.props.ethUsdPrice && !this._hadErrorFetchingUsdPrice());
+
+ if (this.props.buyQuoteInfo && canDisplayCurrency) {
+ return this._displayAmount(secondaryCurrency, this.props.buyQuoteInfo.totalEthAmount);
+ } else {
+ return undefined;
+ }
+ }
+
+ private _displayAmountOrPlaceholder(weiAmount?: BigNumber): React.ReactNode {
+ const { baseCurrency, isLoading } = this.props;
+
+ if (_.isUndefined(weiAmount)) {
+ return (
+ <Container opacity={0.5}>
+ <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} />
+ </Container>
+ );
+ }
+
+ return this._displayAmount(baseCurrency, weiAmount);
+ }
+
+ private _displayAmount(currency: BaseCurrency, weiAmount: BigNumber): React.ReactNode {
+ switch (currency) {
+ case BaseCurrency.USD:
+ return format.ethBaseUnitAmountInUsd(weiAmount, this.props.ethUsdPrice, 2, '');
+ case BaseCurrency.ETH:
+ return format.ethBaseUnitAmount(weiAmount, 4, '');
+ }
+ }
+
+ private _assetAmountLabel(): React.ReactNode {
+ const { assetName, baseCurrency } = this.props;
+ const numTokens = this.props.selectedAssetUnitAmount;
+
+ // Display as 0 if we have a selected asset
+ const displayNumTokens =
+ assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens)
+ ? new BigNumber(0)
+ : numTokens;
+ if (!_.isUndefined(displayNumTokens)) {
+ let numTokensWithSymbol: React.ReactNode = displayNumTokens.toString();
+ if (assetName) {
+ numTokensWithSymbol += ` ${assetName}`;
+ }
+ const pricePerTokenWei = this._pricePerTokenWei();
+ if (pricePerTokenWei) {
+ const atPriceDisplay = (
+ <Text fontColor={ColorOption.lightGrey}>
+ @ {this._displayAmount(baseCurrency, pricePerTokenWei)}
+ </Text>
+ );
+ numTokensWithSymbol = (
+ <React.Fragment>
+ {numTokensWithSymbol} {atPriceDisplay}
+ </React.Fragment>
+ );
+ }
+ return numTokensWithSymbol;
+ }
+ return 'Token Amount';
+ }
+
+ private _pricePerTokenWei(): BigNumber | undefined {
+ const buyQuoteAccessor = oc(this.props.buyQuoteInfo);
+ const assetTotalInWei = buyQuoteAccessor.assetEthAmount();
+ const selectedAssetUnitAmount = this.props.selectedAssetUnitAmount;
+ return !_.isUndefined(assetTotalInWei) &&
+ !_.isUndefined(selectedAssetUnitAmount) &&
+ !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO)
+ ? assetTotalInWei.div(selectedAssetUnitAmount).ceil()
+ : undefined;
+ }
+
+ private _baseCurrencyChoice(choice: BaseCurrency): React.ReactNode {
+ const onClick =
+ choice === BaseCurrency.ETH ? this.props.onBaseCurrencySwitchEth : this.props.onBaseCurrencySwitchUsd;
+ const isSelected = this.props.baseCurrency === choice;
+
+ const textStyle: TextProps = { onClick, fontSize: '12px' };
+ if (isSelected) {
+ textStyle.fontColor = ColorOption.primaryColor;
+ textStyle.fontWeight = 700;
+ } else {
+ textStyle.fontColor = ColorOption.lightGrey;
+ }
+ return <Text {...textStyle}>{choice}</Text>;
+ }
+
+ private _renderHeader(): React.ReactNode {
+ return (
+ <Flex justify="space-between">
+ <SectionHeader>Order Details</SectionHeader>
+ <Container>
+ {this._baseCurrencyChoice(BaseCurrency.ETH)}
+ <Container marginLeft="5px" marginRight="5px" display="inline">
+ <Text fontSize="12px" fontColor={ColorOption.feintGrey}>
+ /
+ </Text>
+ </Container>
+ {this._baseCurrencyChoice(BaseCurrency.USD)}
+ </Container>
+ </Flex>
+ );
+ }
}
-export class EthAmountRow extends React.Component<EthAmountRowProps> {
- public static defaultProps = {
- shouldEmphasize: false,
- isEthAmountInBaseUnits: true,
- };
+export interface OrderDetailsRowProps {
+ labelText: React.ReactNode;
+ isLabelBold?: boolean;
+ isPrimaryValueBold?: boolean;
+ primaryValue: React.ReactNode;
+ secondaryValue?: React.ReactNode;
+}
+export class OrderDetailsRow extends React.Component<OrderDetailsRowProps, {}> {
public render(): React.ReactNode {
- const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props;
-
- const fontWeight = shouldEmphasize ? 700 : 400;
- const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseUnitAmount : format.ethUnitAmount;
return (
<Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
<Flex justify="space-between">
- <Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {rowLabel}
+ <Text fontWeight={this.props.isLabelBold ? 700 : 400} fontColor={ColorOption.grey}>
+ {this.props.labelText}
</Text>
- <Container>
- {this._renderUsdSection()}
- <Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {ethFormatter(
- ethAmount,
- 4,
- <Container opacity={0.5}>
- <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} />
- </Container>,
- )}
- </Text>
- </Container>
+ <Container>{this._renderValues()}</Container>
</Flex>
</Container>
);
}
- private _renderUsdSection(): React.ReactNode {
- const usdFormatter = this.props.isEthAmountInBaseUnits
- ? format.ethBaseUnitAmountInUsd
- : format.ethUnitAmountInUsd;
- const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount);
- return shouldHideUsdPriceSection ? null : (
+
+ private _renderValues(): React.ReactNode {
+ const secondaryValueNode: React.ReactNode = this.props.secondaryValue && (
<Container marginRight="3px" display="inline-block">
- <Text fontColor={ColorOption.lightGrey}>
- ({usdFormatter(this.props.ethAmount, this.props.ethUsdPrice)})
- </Text>
+ <Text fontColor={ColorOption.lightGrey}>({this.props.secondaryValue})</Text>
</Container>
);
+ return (
+ <React.Fragment>
+ {secondaryValueNode}
+ <Text fontWeight={this.props.isPrimaryValueBold ? 700 : 400}>{this.props.primaryValue}</Text>
+ </React.Fragment>
+ );
}
}
diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx
index 7c93f1d1c..abadf4bd6 100644
--- a/packages/instant/src/components/payment_method.tsx
+++ b/packages/instant/src/components/payment_method.tsx
@@ -8,6 +8,7 @@ import { envUtil } from '../util/env';
import { CoinbaseWalletLogo } from './coinbase_wallet_logo';
import { MetaMaskLogo } from './meta_mask_logo';
import { PaymentMethodDropdown } from './payment_method_dropdown';
+import { SectionHeader } from './section_header';
import { Circle } from './ui/circle';
import { Container } from './ui/container';
import { Flex } from './ui/flex';
@@ -29,15 +30,7 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> {
<Container width="100%" height="120px" padding="20px 20px 0px 20px">
<Container marginBottom="12px">
<Flex justify="space-between">
- <Text
- letterSpacing="1px"
- fontColor={ColorOption.primaryColor}
- fontWeight={600}
- textTransform="uppercase"
- fontSize="14px"
- >
- {this._renderTitleText()}
- </Text>
+ <SectionHeader>{this._renderTitleText()}</SectionHeader>
{this._renderTitleLabel()}
</Flex>
</Container>
diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx
new file mode 100644
index 000000000..d0974ebdc
--- /dev/null
+++ b/packages/instant/src/components/section_header.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react';
+
+import { ColorOption } from '../style/theme';
+
+import { Text } from './ui/text';
+
+export interface SectionHeaderProps {}
+export const SectionHeader: React.StatelessComponent<SectionHeaderProps> = props => {
+ return (
+ <Text
+ letterSpacing="1px"
+ fontColor={ColorOption.primaryColor}
+ fontWeight={600}
+ textTransform="uppercase"
+ fontSize="12px"
+ >
+ {props.children}
+ </Text>
+ );
+};
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 204115fa9..2de327cd7 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -122,6 +122,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
window,
state.selectedAsset,
this.props.affiliateInfo,
+ state.baseCurrency,
),
);
analytics.trackInstantOpened();