diff options
Diffstat (limited to 'packages/instant/src/components')
11 files changed, 80 insertions, 77 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 57b3d108e..5b07e7416 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -16,7 +16,7 @@ import { Button } from './ui/button'; export interface BuyButtonProps { buyQuote?: BuyQuote; - assetBuyer?: AssetBuyer; + assetBuyer: AssetBuyer; affiliateInfo?: AffiliateInfo; onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; @@ -33,7 +33,7 @@ export class BuyButton extends React.Component<BuyButtonProps> { onBuyFailure: util.boundNoop, }; public render(): React.ReactNode { - const shouldDisableButton = _.isUndefined(this.props.buyQuote) || _.isUndefined(this.props.assetBuyer); + const shouldDisableButton = _.isUndefined(this.props.buyQuote); return ( <Button width="100%" @@ -49,11 +49,13 @@ export class BuyButton extends React.Component<BuyButtonProps> { private readonly _handleClick = async () => { // The button is disabled when there is no buy quote anyway. const { buyQuote, assetBuyer, affiliateInfo } = this.props; - if (_.isUndefined(buyQuote) || _.isUndefined(assetBuyer)) { + if (_.isUndefined(buyQuote)) { return; } this.props.onValidationPending(buyQuote); + + // TODO(bmillman): move address and balance fetching to the async state const web3Wrapper = new Web3Wrapper(assetBuyer.provider); const takerAddress = await getBestAddress(web3Wrapper); diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx index 7fe4e77e9..bc7319423 100644 --- a/packages/instant/src/components/buy_order_progress.tsx +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -14,12 +14,12 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> = const { buyOrderState } = props; if ( - buyOrderState.processState === OrderProcessState.PROCESSING || - buyOrderState.processState === OrderProcessState.SUCCESS || - buyOrderState.processState === OrderProcessState.FAILURE + buyOrderState.processState === OrderProcessState.Processing || + buyOrderState.processState === OrderProcessState.Success || + buyOrderState.processState === OrderProcessState.Failure ) { const progress = buyOrderState.progress; - const hasEnded = buyOrderState.processState !== OrderProcessState.PROCESSING; + const hasEnded = buyOrderState.processState !== OrderProcessState.Processing; const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; return ( <Container padding="20px 20px 0px 20px" width="100%"> diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index 45ff890b4..bdac25cf2 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -14,7 +14,7 @@ import { Flex } from './ui/flex'; export interface BuyOrderStateButtonProps { buyQuote?: BuyQuote; buyOrderProcessingState: OrderProcessState; - assetBuyer?: AssetBuyer; + assetBuyer: AssetBuyer; affiliateInfo?: AffiliateInfo; onViewTransaction: () => void; onValidationPending: (buyQuote: BuyQuote) => void; @@ -27,7 +27,7 @@ export interface BuyOrderStateButtonProps { } export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonProps> = props => { - if (props.buyOrderProcessingState === OrderProcessState.FAILURE) { + if (props.buyOrderProcessingState === OrderProcessState.Failure) { return ( <Flex justify="space-between"> <Button width="48%" onClick={props.onRetry} fontColor={ColorOption.white} fontSize="16px"> @@ -39,11 +39,11 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP </Flex> ); } else if ( - props.buyOrderProcessingState === OrderProcessState.SUCCESS || - props.buyOrderProcessingState === OrderProcessState.PROCESSING + props.buyOrderProcessingState === OrderProcessState.Success || + props.buyOrderProcessingState === OrderProcessState.Processing ) { return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>; - } else if (props.buyOrderProcessingState === OrderProcessState.VALIDATING) { + } else if (props.buyOrderProcessingState === OrderProcessState.Validating) { return <PlacingOrderButton />; } diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 41b0b44b0..76d5c66ff 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -35,7 +35,7 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> value={this.state.searchQuery} onChange={this._handleSearchInputChange} /> - <Container overflow="scroll" height="275px" marginTop="10px"> + <Container overflow="scroll" height={{ default: '275px', sm: '75vh' }} marginTop="10px"> {_.map(tokens, token => { if (!this._isTokenQueryMatch(token)) { return null; diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 6d87bc292..b07776b2c 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -77,11 +77,11 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { private _renderIcon(): React.ReactNode { const processState = this.props.buyOrderState.processState; - if (processState === OrderProcessState.FAILURE) { + if (processState === OrderProcessState.Failure) { return <Icon icon="failed" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />; - } else if (processState === OrderProcessState.PROCESSING) { + } else if (processState === OrderProcessState.Processing) { return <Spinner widthPx={ICON_HEIGHT} heightPx={ICON_HEIGHT} />; - } else if (processState === OrderProcessState.SUCCESS) { + } else if (processState === OrderProcessState.Success) { return <Icon icon="success" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />; } return undefined; @@ -89,11 +89,11 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { private _renderTopText(): React.ReactNode { const processState = this.props.buyOrderState.processState; - if (processState === OrderProcessState.FAILURE) { + if (processState === OrderProcessState.Failure) { return 'Order failed'; - } else if (processState === OrderProcessState.PROCESSING) { + } else if (processState === OrderProcessState.Processing) { return 'Processing Order...'; - } else if (processState === OrderProcessState.SUCCESS) { + } else if (processState === OrderProcessState.Success) { return 'Tokens received!'; } @@ -101,7 +101,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { } private _renderPlaceholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode { - if (this.props.quoteRequestState === AsyncProcessState.PENDING) { + if (this.props.quoteRequestState === AsyncProcessState.Pending) { return <AmountPlaceholder isPulsating={true} color={PLACEHOLDER_COLOR} />; } if (_.isUndefined(this.props.selectedAssetAmount)) { diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index f1029d70c..9abd7137e 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -26,7 +26,7 @@ export class OrderDetails extends React.Component<OrderDetailsProps> { const ethTokenFee = buyQuoteAccessor.feeEthAmount(); const totalEthAmount = buyQuoteAccessor.totalEthAmount(); return ( - <Container padding="20px" width="100%"> + <Container padding="20px" width="100%" flexGrow={1}> <Container marginBottom="10px"> <Text letterSpacing="1px" diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index db3f32f92..bffa1d7d4 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -1,17 +1,18 @@ import { darken } from 'polished'; +import { MediaChoice, stylesForMedia } from '../../style/media'; import { ColorOption, styled } from '../../style/theme'; import { cssRuleIfExists } from '../../style/util'; export interface ContainerProps { - display?: string; + display?: MediaChoice; position?: string; top?: string; right?: string; bottom?: string; left?: string; - width?: string; - height?: string; + width?: MediaChoice; + height?: MediaChoice; maxWidth?: string; margin?: string; marginTop?: string; @@ -33,6 +34,7 @@ export interface ContainerProps { cursor?: string; overflow?: string; darkenOnHover?: boolean; + flexGrow?: string | number; } export const Container = @@ -42,14 +44,12 @@ export const Container = && { all: initial; box-sizing: border-box; - ${props => cssRuleIfExists(props, 'display')} + ${props => cssRuleIfExists(props, 'flex-grow')} ${props => cssRuleIfExists(props, 'position')} ${props => cssRuleIfExists(props, 'top')} ${props => cssRuleIfExists(props, 'right')} ${props => cssRuleIfExists(props, 'bottom')} ${props => cssRuleIfExists(props, 'left')} - ${props => cssRuleIfExists(props, 'width')} - ${props => cssRuleIfExists(props, 'height')} ${props => cssRuleIfExists(props, 'max-width')} ${props => cssRuleIfExists(props, 'margin')} ${props => cssRuleIfExists(props, 'margin-top')} @@ -67,6 +67,9 @@ export const Container = ${props => cssRuleIfExists(props, 'cursor')} ${props => cssRuleIfExists(props, 'overflow')} ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')}; + ${props => props.display && stylesForMedia('display', props.display)} + ${props => (props.width ? stylesForMedia('width', props.width) : '')} + ${props => (props.height ? stylesForMedia('height', props.height) : '')} background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; &:hover { diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx index 1ec8d1f92..5b00138b8 100644 --- a/packages/instant/src/components/ui/flex.tsx +++ b/packages/instant/src/components/ui/flex.tsx @@ -1,3 +1,4 @@ +import { MediaChoice, stylesForMedia } from '../../style/media'; import { ColorOption, styled } from '../../style/theme'; import { cssRuleIfExists } from '../../style/util'; @@ -6,10 +7,11 @@ export interface FlexProps { flexWrap?: 'wrap' | 'nowrap'; justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end'; align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end'; - width?: string; - height?: string; + width?: MediaChoice; + height?: MediaChoice; backgroundColor?: ColorOption; inline?: boolean; + flexGrow?: number | string; } export const Flex = @@ -21,11 +23,12 @@ export const Flex = display: ${props => (props.inline ? 'inline-flex' : 'flex')}; flex-direction: ${props => props.direction}; flex-wrap: ${props => props.flexWrap}; + ${props => cssRuleIfExists(props, 'flexGrow')} justify-content: ${props => props.justify}; align-items: ${props => props.align}; - ${props => cssRuleIfExists(props, 'width')} - ${props => cssRuleIfExists(props, 'height')} background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; + ${props => (props.width ? stylesForMedia('width', props.width) : '')} + ${props => (props.height ? stylesForMedia('height', props.height) : '')} } `; diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index deb16a0e8..8c9572615 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -15,10 +15,12 @@ export interface OverlayProps { const PlainOverlay: React.StatelessComponent<OverlayProps> = ({ children, className, onClose }) => ( <Flex height="100vh" className={className}> - <Container position="absolute" top="0px" right="0px"> + <Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}> <Icon height={18} width={18} color={ColorOption.white} icon="closeX" onClick={onClose} padding="2em 2em" /> </Container> - <div>{children}</div> + <Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}> + {children} + </Container> </Flex> ); export const Overlay = styled(PlainOverlay)` diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 3f270f2f4..f5f8adefe 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -30,7 +30,11 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain return ( <React.Fragment> <CSSReset /> - <Container width="350px" position="relative"> + <Container + width={{ default: '350px', sm: '100%' }} + height={{ default: 'auto', sm: '100%' }} + position="relative" + > <Container zIndex={zIndex.errorPopup} position="relative"> <LatestError /> </Container> @@ -41,8 +45,9 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain borderRadius="3px" hasBoxShadow={true} overflow="hidden" + height="100%" > - <Flex direction="column" justify="flex-start"> + <Flex direction="column" justify="flex-start" height="100%"> <SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} /> <SelectedAssetBuyOrderProgress /> <LatestBuyQuoteOrderDetails /> diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 0b9408329..1fb5cf64f 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -1,23 +1,20 @@ -import { AssetBuyer } from '@0x/asset-buyer'; -import { ObjectMap, SignedOrder } from '@0x/types'; +import { ObjectMap } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; import * as React from 'react'; import { Provider as ReduxProvider } from 'react-redux'; -import { oc } from 'ts-optchain'; import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; import { asyncData } from '../redux/async_data'; -import { INITIAL_STATE, State } from '../redux/reducer'; +import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; -import { AffiliateInfo, AssetMetaData, Network } from '../types'; +import { AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; import { gasPriceEstimator } from '../util/gas_price_estimator'; -import { getInjectedProvider } from '../util/injected_provider'; +import { providerStateFactory } from '../util/provider_state_factory'; fonts.include(); @@ -25,7 +22,7 @@ export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps & Partial<ZeroExInstantProviderOptionalProps>; export interface ZeroExInstantProviderRequiredProps { - orderSource: string | SignedOrder[]; + orderSource: OrderSource; } export interface ZeroExInstantProviderOptionalProps { @@ -41,30 +38,27 @@ export interface ZeroExInstantProviderOptionalProps { export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> { private readonly _store: Store; // TODO(fragosti): Write tests for this beast once we inject a provider. - private static _mergeInitialStateWithProps(props: ZeroExInstantProviderProps, state: State = INITIAL_STATE): State { - const networkId = props.networkId || state.network; - // TODO: Proper wallet connect flow - const provider = props.provider || getInjectedProvider(); - const assetBuyerOptions = { + private static _mergeDefaultStateWithProps( + props: ZeroExInstantProviderProps, + defaultState: DefaultState = DEFAULT_STATE, + ): State { + // use the networkId passed in with the props, otherwise default to that of the default state (1, mainnet) + const networkId = props.networkId || defaultState.network; + // construct the ProviderState + const providerState = providerStateFactory.getInitialProviderState( + props.orderSource, networkId, - }; - let assetBuyer; - if (_.isString(props.orderSource)) { - assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl( - provider, - props.orderSource, - assetBuyerOptions, - ); - } else { - assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.orderSource, assetBuyerOptions); - } + props.provider, + ); + // merge the additional additionalAssetMetaDataMap with our default map const completeAssetMetaDataMap = { ...props.additionalAssetMetaDataMap, - ...state.assetMetaDataMap, + ...defaultState.assetMetaDataMap, }; + // construct the final state const storeStateFromProps: State = { - ...state, - assetBuyer, + ...defaultState, + providerState, network: networkId, selectedAsset: _.isUndefined(props.defaultSelectedAssetData) ? undefined @@ -74,7 +68,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider networkId, ), selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount) - ? state.selectedAssetAmount + ? undefined : new BigNumber(props.defaultAssetBuyAmount), availableAssets: _.isUndefined(props.availableAssetDatas) ? undefined @@ -86,10 +80,9 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider } constructor(props: ZeroExInstantProviderProps) { super(props); - const initialAppState = ZeroExInstantProvider._mergeInitialStateWithProps(this.props, INITIAL_STATE); + const initialAppState = ZeroExInstantProvider._mergeDefaultStateWithProps(this.props); this._store = store.create(initialAppState); } - public componentDidMount(): void { const state = this._store.getState(); // tslint:disable-next-line:no-floating-promises @@ -108,7 +101,6 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider // tslint:disable-next-line:no-floating-promises this._flashErrorIfWrongNetwork(); } - public render(): React.ReactNode { return ( <ReduxProvider store={this._store}> @@ -116,19 +108,15 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider </ReduxProvider> ); } - private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => { const msToShowError = 30000; // 30 seconds - const network = this._store.getState().network; - const assetBuyerIfExists = this._store.getState().assetBuyer; - const providerIfExists = oc(assetBuyerIfExists).provider(); - if (!_.isUndefined(providerIfExists)) { - const web3Wrapper = new Web3Wrapper(providerIfExists); - const networkOfProvider = await web3Wrapper.getNetworkIdAsync(); - if (network !== networkOfProvider) { - const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`; - errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError); - } + const state = this._store.getState(); + const network = state.network; + const web3Wrapper = state.providerState.web3Wrapper; + const networkOfProvider = await web3Wrapper.getNetworkIdAsync(); + if (network !== networkOfProvider) { + const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`; + errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError); } }; } |