remove unused instant pages
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { Instant as InstantComponent, InstantProps } from 'ts/pages/instant/instant';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { State } from 'ts/redux/reducer';
|
||||
import { ScreenWidths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
|
||||
interface ConnectedState {
|
||||
translate: Translate;
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
interface ConnectedDispatch {
|
||||
dispatcher: Dispatcher;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State, _ownProps: InstantProps): ConnectedState => ({
|
||||
translate: state.translate,
|
||||
screenWidth: state.screenWidth,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||
dispatcher: new Dispatcher(dispatch),
|
||||
});
|
||||
|
||||
export const Instant: React.ComponentClass<InstantProps> = connect(mapStateToProps, mapDispatchToProps)(
|
||||
InstantComponent,
|
||||
);
|
||||
@@ -1,46 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
export interface ActionLinkProps {
|
||||
displayText: string;
|
||||
linkSrc?: string;
|
||||
onClick?: () => void;
|
||||
fontSize?: number;
|
||||
color?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export class ActionLink extends React.Component<ActionLinkProps> {
|
||||
public static defaultProps = {
|
||||
fontSize: 16,
|
||||
color: colors.white,
|
||||
};
|
||||
public render(): React.ReactNode {
|
||||
const { displayText, fontSize, color, className } = this.props;
|
||||
return (
|
||||
<Container className={`flex items-center ${className}`} onClick={this._handleClick} cursor="pointer">
|
||||
<Container>
|
||||
<Text fontSize="16px" fontColor={color}>
|
||||
{displayText}
|
||||
</Text>
|
||||
</Container>
|
||||
<Container paddingTop="1px" paddingLeft="6px">
|
||||
<i className="zmdi zmdi-chevron-right bold" style={{ fontSize, color }} />
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
private readonly _handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
if (!_.isUndefined(this.props.onClick)) {
|
||||
this.props.onClick();
|
||||
} else if (!_.isUndefined(this.props.linkSrc)) {
|
||||
utils.openUrl(this.props.linkSrc);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
import { StandardRelayerAPIOrderProvider } from '@0x/asset-buyer';
|
||||
import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { ObjectMap } from '@0x/types';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { CheckMark } from 'ts/components/ui/check_mark';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { MultiSelect } from 'ts/components/ui/multi_select';
|
||||
import { Select, SelectItemConfig } from 'ts/components/ui/select';
|
||||
import { Spinner } from 'ts/components/ui/spinner';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { ConfigGeneratorAddressInput } from 'ts/pages/instant/config_generator_address_input';
|
||||
import { FeePercentageSlider } from 'ts/pages/instant/fee_percentage_slider';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { WebsitePaths } from 'ts/types';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
|
||||
import { assetMetaDataMap } from '../../../../instant/src/data/asset_meta_data_map';
|
||||
import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../instant/src/types';
|
||||
|
||||
export interface ConfigGeneratorProps {
|
||||
value: ZeroExInstantBaseConfig;
|
||||
onConfigChange: (config: ZeroExInstantBaseConfig) => void;
|
||||
}
|
||||
|
||||
export interface ConfigGeneratorState {
|
||||
isLoadingAvailableTokens: boolean;
|
||||
// Address to token info
|
||||
availableTokens?: ObjectMap<ERC20AssetMetaData>;
|
||||
}
|
||||
|
||||
const SRA_ENDPOINTS = ['https://api.radarrelay.com/0x/v2/', 'https://sra.bamboorelay.com/0x/v2/'];
|
||||
|
||||
export class ConfigGenerator extends React.Component<ConfigGeneratorProps, ConfigGeneratorState> {
|
||||
public state: ConfigGeneratorState = {
|
||||
isLoadingAvailableTokens: true,
|
||||
};
|
||||
public componentDidMount(): void {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this._setAvailableAssetsFromOrderProvider();
|
||||
}
|
||||
public componentDidUpdate(prevProps: ConfigGeneratorProps): void {
|
||||
if (prevProps.value.orderSource !== this.props.value.orderSource) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this._setAvailableAssetsFromOrderProvider();
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: undefined,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
}
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
const { value } = this.props;
|
||||
if (!_.isString(value.orderSource)) {
|
||||
throw new Error('ConfigGenerator component only supports string values as an orderSource.');
|
||||
}
|
||||
return (
|
||||
<Container minWidth="350px">
|
||||
<ConfigGeneratorSection title="Standard relayer API endpoint">
|
||||
<Select value={value.orderSource} items={this._generateItems()} />
|
||||
</ConfigGeneratorSection>
|
||||
<ConfigGeneratorSection {...this._getTokenSelectorProps()}>
|
||||
{this._renderTokenMultiSelectOrSpinner()}
|
||||
</ConfigGeneratorSection>
|
||||
<ConfigGeneratorSection title="Transaction fee ETH address" marginBottom="10px" isOptional={true}>
|
||||
<ConfigGeneratorAddressInput
|
||||
value={value.affiliateInfo ? value.affiliateInfo.feeRecipient : ''}
|
||||
onChange={this._handleAffiliateAddressChange}
|
||||
/>
|
||||
</ConfigGeneratorSection>
|
||||
<ConfigGeneratorSection
|
||||
title="Fee percentage"
|
||||
actionText="Learn more"
|
||||
onActionTextClick={this._handleAffiliatePercentageLearnMoreClick}
|
||||
>
|
||||
<FeePercentageSlider
|
||||
value={value.affiliateInfo.feePercentage}
|
||||
onChange={this._handleAffiliatePercentageChange}
|
||||
isDisabled={
|
||||
_.isUndefined(value.affiliateInfo) ||
|
||||
_.isUndefined(value.affiliateInfo.feeRecipient) ||
|
||||
_.isEmpty(value.affiliateInfo.feeRecipient)
|
||||
}
|
||||
/>
|
||||
</ConfigGeneratorSection>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private readonly _getTokenSelectorProps = (): ConfigGeneratorSectionProps => {
|
||||
if (_.isEmpty(this.state.availableTokens)) {
|
||||
return {
|
||||
title: 'What tokens can users buy?',
|
||||
};
|
||||
}
|
||||
if (_.isUndefined(this.props.value.availableAssetDatas)) {
|
||||
return {
|
||||
title: 'What tokens can users buy?',
|
||||
actionText: 'Unselect All',
|
||||
onActionTextClick: this._handleUnselectAllClick,
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: 'What tokens can users buy?',
|
||||
actionText: 'Select All',
|
||||
onActionTextClick: this._handleSelectAllClick,
|
||||
};
|
||||
};
|
||||
private readonly _generateItems = (): SelectItemConfig[] => {
|
||||
return _.map(SRA_ENDPOINTS, endpoint => ({
|
||||
text: endpoint,
|
||||
onClick: this._handleSRASelection.bind(this, endpoint),
|
||||
}));
|
||||
};
|
||||
private readonly _handleAffiliatePercentageLearnMoreClick = (): void => {
|
||||
window.open(`${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, '_blank');
|
||||
};
|
||||
private readonly _handleSRASelection = (sraEndpoint: string) => {
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
orderSource: sraEndpoint,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleAffiliateAddressChange = (address: string, isValid: boolean) => {
|
||||
const oldConfig: ZeroExInstantBaseConfig = this.props.value;
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...oldConfig,
|
||||
affiliateInfo: {
|
||||
feeRecipient: address,
|
||||
feePercentage: oldConfig.affiliateInfo.feePercentage,
|
||||
},
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleAffiliatePercentageChange = (value: number) => {
|
||||
const oldConfig: ZeroExInstantBaseConfig = this.props.value;
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...oldConfig,
|
||||
affiliateInfo: {
|
||||
feeRecipient: oldConfig.affiliateInfo.feeRecipient,
|
||||
feePercentage: value,
|
||||
},
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleSelectAllClick = () => {
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: undefined,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleUnselectAllClick = () => {
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: [],
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _handleTokenClick = (assetData: string) => {
|
||||
const { value } = this.props;
|
||||
let newAvailableAssetDatas: string[] = [];
|
||||
const allKnownAssetDatas = _.keys(this.state.availableTokens);
|
||||
const availableAssetDatas = value.availableAssetDatas;
|
||||
if (_.isUndefined(availableAssetDatas)) {
|
||||
// It being undefined means it's all tokens.
|
||||
newAvailableAssetDatas = _.pull(allKnownAssetDatas, assetData);
|
||||
} else if (!_.includes(availableAssetDatas, assetData)) {
|
||||
// Add it
|
||||
newAvailableAssetDatas = [...availableAssetDatas, assetData];
|
||||
if (newAvailableAssetDatas.length === allKnownAssetDatas.length) {
|
||||
// If all tokens are manually selected, just show none.
|
||||
newAvailableAssetDatas = undefined;
|
||||
}
|
||||
} else {
|
||||
// Remove it
|
||||
newAvailableAssetDatas = _.pull(availableAssetDatas, assetData);
|
||||
}
|
||||
const newConfig: ZeroExInstantBaseConfig = {
|
||||
...this.props.value,
|
||||
availableAssetDatas: newAvailableAssetDatas,
|
||||
};
|
||||
this.props.onConfigChange(newConfig);
|
||||
};
|
||||
private readonly _setAvailableAssetsFromOrderProvider = async (): Promise<void> => {
|
||||
const { value } = this.props;
|
||||
if (!_.isUndefined(value.orderSource) && _.isString(value.orderSource)) {
|
||||
this.setState({ isLoadingAvailableTokens: true });
|
||||
const networkId = constants.NETWORK_ID_MAINNET;
|
||||
const sraOrderProvider = new StandardRelayerAPIOrderProvider(value.orderSource, networkId);
|
||||
const etherTokenAddress = getContractAddressesForNetworkOrThrow(networkId).etherToken;
|
||||
const etherTokenAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress);
|
||||
const assetDatas = await sraOrderProvider.getAvailableMakerAssetDatasAsync(etherTokenAssetData);
|
||||
const availableTokens = _.reduce(
|
||||
assetDatas,
|
||||
(acc, assetData) => {
|
||||
const metaDataIfExists = assetMetaDataMap[assetData] as ERC20AssetMetaData;
|
||||
if (metaDataIfExists) {
|
||||
acc[assetData] = metaDataIfExists;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as ObjectMap<ERC20AssetMetaData>,
|
||||
);
|
||||
this.setState({ availableTokens, isLoadingAvailableTokens: false });
|
||||
}
|
||||
};
|
||||
private readonly _renderTokenMultiSelectOrSpinner = (): React.ReactNode => {
|
||||
const { value } = this.props;
|
||||
const { availableTokens, isLoadingAvailableTokens } = this.state;
|
||||
const multiSelectHeight = '200px';
|
||||
if (isLoadingAvailableTokens) {
|
||||
return (
|
||||
<Container
|
||||
className="flex flex-column items-center justify-center"
|
||||
height={multiSelectHeight}
|
||||
backgroundColor={colors.white}
|
||||
borderRadius="4px"
|
||||
width="100%"
|
||||
>
|
||||
<Container position="relative" left="12px" marginBottom="20px">
|
||||
<Spinner />
|
||||
</Container>
|
||||
<Text fontSize="16px">Loading...</Text>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
const availableAssetDatas = _.keys(availableTokens);
|
||||
if (availableAssetDatas.length === 0) {
|
||||
return (
|
||||
<Container
|
||||
className="flex flex-column items-center justify-center"
|
||||
height={multiSelectHeight}
|
||||
backgroundColor={colors.white}
|
||||
borderRadius="4px"
|
||||
width="100%"
|
||||
>
|
||||
<Text fontSize="16px">No tokens available. Try another endpoint?</Text>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
const items = _.map(_.keys(availableTokens), assetData => {
|
||||
const metaData = availableTokens[assetData];
|
||||
return {
|
||||
value: assetData,
|
||||
renderItemContent: (isSelected: boolean) => (
|
||||
<Container className="flex items-center">
|
||||
<Container marginRight="10px">
|
||||
<CheckMark isChecked={isSelected} />
|
||||
</Container>
|
||||
<Text
|
||||
fontSize="16px"
|
||||
fontColor={isSelected ? colors.mediumBlue : colors.darkerGrey}
|
||||
fontWeight={300}
|
||||
>
|
||||
<b>{metaData.symbol.toUpperCase()}</b> — {metaData.name}
|
||||
</Text>
|
||||
</Container>
|
||||
),
|
||||
onClick: this._handleTokenClick.bind(this, assetData),
|
||||
};
|
||||
});
|
||||
return <MultiSelect items={items} selectedValues={value.availableAssetDatas} height={multiSelectHeight} />;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ConfigGeneratorSectionProps {
|
||||
title: string;
|
||||
actionText?: string;
|
||||
onActionTextClick?: () => void;
|
||||
isOptional?: boolean;
|
||||
marginBottom?: string;
|
||||
}
|
||||
|
||||
export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSectionProps> = ({
|
||||
title,
|
||||
actionText,
|
||||
onActionTextClick,
|
||||
isOptional,
|
||||
marginBottom,
|
||||
children,
|
||||
}) => (
|
||||
<Container marginBottom={marginBottom}>
|
||||
<Container marginBottom="10px" className="flex justify-between items-center">
|
||||
<Container>
|
||||
<Text fontColor={colors.white} fontSize="16px" lineHeight="18px" display="inline">
|
||||
{title}
|
||||
</Text>
|
||||
{isOptional && (
|
||||
<Text fontColor={colors.grey} fontSize="16px" lineHeight="18px" display="inline">
|
||||
{' '}
|
||||
(optional)
|
||||
</Text>
|
||||
)}
|
||||
</Container>
|
||||
{actionText && (
|
||||
<Text fontSize="12px" fontColor={colors.grey} onClick={onActionTextClick}>
|
||||
{actionText}
|
||||
</Text>
|
||||
)}
|
||||
</Container>
|
||||
{children}
|
||||
</Container>
|
||||
);
|
||||
|
||||
ConfigGeneratorSection.defaultProps = {
|
||||
marginBottom: '30px',
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { ActionLink } from 'ts/pages/instant/action_link';
|
||||
import { CodeDemo } from 'ts/pages/instant/code_demo';
|
||||
import { ConfigGenerator } from 'ts/pages/instant/config_generator';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { WebsitePaths } from 'ts/types';
|
||||
|
||||
import { ZeroExInstantBaseConfig } from '../../../../instant/src/types';
|
||||
|
||||
export interface ConfiguratorProps {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface ConfiguratorState {
|
||||
instantConfig: ZeroExInstantBaseConfig;
|
||||
}
|
||||
|
||||
export class Configurator extends React.Component<ConfiguratorProps> {
|
||||
public state: ConfiguratorState = {
|
||||
instantConfig: {
|
||||
orderSource: 'https://api.radarrelay.com/0x/v2/',
|
||||
availableAssetDatas: undefined,
|
||||
affiliateInfo: {
|
||||
feeRecipient: '',
|
||||
feePercentage: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
public render(): React.ReactNode {
|
||||
const { hash } = this.props;
|
||||
const codeToDisplay = this._generateCodeDemoCode();
|
||||
return (
|
||||
<Container
|
||||
className="flex justify-center py4 px3"
|
||||
id={hash}
|
||||
backgroundColor={colors.instantTertiaryBackground}
|
||||
>
|
||||
<Container className="mx3">
|
||||
<Container className="mb3">
|
||||
<Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}>
|
||||
0x Instant Configurator
|
||||
</Text>
|
||||
</Container>
|
||||
<ConfigGenerator value={this.state.instantConfig} onConfigChange={this._handleConfigChange} />
|
||||
</Container>
|
||||
<Container className="mx3" height="550px">
|
||||
<Container className="mb3 flex justify-between">
|
||||
<Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}>
|
||||
Code Snippet
|
||||
</Text>
|
||||
<ActionLink
|
||||
displayText="Explore the Docs"
|
||||
linkSrc={`${WebsitePaths.Wiki}#Get-Started-With-Instant`}
|
||||
color={colors.grey}
|
||||
/>
|
||||
</Container>
|
||||
<CodeDemo key={codeToDisplay}>{codeToDisplay}</CodeDemo>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private readonly _handleConfigChange = (config: ZeroExInstantBaseConfig) => {
|
||||
this.setState({
|
||||
instantConfig: config,
|
||||
});
|
||||
};
|
||||
private readonly _generateCodeDemoCode = (): string => {
|
||||
const { instantConfig } = this.state;
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="https://instant.0x.org/instant.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
zeroExInstant.render({
|
||||
orderSource: '${instantConfig.orderSource}',${
|
||||
!_.isUndefined(instantConfig.affiliateInfo) && instantConfig.affiliateInfo.feeRecipient
|
||||
? `\n affiliateInfo: {
|
||||
feeRecipient: '${instantConfig.affiliateInfo.feeRecipient.toLowerCase()}',
|
||||
feePercentage: ${instantConfig.affiliateInfo.feePercentage}
|
||||
},`
|
||||
: ''
|
||||
}${
|
||||
!_.isUndefined(instantConfig.availableAssetDatas)
|
||||
? `\n availableAssetDatas: ${this._renderAvailableAssetDatasString(
|
||||
instantConfig.availableAssetDatas,
|
||||
)}`
|
||||
: ''
|
||||
}
|
||||
}, 'body');
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
};
|
||||
private readonly _renderAvailableAssetDatasString = (availableAssetDatas: string[]): string => {
|
||||
const stringAvailableAssetDatas = availableAssetDatas.map(assetData => `'${assetData}'`);
|
||||
if (availableAssetDatas.length < 2) {
|
||||
return `[${stringAvailableAssetDatas.join(', ')}]`;
|
||||
}
|
||||
return `[\n ${stringAvailableAssetDatas.join(
|
||||
', \n ',
|
||||
)}\n ]`;
|
||||
};
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Image } from 'ts/components/ui/image';
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { ActionLink, ActionLinkProps } from 'ts/pages/instant/action_link';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
|
||||
export interface FeatureProps {
|
||||
screenWidth: ScreenWidths;
|
||||
onGetStartedClick: () => void;
|
||||
}
|
||||
|
||||
export const Features = (props: FeatureProps) => {
|
||||
const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
|
||||
const getStartedLinkInfo = {
|
||||
displayText: 'Get started',
|
||||
onClick: props.onGetStartedClick,
|
||||
};
|
||||
const exploreTheDocsLinkInfo = {
|
||||
displayText: 'Explore the docs',
|
||||
linkSrc: `${WebsitePaths.Wiki}#Get-Started-With-Instant`,
|
||||
};
|
||||
const tokenLinkInfos = isSmallScreen ? [getStartedLinkInfo] : [getStartedLinkInfo, exploreTheDocsLinkInfo];
|
||||
return (
|
||||
<Container backgroundColor={colors.instantSecondaryBackground} className="py3 flex flex-column px3">
|
||||
<FeatureItem
|
||||
imgSrc="images/instant/feature_1.svg"
|
||||
title="Support ERC-20 and ERC-721 tokens"
|
||||
description="Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins."
|
||||
linkInfos={tokenLinkInfos}
|
||||
screenWidth={props.screenWidth}
|
||||
/>
|
||||
<FeatureItem
|
||||
imgSrc="images/instant/feature_2.svg"
|
||||
title="Generate revenue for your business"
|
||||
description="With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp."
|
||||
linkInfos={[
|
||||
{
|
||||
displayText: 'Learn about affiliate fees',
|
||||
linkSrc: `${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`,
|
||||
},
|
||||
]}
|
||||
screenWidth={props.screenWidth}
|
||||
/>
|
||||
<FeatureItem
|
||||
imgSrc="images/instant/feature_3.svg"
|
||||
title="Easy and Flexible Integration"
|
||||
description="Use our out-of-the-box design or customize the user interface by integrating the AssetBuyer engine. You can also tap into 0x networked liquidity or choose your own liquidity pool."
|
||||
linkInfos={[
|
||||
{
|
||||
displayText: 'Explore AssetBuyer',
|
||||
linkSrc: `${WebsitePaths.Docs}/asset-buyer`,
|
||||
},
|
||||
]}
|
||||
screenWidth={props.screenWidth}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
interface FeatureItemProps {
|
||||
imgSrc: string;
|
||||
title: string;
|
||||
description: string;
|
||||
linkInfos: ActionLinkProps[];
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
const FeatureItem = (props: FeatureItemProps) => {
|
||||
const { imgSrc, title, description, linkInfos, screenWidth } = props;
|
||||
const isLargeScreen = screenWidth === ScreenWidths.Lg;
|
||||
const maxWidth = isLargeScreen ? '500px' : undefined;
|
||||
const image = (
|
||||
<Container className="center" minWidth="435px" maxHeight="225px">
|
||||
<Image src={imgSrc} additionalStyle={{ filter: 'drop-shadow(0px 4px 4px rgba(0,0,0,.25))' }} />
|
||||
</Container>
|
||||
);
|
||||
const info = (
|
||||
<Container maxWidth={maxWidth}>
|
||||
<Text fontSize="24px" lineHeight="34px" fontColor={colors.white} fontWeight={500}>
|
||||
{title}
|
||||
</Text>
|
||||
<Container marginTop="28px">
|
||||
<Text fontFamily="Roboto Mono" fontSize="14px" lineHeight="2em" fontColor={colors.grey500}>
|
||||
{description}
|
||||
</Text>
|
||||
</Container>
|
||||
<Container className="flex" marginTop="28px">
|
||||
{_.map(linkInfos, linkInfo => (
|
||||
<Container key={linkInfo.displayText} marginRight="32px">
|
||||
<ActionLink {...linkInfo} />
|
||||
</Container>
|
||||
))}
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
return (
|
||||
<Container className="flex flex-column items-center py4 px3">
|
||||
{isLargeScreen ? (
|
||||
<Container className="flex">
|
||||
{image}
|
||||
<Container marginLeft="115px">{info}</Container>
|
||||
</Container>
|
||||
) : (
|
||||
<Container className="flex flex-column items-center" width="100%">
|
||||
{image}
|
||||
<Container marginTop="48px">{info}</Container>
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
import Slider from 'rc-slider';
|
||||
import 'rc-slider/assets/index.css';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Text } from 'ts/components/ui/text';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { injectGlobal } from 'ts/style/theme';
|
||||
|
||||
const SliderWithTooltip = (Slider as any).createSliderWithTooltip(Slider);
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
injectGlobal`
|
||||
.rc-slider-tooltip-inner {
|
||||
box-shadow: none !important;
|
||||
background-color: ${colors.white} !important;
|
||||
border-radius: 4px !important;
|
||||
padding: 3px 12px !important;
|
||||
height: auto !important;
|
||||
position: relative;
|
||||
top: 7px;
|
||||
&: after {
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-width: 6px;
|
||||
bottom: 100%;
|
||||
left: 100%;
|
||||
border-bottom-color: ${colors.white};
|
||||
margin-left: -60%;
|
||||
}
|
||||
}
|
||||
.rc-slider-disabled {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
`;
|
||||
|
||||
export interface FeePercentageSliderProps {
|
||||
value: number;
|
||||
isDisabled: boolean;
|
||||
onChange: (value: number) => void;
|
||||
}
|
||||
|
||||
export class FeePercentageSlider extends React.Component<FeePercentageSliderProps> {
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<SliderWithTooltip
|
||||
disabled={this.props.isDisabled}
|
||||
min={0}
|
||||
max={0.05}
|
||||
step={0.0025}
|
||||
value={this.props.value}
|
||||
onChange={this.props.onChange}
|
||||
tipFormatter={this._feePercentageSliderFormatter}
|
||||
tipProps={{ placement: 'bottom' }}
|
||||
trackStyle={{
|
||||
backgroundColor: '#b4b4b4',
|
||||
}}
|
||||
railStyle={{
|
||||
backgroundColor: '#696969',
|
||||
}}
|
||||
handleStyle={{
|
||||
border: 'none',
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
activeDotStyle={{
|
||||
boxShadow: 'none',
|
||||
border: 'none',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
private readonly _feePercentageSliderFormatter = (value: number): React.ReactNode => {
|
||||
return <Text fontColor={colors.black} fontSize="14px" fontWeight={700}>{`${(value * 100).toFixed(2)}%`}</Text>;
|
||||
};
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import { utils as sharedUtils } from '@0x/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import * as DocumentTitle from 'react-document-title';
|
||||
|
||||
import { Footer } from 'ts/components/footer';
|
||||
import { MetaTags } from 'ts/components/meta_tags';
|
||||
import { TopBar } from 'ts/components/top_bar/top_bar';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Configurator } from 'ts/pages/instant/configurator';
|
||||
import { Features } from 'ts/pages/instant/features';
|
||||
import { Introducing0xInstant } from 'ts/pages/instant/introducing_0x_instant';
|
||||
import { NeedMore } from 'ts/pages/instant/need_more';
|
||||
import { Screenshots } from 'ts/pages/instant/screenshots';
|
||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { colors } from 'ts/style/colors';
|
||||
import { ScreenWidths, WebsitePaths } from 'ts/types';
|
||||
import { Translate } from 'ts/utils/translate';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
export interface InstantProps {
|
||||
location: Location;
|
||||
translate: Translate;
|
||||
dispatcher: Dispatcher;
|
||||
screenWidth: ScreenWidths;
|
||||
}
|
||||
|
||||
export interface InstantState {}
|
||||
|
||||
const CONFIGURATOR_HASH = 'configure';
|
||||
const THROTTLE_TIMEOUT = 100;
|
||||
const DOCUMENT_TITLE = '0x Instant';
|
||||
const DOCUMENT_DESCRIPTION = '0x Instant';
|
||||
|
||||
export class Instant extends React.Component<InstantProps, InstantState> {
|
||||
// TODO: consolidate this small screen scaffolding into one place (its being used in portal and docs as well)
|
||||
private readonly _throttledScreenWidthUpdate: () => void;
|
||||
public constructor(props: InstantProps) {
|
||||
super(props);
|
||||
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||
}
|
||||
public componentDidMount(): void {
|
||||
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<Container overflowX="hidden">
|
||||
<MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} />
|
||||
<DocumentTitle title={DOCUMENT_TITLE} />
|
||||
<TopBar
|
||||
blockchainIsLoaded={false}
|
||||
location={this.props.location}
|
||||
style={{ backgroundColor: colors.instantPrimaryBackground, position: 'relative' }}
|
||||
translate={this.props.translate}
|
||||
isNightVersion={true}
|
||||
/>
|
||||
<Container backgroundColor={colors.instantPrimaryBackground} />
|
||||
<Introducing0xInstant screenWidth={this.props.screenWidth} onCTAClick={this._onGetStartedClick} />
|
||||
<Screenshots screenWidth={this.props.screenWidth} />
|
||||
<Features screenWidth={this.props.screenWidth} onGetStartedClick={this._onGetStartedClick} />
|
||||
{!this._isSmallScreen() && <Configurator hash={CONFIGURATOR_HASH} />}
|
||||
<NeedMore screenWidth={this.props.screenWidth} />
|
||||
<Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private readonly _onGetStartedClick = () => {
|
||||
if (this._isSmallScreen()) {
|
||||
utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`);
|
||||
} else {
|
||||
this._scrollToConfigurator();
|
||||
}
|
||||
};
|
||||
private _isSmallScreen(): boolean {
|
||||
const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
|
||||
return isSmallScreen;
|
||||
}
|
||||
private _scrollToConfigurator(): void {
|
||||
sharedUtils.setUrlHash(CONFIGURATOR_HASH);
|
||||
sharedUtils.scrollToHash(CONFIGURATOR_HASH, '');
|
||||
}
|
||||
private _updateScreenWidth(): void {
|
||||
const newScreenWidth = utils.getScreenWidth();
|
||||
this.props.dispatcher.updateScreenWidth(newScreenWidth);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user