import { BuyQuoteInfo } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { oc } from 'ts-optchain'; 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, 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 { public render(): React.ReactNode { const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice(); return ( {this._renderHeader()} {shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()} ); } private _renderRows(): React.ReactNode { const { buyQuoteInfo } = this.props; return ( ); } private _renderErrorFetchingUsdPrice(): React.ReactNode { return ( There was an error fetching the USD price. Click here {' to view ETH prices'} ); } 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 ( ); } 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 = ( @ {this._displayAmount(baseCurrency, pricePerTokenWei)} ); numTokensWithSymbol = ( {numTokensWithSymbol} {atPriceDisplay} ); } 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 {choice}; } private _renderHeader(): React.ReactNode { return ( Order Details {this._baseCurrencyChoice(BaseCurrency.ETH)} / {this._baseCurrencyChoice(BaseCurrency.USD)} ); } } export interface OrderDetailsRowProps { labelText: React.ReactNode; isLabelBold?: boolean; isPrimaryValueBold?: boolean; primaryValue: React.ReactNode; secondaryValue?: React.ReactNode; } export class OrderDetailsRow extends React.Component { public render(): React.ReactNode { return ( {this.props.labelText} {this._renderValues()} ); } private _renderValues(): React.ReactNode { const secondaryValueNode: React.ReactNode = this.props.secondaryValue && ( ({this.props.secondaryValue}) ); return ( {secondaryValueNode} {this.props.primaryValue} ); } }