aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant/src/components')
-rw-r--r--packages/instant/src/components/amount_input.tsx12
-rw-r--r--packages/instant/src/components/animations/slide_animations.tsx54
-rw-r--r--packages/instant/src/components/animations/slide_up_and_down_animation.tsx96
-rw-r--r--packages/instant/src/components/asset_amount_input.tsx38
-rw-r--r--packages/instant/src/components/buy_button.tsx58
-rw-r--r--packages/instant/src/components/instant_heading.tsx62
-rw-r--r--packages/instant/src/components/order_details.tsx110
-rw-r--r--packages/instant/src/components/sliding_error.tsx24
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx3
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx17
10 files changed, 300 insertions, 174 deletions
diff --git a/packages/instant/src/components/amount_input.tsx b/packages/instant/src/components/amount_input.tsx
index 38810063d..7644f5f67 100644
--- a/packages/instant/src/components/amount_input.tsx
+++ b/packages/instant/src/components/amount_input.tsx
@@ -3,6 +3,7 @@ import * as _ from 'lodash';
import * as React from 'react';
import { ColorOption } from '../style/theme';
+import { util } from '../util/util';
import { Container, Input } from './ui';
@@ -10,10 +11,13 @@ export interface AmountInputProps {
fontColor?: ColorOption;
fontSize?: string;
value?: BigNumber;
- onChange?: (value?: BigNumber) => void;
+ onChange: (value?: BigNumber) => void;
}
export class AmountInput extends React.Component<AmountInputProps> {
+ public static defaultProps = {
+ onChange: util.boundNoop,
+ };
public render(): React.ReactNode {
const { fontColor, fontSize, value } = this.props;
return (
@@ -24,7 +28,7 @@ export class AmountInput extends React.Component<AmountInputProps> {
onChange={this._handleChange}
value={!_.isUndefined(value) ? value.toString() : ''}
placeholder="0.00"
- width="2em"
+ width="2.2em"
/>
</Container>
);
@@ -40,8 +44,6 @@ export class AmountInput extends React.Component<AmountInputProps> {
return;
}
}
- if (!_.isUndefined(this.props.onChange)) {
- this.props.onChange(bigNumberValue);
- }
+ this.props.onChange(bigNumberValue);
};
}
diff --git a/packages/instant/src/components/animations/slide_animations.tsx b/packages/instant/src/components/animations/slide_animations.tsx
new file mode 100644
index 000000000..1f10a2ed6
--- /dev/null
+++ b/packages/instant/src/components/animations/slide_animations.tsx
@@ -0,0 +1,54 @@
+import * as React from 'react';
+
+import { keyframes, styled } from '../../style/theme';
+
+const slideKeyframeGenerator = (fromY: string, toY: string) => keyframes`
+ from {
+ position: relative;
+ top: ${fromY};
+ }
+
+ to {
+ position: relative;
+ top: ${toY};
+ }
+`;
+
+export interface SlideAnimationProps {
+ keyframes: string;
+ animationType: string;
+ animationDirection?: string;
+}
+
+export const SlideAnimation =
+ styled.div <
+ SlideAnimationProps >
+ `
+ animation-name: ${props => props.keyframes};
+ animation-duration: 0.3s;
+ animation-timing-function: ${props => props.animationType};
+ animation-delay: 0s;
+ animation-iteration-count: 1;
+ animation-fill-mode: ${props => props.animationDirection || 'none'};
+ position: relative;
+`;
+
+export interface SlideAnimationComponentProps {
+ downY: string;
+}
+
+export const SlideUpAnimation: React.StatelessComponent<SlideAnimationComponentProps> = props => (
+ <SlideAnimation animationType="ease-in" keyframes={slideKeyframeGenerator(props.downY, '0px')}>
+ {props.children}
+ </SlideAnimation>
+);
+
+export const SlideDownAnimation: React.StatelessComponent<SlideAnimationComponentProps> = props => (
+ <SlideAnimation
+ animationDirection="forwards"
+ animationType="cubic-bezier(0.25, 0.1, 0.25, 1)"
+ keyframes={slideKeyframeGenerator('0px', props.downY)}
+ >
+ {props.children}
+ </SlideAnimation>
+);
diff --git a/packages/instant/src/components/animations/slide_up_and_down_animation.tsx b/packages/instant/src/components/animations/slide_up_and_down_animation.tsx
deleted file mode 100644
index 9c18e0933..000000000
--- a/packages/instant/src/components/animations/slide_up_and_down_animation.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import * as React from 'react';
-
-import { keyframes, styled } from '../../style/theme';
-
-const slideKeyframeGenerator = (fromY: string, toY: string) => keyframes`
- from {
- position: relative;
- top: ${fromY};
- }
-
- to {
- position: relative;
- top: ${toY};
- }
-`;
-
-export interface SlideAnimationProps {
- keyframes: string;
- animationType: string;
- animationDirection?: string;
-}
-
-export const SlideAnimation =
- styled.div <
- SlideAnimationProps >
- `
- animation-name: ${props => props.keyframes};
- animation-duration: 0.3s;
- animation-timing-function: ${props => props.animationType};
- animation-delay: 0s;
- animation-iteration-count: 1;
- animation-fill-mode: ${props => props.animationDirection || 'none'};
- position: relative;
-`;
-
-export interface SlideAnimationComponentProps {
- downY: string;
-}
-
-export const SlideUpAnimationComponent: React.StatelessComponent<SlideAnimationComponentProps> = props => (
- <SlideAnimation animationType="ease-in" keyframes={slideKeyframeGenerator(props.downY, '0px')}>
- {props.children}
- </SlideAnimation>
-);
-
-export const SlideDownAnimationComponent: React.StatelessComponent<SlideAnimationComponentProps> = props => (
- <SlideAnimation
- animationDirection="forwards"
- animationType="cubic-bezier(0.25, 0.1, 0.25, 1)"
- keyframes={slideKeyframeGenerator('0px', props.downY)}
- >
- {props.children}
- </SlideAnimation>
-);
-
-export interface SlideUpAndDownAnimationProps extends SlideAnimationComponentProps {
- delayMs: number;
-}
-
-enum SlideState {
- Up = 'up',
- Down = 'down',
-}
-interface SlideUpAndDownState {
- slideState: SlideState;
-}
-
-export class SlideUpAndDownAnimation extends React.Component<SlideUpAndDownAnimationProps, SlideUpAndDownState> {
- public state = {
- slideState: SlideState.Up,
- };
-
- private _timeoutId?: number;
- public render(): React.ReactNode {
- return this._renderSlide();
- }
- public componentDidMount(): void {
- this._timeoutId = window.setTimeout(() => {
- this.setState({
- slideState: SlideState.Down,
- });
- }, this.props.delayMs);
-
- return;
- }
- public componentWillUnmount(): void {
- if (this._timeoutId) {
- window.clearTimeout(this._timeoutId);
- }
- }
- private _renderSlide(): React.ReactNode {
- const SlideComponent = this.state.slideState === 'up' ? SlideUpAnimationComponent : SlideDownAnimationComponent;
-
- return <SlideComponent downY={this.props.downY}>{this.props.children}</SlideComponent>;
- }
-}
diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx
new file mode 100644
index 000000000..db3dbe7f3
--- /dev/null
+++ b/packages/instant/src/components/asset_amount_input.tsx
@@ -0,0 +1,38 @@
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { assetDataUtil } from '../util/asset_data';
+
+import { ColorOption } from '../style/theme';
+import { util } from '../util/util';
+
+import { AmountInput, AmountInputProps } from './amount_input';
+import { Container, Text } from './ui';
+
+export interface AssetAmountInputProps extends AmountInputProps {
+ assetData?: string;
+ onChange: (value?: BigNumber, assetData?: string) => void;
+}
+
+export class AssetAmountInput extends React.Component<AssetAmountInputProps> {
+ public static defaultProps = {
+ onChange: util.boundNoop,
+ };
+ public render(): React.ReactNode {
+ const { assetData, onChange, ...rest } = this.props;
+ return (
+ <Container>
+ <AmountInput {...rest} onChange={this._handleChange} />
+ <Container display="inline-block" marginLeft="10px">
+ <Text fontSize={rest.fontSize} fontColor={ColorOption.white} textTransform="uppercase">
+ {assetDataUtil.bestNameForAsset(this.props.assetData, '???')}
+ </Text>
+ </Container>
+ </Container>
+ );
+ }
+ private readonly _handleChange = (value?: BigNumber): void => {
+ this.props.onChange(value, this.props.assetData);
+ };
+}
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 5a32b9575..0706817c9 100644
--- a/packages/instant/src/components/buy_button.tsx
+++ b/packages/instant/src/components/buy_button.tsx
@@ -1,19 +1,53 @@
+import { BuyQuote } from '@0xproject/asset-buyer';
+import * as _ from 'lodash';
import * as React from 'react';
import { ColorOption } from '../style/theme';
+import { assetBuyer } from '../util/asset_buyer';
+import { util } from '../util/util';
+import { web3Wrapper } from '../util/web3_wrapper';
import { Button, Container, Text } from './ui';
-export interface BuyButtonProps {}
+export interface BuyButtonProps {
+ buyQuote?: BuyQuote;
+ onClick: (buyQuote: BuyQuote) => void;
+ onBuySuccess: (buyQuote: BuyQuote, txnHash: string) => void;
+ onBuyFailure: (buyQuote: BuyQuote, tnxHash?: string) => void;
+ text: string;
+}
-export const BuyButton: React.StatelessComponent<BuyButtonProps> = props => (
- <Container padding="20px" width="100%">
- <Button width="100%">
- <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
- Buy
- </Text>
- </Button>
- </Container>
-);
-
-BuyButton.displayName = 'BuyButton';
+export class BuyButton extends React.Component<BuyButtonProps> {
+ public static defaultProps = {
+ onClick: util.boundNoop,
+ onBuySuccess: util.boundNoop,
+ onBuyFailure: util.boundNoop,
+ };
+ public render(): React.ReactNode {
+ const shouldDisableButton = _.isUndefined(this.props.buyQuote);
+ return (
+ <Container padding="20px" width="100%">
+ <Button width="100%" onClick={this._handleClick} isDisabled={shouldDisableButton}>
+ <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
+ {this.props.text}
+ </Text>
+ </Button>
+ </Container>
+ );
+ }
+ private readonly _handleClick = async () => {
+ // The button is disabled when there is no buy quote anyway.
+ if (_.isUndefined(this.props.buyQuote)) {
+ return;
+ }
+ this.props.onClick(this.props.buyQuote);
+ let txnHash;
+ try {
+ txnHash = await assetBuyer.executeBuyQuoteAsync(this.props.buyQuote);
+ await web3Wrapper.awaitTransactionSuccessAsync(txnHash);
+ this.props.onBuySuccess(this.props.buyQuote, txnHash);
+ } catch {
+ this.props.onBuyFailure(this.props.buyQuote, txnHash);
+ }
+ };
+}
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index be0414b8d..f57b59b73 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -1,11 +1,58 @@
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
import * as React from 'react';
import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input';
import { ColorOption } from '../style/theme';
+import { AsyncProcessState } from '../types';
+import { format } from '../util/format';
import { Container, Flex, Text } from './ui';
-export interface InstantHeadingProps {}
+export interface InstantHeadingProps {
+ selectedAssetAmount?: BigNumber;
+ totalEthBaseAmount?: BigNumber;
+ ethUsdPrice?: BigNumber;
+ quoteState: AsyncProcessState;
+}
+
+const Placeholder = () => (
+ <Text fontWeight="bold" fontColor={ColorOption.white}>
+ &mdash;
+ </Text>
+);
+const displaytotalEthBaseAmount = ({
+ selectedAssetAmount,
+ totalEthBaseAmount,
+}: InstantHeadingProps): React.ReactNode => {
+ if (_.isUndefined(selectedAssetAmount)) {
+ return '0 ETH';
+ }
+ return format.ethBaseAmount(totalEthBaseAmount, 4, <Placeholder />);
+};
+
+const displayUsdAmount = ({
+ totalEthBaseAmount,
+ selectedAssetAmount,
+ ethUsdPrice,
+}: InstantHeadingProps): React.ReactNode => {
+ if (_.isUndefined(selectedAssetAmount)) {
+ return '$0.00';
+ }
+ return format.ethBaseAmountInUsd(totalEthBaseAmount, ethUsdPrice, 2, <Placeholder />);
+};
+
+const loadingOrAmount = (quoteState: AsyncProcessState, amount: React.ReactNode): React.ReactNode => {
+ if (quoteState === AsyncProcessState.PENDING) {
+ return (
+ <Text fontWeight="bold" fontColor={ColorOption.white}>
+ &hellip;loading
+ </Text>
+ );
+ } else {
+ return amount;
+ }
+};
export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = props => (
<Container backgroundColor={ColorOption.primaryColor} padding="20px" width="100%" borderRadius="3px 3px 0px 0px">
@@ -22,22 +69,15 @@ export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = pro
</Text>
</Container>
<Flex direction="row" justify="space-between">
- <Container>
- <SelectedAssetAmountInput fontSize="45px" />
- <Container display="inline-block" marginLeft="10px">
- <Text fontSize="45px" fontColor={ColorOption.white} textTransform="uppercase">
- rep
- </Text>
- </Container>
- </Container>
+ <SelectedAssetAmountInput fontSize="45px" />
<Flex direction="column" justify="space-between">
<Container marginBottom="5px">
<Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}>
- 0 ETH
+ {loadingOrAmount(props.quoteState, displaytotalEthBaseAmount(props))}
</Text>
</Container>
<Text fontSize="16px" fontColor={ColorOption.white} opacity={0.7}>
- $0.00
+ {loadingOrAmount(props.quoteState, displayUsdAmount(props))}
</Text>
</Flex>
</Flex>
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index dbf2c1f0b..a15ff411b 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -1,53 +1,90 @@
+import { BuyQuoteInfo } from '@0xproject/asset-buyer';
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
import * as React from 'react';
+import { oc } from 'ts-optchain';
import { ColorOption } from '../style/theme';
+import { format } from '../util/format';
import { Container, Flex, Text } from './ui';
-export interface OrderDetailsProps {}
-
-export const OrderDetails: React.StatelessComponent<OrderDetailsProps> = props => (
- <Container padding="20px" width="100%">
- <Container marginBottom="10px">
- <Text
- letterSpacing="1px"
- fontColor={ColorOption.primaryColor}
- fontWeight={600}
- textTransform="uppercase"
- fontSize="14px"
- >
- Order Details
- </Text>
- </Container>
- <OrderDetailsRow name="Token Price" primaryValue=".013 ETH" secondaryValue="$24.32" />
- <OrderDetailsRow name="Fee" primaryValue=".005 ETH" secondaryValue="$1.04" />
- <OrderDetailsRow name="Total Cost" primaryValue="1.66 ETH" secondaryValue="$589.56" shouldEmphasize={true} />
- </Container>
-);
-
-OrderDetails.displayName = 'OrderDetails';
-
-export interface OrderDetailsRowProps {
- name: string;
- primaryValue: string;
- secondaryValue: string;
+export interface OrderDetailsProps {
+ buyQuoteInfo?: BuyQuoteInfo;
+ ethUsdPrice?: BigNumber;
+}
+
+export class OrderDetails extends React.Component<OrderDetailsProps> {
+ public render(): React.ReactNode {
+ const { buyQuoteInfo, ethUsdPrice } = this.props;
+ const buyQuoteAccessor = oc(buyQuoteInfo);
+ const ethAssetPrice = buyQuoteAccessor.ethPerAssetPrice();
+ const ethTokenFee = buyQuoteAccessor.feeEthAmount();
+ const totalEthAmount = buyQuoteAccessor.totalEthAmount();
+ return (
+ <Container padding="20px" width="100%">
+ <Container marginBottom="10px">
+ <Text
+ letterSpacing="1px"
+ fontColor={ColorOption.primaryColor}
+ fontWeight={600}
+ textTransform="uppercase"
+ fontSize="14px"
+ >
+ Order Details
+ </Text>
+ </Container>
+ <EthAmountRow
+ rowLabel="Token Price"
+ ethAmount={ethAssetPrice}
+ ethUsdPrice={ethUsdPrice}
+ isEthAmountInBaseUnits={false}
+ />
+ <EthAmountRow rowLabel="Fee" ethAmount={ethTokenFee} ethUsdPrice={ethUsdPrice} />
+ <EthAmountRow
+ rowLabel="Total Cost"
+ ethAmount={totalEthAmount}
+ ethUsdPrice={ethUsdPrice}
+ shouldEmphasize={true}
+ />
+ </Container>
+ );
+ }
+}
+
+export interface EthAmountRowProps {
+ rowLabel: string;
+ ethAmount?: BigNumber;
+ isEthAmountInBaseUnits?: boolean;
+ ethUsdPrice?: BigNumber;
shouldEmphasize?: boolean;
}
-export const OrderDetailsRow: React.StatelessComponent<OrderDetailsRowProps> = props => {
- const fontWeight = props.shouldEmphasize ? 700 : 400;
+export const EthAmountRow: React.StatelessComponent<EthAmountRowProps> = ({
+ rowLabel,
+ ethAmount,
+ isEthAmountInBaseUnits,
+ ethUsdPrice,
+ shouldEmphasize,
+}) => {
+ const fontWeight = shouldEmphasize ? 700 : 400;
+ const usdFormatter = isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd;
+ const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount;
+ const usdPriceSection = _.isUndefined(ethUsdPrice) ? null : (
+ <Container marginRight="3px" display="inline-block">
+ <Text fontColor={ColorOption.lightGrey}>({usdFormatter(ethAmount, ethUsdPrice)})</Text>
+ </Container>
+ );
return (
<Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
<Flex justify="space-between">
<Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {props.name}
+ {rowLabel}
</Text>
<Container>
- <Container marginRight="3px" display="inline-block">
- <Text fontColor={ColorOption.lightGrey}>({props.secondaryValue}) </Text>
- </Container>
+ {usdPriceSection}
<Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {props.primaryValue}
+ {ethFormatter(ethAmount)}
</Text>
</Container>
</Flex>
@@ -55,8 +92,9 @@ export const OrderDetailsRow: React.StatelessComponent<OrderDetailsRowProps> = p
);
};
-OrderDetailsRow.defaultProps = {
+EthAmountRow.defaultProps = {
shouldEmphasize: false,
+ isEthAmountInBaseUnits: true,
};
-OrderDetailsRow.displayName = 'OrderDetailsRow';
+EthAmountRow.displayName = 'EthAmountRow';
diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx
index 0237fb7e9..3865a8797 100644
--- a/packages/instant/src/components/sliding_error.tsx
+++ b/packages/instant/src/components/sliding_error.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
import { ColorOption } from '../style/theme';
-import { SlideUpAndDownAnimation } from './animations/slide_up_and_down_animation';
+import { SlideDownAnimation, SlideUpAnimation } from './animations/slide_animations';
import { Container, Text } from './ui';
@@ -20,8 +20,8 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
borderRadius="6px"
marginBottom="10px"
>
- <Container marginRight="5px" display="inline">
- {props.icon}
+ <Container marginRight="5px" display="inline" top="3px" position="relative">
+ <Text fontSize="20px">{props.icon}</Text>
</Container>
<Text fontWeight="500" fontColor={ColorOption.darkOrange}>
{props.message}
@@ -29,8 +29,16 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
</Container>
);
-export const SlidingError: React.StatelessComponent<ErrorProps> = props => (
- <SlideUpAndDownAnimation downY="120px" delayMs={5000}>
- <Error icon={props.icon} message={props.message} />
- </SlideUpAndDownAnimation>
-);
+export type SlidingDirection = 'up' | 'down';
+export interface SlidingErrorProps extends ErrorProps {
+ direction: SlidingDirection;
+}
+export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props => {
+ const AnimationComponent = props.direction === 'up' ? SlideUpAnimation : SlideDownAnimation;
+
+ return (
+ <AnimationComponent downY="120px">
+ <Error icon={props.icon} message={props.message} />
+ </AnimationComponent>
+ );
+};
diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx
index 0e6230d1b..f6472e811 100644
--- a/packages/instant/src/components/zero_ex_instant.tsx
+++ b/packages/instant/src/components/zero_ex_instant.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { Provider } from 'react-redux';
+import { asyncData } from '../redux/async_data';
import { store } from '../redux/store';
import { fonts } from '../style/fonts';
import { theme, ThemeProvider } from '../style/theme';
@@ -8,6 +9,8 @@ import { theme, ThemeProvider } from '../style/theme';
import { ZeroExInstantContainer } from './zero_ex_instant_container';
fonts.include();
+// tslint:disable-next-line:no-floating-promises
+asyncData.fetchAndDispatchToStore();
export interface ZeroExInstantProps {}
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index a384c5f1b..cf918d890 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -1,16 +1,21 @@
import * as React from 'react';
+import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
+import { LatestError } from '../containers/latest_error';
+import { SelectedAssetBuyButton } from '../containers/selected_asset_buy_button';
+import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
+
import { ColorOption } from '../style/theme';
-import { BuyButton } from './buy_button';
-import { InstantHeading } from './instant_heading';
-import { OrderDetails } from './order_details';
import { Container, Flex } from './ui';
export interface ZeroExInstantContainerProps {}
export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantContainerProps> = props => (
<Container width="350px">
+ <Container zIndex={1} position="relative">
+ <LatestError />
+ </Container>
<Container
zIndex={2}
position="relative"
@@ -19,9 +24,9 @@ export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantConta
hasBoxShadow={true}
>
<Flex direction="column" justify="flex-start">
- <InstantHeading />
- <OrderDetails />
- <BuyButton />
+ <SelectedAssetInstantHeading />
+ <LatestBuyQuoteOrderDetails />
+ <SelectedAssetBuyButton />
</Flex>
</Container>
</Container>