aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/components')
-rw-r--r--packages/website/ts/components/aboutPageLayout.tsx70
-rw-r--r--packages/website/ts/components/animatedChatIcon.tsx103
-rw-r--r--packages/website/ts/components/animatedCompassIcon.tsx53
-rw-r--r--packages/website/ts/components/banner.tsx144
-rw-r--r--packages/website/ts/components/blockIconLink.tsx84
-rw-r--r--packages/website/ts/components/button.tsx104
-rw-r--r--packages/website/ts/components/chapter_link.tsx15
-rw-r--r--packages/website/ts/components/definition.tsx139
-rw-r--r--packages/website/ts/components/dialogs/blockchain_err_dialog.tsx166
-rw-r--r--packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx194
-rw-r--r--packages/website/ts/components/dialogs/ledger_config_dialog.tsx307
-rw-r--r--packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx36
-rw-r--r--packages/website/ts/components/dialogs/send_dialog.tsx137
-rw-r--r--packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx93
-rw-r--r--packages/website/ts/components/documentation/docs_logo.tsx37
-rw-r--r--packages/website/ts/components/documentation/docs_top_bar.tsx108
-rw-r--r--packages/website/ts/components/documentation/overview_content.tsx134
-rw-r--r--packages/website/ts/components/documentation/sidebar_header.tsx60
-rw-r--r--packages/website/ts/components/documentation/tutorial_button.tsx59
-rw-r--r--packages/website/ts/components/documentation/version_drop_down.tsx80
-rw-r--r--packages/website/ts/components/dropdowns/developers_drop_down.tsx162
-rw-r--r--packages/website/ts/components/dropdowns/dropdown_developers.tsx184
-rw-r--r--packages/website/ts/components/dropdowns/dropdown_products.tsx48
-rw-r--r--packages/website/ts/components/dropdowns/network_drop_down.tsx40
-rw-r--r--packages/website/ts/components/eth_weth_conversion_button.tsx128
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx448
-rw-r--r--packages/website/ts/components/fill_order.tsx661
-rw-r--r--packages/website/ts/components/fill_order_json.tsx73
-rw-r--r--packages/website/ts/components/fill_warning_dialog.tsx46
-rw-r--r--packages/website/ts/components/flash_messages/asset_send_completed.tsx34
-rw-r--r--packages/website/ts/components/flash_messages/transaction_submitted.tsx26
-rw-r--r--packages/website/ts/components/footer.tsx168
-rw-r--r--packages/website/ts/components/generate_order/asset_picker.tsx284
-rw-r--r--packages/website/ts/components/generate_order/generate_order_form.tsx385
-rw-r--r--packages/website/ts/components/generate_order/new_token_form.tsx229
-rw-r--r--packages/website/ts/components/hamburger.tsx68
-rw-r--r--packages/website/ts/components/header.tsx249
-rw-r--r--packages/website/ts/components/hero.tsx143
-rw-r--r--packages/website/ts/components/heroAnimation.tsx123
-rw-r--r--packages/website/ts/components/heroImage.tsx27
-rw-r--r--packages/website/ts/components/icon.tsx66
-rw-r--r--packages/website/ts/components/image.tsx17
-rw-r--r--packages/website/ts/components/inputs/address_input.tsx71
-rw-r--r--packages/website/ts/components/inputs/allowance_state_toggle.tsx160
-rw-r--r--packages/website/ts/components/inputs/balance_bounded_input.tsx139
-rw-r--r--packages/website/ts/components/inputs/eth_amount_input.tsx65
-rw-r--r--packages/website/ts/components/inputs/expiration_input.tsx100
-rw-r--r--packages/website/ts/components/inputs/hash_input.tsx68
-rw-r--r--packages/website/ts/components/inputs/identicon_address_input.tsx52
-rw-r--r--packages/website/ts/components/inputs/token_amount_input.tsx152
-rw-r--r--packages/website/ts/components/inputs/token_input.tsx103
-rw-r--r--packages/website/ts/components/link.tsx61
-rw-r--r--packages/website/ts/components/logo.tsx38
-rw-r--r--packages/website/ts/components/meta_tags.tsx25
-rw-r--r--packages/website/ts/components/mobileNav.tsx112
-rw-r--r--packages/website/ts/components/modals/input.tsx92
-rw-r--r--packages/website/ts/components/modals/modal_contact.tsx390
-rw-r--r--packages/website/ts/components/nested_sidebar_menu.tsx101
-rw-r--r--packages/website/ts/components/newLayout.tsx134
-rw-r--r--packages/website/ts/components/newsletter_form.tsx191
-rw-r--r--packages/website/ts/components/old_footer.tsx228
-rw-r--r--packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx40
-rw-r--r--packages/website/ts/components/onboarding/congrats_onboarding_step.tsx15
-rw-r--r--packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx42
-rw-r--r--packages/website/ts/components/onboarding/intro_onboarding_step.tsx30
-rw-r--r--packages/website/ts/components/onboarding/onboarding_card.tsx115
-rw-r--r--packages/website/ts/components/onboarding/onboarding_flow.tsx182
-rw-r--r--packages/website/ts/components/onboarding/onboarding_tooltip.tsx30
-rw-r--r--packages/website/ts/components/onboarding/portal_onboarding_flow.tsx281
-rw-r--r--packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx30
-rw-r--r--packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx8
-rw-r--r--packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx88
-rw-r--r--packages/website/ts/components/order_json.tsx179
-rw-r--r--packages/website/ts/components/portal/back_button.tsx40
-rw-r--r--packages/website/ts/components/portal/drawer_menu.tsx77
-rw-r--r--packages/website/ts/components/portal/loading.tsx21
-rw-r--r--packages/website/ts/components/portal/menu.tsx120
-rw-r--r--packages/website/ts/components/portal/portal.tsx749
-rw-r--r--packages/website/ts/components/portal/section.tsx14
-rw-r--r--packages/website/ts/components/portal/text_header.tsx16
-rw-r--r--packages/website/ts/components/relayer_index/relayer_grid_tile.tsx148
-rw-r--r--packages/website/ts/components/relayer_index/relayer_index.tsx126
-rw-r--r--packages/website/ts/components/relayer_index/relayer_top_tokens.tsx61
-rw-r--r--packages/website/ts/components/sections/landing/about.tsx81
-rw-r--r--packages/website/ts/components/sections/landing/clients.tsx110
-rw-r--r--packages/website/ts/components/sections/landing/cta.tsx29
-rw-r--r--packages/website/ts/components/sections/landing/hero.tsx31
-rw-r--r--packages/website/ts/components/send_button.tsx94
-rw-r--r--packages/website/ts/components/siteWrap.tsx146
-rw-r--r--packages/website/ts/components/slider/slider.tsx177
-rw-r--r--packages/website/ts/components/text.tsx77
-rw-r--r--packages/website/ts/components/token_balances.tsx658
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx154
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx279
-rw-r--r--packages/website/ts/components/top_bar/top_bar_menu_item.tsx47
-rw-r--r--packages/website/ts/components/track_token_confirmation.tsx61
-rw-r--r--packages/website/ts/components/trade_history/trade_history.tsx132
-rw-r--r--packages/website/ts/components/trade_history/trade_history_item.tsx176
-rw-r--r--packages/website/ts/components/ui/account_connection.tsx40
-rw-r--r--packages/website/ts/components/ui/alert.tsx25
-rw-r--r--packages/website/ts/components/ui/allowance_state_view.tsx51
-rw-r--r--packages/website/ts/components/ui/balance.tsx27
-rw-r--r--packages/website/ts/components/ui/button.tsx105
-rw-r--r--packages/website/ts/components/ui/check_mark.tsx31
-rw-r--r--packages/website/ts/components/ui/circle.tsx16
-rw-r--r--packages/website/ts/components/ui/container.tsx100
-rw-r--r--packages/website/ts/components/ui/copy_icon.tsx78
-rw-r--r--packages/website/ts/components/ui/custom_menu_item.tsx50
-rw-r--r--packages/website/ts/components/ui/drop_down.tsx139
-rw-r--r--packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx31
-rw-r--r--packages/website/ts/components/ui/ethereum_address.tsx30
-rw-r--r--packages/website/ts/components/ui/etherscan_icon.tsx39
-rw-r--r--packages/website/ts/components/ui/fake_text_field.tsx34
-rw-r--r--packages/website/ts/components/ui/flash_message.tsx40
-rw-r--r--packages/website/ts/components/ui/help_tooltip.tsx22
-rw-r--r--packages/website/ts/components/ui/icon_button.tsx64
-rw-r--r--packages/website/ts/components/ui/identicon.tsx48
-rw-r--r--packages/website/ts/components/ui/image.tsx49
-rw-r--r--packages/website/ts/components/ui/input_label.tsx25
-rw-r--r--packages/website/ts/components/ui/island.tsx29
-rw-r--r--packages/website/ts/components/ui/lifecycle_raised_button.tsx102
-rw-r--r--packages/website/ts/components/ui/multi_select.tsx66
-rw-r--r--packages/website/ts/components/ui/overlay.tsx32
-rw-r--r--packages/website/ts/components/ui/party.tsx141
-rw-r--r--packages/website/ts/components/ui/pointer.tsx72
-rw-r--r--packages/website/ts/components/ui/required_label.tsx15
-rw-r--r--packages/website/ts/components/ui/retry.tsx32
-rw-r--r--packages/website/ts/components/ui/simple_menu.tsx88
-rw-r--r--packages/website/ts/components/ui/spinner.tsx54
-rw-r--r--packages/website/ts/components/ui/swap_icon.tsx41
-rw-r--r--packages/website/ts/components/ui/text.tsx79
-rw-r--r--packages/website/ts/components/ui/token_icon.tsx34
-rw-r--r--packages/website/ts/components/visual_order.tsx73
-rw-r--r--packages/website/ts/components/wallet/body_overlay.tsx136
-rw-r--r--packages/website/ts/components/wallet/null_token_row.tsx41
-rw-r--r--packages/website/ts/components/wallet/placeholder.tsx25
-rw-r--r--packages/website/ts/components/wallet/standard_icon_row.tsx44
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx527
-rw-r--r--packages/website/ts/components/wallet/wrap_ether_item.tsx230
139 files changed, 0 insertions, 15583 deletions
diff --git a/packages/website/ts/components/aboutPageLayout.tsx b/packages/website/ts/components/aboutPageLayout.tsx
deleted file mode 100644
index 51c1a661e..000000000
--- a/packages/website/ts/components/aboutPageLayout.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { Button } from 'ts/components/button';
-import { ChapterLink } from 'ts/components/chapter_link';
-import { Column, Section } from 'ts/components/newLayout';
-import { SiteWrap } from 'ts/components/siteWrap';
-import { Heading, Paragraph } from 'ts/components/text';
-
-import { addFadeInAnimation } from 'ts/constants/animations';
-import { WebsitePaths } from 'ts/types';
-
-interface Props {
- title: string;
- description: React.ReactNode | string;
- linkLabel?: string;
- href?: string;
- to?: string;
- children?: React.ReactNode;
-}
-
-export const AboutPageLayout = (props: Props) => (
- <SiteWrap theme="light">
- <Section isFlex={true} maxWidth="1170px" wrapWidth="100%">
- <Column>
- <ChapterLink to={WebsitePaths.AboutMission}>Mission</ChapterLink>
- <ChapterLink to={WebsitePaths.AboutTeam}>Team</ChapterLink>
- <ChapterLink to={WebsitePaths.AboutPress}>Press</ChapterLink>
- <ChapterLink to={WebsitePaths.AboutJobs}>Jobs</ChapterLink>
- </Column>
-
- <Column width="70%" maxWidth="800px">
- <Column width="100%" maxWidth="680px">
- <AnimatedHeading size="medium">{props.title}</AnimatedHeading>
-
- <AnimatedParagraph size="medium" marginBottom="60px" isMuted={0.65}>
- {props.description}
- </AnimatedParagraph>
-
- {props.linkLabel && (props.href || props.to) && (
- <AnimatedLink
- to={props.to}
- href={props.href}
- target={!_.isUndefined(props.href) ? '_blank' : undefined}
- isWithArrow={true}
- isAccentColor={true}
- >
- {props.linkLabel}
- </AnimatedLink>
- )}
- </Column>
- </Column>
- </Section>
-
- {props.children}
- </SiteWrap>
-);
-
-const AnimatedHeading = styled(Heading)`
- ${addFadeInAnimation('0.5s')};
-`;
-
-const AnimatedParagraph = styled(Paragraph)`
- ${addFadeInAnimation('0.5s', '0.15s')};
-`;
-
-const AnimatedLink = styled(Button)`
- ${addFadeInAnimation('0.6s', '0.3s')};
-`;
diff --git a/packages/website/ts/components/animatedChatIcon.tsx b/packages/website/ts/components/animatedChatIcon.tsx
deleted file mode 100644
index 770536259..000000000
--- a/packages/website/ts/components/animatedChatIcon.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import * as React from 'react';
-import styled, { keyframes } from 'styled-components';
-
-export const AnimatedChatIcon = () => (
- <svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
- <mask id="mask30" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="150" height="150">
- <circle cx="75" cy="75" r="73" fill="#00AE99" stroke="#00AE99" stroke-width="3" />
- </mask>
-
- <g mask="url(#mask30)">
- <circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3" />
-
- <Rays>
- <path vector-effect="non-scaling-stroke" d="M76 37H137.5" stroke="#00AE99" stroke-width="3" />
- <path
- vector-effect="non-scaling-stroke"
- d="M37 73.5L37 12M113 137.5L113 75"
- stroke="#00AE99"
- stroke-width="3"
- />
- <path vector-effect="non-scaling-stroke" d="M13 113H71.5" stroke="#00AE99" stroke-width="3" />
- <path
- vector-effect="non-scaling-stroke"
- d="M49.087 47.5264L92.574 4.03932"
- stroke="#00AE99"
- stroke-width="3"
- />
- <path
- vector-effect="non-scaling-stroke"
- d="M47.3192 100.913L3.8321 57.4259M146.314 92.4277L102.12 48.2335"
- stroke="#00AE99"
- stroke-width="3"
- />
- <path
- vector-effect="non-scaling-stroke"
- d="M58.2793 145.814L101.766 102.327"
- stroke="#00AE99"
- stroke-width="3"
- />
- </Rays>
-
- <Bubble>
- <path
- vector-effect="non-scaling-stroke"
- d="M113 75C113 85.3064 108.897 94.6546 102.235 101.5C98.4048 105.436 71 132.5 71 132.5V112.792C51.8933 110.793 37 94.6359 37 75C37 54.0132 54.0132 37 75 37C95.9868 37 113 54.0132 113 75Z"
- stroke="#00AE99"
- strokeWidth="3"
- />
- </Bubble>
-
- <Dot delay={0} vector-effect="non-scaling-stroke" cx="75" cy="75" r="4" stroke="#00AE99" strokeWidth="3" />
- <Dot
- delay={4.4}
- vector-effect="non-scaling-stroke"
- cx="91"
- cy="75"
- r="4"
- stroke="#00AE99"
- strokeWidth="3"
- />
- <Dot
- delay={-4.6}
- vector-effect="non-scaling-stroke"
- cx="59"
- cy="75"
- r="4"
- stroke="#00AE99"
- strokeWidth="3"
- />
- </g>
- </svg>
-);
-
-const scale = keyframes`
- 0% { transform: scale(1.2) }
- 15% { transform: scale(1) }
- 85% { transform: scale(1) }
- 100% { transform: scale(1.2) }
-`;
-
-const fadeInOut = keyframes`
- 0%, 30%, 50%, 100% {
- transform: initial;
- }
-
- 40% {
- transform: translateY(-5px);
- }
-`;
-
-const Bubble = styled.g`
- animation: ${scale} 4s infinite cubic-bezier(0.175, 0.885, 0.32, 1.275);
- transform-origin: 50% 50%;
-`;
-
-const Rays = styled.g`
- animation: ${scale} 4s infinite cubic-bezier(0.175, 0.885, 0.32, 1.275);
- transform-origin: 50% 50%;
-`;
-
-const Dot = styled.circle<{ delay: number }>`
- animation: ${fadeInOut} 4s ${props => `${props.delay}s`} infinite;
-`;
diff --git a/packages/website/ts/components/animatedCompassIcon.tsx b/packages/website/ts/components/animatedCompassIcon.tsx
deleted file mode 100644
index 5388f95ca..000000000
--- a/packages/website/ts/components/animatedCompassIcon.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import * as React from 'react';
-import styled, { keyframes } from 'styled-components';
-
-export const AnimatedCompassIcon = () => (
- <svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
- <g>
- <circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3" />
- <circle cx="75" cy="75" r="58" stroke="#00AE99" stroke-width="3" />
- <Needle
- d="M62.9792 62.9792L36.6447 113.355L87.0208 87.0208M62.9792 62.9792L113.355 36.6447L87.0208 87.0208M62.9792 62.9792L87.0208 87.0208"
- stroke="#00AE99"
- strokeWidth="3"
- />
-
- <Dial>
- <path d="M75 2V17M75 133V148" stroke="#00AE99" stroke-width="3" />
- <path d="M2 75L17 75M133 75L148 75" stroke="#00AE99" stroke-width="3" />
- <path d="M11.7801 38.5L24.7705 46M125.229 104L138.22 111.5" stroke="#00AE99" stroke-width="3" />
- <path d="M38.5001 11.7801L46.0001 24.7705M104 125.229L111.5 138.22" stroke="#00AE99" stroke-width="3" />
- <path d="M111.5 11.7801L104 24.7705M46 125.229L38.5 138.22" stroke="#00AE99" stroke-width="3" />
- <path d="M138.22 38.5L125.229 46M24.7705 104L11.7801 111.5" stroke="#00AE99" stroke-width="3" />
- </Dial>
- </g>
- </svg>
-);
-
-const point = keyframes`
- 0% { transform: rotate(0deg) }
- 20% { transform: rotate(10deg) }
- 30% { transform: rotate(30deg) }
- 60% { transform: rotate(-20deg) }
- 80% { transform: rotate(-20deg) }
- 100% { transform: rotate(0deg) }
-`;
-
-const rotate = keyframes`
- 0% { transform: rotate(0deg) }
- 20% { transform: rotate(-10deg) }
- 30% { transform: rotate(-30deg) }
- 60% { transform: rotate(20deg) }
- 80% { transform: rotate(20deg) }
- 100% { transform: rotate(0deg) }
-`;
-
-const Needle = styled.path`
- animation: ${point} 5s infinite;
- transform-origin: 50% 50%;
-`;
-
-const Dial = styled.g`
- animation: ${rotate} 5s infinite;
- transform-origin: 50% 50%;
-`;
diff --git a/packages/website/ts/components/banner.tsx b/packages/website/ts/components/banner.tsx
deleted file mode 100644
index ce3fd499a..000000000
--- a/packages/website/ts/components/banner.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { colors } from 'ts/style/colors';
-
-import { Button } from 'ts/components/button';
-import { ThemeInterface } from 'ts/components/siteWrap';
-import { Paragraph } from 'ts/components/text';
-
-import { Column, Section } from 'ts/components/newLayout';
-
-interface Props {
- heading?: string;
- subline?: string;
- mainCta?: CTAButton;
- secondaryCta?: CTAButton;
- theme?: ThemeInterface;
-}
-
-interface CTAButton {
- text: string;
- href?: string;
- onClick?: () => void;
- shouldOpenInNewTab?: boolean;
-}
-
-interface BorderProps {
- isBottom?: boolean;
-}
-
-export const Banner: React.StatelessComponent<Props> = (props: Props) => {
- const { heading, subline, mainCta, secondaryCta } = props;
- return (
- <CustomSection bgColor={colors.brandDark} isFlex={true} flexBreakpoint="900px" paddingMobile="120px 0">
- <Border />
- <Border isBottom={true} />
-
- <Column>
- <CustomHeading>{heading}</CustomHeading>
-
- {subline && (
- <Paragraph color={colors.white} isMuted={0.5} isNoMargin={true}>
- {subline}
- </Paragraph>
- )}
- </Column>
- <Column>
- <ButtonWrap>
- {mainCta && (
- <Button
- color={colors.white}
- isTransparent={false}
- href={mainCta.href}
- target={mainCta.shouldOpenInNewTab ? '_blank' : ''}
- >
- {mainCta.text}
- </Button>
- )}
-
- {secondaryCta && (
- <Button
- color={colors.white}
- href={secondaryCta.href}
- onClick={secondaryCta.onClick}
- isTransparent={true}
- >
- {secondaryCta.text}
- </Button>
- )}
- </ButtonWrap>
- </Column>
- </CustomSection>
- );
-};
-
-const CustomSection = styled(Section)`
- color: ${colors.white};
- margin-top: 30px;
-
- @media (max-width: 900px) {
- text-align: center;
-
- p {
- margin-bottom: 30px;
- }
-
- div:last-child {
- margin-bottom: 0;
- }
- }
-`;
-
-const CustomHeading = styled.h2`
- font-size: 34px;
- font-weight: 400;
- margin-bottom: 10px @media (max-width: 768px) {
- font-size: 30px;
- }
-`;
-
-const ButtonWrap = styled.div`
- display: inline-block;
-
- @media (min-width: 768px) {
- * + * {
- margin-left: 15px;
- }
- }
-
- @media (max-width: 768px) {
- a,
- button {
- display: block;
- width: 220px;
- }
-
- * + * {
- margin-top: 15px;
- }
- }
-`;
-
-// Note let's refactor this
-// is it absolutely necessary to have a stateless component
-// to pass props down into the styled icon?
-const Border = styled.div<BorderProps>`
- position: absolute;
- background-image: ${props =>
- props.isBottom ? 'url(/images/banner/bottomofcta.png);' : 'url(/images/banner/topofcta.png);'};
- background-position: ${props => (props.isBottom ? 'left top' : 'left bottom')};
- left: 0;
- width: calc(100% + 214px);
- height: 40px;
- top: ${props => !props.isBottom && 0};
- bottom: ${props => props.isBottom && 0};
- transform: translate(-112px);
-
- @media (max-width: 768px) {
- width: calc(100% + 82px);
- height: 40px;
- transform: translate(-41px);
- background-size: auto 80px;
- }
-`;
diff --git a/packages/website/ts/components/blockIconLink.tsx b/packages/website/ts/components/blockIconLink.tsx
deleted file mode 100644
index ff7712595..000000000
--- a/packages/website/ts/components/blockIconLink.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { History, Location } from 'history';
-import * as React from 'react';
-import { match, withRouter } from 'react-router-dom';
-import styled from 'styled-components';
-
-import { Button } from 'ts/components/button';
-import { Icon } from 'ts/components/icon';
-
-interface BaseComponentProps {
- icon?: string;
- iconComponent?: React.ReactNode;
- title: string;
- linkLabel: string;
- linkUrl?: string;
- linkAction?: () => void;
- history: History;
- location: Location;
- match: match<any>;
-}
-
-class BaseComponent extends React.PureComponent<BaseComponentProps> {
- public onClick = (): void => {
- const { linkAction, linkUrl } = this.props;
-
- if (linkAction) {
- linkAction();
- } else {
- this.props.history.push(linkUrl);
- }
- };
-
- public render(): React.ReactNode {
- const { icon, iconComponent, linkUrl, linkAction, title, linkLabel } = this.props;
-
- return (
- <Wrap onClick={this.onClick}>
- <div>
- <Icon name={icon} component={iconComponent} size="large" margin={[0, 0, 'default', 0]} />
-
- <Title>{title}</Title>
-
- <Button isWithArrow={true} isTransparent={true} href={linkUrl} onClick={linkAction}>
- {linkLabel}
- </Button>
- </div>
- </Wrap>
- );
- }
-}
-
-export const BlockIconLink = withRouter<BaseComponentProps>(BaseComponent);
-
-const Wrap = styled.div`
- width: calc(50% - 15px);
- height: 400px;
- padding: 40px;
- display: flex;
- justify-content: center;
- align-items: center;
- text-align: center;
- transition: background-color 0.25s;
- background-color: ${props => props.theme.lightBgColor};
- cursor: pointer;
-
- a,
- button {
- pointer-events: none;
- }
-
- @media (max-width: 900px) {
- width: 100%;
- margin-top: 30px;
- }
-
- &:hover {
- background-color: #002d28;
- }
-`;
-
-const Title = styled.h2`
- font-size: 20px;
- margin-bottom: 30px;
- color: ${props => props.theme.linkColor};
-`;
diff --git a/packages/website/ts/components/button.tsx b/packages/website/ts/components/button.tsx
deleted file mode 100644
index 31a74e599..000000000
--- a/packages/website/ts/components/button.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import * as React from 'react';
-import { Link as ReactRouterLink } from 'react-router-dom';
-import styled from 'styled-components';
-
-import { ThemeInterface } from 'ts/components/siteWrap';
-
-import { colors } from 'ts/style/colors';
-
-interface ButtonInterface {
- bgColor?: string;
- borderColor?: string;
- color?: string;
- children?: React.ReactNode | string;
- isTransparent?: boolean;
- isNoBorder?: boolean;
- isNoPadding?: boolean;
- isWithArrow?: boolean;
- isAccentColor?: boolean;
- hasIcon?: boolean | string;
- isInline?: boolean;
- href?: string;
- type?: string;
- target?: string;
- to?: string;
- onClick?: () => any;
- theme?: ThemeInterface;
- shouldUseAnchorTag?: boolean;
-}
-
-export const Button: React.StatelessComponent<ButtonInterface> = (props: ButtonInterface) => {
- const { children, href, isWithArrow, to, shouldUseAnchorTag, target } = props;
- let linkElem;
-
- if (href || shouldUseAnchorTag) {
- linkElem = 'a';
- }
- if (to) {
- linkElem = ReactRouterLink;
- }
-
- const Component = linkElem ? ButtonBase.withComponent<any>(linkElem) : ButtonBase;
- const targetProp = href && target ? { target } : {};
-
- return (
- <Component {...props} {...targetProp}>
- {children}
-
- {isWithArrow && (
- <svg width="16" height="15" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path d="M4.484.246l.024 1.411 8.146.053L.817 13.547l.996.996L13.65 2.706l.052 8.146 1.412.024L15.045.315 4.484.246z" />
- </svg>
- )}
- </Component>
- );
-};
-
-Button.defaultProps = {
- borderColor: 'rgba(255, 255, 255, .4)',
-};
-
-const ButtonBase = styled.button<ButtonInterface>`
- appearance: none;
- border: 1px solid transparent;
- display: inline-block;
- background-color: ${props => props.bgColor || colors.brandLight};
- background-color: ${props => (props.isTransparent || props.isWithArrow) && 'transparent'};
- border-color: ${props => props.isTransparent && !props.isWithArrow && props.borderColor};
- color: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)};
- padding: ${props => !props.isNoPadding && !props.isWithArrow && '18px 30px'};
- white-space: ${props => props.isWithArrow && 'nowrap'};
- text-align: center;
- font-size: ${props => (props.isWithArrow ? '20px' : '18px')};
- text-decoration: none;
- cursor: pointer;
- outline: none;
- transition: background-color 0.35s, border-color 0.35s;
-
- // @todo Refactor to use theme props
- ${props =>
- props.bgColor === 'dark' &&
- `
- background-color: ${colors.brandDark};
- color: ${colors.white};
- `}
-
- svg {
- margin-left: 9px;
- transition: transform 0.5s;
- transform: translate3d(-2px, 2px, 0);
- }
-
- path {
- fill: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)};
- }
-
- &:hover {
- background-color: ${props => !props.isTransparent && !props.isWithArrow && '#04BEA8'};
- border-color: ${props => props.isTransparent && !props.isNoBorder && !props.isWithArrow && '#00AE99'};
-
- svg {
- transform: translate3d(2px, -2px, 0);
- }
- }
-`;
diff --git a/packages/website/ts/components/chapter_link.tsx b/packages/website/ts/components/chapter_link.tsx
deleted file mode 100644
index fd974cec1..000000000
--- a/packages/website/ts/components/chapter_link.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { NavLink as ReactRouterLink } from 'react-router-dom';
-import styled from 'styled-components';
-
-export const ChapterLink = styled(ReactRouterLink).attrs({
- activeStyle: { opacity: 1 },
-})`
- font-size: 1.222222222rem;
- display: block;
- opacity: 0.5;
- margin-bottom: 1.666666667rem;
-
- &:hover {
- opacity: 1;
- }
-`;
diff --git a/packages/website/ts/components/definition.tsx b/packages/website/ts/components/definition.tsx
deleted file mode 100644
index bd7a40425..000000000
--- a/packages/website/ts/components/definition.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { Button } from 'ts/components/button';
-import { Icon } from 'ts/components/icon';
-import { Heading, Paragraph } from 'ts/components/text';
-
-export interface Action {
- label: string;
- url?: string;
- onClick?: () => void;
- shouldUseAnchorTag?: boolean;
-}
-
-interface Props {
- isInline?: boolean;
- isInlineIcon?: boolean;
- isCentered?: boolean;
- isWithMargin?: boolean;
- icon: string;
- iconSize?: 'medium' | 'large' | number;
- fontSize?: 'default' | 'medium' | number;
- title: string;
- titleSize?: 'small' | 'default' | number;
- description: React.ReactNode | string;
- actions?: Action[];
-}
-
-export const Definition = (props: Props) => (
- <Wrap {...props}>
- <Icon name={props.icon} size={props.iconSize || 'medium'} margin={[0, 0, 'default', 0]} />
-
- <TextWrap {...props}>
- <Heading
- asElement="h2"
- fontWeight="400"
- marginBottom={props.titleSize === 'small' ? '7px' : '15px'}
- size={props.titleSize || 'default'}
- >
- {props.title}
- </Heading>
-
- {typeof props.description === 'string' ? (
- <Paragraph isMuted={true} size={props.fontSize || 'default'}>
- {props.description}
- </Paragraph>
- ) : (
- <>{props.description}</>
- )}
-
- {props.actions && (
- <LinkWrap>
- {props.actions.map((item, index) => (
- <Button
- key={`dlink-${index}`}
- href={item.url}
- onClick={item.onClick}
- isWithArrow={true}
- isAccentColor={true}
- shouldUseAnchorTag={item.shouldUseAnchorTag}
- target="_blank"
- >
- {item.label}
- </Button>
- ))}
- </LinkWrap>
- )}
- </TextWrap>
- </Wrap>
-);
-
-const Wrap = styled.div<Props>`
- max-width: ${props => props.isInline && '354px'};
-
- & + & {
- margin-top: ${props => props.isInlineIcon && '120px'};
- margin-top: ${props => props.isWithMargin && '60px'};
- }
-
- @media (min-width: 768px) {
- width: ${props => (props.isInline ? 'calc(33.3333% - 30px)' : '100%')};
- display: ${props => props.isInlineIcon && 'flex'};
- justify-content: ${props => props.isInlineIcon && 'space-between'};
- align-items: ${props => props.isInlineIcon && 'center'};
- text-align: ${props => (props.isInlineIcon || !props.isCentered) && 'left'};
- }
-
- @media (max-width: 768px) {
- margin: 0 auto;
-
- & + & {
- margin-top: ${props => props.isInline && '60px'};
- }
- }
-`;
-
-const TextWrap = styled.div<Props>`
- width: 100%;
- max-width: 560px;
-
- ul {
- padding-top: 10px;
- padding-left: 1rem;
- }
-
- li {
- color: ${props => props.theme.paragraphColor};
- font-size: ${props => `var(--${props.fontSize || 'default'}Paragraph)`};
- font-weight: 300;
- list-style: disc;
- opacity: 0.75;
- line-height: 1.444444444;
- margin-bottom: 1rem;
- }
-
- @media (min-width: 768px) {
- margin-left: ${props => props.isInlineIcon && '60px'};
- }
-`;
-
-const LinkWrap = styled.div`
- margin-top: 60px;
-
- @media (min-width: 768px) {
- display: inline-flex;
-
- a + a {
- margin-left: 60px;
- }
- }
-
- @media (max-width: 768px) {
- max-width: 250px;
-
- a + a {
- margin-top: 15px;
- }
- }
-`;
diff --git a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx b/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx
deleted file mode 100644
index 1c47903db..000000000
--- a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-import { colors, Networks } from '@0x/react-shared';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { BlockchainErrs } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-interface BlockchainErrDialogProps {
- blockchain: Blockchain;
- blockchainErr: BlockchainErrs;
- isOpen: boolean;
- userAddress: string;
- toggleDialogFn: (isOpen: boolean) => void;
- networkId: number;
-}
-
-export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProps, undefined> {
- public render(): React.ReactNode {
- const dialogActions = [
- <FlatButton
- key="blockchainErrOk"
- label="Ok"
- primary={true}
- onClick={this.props.toggleDialogFn.bind(this.props.toggleDialogFn, false)}
- />,
- ];
-
- const hasWalletAddress = this.props.userAddress !== '';
- return (
- <Dialog
- title={this._getTitle(hasWalletAddress)}
- titleStyle={{ fontWeight: 100 }}
- actions={dialogActions}
- open={this.props.isOpen}
- contentStyle={{ width: 400 }}
- onRequestClose={this.props.toggleDialogFn.bind(this.props.toggleDialogFn, false)}
- autoScrollBodyContent={true}
- >
- <div className="pt2" style={{ color: colors.grey700 }}>
- {this._renderExplanation(hasWalletAddress)}
- </div>
- </Dialog>
- );
- }
- private _getTitle(hasWalletAddress: boolean): string {
- if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
- return '0x smart contracts not found';
- } else if (!hasWalletAddress) {
- return 'Enable wallet communication';
- } else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) {
- return 'Disconnected from Ethereum network';
- } else if (this.props.blockchainErr === BlockchainErrs.DefaultTokensNotInTokenRegistry) {
- return 'Default TokenRegistry tokens missing';
- } else {
- return 'Unexpected error';
- }
- }
- private _renderExplanation(hasWalletAddress: boolean): React.ReactNode {
- if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
- return this._renderContractsNotDeployedExplanation();
- } else if (!hasWalletAddress) {
- return this._renderNoWalletFoundExplanation();
- } else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) {
- return this._renderDisconnectedFromNode();
- } else if (this.props.blockchainErr === BlockchainErrs.DefaultTokensNotInTokenRegistry) {
- return this._renderDefaultTokenNotInTokenRegistry();
- } else {
- return this._renderUnexpectedErrorExplanation();
- }
- }
- private _renderDisconnectedFromNode(): React.ReactNode {
- return (
- <div>
- You were disconnected from the backing Ethereum node. If using{' '}
- <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank">
- Metamask
- </a>{' '}
- or{' '}
- <a href={constants.URL_MIST_DOWNLOAD} target="_blank">
- Mist
- </a>{' '}
- try refreshing the page. If using a locally hosted Ethereum node, make sure it's still running.
- </div>
- );
- }
- private _renderDefaultTokenNotInTokenRegistry(): React.ReactNode {
- return (
- <div>
- The TokenRegistry deployed on your network does not contain the needed default tokens for 0x Portal to
- operate. Please try one of the supported networks (Mainnet, Kovan, Ropsten, Rinkeby). If on a local
- Testnet, make sure the TokenRegistry contract is deployed and loaded with some default tokens (i.e WETH
- & ZRX).
- </div>
- );
- }
- private _renderUnexpectedErrorExplanation(): React.ReactNode {
- return <div>We encountered an unexpected error. Please try refreshing the page.</div>;
- }
- private _renderNoWalletFoundExplanation(): React.ReactNode {
- return (
- <div>
- <div>
- We were unable to access an Ethereum wallet you control. In order to interact with the 0x portal
- dApp, we need a way to interact with one of your Ethereum wallets. There are two easy ways you can
- enable us to do that:
- </div>
- <h4>1. Metamask chrome extension</h4>
- <div>
- You can install the{' '}
- <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank">
- Metamask
- </a>{' '}
- Chrome extension Ethereum wallet. Once installed and set up, refresh this page.
- <div className="pt1">
- <span className="bold">Note:</span> If you already have Metamask installed, make sure it is
- unlocked.
- </div>
- </div>
- <h4>Parity Signer</h4>
- <div>
- The{' '}
- <a href={constants.URL_PARITY_CHROME_STORE} target="_blank">
- Parity Signer Chrome extension
- </a>{' '}
- lets you connect to a locally running Parity node. Make sure you have started your local Parity node
- with `parity ui` or `parity --chain kovan ui` in order to connect to mainnet or Kovan respectively.
- </div>
- <div className="pt2">
- <span className="bold">Note:</span> If you have done one of the above steps and are still seeing
- this message, we might still be unable to retrieve an Ethereum address by calling
- `web3.eth.accounts`. Make sure you have created at least one Ethereum address.
- </div>
- </div>
- );
- }
- private _renderContractsNotDeployedExplanation(): React.ReactNode {
- return (
- <div>
- <div>
- The 0x smart contracts are not deployed on the Ethereum network you are currently connected to
- (network Id: {this.props.networkId}). In order to use the 0x portal dApp, please connect to the{' '}
- {Networks.Kovan} testnet (network Id: {constants.NETWORK_ID_KOVAN}) or ${constants.MAINNET_NAME}{' '}
- (network Id: ${constants.NETWORK_ID_MAINNET}).
- </div>
- <h4>Metamask</h4>
- <div>
- If you are using{' '}
- <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank">
- Metamask
- </a>
- , you can switch networks in the top left corner of the extension popover.
- </div>
- <h4>Parity Signer</h4>
- <div>
- If using the{' '}
- <a href={constants.URL_PARITY_CHROME_STORE} target="_blank">
- Parity Signer Chrome extension
- </a>
- , make sure to start your local Parity node with `parity ui` or `parity --chain Kovan ui` in order
- to connect to mainnet \ or Kovan respectively.
- </div>
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
deleted file mode 100644
index 5ca272b1a..000000000
--- a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input';
-import { Side, Token } from 'ts/types';
-
-interface EthWethConversionDialogProps {
- blockchain: Blockchain;
- userAddress: string;
- networkId: number;
- direction: Side;
- onComplete: (direction: Side, value: BigNumber) => void;
- onCancelled: () => void;
- isOpen: boolean;
- token: Token;
- etherBalanceInWei?: BigNumber;
- lastForceTokenStateRefetch: number;
-}
-
-interface EthWethConversionDialogState {
- value?: BigNumber;
- shouldShowIncompleteErrs: boolean;
- hasErrors: boolean;
- isEthTokenBalanceLoaded: boolean;
- ethTokenBalance: BigNumber;
-}
-
-export class EthWethConversionDialog extends React.Component<
- EthWethConversionDialogProps,
- EthWethConversionDialogState
-> {
- private _isUnmounted: boolean;
- constructor(props: EthWethConversionDialogProps) {
- super(props);
- this._isUnmounted = false;
- this.state = {
- shouldShowIncompleteErrs: false,
- hasErrors: false,
- isEthTokenBalanceLoaded: false,
- ethTokenBalance: new BigNumber(0),
- };
- }
- public componentWillMount(): void {
- // tslint:disable-next-line:no-floating-promises
- this._fetchEthTokenBalanceAsync();
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public render(): React.ReactNode {
- const convertDialogActions = [
- <FlatButton key="cancel" label="Cancel" onClick={this._onCancel.bind(this)} />,
- <FlatButton key="convert" label="Convert" primary={true} onClick={this._onConvertClick.bind(this)} />,
- ];
- const title = this.props.direction === Side.Deposit ? 'Wrap ETH' : 'Unwrap WETH';
- return !_.isUndefined(this.props.etherBalanceInWei) ? (
- <Dialog
- title={title}
- titleStyle={{ fontWeight: 100 }}
- actions={convertDialogActions}
- contentStyle={{ width: 448 }}
- open={this.props.isOpen}
- >
- {this._renderConversionDialogBody()}
- </Dialog>
- ) : null;
- }
- private _renderConversionDialogBody(): React.ReactNode {
- const explanation =
- this.props.direction === Side.Deposit
- ? 'Convert your Ether into a tokenized, tradable form.'
- : "Convert your Wrapped Ether back into it's native form.";
- const isWrappedVersion = this.props.direction === Side.Receive;
- return (
- <div>
- <div className="pb2">{explanation}</div>
- <div className="mx-auto" style={{ maxWidth: 312 }}>
- <div className="flex">
- {this._renderCurrency(isWrappedVersion)}
- <div style={{ paddingTop: 68 }}>
- <i style={{ fontSize: 28, color: colors.darkBlue }} className="zmdi zmdi-arrow-right" />
- </div>
- {this._renderCurrency(!isWrappedVersion)}
- </div>
- <div className="pt2 mx-auto" style={{ width: 245 }}>
- {this.props.direction === Side.Receive ? (
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- token={this.props.token}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={true}
- shouldCheckAllowance={false}
- onChange={this._onValueChange.bind(this)}
- amount={this.state.value}
- />
- ) : (
- <EthAmountInput
- amount={this.state.value}
- onChange={this._onValueChange.bind(this)}
- shouldCheckBalance={true}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- />
- )}
- <div className="pt1" style={{ fontSize: 12 }}>
- <div className="left">1 ETH = 1 WETH</div>
- {this.props.direction === Side.Receive && this.state.isEthTokenBalanceLoaded && (
- <div
- className="right"
- onClick={this._onMaxClick.bind(this)}
- style={{
- color: colors.darkBlue,
- textDecoration: 'underline',
- cursor: 'pointer',
- }}
- >
- Max
- </div>
- )}
- </div>
- </div>
- </div>
- </div>
- );
- }
- private _renderCurrency(isWrappedVersion: boolean): React.ReactNode {
- const name = isWrappedVersion ? 'Wrapped Ether' : 'Ether';
- const iconUrl = isWrappedVersion ? '/images/token_icons/ether_erc20.png' : '/images/ether.png';
- const symbol = isWrappedVersion ? 'WETH' : 'ETH';
- return (
- <div className="mx-auto pt2">
- <div className="center" style={{ color: colors.darkBlue }}>
- {name}
- </div>
- <div className="center py2">
- <img src={iconUrl} style={{ width: 60 }} />
- </div>
- <div className="center" style={{ fontSize: 12 }}>
- ({symbol})
- </div>
- </div>
- );
- }
- private _onMaxClick(): void {
- this.setState({
- value: this.state.ethTokenBalance,
- });
- }
- private _onValueChange(isValid: boolean, amount?: BigNumber): void {
- this.setState({
- value: amount,
- hasErrors: !isValid,
- });
- }
- private _onConvertClick(): void {
- if (this.state.hasErrors) {
- this.setState({
- shouldShowIncompleteErrs: true,
- });
- } else {
- const value = this.state.value;
- this.setState({
- value: undefined,
- });
- this.props.onComplete(this.props.direction, value);
- }
- }
- private _onCancel(): void {
- this.setState({
- value: undefined,
- });
- this.props.onCancelled();
- }
- private async _fetchEthTokenBalanceAsync(): Promise<void> {
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const [balance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- this.props.token.address,
- );
- if (!this._isUnmounted) {
- this.setState({
- isEthTokenBalanceLoaded: true,
- ethTokenBalance: balance,
- });
- }
- }
-}
diff --git a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
deleted file mode 100644
index 527353aa0..000000000
--- a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx
+++ /dev/null
@@ -1,307 +0,0 @@
-import { colors, constants as sharedConstants } from '@0x/react-shared';
-import { BigNumber, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
-import TextField from 'material-ui/TextField';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-import { Blockchain } from 'ts/blockchain';
-import { NetworkDropDown } from 'ts/components/dropdowns/network_drop_down';
-import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { ProviderType } from 'ts/types';
-import { configs } from 'ts/utils/configs';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-const VALID_ETHEREUM_DERIVATION_PATH_PREFIX = `44'/60'`;
-
-enum LedgerSteps {
- Connect,
- SelectAddress,
-}
-
-interface LedgerConfigDialogProps {
- isOpen: boolean;
- toggleDialogFn: (isOpen: boolean) => void;
- dispatcher: Dispatcher;
- blockchain: Blockchain;
- networkId?: number;
- providerType: ProviderType;
-}
-
-interface LedgerConfigDialogState {
- connectionErrMsg: string;
- stepIndex: LedgerSteps;
- userAddresses: string[];
- addressBalances: BigNumber[];
- derivationPath: string;
- derivationErrMsg: string;
- preferredNetworkId: number;
-}
-
-export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, LedgerConfigDialogState> {
- public static defaultProps = {
- networkId: 1,
- };
- constructor(props: LedgerConfigDialogProps) {
- super(props);
- const derivationPathIfExists = props.blockchain.getLedgerDerivationPathIfExists();
- this.state = {
- connectionErrMsg: '',
- stepIndex: LedgerSteps.Connect,
- userAddresses: [],
- addressBalances: [],
- derivationPath: _.isUndefined(derivationPathIfExists)
- ? configs.DEFAULT_DERIVATION_PATH
- : derivationPathIfExists,
- derivationErrMsg: '',
- preferredNetworkId: props.networkId,
- };
- }
- public render(): React.ReactNode {
- const dialogActions = [
- <FlatButton key="ledgerConnectCancel" label="Cancel" onClick={this._onClose.bind(this)} />,
- ];
- const dialogTitle =
- this.state.stepIndex === LedgerSteps.Connect ? 'Connect to your Ledger' : 'Select desired address';
- return (
- <Dialog
- title={dialogTitle}
- titleStyle={{ fontWeight: 100 }}
- actions={dialogActions}
- open={this.props.isOpen}
- onRequestClose={this._onClose.bind(this)}
- autoScrollBodyContent={true}
- bodyStyle={{ paddingBottom: 0 }}
- >
- <div style={{ color: colors.grey700, paddingTop: 1 }}>
- {this.state.stepIndex === LedgerSteps.Connect && this._renderConnectStep()}
- {this.state.stepIndex === LedgerSteps.SelectAddress && this._renderSelectAddressStep()}
- </div>
- </Dialog>
- );
- }
- private _renderConnectStep(): React.ReactNode {
- const networkIds = _.values(sharedConstants.NETWORK_ID_BY_NAME);
- return (
- <div>
- <div className="h4 pt3">Follow these instructions before proceeding:</div>
- <ol className="mb0">
- <li className="pb1">Connect your Ledger Nano S & Open the Ethereum application</li>
- <li className="pb1">Verify that "Browser Support" AND "Contract Data" are enabled in Settings</li>
- <li className="pb1">
- If no Browser Support is found in settings, verify that you have{' '}
- <a href="https://www.ledgerwallet.com/apps/manager" target="_blank">
- Firmware >1.2
- </a>
- </li>
- <li>Choose your desired network:</li>
- </ol>
- <div className="pb2">
- <NetworkDropDown
- updateSelectedNetwork={this._onSelectedNetworkUpdated.bind(this)}
- selectedNetworkId={this.state.preferredNetworkId}
- avialableNetworkIds={networkIds}
- />
- </div>
- <div className="center pb3">
- <LifeCycleRaisedButton
- isPrimary={true}
- labelReady="Connect to Ledger"
- labelLoading="Connecting..."
- labelComplete="Connected!"
- onClickAsyncFn={this._onConnectLedgerClickAsync.bind(this, true)}
- />
- {!_.isEmpty(this.state.connectionErrMsg) && (
- <div className="pt2 left-align" style={{ color: colors.red200 }}>
- {this.state.connectionErrMsg}
- </div>
- )}
- </div>
- </div>
- );
- }
- private _renderSelectAddressStep(): React.ReactNode {
- return (
- <div>
- <div>
- <Table bodyStyle={{ height: 300 }} onRowSelection={this._onAddressSelected.bind(this)}>
- <TableHeader displaySelectAll={false}>
- <TableRow>
- <TableHeaderColumn colSpan={2}>Address</TableHeaderColumn>
- <TableHeaderColumn>Balance</TableHeaderColumn>
- </TableRow>
- </TableHeader>
- <TableBody>{this._renderAddressTableRows()}</TableBody>
- </Table>
- </div>
- <div className="flex pt2" style={{ height: 100 }}>
- <div className="overflow-hidden" style={{ width: 180 }}>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText="Update path derivation (advanced)"
- value={this.state.derivationPath}
- errorText={this.state.derivationErrMsg}
- onChange={this._onDerivationPathChanged.bind(this)}
- />
- </div>
- <div className="pl2" style={{ paddingTop: 28 }}>
- <LifeCycleRaisedButton
- labelReady="Update"
- labelLoading="Updating..."
- labelComplete="Updated!"
- onClickAsyncFn={this._onFetchAddressesForDerivationPathAsync.bind(this)}
- />
- </div>
- </div>
- </div>
- );
- }
- private _renderAddressTableRows(): React.ReactNode {
- const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => {
- const balanceInWei = this.state.addressBalances[i];
- const addressTooltipId = `address-${userAddress}`;
- const balanceTooltipId = `balance-${userAddress}`;
- const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
- // We specifically prefix kovan ETH.
- // TODO: We should probably add prefixes for all networks
- const isKovanNetwork = networkName === 'Kovan';
- const balanceInEth = Web3Wrapper.toUnitAmount(balanceInWei, constants.DECIMAL_PLACES_ETH);
- const balanceString = `${balanceInEth.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`;
- return (
- <TableRow key={userAddress} style={{ height: 40 }}>
- <TableRowColumn colSpan={2}>
- <div data-tip={true} data-for={addressTooltipId}>
- {userAddress}
- </div>
- <ReactTooltip id={addressTooltipId}>{userAddress}</ReactTooltip>
- </TableRowColumn>
- <TableRowColumn>
- <div data-tip={true} data-for={balanceTooltipId}>
- {balanceString}
- </div>
- <ReactTooltip id={balanceTooltipId}>{balanceString}</ReactTooltip>
- </TableRowColumn>
- </TableRow>
- );
- });
- return rows;
- }
- private _onClose(): void {
- this.setState({
- connectionErrMsg: '',
- stepIndex: LedgerSteps.Connect,
- });
- const isOpen = false;
- this.props.toggleDialogFn(isOpen);
- }
- private _onAddressSelected(selectedRowIndexes: number[]): void {
- const selectedRowIndex = selectedRowIndexes[0];
- const selectedAddress = this.state.userAddresses[selectedRowIndex];
- const selectAddressBalance = this.state.addressBalances[selectedRowIndex];
- this.props.dispatcher.updateUserAddress(selectedAddress);
- this.props.blockchain.updateWeb3WrapperPrevUserAddress(selectedAddress);
- // tslint:disable-next-line:no-floating-promises
- this.props.blockchain.fetchTokenInformationAsync();
- this.props.dispatcher.updateUserWeiBalance(selectAddressBalance);
- this.setState({
- stepIndex: LedgerSteps.Connect,
- });
- const isOpen = false;
- this.props.toggleDialogFn(isOpen);
- }
- private async _onFetchAddressesForDerivationPathAsync(): Promise<boolean> {
- const currentlySetPath = this.props.blockchain.getLedgerDerivationPathIfExists();
- let didSucceed;
- if (currentlySetPath === this.state.derivationPath) {
- didSucceed = true;
- return didSucceed;
- }
- this.props.blockchain.updateLedgerDerivationPathIfExists(this.state.derivationPath);
- didSucceed = await this._fetchAddressesAndBalancesAsync();
- if (!didSucceed) {
- this.setState({
- derivationErrMsg: 'Failed to connect to Ledger.',
- });
- }
- return didSucceed;
- }
- private async _fetchAddressesAndBalancesAsync(): Promise<boolean> {
- let userAddresses: string[];
- const addressBalances: BigNumber[] = [];
- try {
- userAddresses = await this._getUserAddressesAsync();
- for (const address of userAddresses) {
- const balanceInWei = await this.props.blockchain.getBalanceInWeiAsync(address);
- addressBalances.push(balanceInWei);
- }
- } catch (err) {
- logUtils.log(`Ledger error: ${JSON.stringify(err)}`);
- this.setState({
- connectionErrMsg: 'Failed to connect. Follow the instructions and try again.',
- });
- return false;
- }
- this.setState({
- userAddresses,
- addressBalances,
- });
- return true;
- }
- private _onDerivationPathChanged(_event: any, derivationPath: string): void {
- let derivationErrMsg = '';
- if (!_.startsWith(derivationPath, VALID_ETHEREUM_DERIVATION_PATH_PREFIX)) {
- derivationErrMsg = 'Must be valid Ethereum path.';
- }
-
- this.setState({
- derivationPath,
- derivationErrMsg,
- });
- }
- private async _onConnectLedgerClickAsync(): Promise<boolean> {
- const isU2FSupported = await utils.isU2FSupportedAsync();
- if (!isU2FSupported) {
- logUtils.log(`U2F not supported in this browser`);
- this.setState({
- connectionErrMsg: 'U2F not supported by this browser. Try using Chrome.',
- });
- return false;
- }
-
- if (
- this.props.providerType !== ProviderType.Ledger ||
- (this.props.providerType === ProviderType.Ledger && this.props.networkId !== this.state.preferredNetworkId)
- ) {
- await this.props.blockchain.updateProviderToLedgerAsync(this.state.preferredNetworkId);
- }
-
- const didSucceed = await this._fetchAddressesAndBalancesAsync();
- if (didSucceed) {
- this.setState({
- stepIndex: LedgerSteps.SelectAddress,
- connectionErrMsg: '',
- });
- }
- return didSucceed;
- }
- private async _getUserAddressesAsync(): Promise<string[]> {
- let userAddresses: string[];
- userAddresses = await this.props.blockchain.getUserAccountsAsync();
-
- if (_.isEmpty(userAddresses)) {
- throw new Error('No addresses retrieved.');
- }
- return userAddresses;
- }
- private _onSelectedNetworkUpdated(_event: any, _index: number, networkId: number): void {
- this.setState({
- preferredNetworkId: networkId,
- });
- }
-}
diff --git a/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx b/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx
deleted file mode 100644
index 326df2a8c..000000000
--- a/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { colors } from '@0x/react-shared';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-
-interface PortalDisclaimerDialogProps {
- isOpen: boolean;
- onToggleDialog: () => void;
-}
-
-export const PortalDisclaimerDialog = (props: PortalDisclaimerDialogProps) => {
- return (
- <Dialog
- title="0x Portal Disclaimer"
- titleStyle={{ fontWeight: 100 }}
- actions={[<FlatButton key="portalAgree" label="I Agree" onClick={props.onToggleDialog} />]}
- open={props.isOpen}
- onRequestClose={props.onToggleDialog}
- autoScrollBodyContent={true}
- modal={true}
- >
- <div className="pt2" style={{ color: colors.grey700 }}>
- <div>
- 0x Portal is a free software-based tool intended to help users to buy and sell ERC20-compatible
- blockchain tokens through the 0x protocol on a purely peer-to-peer basis. 0x portal is not a
- regulated marketplace, exchange or intermediary of any kind, and therefore, you should only use 0x
- portal to exchange tokens that are not securities, commodity interests, or any other form of
- regulated instrument. 0x has not attempted to screen or otherwise limit the tokens that you may
- enter in 0x Portal. By clicking “I Agree” below, you understand that you are solely responsible for
- using 0x Portal and buying and selling tokens using 0x Portal in compliance with all applicable laws
- and regulations.
- </div>
- </div>
- </Dialog>
- );
-};
diff --git a/packages/website/ts/components/dialogs/send_dialog.tsx b/packages/website/ts/components/dialogs/send_dialog.tsx
deleted file mode 100644
index 5f6927cef..000000000
--- a/packages/website/ts/components/dialogs/send_dialog.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { AddressInput } from 'ts/components/inputs/address_input';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input';
-import { Token } from 'ts/types';
-
-interface SendDialogProps {
- blockchain: Blockchain;
- userAddress: string;
- networkId: number;
- onComplete: (recipient: string, value: BigNumber) => void;
- onCancelled: () => void;
- isOpen: boolean;
- asset: Token | 'ETH';
- lastForceTokenStateRefetch: number;
-}
-
-interface SendDialogState {
- value?: BigNumber;
- recipient: string;
- shouldShowIncompleteErrs: boolean;
- isAmountValid: boolean;
-}
-
-export class SendDialog extends React.Component<SendDialogProps, SendDialogState> {
- constructor(props: SendDialogProps) {
- super(props);
- this.state = {
- recipient: '',
- shouldShowIncompleteErrs: false,
- isAmountValid: false,
- };
- }
- public render(): React.ReactNode {
- const transferDialogActions = [
- <FlatButton key="cancelTransfer" label="Cancel" onClick={this._onCancel.bind(this)} />,
- <FlatButton
- key="sendTransfer"
- disabled={this._hasErrors()}
- label="Send"
- primary={true}
- onClick={this._onSendClick.bind(this)}
- />,
- ];
- return (
- <Dialog
- title="I want to send"
- titleStyle={{ fontWeight: 100 }}
- actions={transferDialogActions}
- open={this.props.isOpen}
- >
- {this._renderSendDialogBody()}
- </Dialog>
- );
- }
- private _renderSendDialogBody(): React.ReactNode {
- const input =
- this.props.asset === 'ETH' ? (
- <EthAmountInput
- label="Amount to send"
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={true}
- shouldShowErrs={true}
- onChange={this._onValueChange.bind(this)}
- amount={this.state.value}
- />
- ) : (
- <TokenAmountInput
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- label="Amount to send"
- token={this.props.asset}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={true}
- shouldCheckAllowance={false}
- onChange={this._onValueChange.bind(this)}
- amount={this.state.value}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- />
- );
- return (
- <div className="mx-auto" style={{ maxWidth: 300 }}>
- <div style={{ height: 80 }}>
- <AddressInput
- initialAddress={this.state.recipient}
- updateAddress={this._onRecipientChange.bind(this)}
- isRequired={true}
- label="Recipient address'"
- hintText="Address"
- />
- </div>
- {input}
- </div>
- );
- }
- private _onRecipientChange(recipient?: string): void {
- this.setState({
- shouldShowIncompleteErrs: false,
- recipient,
- });
- }
- private _onValueChange(isValid: boolean, amount?: BigNumber): void {
- this.setState({
- isAmountValid: isValid,
- value: amount,
- });
- }
- private _onSendClick(): void {
- if (this._hasErrors()) {
- this.setState({
- shouldShowIncompleteErrs: true,
- });
- } else {
- const value = this.state.value;
- this.setState({
- recipient: undefined,
- value: undefined,
- });
- this.props.onComplete(this.state.recipient, value);
- }
- }
- private _onCancel(): void {
- this.setState({
- value: undefined,
- });
- this.props.onCancelled();
- }
- private _hasErrors(): boolean {
- return _.isUndefined(this.state.recipient) || _.isUndefined(this.state.value) || !this.state.isAmountValid;
- }
-}
diff --git a/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx b/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx
deleted file mode 100644
index c8d5af6b6..000000000
--- a/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as moment from 'moment';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation';
-import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { Token, TokenByAddress } from 'ts/types';
-
-interface TrackTokenConfirmationDialogProps {
- tokens: Token[];
- tokenByAddress: TokenByAddress;
- isOpen: boolean;
- onToggleDialog: (didConfirmTokenTracking: boolean) => void;
- dispatcher: Dispatcher;
- networkId: number;
- blockchain: Blockchain;
- userAddress: string;
-}
-
-interface TrackTokenConfirmationDialogState {
- isAddingTokenToTracked: boolean;
-}
-
-export class TrackTokenConfirmationDialog extends React.Component<
- TrackTokenConfirmationDialogProps,
- TrackTokenConfirmationDialogState
-> {
- constructor(props: TrackTokenConfirmationDialogProps) {
- super(props);
- this.state = {
- isAddingTokenToTracked: false,
- };
- }
- public render(): React.ReactNode {
- const tokens = this.props.tokens;
- return (
- <Dialog
- title="Tracking confirmation"
- titleStyle={{ fontWeight: 100 }}
- actions={[
- <FlatButton
- key="trackNo"
- label="No"
- onClick={this._onTrackConfirmationRespondedAsync.bind(this, false)}
- />,
- <FlatButton
- key="trackYes"
- label="Yes"
- onClick={this._onTrackConfirmationRespondedAsync.bind(this, true)}
- />,
- ]}
- open={this.props.isOpen}
- onRequestClose={this.props.onToggleDialog.bind(this, false)}
- autoScrollBodyContent={true}
- >
- <div className="pt2">
- <TrackTokenConfirmation
- tokens={tokens}
- networkId={this.props.networkId}
- tokenByAddress={this.props.tokenByAddress}
- isAddingTokenToTracked={this.state.isAddingTokenToTracked}
- />
- </div>
- </Dialog>
- );
- }
- private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean): Promise<void> {
- if (!didUserAcceptTracking) {
- this.props.onToggleDialog(didUserAcceptTracking);
- return;
- }
- this.setState({
- isAddingTokenToTracked: true,
- });
- const currentTimestamp = moment().unix();
- for (const token of this.props.tokens) {
- const newTokenEntry = {
- ...token,
- trackedTimestamp: currentTimestamp,
- };
-
- trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry);
- this.props.dispatcher.updateTokenByAddress([newTokenEntry]);
- }
-
- this.setState({
- isAddingTokenToTracked: false,
- });
- this.props.onToggleDialog(didUserAcceptTracking);
- }
-}
diff --git a/packages/website/ts/components/documentation/docs_logo.tsx b/packages/website/ts/components/documentation/docs_logo.tsx
deleted file mode 100644
index ac331db79..000000000
--- a/packages/website/ts/components/documentation/docs_logo.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Link } from '@0x/react-shared';
-import * as React from 'react';
-import { styled } from 'ts/style/theme';
-import { WebsitePaths } from 'ts/types';
-
-import { Container } from '../ui/container';
-
-export interface DocsLogoProps {
- containerStyle?: React.CSSProperties;
-}
-
-const Image = styled.img`
- &:hover {
- opacity: 0.7;
- }
-`;
-
-export const DocsLogo: React.StatelessComponent<DocsLogoProps> = props => {
- return (
- <Container className="flex">
- <Container>
- <Link to={WebsitePaths.Home}>
- <Image src="/images/developers/logo/0x.svg" height={34} />
- </Link>
- </Container>
- <Container paddingTop="6px" paddingLeft="7px">
- <Link to={WebsitePaths.Docs}>
- <Image src="/images/developers/logo/docs.svg" height={20} />
- </Link>
- </Container>
- </Container>
- );
-};
-
-DocsLogo.defaultProps = {
- containerStyle: {},
-};
diff --git a/packages/website/ts/components/documentation/docs_top_bar.tsx b/packages/website/ts/components/documentation/docs_top_bar.tsx
deleted file mode 100644
index c4291b78f..000000000
--- a/packages/website/ts/components/documentation/docs_top_bar.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { ALink, colors, Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import Drawer from 'material-ui/Drawer';
-import * as React from 'react';
-import { DocsLogo } from 'ts/components/documentation/docs_logo';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { Deco, Key, ScreenWidths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-
-export interface DocsTopBarProps {
- location: Location;
- screenWidth: ScreenWidths;
- translate: Translate;
- sidebar?: React.ReactNode;
-}
-
-interface DocsTopBarState {
- isDrawerOpen: boolean;
-}
-
-export class DocsTopBar extends React.Component<DocsTopBarProps, DocsTopBarState> {
- constructor(props: DocsTopBarProps) {
- super(props);
- this.state = {
- isDrawerOpen: false,
- };
- }
- public componentWillReceiveProps(nextProps: DocsTopBarProps): void {
- if (nextProps.location.pathname !== this.props.location.pathname) {
- this.setState({
- isDrawerOpen: false,
- });
- }
- }
- public render(): React.ReactNode {
- return (
- <Container height={80}>
- <Container
- className="flex items-center lg-pt3 md-pt3 sm-pt1 lg-justify-end md-justify-end sm-justify-start"
- width="100%"
- >
- <Container className="sm-hide xs-hide">
- <Container className="flex items-center justify-between right" width="250px">
- {this._renderMenuItems(constants.DEVELOPER_TOPBAR_LINKS)}
- </Container>
- </Container>
- <Container className="lg-hide md-hide">
- <Container paddingTop="6px">
- <DocsLogo />
- </Container>
- </Container>
- <Container className="md-hide lg-hide absolute" right="18px" top="12px">
- <i
- className="zmdi zmdi-menu"
- style={{
- color: colors.grey700,
- fontSize: 30,
- cursor: 'pointer',
- }}
- onClick={this._onMenuButtonClick.bind(this)}
- />
- </Container>
- </Container>
- <Container width={'100%'} height={'1px'} backgroundColor={colors.grey300} marginTop={'16px'} />
- {this.props.screenWidth === ScreenWidths.Sm && this._renderDrawer()}
- </Container>
- );
- }
- private _renderMenuItems(menuItemLinks: ALink[]): React.ReactNode {
- const menuItems = _.map(menuItemLinks, menuItemInfo => {
- return (
- <Link
- key={`menu-item-${menuItemInfo.title}`}
- to={menuItemInfo.to}
- shouldOpenInNewTab={menuItemInfo.shouldOpenInNewTab}
- >
- <Container className="flex items-center" paddingLeft="4px">
- <Text fontSize="16px" fontColor={colors.lightLinkBlue} fontWeight="bold">
- {this.props.translate.get(menuItemInfo.title as Key, Deco.Cap)}
- </Text>
- </Container>
- </Link>
- );
- });
- return menuItems;
- }
- private _renderDrawer(): React.ReactNode {
- return (
- <Drawer
- open={this.state.isDrawerOpen}
- docked={false}
- openSecondary={true}
- onRequestChange={this._onMenuButtonClick.bind(this)}
- >
- <Container className="clearfix pl1 pt2" onClick={this._onMenuButtonClick.bind(this)}>
- {this.props.sidebar}
- </Container>
- </Drawer>
- );
- }
- private _onMenuButtonClick(): void {
- this.setState({
- isDrawerOpen: !this.state.isDrawerOpen,
- });
- }
-}
diff --git a/packages/website/ts/components/documentation/overview_content.tsx b/packages/website/ts/components/documentation/overview_content.tsx
deleted file mode 100644
index caabaf874..000000000
--- a/packages/website/ts/components/documentation/overview_content.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import { colors, Link, MarkdownLinkBlock, utils as sharedUtils } from '@0x/react-shared';
-import { ObjectMap } from '@0x/types';
-import * as _ from 'lodash';
-import * as React from 'react';
-import * as ReactMarkdown from 'react-markdown';
-import { Element as ScrollElement } from 'react-scroll';
-import { TutorialButton } from 'ts/components/documentation/tutorial_button';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { Deco, Key, Package, TutorialInfo } from 'ts/types';
-import { Translate } from 'ts/utils/translate';
-
-export interface OverviewContentProps {
- translate: Translate;
- tutorials: TutorialInfo[];
- categoryToPackages: ObjectMap<Package[]>;
-}
-
-export interface OverviewContentState {}
-
-export class OverviewContent extends React.Component<OverviewContentProps, OverviewContentState> {
- public render(): React.ReactNode {
- return (
- <Container>
- {this._renderSectionTitle(this.props.translate.get(Key.StartBuildOn0x, Deco.Cap))}
- <Container paddingTop="12px">
- {this._renderSectionDescription(this.props.translate.get(Key.StartBuildOn0xDescription, Deco.Cap))}
- <Container marginTop="36px">
- {_.map(this.props.tutorials, tutorialInfo => (
- <ScrollElement
- name={sharedUtils.getIdFromName(
- this.props.translate.get(tutorialInfo.link.title as Key, Deco.Cap),
- )}
- key={`tutorial-${tutorialInfo.link.title}`}
- >
- <TutorialButton translate={this.props.translate} tutorialInfo={tutorialInfo} />
- </ScrollElement>
- ))}
- </Container>
- </Container>
- <Container marginTop="32px" paddingBottom="100px">
- {this._renderSectionTitle(this.props.translate.get(Key.LibrariesAndTools, Deco.CapWords))}
- <Container paddingTop="12px">
- {this._renderSectionDescription(
- this.props.translate.get(Key.LibrariesAndToolsDescription, Deco.Cap),
- )}
- <Container marginTop="36px">
- {_.map(this.props.categoryToPackages, (pkgs, category) =>
- this._renderPackageCategory(category, pkgs),
- )}
- </Container>
- </Container>
- </Container>
- </Container>
- );
- }
- private _renderPackageCategory(category: string, pkgs: Package[]): React.ReactNode {
- return (
- <Container key={`category-${category}`}>
- <Text fontSize="18px">{category}</Text>
- <Container>{_.map(pkgs, pkg => this._renderPackage(pkg))}</Container>
- </Container>
- );
- }
- private _renderPackage(pkg: Package): React.ReactNode {
- const id = sharedUtils.getIdFromName(pkg.link.title);
- return (
- <ScrollElement name={id} key={`package-${pkg.link.title}`}>
- <Container className="pb2">
- <Container width="100%" height="1px" backgroundColor={colors.grey300} marginTop="11px" />
- <Container className="clearfix mt2 pt1">
- <Container className="md-col lg-col md-col-4 lg-col-4">
- <Link
- to={pkg.link.to}
- fontColor={colors.lightLinkBlue}
- shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab}
- >
- <Text Tag="div" fontColor={colors.lightLinkBlue} fontWeight="bold">
- {pkg.link.title}
- </Text>
- </Link>
- </Container>
- <Container className="md-col lg-col md-col-6 lg-col-6 sm-py2">
- <Text fontColor={colors.grey700}>
- <ReactMarkdown
- source={pkg.description}
- renderers={{
- link: MarkdownLinkBlock,
- paragraph: 'span',
- }}
- />
- </Text>
- </Container>
- <Container className="md-col lg-col md-col-2 lg-col-2 sm-pb2 relative">
- <Container position="absolute" right="0px">
- <Link
- to={pkg.link.to}
- fontColor={colors.lightLinkBlue}
- shouldOpenInNewTab={!!pkg.link.shouldOpenInNewTab}
- >
- <Container className="flex">
- <Container>{this.props.translate.get(Key.More, Deco.Cap)}</Container>
- <Container paddingTop="1px" paddingLeft="6px">
- <i
- className="zmdi zmdi-chevron-right bold"
- style={{ fontSize: 18, color: colors.lightLinkBlue }}
- />
- </Container>
- </Container>
- </Link>
- </Container>
- </Container>
- </Container>
- </Container>
- </ScrollElement>
- );
- }
- private _renderSectionTitle(text: string): React.ReactNode {
- return (
- <Container paddingTop="30px">
- <Text fontColor={colors.projectsGrey} fontSize="30px" fontWeight="bold">
- {text}
- </Text>
- </Container>
- );
- }
- private _renderSectionDescription(text: string): React.ReactNode {
- return (
- <Text fontColor={colors.linkSectionGrey} fontSize="16px" fontFamily="Roboto Mono">
- {text}
- </Text>
- );
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/documentation/sidebar_header.tsx b/packages/website/ts/components/documentation/sidebar_header.tsx
deleted file mode 100644
index d158ab926..000000000
--- a/packages/website/ts/components/documentation/sidebar_header.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { VersionDropDown } from 'ts/components/documentation/version_drop_down';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { ScreenWidths } from 'ts/types';
-
-export interface SidebarHeaderProps {
- screenWidth: ScreenWidths;
- title: string;
- docsVersion?: string;
- availableDocVersions?: string[];
- onVersionSelected?: () => void;
-}
-
-export const SidebarHeader: React.StatelessComponent<SidebarHeaderProps> = ({
- screenWidth,
- title,
- docsVersion,
- availableDocVersions,
- onVersionSelected,
-}) => {
- return (
- <Container>
- <Container className="flex justify-bottom">
- <Container className="col col-8 pl1">
- <Text
- fontColor={colors.lightLinkBlue}
- fontSize={screenWidth === ScreenWidths.Sm ? '20px' : '22px'}
- fontWeight="bold"
- lineHeight="26px"
- >
- {title}
- </Text>
- </Container>
- {!_.isUndefined(docsVersion) &&
- !_.isUndefined(availableDocVersions) &&
- !_.isUndefined(onVersionSelected) && (
- <div className="col col-4 pl1" style={{ alignSelf: 'flex-end', paddingBottom: 4 }}>
- <Container className="right">
- <VersionDropDown
- selectedVersion={docsVersion}
- versions={availableDocVersions}
- onVersionSelected={onVersionSelected}
- />
- </Container>
- </div>
- )}
- </Container>
- <Container
- width={'100%'}
- height={'1px'}
- backgroundColor={colors.grey300}
- marginTop="20px"
- marginBottom="27px"
- />
- </Container>
- );
-};
diff --git a/packages/website/ts/components/documentation/tutorial_button.tsx b/packages/website/ts/components/documentation/tutorial_button.tsx
deleted file mode 100644
index b747ef598..000000000
--- a/packages/website/ts/components/documentation/tutorial_button.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { colors, Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { Deco, Key, TutorialInfo } from 'ts/types';
-import { Translate } from 'ts/utils/translate';
-
-import { styled } from 'ts/style/theme';
-
-export interface TutorialButtonProps {
- className?: string;
- translate: Translate;
- tutorialInfo: TutorialInfo;
-}
-
-const PlainTutorialButton: React.StatelessComponent<TutorialButtonProps> = ({ translate, tutorialInfo, className }) => (
- <Container className={className}>
- <Link to={tutorialInfo.link.to} shouldOpenInNewTab={tutorialInfo.link.shouldOpenInNewTab}>
- <div className="flex relative">
- <div className="col col-1 flex items-center sm-pr3">
- <img src={tutorialInfo.iconUrl} height={40} />
- </div>
- <div className="lg-pl2 md-pl2 sm-pl3 col col-10">
- <Text Tag="div" fontSize="18" fontColor={colors.lightLinkBlue} fontWeight="bold">
- {translate.get(tutorialInfo.link.title as Key, Deco.Cap)}
- </Text>
- <Text Tag="div" fontColor={colors.grey750} fontSize="16">
- {translate.get(tutorialInfo.description as Key, Deco.Cap)}
- </Text>
- </div>
- <div className="col col-1 flex items-center justify-end">
- <div className="right">
- <i
- className="zmdi zmdi-chevron-right bold"
- style={{ fontSize: 26, color: colors.lightLinkBlue }}
- />
- </div>
- </div>
- </div>
- </Link>
- </Container>
-);
-
-export const TutorialButton = styled(PlainTutorialButton)`
- border-radius: 4px;
- border: 1px solid ${colors.grey325};
- background-color: ${colors.white};
- &:hover {
- border: 1px solid ${colors.lightLinkBlue};
- background-color: ${colors.lightestBlue};
- }
- padding: 20px;
- margin-bottom: 15px;
-`;
-
-TutorialButton.defaultProps = {};
-
-TutorialButton.displayName = 'TutorialButton';
diff --git a/packages/website/ts/components/documentation/version_drop_down.tsx b/packages/website/ts/components/documentation/version_drop_down.tsx
deleted file mode 100644
index 5e77530fd..000000000
--- a/packages/website/ts/components/documentation/version_drop_down.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down';
-import { Text } from 'ts/components/ui/text';
-import { styled } from 'ts/style/theme';
-
-interface ActiveNodeProps {
- className?: string;
- selectedVersion: string;
-}
-
-const PlainActiveNode: React.StatelessComponent<ActiveNodeProps> = ({ className, selectedVersion }) => (
- <Container className={className}>
- <Container className="flex justify-center">
- <Text fontColor={colors.grey700} fontSize="12px">
- v {selectedVersion}
- </Text>
- <Container paddingLeft="6px">
- <i className="zmdi zmdi-chevron-down" style={{ fontSize: 17, color: 'rgba(153, 153, 153, 0.8)' }} />
- </Container>
- </Container>
- </Container>
-);
-
-const ActiveNode = styled(PlainActiveNode)`
- cursor: pointer;
- border: 1px solid ${colors.beigeWhite};
- border-radius: 4px;
- padding: 4px 6px 4px 8px;
-`;
-
-interface VersionDropDownProps {
- selectedVersion: string;
- versions: string[];
- onVersionSelected: (semver: string) => void;
-}
-
-interface VersionDropDownState {}
-
-export class VersionDropDown extends React.Component<VersionDropDownProps, VersionDropDownState> {
- public render(): React.ReactNode {
- const activeNode = <ActiveNode selectedVersion={this.props.selectedVersion} />;
- return (
- <DropDown
- activateEvent={DropdownMouseEvent.Click}
- activeNode={activeNode}
- popoverContent={this._renderDropdownMenu()}
- anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
- targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
- popoverStyle={{ borderRadius: 4 }}
- />
- );
- }
- private _renderDropdownMenu(): React.ReactNode {
- const items = _.map(this.props.versions, version => {
- const isSelected = version === this.props.selectedVersion;
- return (
- <Container key={`dropdown-items-${version}`}>
- <Button
- borderRadius="0px"
- padding="0.8em 0em"
- width="100%"
- isDisabled={isSelected}
- onClick={this._onClick.bind(this, version)}
- >
- v {version}
- </Button>
- </Container>
- );
- });
- const dropdownMenu = <Container width="88px">{items}</Container>;
- return dropdownMenu;
- }
- private _onClick(selectedVersion: string): void {
- this.props.onVersionSelected(selectedVersion);
- }
-}
diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx
deleted file mode 100644
index 079132f2b..000000000
--- a/packages/website/ts/components/dropdowns/developers_drop_down.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import { ALink, colors, Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { DropDown } from 'ts/components/ui/drop_down';
-import { Text } from 'ts/components/ui/text';
-import { Deco, Key, WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-
-const gettingStartedKeyToLinkInfo1: ALink[] = [
- {
- title: Key.BuildARelayer,
- to: `${WebsitePaths.Wiki}#Build-A-Relayer`,
- },
- {
- title: Key.OrderBasics,
- to: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`,
- },
-];
-const gettingStartedKeyToLinkInfo2: ALink[] = [
- {
- title: Key.DevelopOnEthereum,
- to: `${WebsitePaths.Wiki}#Ethereum-Development`,
- },
- {
- title: Key.UseNetworkedLiquidity,
- to: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`,
- },
-];
-const popularDocsToLinkInfos: ALink[] = [
- {
- title: Key.ZeroExJs,
- to: WebsitePaths.ZeroExJs,
- },
- {
- title: Key.Connect,
- to: WebsitePaths.Connect,
- },
- {
- title: Key.SmartContract,
- to: WebsitePaths.SmartContracts,
- },
-];
-const usefulLinksToLinkInfo: ALink[] = [
- {
- title: Key.Wiki,
- to: WebsitePaths.Wiki,
- },
- {
- title: Key.Github,
- to: constants.URL_GITHUB_ORG,
- shouldOpenInNewTab: true,
- },
- {
- title: Key.ProtocolSpecification,
- to: constants.URL_PROTOCOL_SPECIFICATION,
- shouldOpenInNewTab: true,
- },
-];
-
-interface DevelopersDropDownProps {
- location: Location;
- translate: Translate;
- menuItemStyles: React.CSSProperties;
- menuIconStyle: React.CSSProperties;
-}
-
-interface DevelopersDropDownState {}
-
-export class DevelopersDropDown extends React.Component<DevelopersDropDownProps, DevelopersDropDownState> {
- public render(): React.ReactNode {
- const activeNode = (
- <Container className="flex relative" paddingRight="10">
- <Text fontColor={this.props.menuIconStyle.color}>
- {this.props.translate.get(Key.Developers, Deco.Cap)}
- </Text>
- </Container>
- );
- return (
- <DropDown
- activeNode={activeNode}
- popoverContent={this._renderDropdownMenu()}
- anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
- targetOrigin={{ horizontal: 'left', vertical: 'top' }}
- style={this.props.menuItemStyles}
- popoverStyle={{ borderRadius: 4, width: 397, height: 373, marginTop: 0 }}
- />
- );
- }
- private _renderDropdownMenu(): React.ReactNode {
- const sectionPadding = '26px';
- const dropdownMenu = (
- <Container>
- <Container className="flex" padding={sectionPadding}>
- <Container paddingRight="45px">
- {this._renderLinkSection(gettingStartedKeyToLinkInfo1, 'Getting started')}
- </Container>
- <Container>{this._renderLinkSection(gettingStartedKeyToLinkInfo2)}</Container>
- </Container>
- <Container width="100%" height="1px" backgroundColor={colors.grey300} />
- <Container className="flex" padding={sectionPadding}>
- <Container paddingRight="62px">
- <Container>{this._renderLinkSection(popularDocsToLinkInfos, 'Popular docs')}</Container>
- </Container>
- <Container>
- <Container>{this._renderLinkSection(usefulLinksToLinkInfo, 'Useful links')}</Container>
- </Container>
- </Container>
- <Link to={WebsitePaths.Docs} fontColor={colors.lightBlueA700}>
- <Container
- padding="0.9rem"
- backgroundColor={colors.lightBgGrey}
- borderBottomLeftRadius={4}
- borderBottomRightRadius={4}
- >
- <Text fontColor={colors.lightBlueA700} fontWeight="bold" fontSize="14px" textAlign="center">
- {this.props.translate.get(Key.ViewAllDocumentation, Deco.Upper)}
- </Text>
- </Container>
- </Link>
- </Container>
- );
- return dropdownMenu;
- }
- private _renderLinkSection(links: ALink[], title: string = ''): React.ReactNode {
- const numLinks = links.length;
- let i = 0;
- const renderLinks = _.map(links, (link: ALink) => {
- const isWikiLink = _.startsWith(link.to, WebsitePaths.Wiki) && _.includes(link.to, '#');
- const isOnWiki = this.props.location.pathname === WebsitePaths.Wiki;
- let to = link.to;
- if (isWikiLink && isOnWiki) {
- to = `${link.to.split('#')[1]}`;
- }
- i++;
- const isLast = i === numLinks;
- const linkText = this.props.translate.get(link.title as Key, Deco.Cap);
- return (
- <Container className={`pr1 pt1 ${!isLast && 'pb1'}`} key={`dev-dropdown-link-${link.title}`}>
- <Link to={to} shouldOpenInNewTab={!!link.shouldOpenInNewTab}>
- <Text fontFamily="Roboto, Roboto Mono" fontColor={colors.lightBlueA700}>
- {linkText}
- </Text>
- </Link>
- </Container>
- );
- });
- return (
- <Container>
- <Container height="33px">
- {!_.isEmpty(title) && (
- <Text letterSpacing={1} fontColor={colors.linkSectionGrey} fontSize="14px" fontWeight={600}>
- {title.toUpperCase()}
- </Text>
- )}
- </Container>
- {renderLinks}
- </Container>
- );
- }
-}
diff --git a/packages/website/ts/components/dropdowns/dropdown_developers.tsx b/packages/website/ts/components/dropdowns/dropdown_developers.tsx
deleted file mode 100644
index 590d2ead9..000000000
--- a/packages/website/ts/components/dropdowns/dropdown_developers.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import { Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import styled, { withTheme } from 'styled-components';
-
-import { Button } from 'ts/components/button';
-import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
-import { ThemeValuesInterface } from 'ts/components/siteWrap';
-import { Heading } from 'ts/components/text';
-import { WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-interface Props {
- theme: ThemeValuesInterface;
-}
-
-interface LinkConfig {
- label: string;
- url: string;
- shouldOpenInNewTab?: boolean;
-}
-
-const introData: LinkConfig[] = [
- {
- label: 'Build a relayer',
- url: `${WebsitePaths.Wiki}#Build-A-Relayer`,
- },
- {
- label: 'Develop on Ethereum',
- url: `${WebsitePaths.Wiki}#Ethereum-Development`,
- },
- {
- label: 'Make & take orders',
- url: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`,
- },
- {
- label: 'Use networked liquidity',
- url: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`,
- },
- {
- label: 'Market making',
- url: `${WebsitePaths.MarketMaker}`,
- },
-];
-
-const docsData: LinkConfig[] = [
- {
- label: '0x.js',
- url: WebsitePaths.ZeroExJs,
- },
- {
- label: '0x Connect',
- url: WebsitePaths.Connect,
- },
- {
- label: 'Smart Contract',
- url: WebsitePaths.SmartContracts,
- },
-];
-
-const linksData: LinkConfig[] = [
- {
- label: 'Wiki',
- url: WebsitePaths.Wiki,
- },
- {
- label: 'Github',
- url: constants.URL_GITHUB_ORG,
- shouldOpenInNewTab: true,
- },
- {
- label: 'Protocol specification',
- url: constants.URL_PROTOCOL_SPECIFICATION,
- shouldOpenInNewTab: true,
- },
-];
-
-export const DropdownDevelopers: React.FunctionComponent<Props> = withTheme((props: Props) => (
- <>
- <DropdownWrap>
- <div>
- <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}>
- Getting Started
- </Heading>
-
- <StyledGrid isCentered={false} isWrapped={true}>
- {_.map(introData, (item, index) => (
- <li>
- <Link key={`introLink-${index}`} to={item.url}>
- {item.label}
- </Link>
- </li>
- ))}
- </StyledGrid>
- </div>
-
- <StyledWrap>
- <Column width="calc(100% - 15px)">
- <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}>
- Popular Docs
- </Heading>
-
- <ul>
- {_.map(docsData, (item, index) => (
- <li key={`docsLink-${index}`}>
- <Link to={item.url} shouldOpenInNewTab={item.shouldOpenInNewTab}>
- {item.label}
- </Link>
- </li>
- ))}
- </ul>
- </Column>
-
- <Column width="calc(100% - 15px)">
- <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}>
- Useful Links
- </Heading>
-
- <ul>
- {_.map(linksData, (item, index) => (
- <li key={`usefulLink-${index}`}>
- <Link to={item.url} shouldOpenInNewTab={item.shouldOpenInNewTab}>
- {item.label}
- </Link>
- </li>
- ))}
- </ul>
- </Column>
- </StyledWrap>
-
- <StyledLink
- to={WebsitePaths.Docs}
- bgColor={props.theme.dropdownButtonBg}
- isAccentColor={true}
- isNoBorder={true}
- >
- View All Documentation
- </StyledLink>
- </DropdownWrap>
- </>
-));
-
-const DropdownWrap = styled.div`
- padding: 15px 30px 75px 30px;
-
- a {
- color: inherit;
- }
-
- li {
- margin: 8px 0;
- }
-`;
-
-const StyledGrid = styled(WrapGrid.withComponent('ul'))`
- li {
- width: 50%;
- flex-shrink: 0;
- }
-`;
-
-const StyledWrap = styled(FlexWrap)`
- padding-top: 20px;
- margin-top: 30px;
- position: relative;
-
- &:before {
- content: '';
- width: 100%;
- height: 1px;
- background-color: ${props => props.theme.dropdownColor};
- opacity: 0.15;
- position: absolute;
- top: 0;
- left: 0;
- }
-`;
-
-const StyledLink = styled(Button)`
- width: 100%;
- position: absolute;
- bottom: 0;
- left: 0;
-`;
diff --git a/packages/website/ts/components/dropdowns/dropdown_products.tsx b/packages/website/ts/components/dropdowns/dropdown_products.tsx
deleted file mode 100644
index 93fd1a4fe..000000000
--- a/packages/website/ts/components/dropdowns/dropdown_products.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Link } from 'react-router-dom';
-import styled from 'styled-components';
-import { Heading, Paragraph } from 'ts/components/text';
-import { WebsitePaths } from 'ts/types';
-
-const navData = [
- {
- title: '0x Instant',
- description: 'Simple crypto purchasing',
- url: WebsitePaths.Instant,
- },
- {
- title: '0x Launch Kit',
- description: 'Build on the 0x protocol',
- url: WebsitePaths.LaunchKit,
- },
-];
-
-export const DropdownProducts: React.FunctionComponent<{}> = () => (
- <List>
- {_.map(navData, (item, index) => (
- <li key={`productLink-${index}`}>
- <Link to={item.url}>
- <Heading asElement="h3" color="inherit" isNoMargin={true} size="small">
- {item.title}
- </Heading>
-
- {item.description && (
- <Paragraph color="inherit" isNoMargin={true} size="small" isMuted={0.5}>
- {item.description}
- </Paragraph>
- )}
- </Link>
- </li>
- ))}
- </List>
-);
-
-const List = styled.ul`
- a {
- padding: 15px 30px;
- display: block;
- color: inherit;
- }
-`;
diff --git a/packages/website/ts/components/dropdowns/network_drop_down.tsx b/packages/website/ts/components/dropdowns/network_drop_down.tsx
deleted file mode 100644
index df2d72edc..000000000
--- a/packages/website/ts/components/dropdowns/network_drop_down.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { constants as sharedConstants } from '@0x/react-shared';
-import * as _ from 'lodash';
-import DropDownMenu from 'material-ui/DropDownMenu';
-import MenuItem from 'material-ui/MenuItem';
-import * as React from 'react';
-
-interface NetworkDropDownProps {
- updateSelectedNetwork: (e: any, index: number, value: number) => void;
- selectedNetworkId: number;
- avialableNetworkIds: number[];
-}
-
-interface NetworkDropDownState {}
-
-export class NetworkDropDown extends React.Component<NetworkDropDownProps, NetworkDropDownState> {
- public render(): React.ReactNode {
- return (
- <div className="mx-auto" style={{ width: 120 }}>
- <DropDownMenu value={this.props.selectedNetworkId} onChange={this.props.updateSelectedNetwork}>
- {this._renderDropDownItems()}
- </DropDownMenu>
- </div>
- );
- }
- private _renderDropDownItems(): React.ReactNode {
- const items = _.map(this.props.avialableNetworkIds, networkId => {
- const networkName = sharedConstants.NETWORK_NAME_BY_ID[networkId];
- const primaryText = (
- <div className="flex">
- <div className="pr1" style={{ width: 14, paddingTop: 2 }}>
- <img src={`/images/network_icons/${networkName.toLowerCase()}.png`} style={{ width: 14 }} />
- </div>
- <div>{networkName}</div>
- </div>
- );
- return <MenuItem key={networkId} value={networkId} primaryText={primaryText} />;
- });
- return items;
- }
-}
diff --git a/packages/website/ts/components/eth_weth_conversion_button.tsx b/packages/website/ts/components/eth_weth_conversion_button.tsx
deleted file mode 100644
index 536ba924b..000000000
--- a/packages/website/ts/components/eth_weth_conversion_button.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import { BigNumber, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import RaisedButton from 'material-ui/RaisedButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { EthWethConversionDialog } from 'ts/components/dialogs/eth_weth_conversion_dialog';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { BlockchainCallErrs, Side, Token } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-interface EthWethConversionButtonProps {
- userAddress: string;
- networkId: number;
- direction: Side;
- ethToken: Token;
- dispatcher: Dispatcher;
- blockchain: Blockchain;
- userEtherBalanceInWei: BigNumber;
- isOutdatedWrappedEther: boolean;
- onConversionSuccessful?: () => void;
- isDisabled?: boolean;
- lastForceTokenStateRefetch: number;
- refetchEthTokenStateAsync: () => Promise<void>;
-}
-
-interface EthWethConversionButtonState {
- isEthConversionDialogVisible: boolean;
- isEthConversionHappening: boolean;
-}
-
-export class EthWethConversionButton extends React.Component<
- EthWethConversionButtonProps,
- EthWethConversionButtonState
-> {
- public static defaultProps: Partial<EthWethConversionButtonProps> = {
- isDisabled: false,
- onConversionSuccessful: _.noop.bind(_),
- };
- public constructor(props: EthWethConversionButtonProps) {
- super(props);
- this.state = {
- isEthConversionDialogVisible: false,
- isEthConversionHappening: false,
- };
- }
- public render(): React.ReactNode {
- const labelStyle = this.state.isEthConversionHappening ? { fontSize: 10 } : {};
- let callToActionLabel;
- let inProgressLabel;
- if (this.props.direction === Side.Deposit) {
- callToActionLabel = 'Wrap';
- inProgressLabel = 'Wrapping...';
- } else {
- callToActionLabel = 'Unwrap';
- inProgressLabel = 'Unwrapping...';
- }
- return (
- <div>
- <RaisedButton
- style={{ width: '100%' }}
- labelStyle={labelStyle}
- disabled={this.props.isDisabled || this.state.isEthConversionHappening}
- label={this.state.isEthConversionHappening ? inProgressLabel : callToActionLabel}
- onClick={this._toggleConversionDialog.bind(this)}
- />
- <EthWethConversionDialog
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- direction={this.props.direction}
- isOpen={this.state.isEthConversionDialogVisible}
- onComplete={this._onConversionAmountSelectedAsync.bind(this)}
- onCancelled={this._toggleConversionDialog.bind(this)}
- etherBalanceInWei={this.props.userEtherBalanceInWei}
- token={this.props.ethToken}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- />
- </div>
- );
- }
- private _toggleConversionDialog(): void {
- this.setState({
- isEthConversionDialogVisible: !this.state.isEthConversionDialogVisible,
- });
- }
- private async _onConversionAmountSelectedAsync(direction: Side, value: BigNumber): Promise<void> {
- this.setState({
- isEthConversionHappening: true,
- });
- this._toggleConversionDialog();
- const token = this.props.ethToken;
- try {
- if (direction === Side.Deposit) {
- await this.props.blockchain.convertEthToWrappedEthTokensAsync(token.address, value);
- const ethAmount = Web3Wrapper.toUnitAmount(value, constants.DECIMAL_PLACES_ETH);
- this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount.toString()} ETH to WETH`);
- } else {
- await this.props.blockchain.convertWrappedEthTokensToEthAsync(token.address, value);
- const tokenAmount = Web3Wrapper.toUnitAmount(value, token.decimals);
- this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount.toString()} WETH to ETH`);
- }
- if (!this.props.isOutdatedWrappedEther) {
- await this.props.refetchEthTokenStateAsync();
- }
- this.props.onConversionSuccessful();
- } catch (err) {
- const errMsg = `${err}`;
- if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- } else if (!utils.didUserDenyWeb3Request(errMsg)) {
- logUtils.log(`Unexpected error encountered: ${err}`);
- logUtils.log(err.stack);
- const errorMsg =
- direction === Side.Deposit
- ? 'Failed to wrap your ETH. Please try again.'
- : 'Failed to unwrap your WETH. Please try again.';
- this.props.dispatcher.showFlashMessage(errorMsg);
- errorReporter.report(err);
- }
- }
- this.setState({
- isEthConversionHappening: false,
- });
- }
-}
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx
deleted file mode 100644
index dc597b18f..000000000
--- a/packages/website/ts/components/eth_wrappers.tsx
+++ /dev/null
@@ -1,448 +0,0 @@
-import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import Divider from 'material-ui/Divider';
-import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
-import * as moment from 'moment';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-import { Blockchain } from 'ts/blockchain';
-import { EthWethConversionButton } from 'ts/components/eth_weth_conversion_button';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import {
- OutdatedWrappedEtherByNetworkId,
- Side,
- Token,
- TokenByAddress,
- TokenState,
- TokenStateByAddress,
-} from 'ts/types';
-import { configs } from 'ts/utils/configs';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-const DATE_FORMAT = 'D/M/YY';
-const ICON_DIMENSION = 40;
-const ETHER_ICON_PATH = '/images/ether.png';
-const OUTDATED_WETH_ICON_PATH = '/images/wrapped_eth_gray.png';
-
-interface EthWrappersProps {
- networkId: number;
- blockchain: Blockchain;
- dispatcher: Dispatcher;
- tokenByAddress: TokenByAddress;
- userAddress: string;
- userEtherBalanceInWei?: BigNumber;
- lastForceTokenStateRefetch: number;
- isFullWidth?: boolean;
-}
-
-interface EthWrappersState {
- ethTokenState: TokenState;
- outdatedWETHStateByAddress: TokenStateByAddress;
-}
-
-export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
- public static defaultProps: Partial<EthWrappersProps> = {
- isFullWidth: false,
- };
- private _isUnmounted: boolean;
- constructor(props: EthWrappersProps) {
- super(props);
- this._isUnmounted = false;
- const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
- const outdatedWETHStateByAddress: TokenStateByAddress = {};
- _.each(outdatedWETHAddresses, outdatedWETHAddress => {
- outdatedWETHStateByAddress[outdatedWETHAddress] = {
- balance: new BigNumber(0),
- allowance: new BigNumber(0),
- isLoaded: false,
- };
- });
- this.state = {
- outdatedWETHStateByAddress,
- ethTokenState: {
- balance: new BigNumber(0),
- allowance: new BigNumber(0),
- isLoaded: false,
- },
- };
- }
- public componentWillReceiveProps(nextProps: EthWrappersProps): void {
- if (
- nextProps.userAddress !== this.props.userAddress ||
- nextProps.networkId !== this.props.networkId ||
- nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
- ) {
- // tslint:disable-next-line:no-floating-promises
- this._fetchWETHStateAsync();
- }
- }
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- // tslint:disable-next-line:no-floating-promises
- this._fetchWETHStateAsync();
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public render(): React.ReactNode {
- const etherToken = this._getEthToken();
- const wethBalance = Web3Wrapper.toUnitAmount(this.state.ethTokenState.balance, constants.DECIMAL_PLACES_ETH);
- const isBidirectional = true;
- const etherscanUrl = sharedUtils.getEtherScanLinkIfExists(
- etherToken.address,
- this.props.networkId,
- EtherscanLinkSuffixes.Address,
- );
- const tokenLabel = this._renderToken(
- 'Wrapped Ether',
- etherToken.address,
- utils.getTokenIconUrl(etherToken.symbol),
- );
- const userEtherBalanceInEth = !_.isUndefined(this.props.userEtherBalanceInWei)
- ? Web3Wrapper.toUnitAmount(this.props.userEtherBalanceInWei, constants.DECIMAL_PLACES_ETH)
- : undefined;
- const rootClassName = this.props.isFullWidth ? 'clearfix' : 'clearfix lg-px4 md-px4 sm-px2';
- return (
- <div className={rootClassName} style={{ minHeight: 600 }}>
- <div className="relative">
- <h3>ETH Wrapper</h3>
- <div className="absolute" style={{ top: 0, right: 0 }}>
- <a target="_blank" href={constants.URL_WETH_IO} style={{ color: colors.grey }}>
- <div className="flex">
- <div>About Wrapped ETH</div>
- <div className="pl1">
- <i className="zmdi zmdi-open-in-new" />
- </div>
- </div>
- </a>
- </div>
- </div>
- <Divider />
- <div>
- <div className="py2">Wrap ETH into an ERC20-compliant Ether token. 1 ETH = 1 WETH.</div>
- <div>
- <Table selectable={false} style={{ backgroundColor: 'transparent' }}>
- <TableHeader displaySelectAll={false} adjustForCheckbox={false}>
- <TableRow>
- <TableHeaderColumn>ETH Token</TableHeaderColumn>
- <TableHeaderColumn>Balance</TableHeaderColumn>
- <TableHeaderColumn className="center">
- {this._renderActionColumnTitle(isBidirectional)}
- </TableHeaderColumn>
- </TableRow>
- </TableHeader>
- <TableBody displayRowCheckbox={false}>
- <TableRow key="ETH">
- <TableRowColumn className="py1">
- <div className="flex">
- <img
- style={{
- width: ICON_DIMENSION,
- height: ICON_DIMENSION,
- }}
- src={ETHER_ICON_PATH}
- />
- <div className="ml2 sm-hide xs-hide" style={{ marginTop: 12 }}>
- ETH
- </div>
- </div>
- </TableRowColumn>
- <TableRowColumn>
- {!_.isUndefined(userEtherBalanceInEth) ? (
- `${userEtherBalanceInEth.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} ETH`
- ) : (
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- )}
- </TableRowColumn>
- <TableRowColumn>
- <EthWethConversionButton
- refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- isOutdatedWrappedEther={false}
- direction={Side.Deposit}
- ethToken={etherToken}
- dispatcher={this.props.dispatcher}
- blockchain={this.props.blockchain}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- isDisabled={_.isUndefined(userEtherBalanceInEth)}
- />
- </TableRowColumn>
- </TableRow>
- <TableRow key="WETH">
- <TableRowColumn className="py1">
- {this._renderTokenLink(tokenLabel, etherscanUrl)}
- </TableRowColumn>
- <TableRowColumn>
- {this.state.ethTokenState.isLoaded ? (
- `${wethBalance.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} WETH`
- ) : (
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- )}
- </TableRowColumn>
- <TableRowColumn>
- <EthWethConversionButton
- refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- isOutdatedWrappedEther={false}
- direction={Side.Receive}
- isDisabled={!this.state.ethTokenState.isLoaded}
- ethToken={etherToken}
- dispatcher={this.props.dispatcher}
- blockchain={this.props.blockchain}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- />
- </TableRowColumn>
- </TableRow>
- </TableBody>
- </Table>
- </div>
- </div>
- <div>
- <h4>Outdated WETH</h4>
- <Divider />
- <div className="pt2" style={{ lineHeight: 1.5 }}>
- The{' '}
- <a href={constants.URL_CANONICAL_WETH_POST} target="_blank">
- canonical WETH
- </a>{' '}
- contract is updated when necessary. Unwrap outdated WETH in order to
 retrieve your ETH and move
- it to the updated WETH token.
- </div>
- <div>
- <Table selectable={false} style={{ backgroundColor: 'transparent' }}>
- <TableHeader displaySelectAll={false} adjustForCheckbox={false}>
- <TableRow>
- <TableHeaderColumn>WETH Version</TableHeaderColumn>
- <TableHeaderColumn>Balance</TableHeaderColumn>
- <TableHeaderColumn className="center">
- {this._renderActionColumnTitle(!isBidirectional)}
- </TableHeaderColumn>
- </TableRow>
- </TableHeader>
- <TableBody displayRowCheckbox={false}>{this._renderOutdatedWeths(etherToken)}</TableBody>
- </Table>
- </div>
- </div>
- </div>
- );
- }
- private _renderActionColumnTitle(isBidirectional: boolean): React.ReactNode {
- let iconClass = 'zmdi-long-arrow-right';
- let leftSymbol = 'WETH';
- let rightSymbol = 'ETH';
- if (isBidirectional) {
- iconClass = 'zmdi-swap';
- leftSymbol = 'ETH';
- rightSymbol = 'WETH';
- }
- return (
- <div className="flex mx-auto" style={{ width: 85 }}>
- <div style={{ paddingTop: 3 }}>{leftSymbol}</div>
- <div className="px1">
- <i style={{ fontSize: 18 }} className={`zmdi ${iconClass}`} />
- </div>
- <div style={{ paddingTop: 3 }}>{rightSymbol}</div>
- </div>
- );
- }
- private _renderOutdatedWeths(etherToken: Token): React.ReactNode {
- const rows = _.map(
- configs.OUTDATED_WRAPPED_ETHERS,
- (outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => {
- const outdatedWETHIfExists = outdatedWETHByNetworkId[this.props.networkId];
- if (_.isUndefined(outdatedWETHIfExists)) {
- return null; // noop
- }
- const timestampMsRange = outdatedWETHIfExists.timestampMsRange;
- let dateRange: string;
- if (!_.isUndefined(timestampMsRange)) {
- const startMoment = moment(timestampMsRange.startTimestampMs);
- const endMoment = moment(timestampMsRange.endTimestampMs);
- dateRange = `${startMoment.format(DATE_FORMAT)}-${endMoment.format(DATE_FORMAT)}`;
- } else {
- dateRange = '-';
- }
- const outdatedEtherToken = {
- ...etherToken,
- address: outdatedWETHIfExists.address,
- };
- const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETHIfExists.address];
- const isStateLoaded = outdatedEtherTokenState.isLoaded;
- const balanceInEthIfExists = isStateLoaded
- ? Web3Wrapper.toUnitAmount(outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH).toFixed(
- configs.AMOUNT_DISPLAY_PRECSION,
- )
- : undefined;
- const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind(
- this,
- outdatedWETHIfExists.address,
- );
- const etherscanUrl = sharedUtils.getEtherScanLinkIfExists(
- outdatedWETHIfExists.address,
- this.props.networkId,
- EtherscanLinkSuffixes.Address,
- );
- const tokenLabel = this._renderToken(dateRange, outdatedEtherToken.address, OUTDATED_WETH_ICON_PATH);
- return (
- <TableRow key={`weth-${outdatedWETHIfExists.address}`}>
- <TableRowColumn className="py1">
- {this._renderTokenLink(tokenLabel, etherscanUrl)}
- </TableRowColumn>
- <TableRowColumn>
- {isStateLoaded ? (
- `${balanceInEthIfExists} WETH`
- ) : (
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- )}
- </TableRowColumn>
- <TableRowColumn>
- <EthWethConversionButton
- refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- isDisabled={!isStateLoaded}
- isOutdatedWrappedEther={true}
- direction={Side.Receive}
- ethToken={outdatedEtherToken}
- dispatcher={this.props.dispatcher}
- blockchain={this.props.blockchain}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- onConversionSuccessful={onConversionSuccessful}
- />
- </TableRowColumn>
- </TableRow>
- );
- },
- );
- return rows;
- }
- private _renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string): React.ReactNode {
- return (
- <span>
- {_.isUndefined(etherscanUrl) ? (
- tokenLabel
- ) : (
- <a href={etherscanUrl} target="_blank" style={{ textDecoration: 'none' }}>
- {tokenLabel}
- </a>
- )}
- </span>
- );
- }
- private _renderToken(name: string, address: string, imgPath: string): React.ReactNode {
- const tooltipId = `tooltip-${address}`;
- return (
- <div className="flex">
- <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={imgPath} />
- <div className="ml2 sm-hide xs-hide" style={{ marginTop: 12 }}>
- <span data-tip={true} data-for={tooltipId}>
- {name}
- </span>
- <ReactTooltip id={tooltipId}>{address}</ReactTooltip>
- </div>
- </div>
- );
- }
- private async _onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string): Promise<void> {
- const currentOutdatedWETHState = this.state.outdatedWETHStateByAddress[outdatedWETHAddress];
- this.setState({
- outdatedWETHStateByAddress: {
- ...this.state.outdatedWETHStateByAddress,
- [outdatedWETHAddress]: {
- balance: currentOutdatedWETHState.balance,
- allowance: currentOutdatedWETHState.allowance,
- isLoaded: false,
- },
- },
- });
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- outdatedWETHAddress,
- );
- this.setState({
- outdatedWETHStateByAddress: {
- ...this.state.outdatedWETHStateByAddress,
- [outdatedWETHAddress]: {
- balance,
- allowance,
- isLoaded: true,
- },
- },
- });
- }
- private async _fetchWETHStateAsync(): Promise<void> {
- const tokens = _.values(this.props.tokenByAddress);
- const wethToken = _.find(tokens, token => token.symbol === 'WETH');
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const [wethBalance, wethAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- wethToken.address,
- );
-
- const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
- const outdatedWETHStateByAddress: TokenStateByAddress = {};
- for (const address of outdatedWETHAddresses) {
- const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- address,
- );
- outdatedWETHStateByAddress[address] = {
- balance,
- allowance,
- isLoaded: true,
- };
- }
- if (!this._isUnmounted) {
- this.setState({
- outdatedWETHStateByAddress,
- ethTokenState: {
- balance: wethBalance,
- allowance: wethAllowance,
- isLoaded: true,
- },
- });
- }
- }
- private _getOutdatedWETHAddresses(): string[] {
- const outdatedWETHAddresses = _.compact(
- _.map(configs.OUTDATED_WRAPPED_ETHERS, outdatedWrappedEtherByNetwork => {
- const outdatedWrappedEtherIfExists = outdatedWrappedEtherByNetwork[this.props.networkId];
- if (_.isUndefined(outdatedWrappedEtherIfExists)) {
- return undefined;
- }
- const address = outdatedWrappedEtherIfExists.address;
- return address;
- }),
- );
- return outdatedWETHAddresses;
- }
- private _getEthToken(): Token {
- const tokens = _.values(this.props.tokenByAddress);
- const etherToken = _.find(tokens, { symbol: 'WETH' });
- return etherToken;
- }
- private async _refetchEthTokenStateAsync(): Promise<void> {
- const etherToken = this._getEthToken();
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- etherToken.address,
- );
- this.setState({
- ethTokenState: {
- balance,
- allowance,
- isLoaded: true,
- },
- });
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx
deleted file mode 100644
index 95a3671c4..000000000
--- a/packages/website/ts/components/fill_order.tsx
+++ /dev/null
@@ -1,661 +0,0 @@
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { colors, Link } from '@0x/react-shared';
-import { BigNumber, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as accounting from 'accounting';
-import * as _ from 'lodash';
-import { Card, CardHeader, CardText } from 'material-ui/Card';
-import Divider from 'material-ui/Divider';
-import RaisedButton from 'material-ui/RaisedButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { TrackTokenConfirmationDialog } from 'ts/components/dialogs/track_token_confirmation_dialog';
-import { FillOrderJSON } from 'ts/components/fill_order_json';
-import { FillWarningDialog } from 'ts/components/fill_warning_dialog';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { Alert } from 'ts/components/ui/alert';
-import { EthereumAddress } from 'ts/components/ui/ethereum_address';
-import { Identicon } from 'ts/components/ui/identicon';
-import { VisualOrder } from 'ts/components/visual_order';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
-import { validator } from 'ts/schemas/validator';
-import { AlertTypes, BlockchainErrs, PortalOrder, Token, TokenByAddress, WebsitePaths } from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { orderParser } from 'ts/utils/order_parser';
-import { utils } from 'ts/utils/utils';
-
-interface FillOrderProps {
- blockchain: Blockchain;
- blockchainErr: BlockchainErrs;
- orderFillAmount: BigNumber;
- isOrderInUrl: boolean;
- networkId: number;
- userAddress: string;
- tokenByAddress: TokenByAddress;
- initialOrder: PortalOrder;
- dispatcher: Dispatcher;
- lastForceTokenStateRefetch: number;
- isFullWidth?: boolean;
- shouldHideHeader?: boolean;
-}
-
-interface FillOrderState {
- didOrderValidationRun: boolean;
- areAllInvolvedTokensTracked: boolean;
- globalErrMsg: string;
- orderJSON: string;
- orderJSONErrMsg: string;
- parsedOrder: PortalOrder;
- didFillOrderSucceed: boolean;
- didCancelOrderSucceed: boolean;
- unavailableTakerAmount: BigNumber;
- isMakerTokenAddressInRegistry: boolean;
- isTakerTokenAddressInRegistry: boolean;
- isFillWarningDialogOpen: boolean;
- isFilling: boolean;
- isCancelling: boolean;
- isConfirmingTokenTracking: boolean;
- tokensToTrack: Token[];
-}
-
-export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
- public static defaultProps: Partial<FillOrderProps> = {
- isFullWidth: false,
- shouldHideHeader: false,
- };
- private _isUnmounted: boolean;
- constructor(props: FillOrderProps) {
- super(props);
- this._isUnmounted = false;
- this.state = {
- globalErrMsg: '',
- didOrderValidationRun: false,
- areAllInvolvedTokensTracked: false,
- didFillOrderSucceed: false,
- didCancelOrderSucceed: false,
- orderJSON: _.isUndefined(this.props.initialOrder) ? '' : JSON.stringify(this.props.initialOrder),
- orderJSONErrMsg: '',
- parsedOrder: this.props.initialOrder,
- unavailableTakerAmount: new BigNumber(0),
- isMakerTokenAddressInRegistry: false,
- isTakerTokenAddressInRegistry: false,
- isFillWarningDialogOpen: false,
- isFilling: false,
- isCancelling: false,
- isConfirmingTokenTracking: false,
- tokensToTrack: [],
- };
- }
- public componentWillMount(): void {
- if (!_.isEmpty(this.state.orderJSON)) {
- // tslint:disable-next-line:no-floating-promises
- this._validateFillOrderFireAndForgetAsync(this.state.orderJSON);
- }
- }
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public render(): React.ReactNode {
- const rootClassName = this.props.isFullWidth ? 'clearfix' : 'lg-px4 md-px4 sm-px2';
- return (
- <div className={rootClassName} style={{ minHeight: 600 }}>
- {!this.props.shouldHideHeader && (
- <div>
- <h3>Fill an order</h3>
- <Divider />
- </div>
- )}
- <div>
- {!this.props.isOrderInUrl && (
- <div>
- <div className="pt2 pb2">Paste an order JSON snippet below to begin</div>
- <div className="pb2">Order JSON</div>
- <FillOrderJSON
- blockchain={this.props.blockchain}
- tokenByAddress={this.props.tokenByAddress}
- orderJSON={this.state.orderJSON}
- onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
- />
- {this._renderOrderJsonNotices()}
- </div>
- )}
- <div>
- {!_.isUndefined(this.state.parsedOrder) &&
- this.state.didOrderValidationRun &&
- this.state.areAllInvolvedTokensTracked &&
- this._renderVisualOrder()}
- </div>
- {this.props.isOrderInUrl && (
- <div className="pt2">
- <Card
- style={{
- boxShadow: 'none',
- backgroundColor: 'none',
- border: '1px solid #eceaea',
- }}
- >
- <CardHeader title="Order JSON" actAsExpander={true} showExpandableButton={true} />
- <CardText expandable={true}>
- <FillOrderJSON
- blockchain={this.props.blockchain}
- tokenByAddress={this.props.tokenByAddress}
- orderJSON={this.state.orderJSON}
- onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
- />
- </CardText>
- </Card>
- {this._renderOrderJsonNotices()}
- </div>
- )}
- </div>
- <FillWarningDialog
- isOpen={this.state.isFillWarningDialogOpen}
- onToggleDialog={this._onFillWarningClosed.bind(this)}
- />
- <TrackTokenConfirmationDialog
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- tokenByAddress={this.props.tokenByAddress}
- dispatcher={this.props.dispatcher}
- tokens={this.state.tokensToTrack}
- isOpen={this.state.isConfirmingTokenTracking}
- onToggleDialog={this._onToggleTrackConfirmDialog.bind(this)}
- />
- </div>
- );
- }
- private _renderOrderJsonNotices(): React.ReactNode {
- return (
- <div>
- {!_.isUndefined(this.props.initialOrder) && !this.state.didOrderValidationRun && (
- <div className="pt2">
- <span className="pr1">
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- </span>
- <span>Validating order...</span>
- </div>
- )}
- {!_.isEmpty(this.state.orderJSONErrMsg) && (
- <Alert type={AlertTypes.Error} message={this.state.orderJSONErrMsg} />
- )}
- </div>
- );
- }
- private _renderVisualOrder(): React.ReactNode {
- const takerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.takerAssetData)
- .tokenAddress;
- const takerToken = this.props.tokenByAddress[takerTokenAddress];
- const orderTakerAmount = this.state.parsedOrder.signedOrder.takerAssetAmount;
- const orderMakerAmount = this.state.parsedOrder.signedOrder.makerAssetAmount;
- const takerAssetToken = {
- amount: orderTakerAmount.minus(this.state.unavailableTakerAmount),
- symbol: takerToken.symbol,
- };
- const fillToken = this.props.tokenByAddress[takerTokenAddress];
- const makerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.makerAssetData)
- .tokenAddress;
- const makerToken = this.props.tokenByAddress[makerTokenAddress];
- const makerAssetToken = {
- amount: orderMakerAmount
- .times(takerAssetToken.amount)
- .div(orderTakerAmount)
- .integerValue(BigNumber.ROUND_FLOOR),
- symbol: makerToken.symbol,
- };
- const fillAssetToken = {
- amount: this.props.orderFillAmount,
- symbol: takerToken.symbol,
- };
- const parsedOrderExpiration = this.state.parsedOrder.signedOrder.expirationTimeSeconds;
-
- let orderReceiveAmount = 0;
- if (!_.isUndefined(this.props.orderFillAmount)) {
- const orderReceiveAmountBigNumber = orderMakerAmount
- .times(this.props.orderFillAmount)
- .dividedBy(orderTakerAmount)
- .integerValue(BigNumber.ROUND_FLOOR);
- orderReceiveAmount = this._formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals);
- }
- const isUserMaker =
- !_.isUndefined(this.state.parsedOrder) &&
- this.state.parsedOrder.signedOrder.makerAddress === this.props.userAddress;
- const expiryDate = utils.convertToReadableDateTimeFromUnixTimestamp(parsedOrderExpiration);
- return (
- <div className="pt3 pb1">
- <div className="clearfix pb2" style={{ width: '100%' }}>
- <div className="inline left">Order details</div>
- <div className="inline right" style={{ minWidth: 208 }}>
- <div className="col col-4 pl2" style={{ color: colors.grey }}>
- Maker:
- </div>
- <div className="col col-2 pr1">
- <Identicon address={this.state.parsedOrder.signedOrder.makerAddress} diameter={23} />
- </div>
- <div className="col col-6">
- <EthereumAddress
- address={this.state.parsedOrder.signedOrder.makerAddress}
- networkId={this.props.networkId}
- />
- </div>
- </div>
- </div>
- <div className="lg-px4 md-px4 sm-px0">
- <div className="lg-px4 md-px4 sm-px1 pt1">
- <VisualOrder
- makerAssetToken={makerAssetToken}
- takerAssetToken={takerAssetToken}
- tokenByAddress={this.props.tokenByAddress}
- makerToken={makerToken}
- takerToken={takerToken}
- networkId={this.props.networkId}
- isMakerTokenAddressInRegistry={this.state.isMakerTokenAddressInRegistry}
- isTakerTokenAddressInRegistry={this.state.isTakerTokenAddressInRegistry}
- />
- <div className="center pt3 pb2">Expires: {expiryDate} UTC</div>
- </div>
- </div>
- {!isUserMaker && (
- <div className="clearfix mx-auto relative" style={{ width: 235, height: 108 }}>
- <TokenAmountInput
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- label="Fill amount"
- onChange={this._onFillAmountChange.bind(this)}
- shouldShowIncompleteErrs={false}
- token={fillToken}
- amount={fillAssetToken.amount}
- shouldCheckBalance={true}
- shouldCheckAllowance={true}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- />
- <div
- className="absolute sm-hide xs-hide"
- style={{
- color: colors.grey400,
- right: -247,
- top: 39,
- width: 242,
- }}
- >
- = {accounting.formatNumber(orderReceiveAmount, 6)} {makerToken.symbol}
- </div>
- </div>
- )}
- <div>
- {isUserMaker ? (
- <div>
- <RaisedButton
- style={{ width: '100%' }}
- disabled={this.state.isCancelling}
- label={this.state.isCancelling ? 'Cancelling order...' : 'Cancel order'}
- onClick={this._onCancelOrderClickFireAndForgetAsync.bind(this)}
- />
- {this.state.didCancelOrderSucceed && (
- <Alert type={AlertTypes.Success} message={this._renderCancelSuccessMsg()} />
- )}
- </div>
- ) : (
- <div>
- <RaisedButton
- style={{ width: '100%' }}
- disabled={this.state.isFilling}
- label={this.state.isFilling ? 'Filling order...' : 'Fill order'}
- onClick={this._onFillOrderClick.bind(this)}
- />
- {!_.isEmpty(this.state.globalErrMsg) && (
- <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} />
- )}
- {this.state.didFillOrderSucceed && (
- <Alert type={AlertTypes.Success} message={this._renderFillSuccessMsg()} />
- )}
- </div>
- )}
- </div>
- </div>
- );
- }
- private _renderFillSuccessMsg(): React.ReactNode {
- return (
- <div>
- Order successfully filled. See the trade details in your{' '}
- <Link to={`${WebsitePaths.Portal}/trades`} fontColor={colors.white}>
- trade history
- </Link>
- </div>
- );
- }
- private _renderCancelSuccessMsg(): React.ReactNode {
- return <div>Order successfully cancelled.</div>;
- }
- private _onFillOrderClick(): void {
- if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) {
- this.setState({
- isFillWarningDialogOpen: true,
- });
- } else {
- // tslint:disable-next-line:no-floating-promises
- this._onFillOrderClickFireAndForgetAsync();
- }
- }
- private _onFillWarningClosed(didUserCancel: boolean): void {
- this.setState({
- isFillWarningDialogOpen: false,
- });
- if (!didUserCancel) {
- // tslint:disable-next-line:no-floating-promises
- this._onFillOrderClickFireAndForgetAsync();
- }
- }
- private _onFillAmountChange(_isValid: boolean, amount?: BigNumber): void {
- this.props.dispatcher.updateOrderFillAmount(amount);
- }
- private _onFillOrderJSONChanged(event: any): void {
- const orderJSON = event.target.value;
- this.setState({
- didOrderValidationRun: _.isEmpty(orderJSON) && _.isEmpty(this.state.orderJSONErrMsg),
- didFillOrderSucceed: false,
- });
- // tslint:disable-next-line:no-floating-promises
- this._validateFillOrderFireAndForgetAsync(orderJSON);
- }
- private async _checkForUntrackedTokensAndAskToAddAsync(): Promise<void> {
- if (!_.isEmpty(this.state.orderJSONErrMsg)) {
- return;
- }
- const makerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.makerAssetData)
- .tokenAddress;
- const takerTokenAddress = assetDataUtils.decodeERC20AssetData(this.state.parsedOrder.signedOrder.takerAssetData)
- .tokenAddress;
- const makerTokenIfExists = this.props.tokenByAddress[makerTokenAddress];
- const takerTokenIfExists = this.props.tokenByAddress[takerTokenAddress];
- const tokensToTrack: Token[] = [];
- const isUnseenMakerToken = _.isUndefined(makerTokenIfExists);
- const isMakerTokenTracked = !_.isUndefined(makerTokenIfExists) && utils.isTokenTracked(makerTokenIfExists);
- if (isUnseenMakerToken) {
- tokensToTrack.push({
- ...this.state.parsedOrder.metadata.makerToken,
- address: makerTokenAddress,
- iconUrl: undefined,
- trackedTimestamp: undefined,
- isRegistered: false,
- });
- } else if (!isMakerTokenTracked) {
- tokensToTrack.push(makerTokenIfExists);
- }
- const isUnseenTakerToken = _.isUndefined(takerTokenIfExists);
- const isTakerTokenTracked = !_.isUndefined(takerTokenIfExists) && utils.isTokenTracked(takerTokenIfExists);
- if (isUnseenTakerToken) {
- tokensToTrack.push({
- ...this.state.parsedOrder.metadata.takerToken,
- address: takerTokenAddress,
- iconUrl: undefined,
- trackedTimestamp: undefined,
- isRegistered: false,
- });
- } else if (!isTakerTokenTracked) {
- tokensToTrack.push(takerTokenIfExists);
- }
- if (!_.isEmpty(tokensToTrack)) {
- this.setState({
- isConfirmingTokenTracking: true,
- tokensToTrack,
- });
- } else {
- this.setState({
- areAllInvolvedTokensTracked: true,
- });
- }
- }
- private async _validateFillOrderFireAndForgetAsync(orderJSON: string): Promise<void> {
- let orderJSONErrMsg = '';
- let parsedOrder: PortalOrder;
- let orderHash: string;
- try {
- const order = orderParser.parseJsonString(orderJSON);
- const validationResult = validator.validate(order, portalOrderSchema);
- if (validationResult.errors.length > 0) {
- orderJSONErrMsg = 'Submitted order JSON is not a valid order';
- logUtils.log(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`);
- return;
- }
- parsedOrder = order;
- const signedOrder = parsedOrder.signedOrder;
- orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const exchangeContractAddr = this.props.blockchain.getExchangeContractAddressIfExists();
- const signature = signedOrder.signature;
- const isSignatureValid = await this.props.blockchain.isValidSignatureAsync(
- orderHash,
- signature,
- signedOrder.makerAddress,
- );
- if (exchangeContractAddr !== signedOrder.exchangeAddress) {
- orderJSONErrMsg = 'This order was made on another network or using a deprecated Exchange contract';
- parsedOrder = undefined;
- } else if (!isSignatureValid) {
- orderJSONErrMsg = 'Order signature is invalid';
- parsedOrder = undefined;
- } else {
- // Update user supplied order cache so that if they navigate away from fill view
- // e.g to set a token allowance, when they come back, the fill order persists
- this.props.dispatcher.updateUserSuppliedOrderCache(parsedOrder);
- }
- } catch (err) {
- logUtils.log(`Validate order err: ${err}`);
- if (!_.isEmpty(orderJSON)) {
- orderJSONErrMsg = 'Submitted order JSON is not valid JSON';
- }
- if (!this._isUnmounted) {
- this.setState({
- didOrderValidationRun: true,
- orderJSON,
- orderJSONErrMsg,
- parsedOrder,
- });
- }
- return;
- }
-
- let unavailableTakerAmount = new BigNumber(0);
- if (!_.isEmpty(orderJSONErrMsg)) {
- // Clear cache entry if user updates orderJSON to invalid entry
- this.props.dispatcher.updateUserSuppliedOrderCache(undefined);
- } else {
- unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash);
- const makerTokenAddress = assetDataUtils.decodeERC20AssetData(parsedOrder.signedOrder.makerAssetData)
- .tokenAddress;
- const takerTokenAddress = assetDataUtils.decodeERC20AssetData(parsedOrder.signedOrder.takerAssetData)
- .tokenAddress;
- const isMakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync(
- makerTokenAddress,
- );
- const isTakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync(
- takerTokenAddress,
- );
- this.setState({
- isMakerTokenAddressInRegistry,
- isTakerTokenAddressInRegistry,
- });
- }
-
- this.setState({
- didOrderValidationRun: true,
- orderJSON,
- orderJSONErrMsg,
- parsedOrder,
- unavailableTakerAmount,
- });
-
- await this._checkForUntrackedTokensAndAskToAddAsync();
- }
- private _trackOrderEvent(eventName: string): void {
- const parsedOrder = this.state.parsedOrder;
- analytics.trackOrderEvent(eventName, parsedOrder);
- }
- private async _onFillOrderClickFireAndForgetAsync(): Promise<void> {
- if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return;
- }
-
- this.setState({
- isFilling: true,
- didFillOrderSucceed: false,
- });
-
- const parsedOrder = this.state.parsedOrder;
- const takerFillAmount = this.props.orderFillAmount;
-
- if (_.isUndefined(this.props.userAddress)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- this.setState({
- isFilling: false,
- });
- return;
- }
- let globalErrMsg = '';
-
- if (_.isUndefined(takerFillAmount)) {
- globalErrMsg = 'You must specify a fill amount';
- }
-
- const signedOrder = parsedOrder.signedOrder;
- if (_.isEmpty(globalErrMsg)) {
- try {
- await this.props.blockchain.validateFillOrderThrowIfInvalidAsync(
- signedOrder,
- takerFillAmount,
- this.props.userAddress,
- );
- } catch (err) {
- globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.signedOrder.takerAddress);
- }
- }
- if (!_.isEmpty(globalErrMsg)) {
- this.setState({
- isFilling: false,
- globalErrMsg,
- });
- return;
- }
- try {
- const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync(
- signedOrder,
- this.props.orderFillAmount,
- );
- this._trackOrderEvent('Fill Order Success');
- // After fill completes, let's force fetch the token balances
- this.props.dispatcher.forceTokenStateRefetch();
- this.setState({
- isFilling: false,
- didFillOrderSucceed: true,
- globalErrMsg: '',
- unavailableTakerAmount: this.state.unavailableTakerAmount.plus(orderFilledAmount),
- });
- return;
- } catch (err) {
- this.setState({
- isFilling: false,
- });
- this._trackOrderEvent('Fill Order Failure');
- const errMsg = `${err}`;
- if (utils.didUserDenyWeb3Request(errMsg)) {
- return;
- }
- globalErrMsg = 'Failed to fill order, please refresh and try again';
- logUtils.log(`${err}`);
- this.setState({
- globalErrMsg,
- });
- errorReporter.report(err);
- return;
- }
- }
- private async _onCancelOrderClickFireAndForgetAsync(): Promise<void> {
- if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return;
- }
-
- this.setState({
- isCancelling: true,
- didCancelOrderSucceed: false,
- });
-
- const parsedOrder = this.state.parsedOrder;
- const takerAddress = this.props.userAddress;
-
- if (_.isUndefined(takerAddress)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- this.setState({
- isFilling: false,
- });
- return;
- }
- let globalErrMsg = '';
- const signedOrder = parsedOrder.signedOrder;
- const takerTokenAmount = signedOrder.takerAssetAmount;
- if (!_.isEmpty(globalErrMsg)) {
- this.setState({
- isCancelling: false,
- globalErrMsg,
- });
- return;
- }
- try {
- await this.props.blockchain.cancelOrderAsync(signedOrder);
- this.setState({
- isCancelling: false,
- didCancelOrderSucceed: true,
- globalErrMsg: '',
- unavailableTakerAmount: takerTokenAmount,
- });
- this._trackOrderEvent('Cancel Order Success');
- return;
- } catch (err) {
- this.setState({
- isCancelling: false,
- });
- const errMsg = `${err}`;
- if (utils.didUserDenyWeb3Request(errMsg)) {
- return;
- }
- this._trackOrderEvent('Cancel Order Failure');
- globalErrMsg = 'Failed to cancel order, please refresh and try again';
- logUtils.log(`${err}`);
- this.setState({
- globalErrMsg,
- });
- errorReporter.report(err);
- return;
- }
- }
- private _formatCurrencyAmount(amount: BigNumber, decimals: number): number {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000;
- return roundedUnitAmount;
- }
- private _onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean): void {
- if (!didConfirmTokenTracking) {
- this.setState({
- orderJSON: '',
- orderJSONErrMsg: '',
- parsedOrder: undefined,
- });
- } else {
- this.setState({
- areAllInvolvedTokensTracked: true,
- });
- }
- this.setState({
- isConfirmingTokenTracking: !this.state.isConfirmingTokenTracking,
- tokensToTrack: [],
- });
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/fill_order_json.tsx b/packages/website/ts/components/fill_order_json.tsx
deleted file mode 100644
index 41413eac2..000000000
--- a/packages/website/ts/components/fill_order_json.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-import Paper from 'material-ui/Paper';
-import TextField from 'material-ui/TextField';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { Side, TokenByAddress } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-interface FillOrderJSONProps {
- blockchain: Blockchain;
- tokenByAddress: TokenByAddress;
- orderJSON: string;
- onFillOrderJSONChanged: (event: any) => void;
-}
-
-interface FillOrderJSONState {}
-
-export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrderJSONState> {
- public render(): React.ReactNode {
- const tokenAddresses = _.keys(this.props.tokenByAddress);
- const exchangeContract = this.props.blockchain.getExchangeContractAddressIfExists();
- const hintSideToAssetToken = {
- [Side.Deposit]: {
- amount: new BigNumber(35),
- address: tokenAddresses[0],
- },
- [Side.Receive]: {
- amount: new BigNumber(89),
- address: tokenAddresses[1],
- },
- };
- const hintOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec();
- const hintECSignature = '0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33';
- const hintSalt = generatePseudoRandomSalt();
- const feeRecipient = constants.NULL_ADDRESS;
- const hintOrder = utils.generateOrder(
- exchangeContract,
- hintSideToAssetToken,
- hintOrderExpiryTimestamp,
- '',
- '',
- constants.MAKER_FEE,
- constants.TAKER_FEE,
- feeRecipient,
- hintECSignature,
- this.props.tokenByAddress,
- hintSalt,
- );
- const hintOrderJSON = `${JSON.stringify(hintOrder, null, '\t').substring(0, 500)}...`;
- return (
- <div>
- <Paper className="p1 overflow-hidden" style={{ height: 164 }}>
- <TextField
- id="orderJSON"
- hintStyle={{ bottom: 0, top: 0 }}
- fullWidth={true}
- value={this.props.orderJSON}
- onChange={this.props.onFillOrderJSONChanged.bind(this)}
- hintText={hintOrderJSON}
- multiLine={true}
- rows={6}
- rowsMax={6}
- underlineStyle={{ display: 'none' }}
- textareaStyle={{ marginTop: 0 }}
- />
- </Paper>
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/fill_warning_dialog.tsx b/packages/website/ts/components/fill_warning_dialog.tsx
deleted file mode 100644
index 5be09e6c2..000000000
--- a/packages/website/ts/components/fill_warning_dialog.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { colors } from '@0x/react-shared';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-
-interface FillWarningDialogProps {
- isOpen: boolean;
- onToggleDialog: (didUserCancel: boolean) => void;
-}
-
-export const FillWarningDialog = (props: FillWarningDialogProps) => {
- const didCancel = true;
- return (
- <Dialog
- title="Warning"
- titleStyle={{ fontWeight: 100, color: colors.red500 }}
- actions={[
- <FlatButton
- key="fillWarningCancel"
- label="Cancel"
- onClick={() => props.onToggleDialog(didCancel)} // tslint:disable-line:jsx-no-lambda
- />,
- <FlatButton
- key="fillWarningContinue"
- label="Fill Order"
- onClick={() => props.onToggleDialog(!didCancel)} // tslint:disable-line:jsx-no-lambda
- />,
- ]}
- open={props.isOpen}
- onRequestClose={() => props.onToggleDialog(didCancel)} // tslint:disable-line:jsx-no-lambda
- autoScrollBodyContent={true}
- modal={true}
- >
- <div className="pt2" style={{ color: colors.grey700 }}>
- <div>
- At least one of the tokens in this order was not found in the token registry smart contract and may
- be counterfeit. It is your responsibility to verify the token addresses on Etherscan (
- <a href="https://0x.org/wiki#Verifying-Custom-Tokens" target="_blank">
- See this how-to guide
- </a>
- ) before filling an order. <b>This action may result in the loss of funds</b>.
- </div>
- </div>
- </Dialog>
- );
-};
diff --git a/packages/website/ts/components/flash_messages/asset_send_completed.tsx b/packages/website/ts/components/flash_messages/asset_send_completed.tsx
deleted file mode 100644
index b895126dc..000000000
--- a/packages/website/ts/components/flash_messages/asset_send_completed.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { utils } from 'ts/utils/utils';
-
-interface AssetSendCompletedProps {
- etherScanLinkIfExists?: string;
- toAddress: string;
- amountInBaseUnits: BigNumber;
- decimals: number;
- symbol: string;
-}
-
-interface AssetSendCompletedState {}
-
-export class AssetSendCompleted extends React.Component<AssetSendCompletedProps, AssetSendCompletedState> {
- public render(): React.ReactNode {
- const etherScanLink = !_.isUndefined(this.props.etherScanLinkIfExists) && (
- <a style={{ color: colors.white }} href={`${this.props.etherScanLinkIfExists}`} target="_blank">
- Verify on Etherscan
- </a>
- );
- const amountInUnits = Web3Wrapper.toUnitAmount(this.props.amountInBaseUnits, this.props.decimals);
- const truncatedAddress = utils.getAddressBeginAndEnd(this.props.toAddress);
- return (
- <div>
- {`Sent ${amountInUnits} ${this.props.symbol} to ${truncatedAddress}: `}
- {etherScanLink}
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/flash_messages/transaction_submitted.tsx b/packages/website/ts/components/flash_messages/transaction_submitted.tsx
deleted file mode 100644
index b1d909baa..000000000
--- a/packages/website/ts/components/flash_messages/transaction_submitted.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-interface TransactionSubmittedProps {
- etherScanLinkIfExists?: string;
-}
-
-interface TransactionSubmittedState {}
-
-export class TransactionSubmitted extends React.Component<TransactionSubmittedProps, TransactionSubmittedState> {
- public render(): React.ReactNode {
- if (_.isUndefined(this.props.etherScanLinkIfExists)) {
- return <div>Transaction submitted to the network</div>;
- } else {
- return (
- <div>
- Transaction submitted to the network:{' '}
- <a style={{ color: colors.white }} href={`${this.props.etherScanLinkIfExists}`} target="_blank">
- Verify on Etherscan
- </a>
- </div>
- );
- }
- }
-}
diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx
deleted file mode 100644
index 3765a32ca..000000000
--- a/packages/website/ts/components/footer.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import { Link as SmartLink } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import MediaQuery from 'react-responsive';
-import styled from 'styled-components';
-
-import { Logo } from 'ts/components/logo';
-import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
-import { NewsletterForm } from 'ts/components/newsletter_form';
-import { WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-interface LinkInterface {
- text: string;
- url: string;
- shouldOpenInNewTab?: boolean;
-}
-
-interface LinkRows {
- heading: string;
- isOnMobile?: boolean;
- links: LinkInterface[];
-}
-
-interface LinkListProps {
- links: LinkInterface[];
-}
-
-const linkRows: LinkRows[] = [
- {
- heading: 'Products',
- isOnMobile: true,
- links: [
- { url: WebsitePaths.Instant, text: '0x Instant' },
- { url: WebsitePaths.LaunchKit, text: '0x Launch Kit' },
- ],
- },
- {
- heading: 'Developers',
- links: [
- { url: WebsitePaths.Docs, text: 'Documentation' },
- { url: constants.URL_GITHUB_ORG, text: 'GitHub', shouldOpenInNewTab: true },
- { url: constants.URL_PROTOCOL_SPECIFICATION, text: 'Protocol Spec', shouldOpenInNewTab: true },
- ],
- },
- {
- heading: 'About',
- isOnMobile: true,
- links: [
- { url: WebsitePaths.AboutMission, text: 'Mission' },
- { url: WebsitePaths.AboutTeam, text: 'Team' },
- { url: WebsitePaths.AboutJobs, text: 'Jobs' },
- { url: WebsitePaths.AboutPress, text: 'Press' },
- { url: WebsitePaths.Ecosystem, text: 'Grant Program' },
- ],
- },
- {
- heading: 'Community',
- isOnMobile: true,
- links: [
- { url: constants.URL_TWITTER, text: 'Twitter', shouldOpenInNewTab: true },
- { url: constants.URL_ZEROEX_CHAT, text: 'Discord Chat', shouldOpenInNewTab: true },
- { url: constants.URL_FACEBOOK, text: 'Facebook', shouldOpenInNewTab: true },
- { url: constants.URL_REDDIT, text: 'Reddit', shouldOpenInNewTab: true },
- ],
- },
-];
-
-export const Footer: React.StatelessComponent = () => (
- <FooterWrap>
- <FlexWrap>
- <FooterColumn width="35%">
- <Logo />
- <NewsletterForm />
- </FooterColumn>
-
- <FooterColumn width="55%">
- <WrapGrid isCentered={false} isWrapped={true}>
- {_.map(linkRows, (row: LinkRows, index) => (
- <MediaQuery minWidth={row.isOnMobile ? 0 : 768} key={`fc-${index}`}>
- <FooterSectionWrap>
- <RowHeading>{row.heading}</RowHeading>
-
- <LinkList links={row.links} />
- </FooterSectionWrap>
- </MediaQuery>
- ))}
- </WrapGrid>
- </FooterColumn>
- </FlexWrap>
- </FooterWrap>
-);
-
-const LinkList = (props: LinkListProps) => (
- <List>
- {_.map(props.links, (link, index) => (
- <li key={`fl-${index}`}>
- <Link to={link.url} shouldOpenInNewTab={link.shouldOpenInNewTab}>
- {link.text}
- </Link>
- </li>
- ))}
- </List>
-);
-
-const FooterWrap = styled.footer`
- padding: 40px 30px 30px 30px;
- margin-top: 30px;
- background-color: ${props => props.theme.footerBg};
- color: ${props => props.theme.footerColor};
-
- path {
- fill: ${props => props.theme.footerColor};
- }
-
- @media (min-width: 768px) {
- height: 350px;
- }
-`;
-
-const FooterColumn = styled(Column)`
- @media (min-width: 768px) {
- width: ${props => props.width};
- }
-
- @media (max-width: 768px) {
- text-align: left;
- }
-`;
-
-const FooterSectionWrap = styled(FooterColumn)`
- @media (max-width: 768px) {
- width: 50%;
-
- & + & {
- margin-top: 0;
- margin-bottom: 30px;
- }
- }
-`;
-
-const RowHeading = styled.h3`
- color: inherit;
- font-weight: 700;
- font-size: 16px;
- margin-bottom: 1.25em;
- opacity: 0.75;
-`;
-
-const List = styled.ul`
- li + li {
- margin-top: 8px;
- }
-`;
-
-const Link = styled(SmartLink)`
- color: inherit;
- opacity: 0.5;
- display: block;
- font-size: 16px;
- line-height: 20px;
- transition: opacity 0.25s;
- text-decoration: none;
-
- &:hover {
- opacity: 0.8;
- }
-`;
diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx
deleted file mode 100644
index d3f11f962..000000000
--- a/packages/website/ts/components/generate_order/asset_picker.tsx
+++ /dev/null
@@ -1,284 +0,0 @@
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as moment from 'moment';
-import * as React from 'react';
-import firstBy from 'thenby';
-
-import { Blockchain } from 'ts/blockchain';
-import { NewTokenForm } from 'ts/components/generate_order/new_token_form';
-import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation';
-import { TokenIcon } from 'ts/components/ui/token_icon';
-import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { DialogConfigs, Token, TokenByAddress, TokenVisibility } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-const TOKEN_ICON_DIMENSION = 100;
-const TILE_DIMENSION = 146;
-enum AssetViews {
- AssetPicker = 'ASSET_PICKER',
- NewTokenForm = 'NEW_TOKEN_FORM',
- ConfirmTrackToken = 'CONFIRM_TRACK_TOKEN',
-}
-
-interface AssetPickerProps {
- userAddress: string;
- blockchain: Blockchain;
- dispatcher: Dispatcher;
- networkId: number;
- isOpen: boolean;
- currentTokenAddress: string;
- onTokenChosen: (tokenAddress: string) => void;
- tokenByAddress: TokenByAddress;
- tokenVisibility?: TokenVisibility;
-}
-
-interface AssetPickerState {
- assetView: AssetViews;
- hoveredAddress: string | undefined;
- chosenTrackTokenAddress: string;
- isAddingTokenToTracked: boolean;
-}
-
-export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerState> {
- public static defaultProps: Partial<AssetPickerProps> = {
- tokenVisibility: TokenVisibility.All,
- };
- private readonly _dialogConfigsByAssetView: { [assetView: string]: DialogConfigs };
- constructor(props: AssetPickerProps) {
- super(props);
- this.state = {
- assetView: AssetViews.AssetPicker,
- hoveredAddress: undefined,
- chosenTrackTokenAddress: undefined,
- isAddingTokenToTracked: false,
- };
- this._dialogConfigsByAssetView = {
- [AssetViews.AssetPicker]: {
- title: 'Select token',
- isModal: false,
- actions: [],
- },
- [AssetViews.NewTokenForm]: {
- title: 'Add an ERC20 token',
- isModal: false,
- actions: [],
- },
- [AssetViews.ConfirmTrackToken]: {
- title: 'Tracking confirmation',
- isModal: true,
- actions: [
- <FlatButton
- key="noTracking"
- label="No"
- onClick={this._onTrackConfirmationRespondedAsync.bind(this, false)}
- />,
- <FlatButton
- key="yesTrack"
- label="Yes"
- onClick={this._onTrackConfirmationRespondedAsync.bind(this, true)}
- />,
- ],
- },
- };
- }
- public render(): React.ReactNode {
- const dialogConfigs: DialogConfigs = this._dialogConfigsByAssetView[this.state.assetView];
- return (
- <Dialog
- title={dialogConfigs.title}
- modal={dialogConfigs.isModal}
- open={this.props.isOpen}
- actions={dialogConfigs.actions}
- autoScrollBodyContent={true}
- onRequestClose={this._onCloseDialog.bind(this)}
- >
- {this.state.assetView === AssetViews.AssetPicker && this._renderAssetPicker()}
- {this.state.assetView === AssetViews.NewTokenForm && (
- <NewTokenForm
- blockchain={this.props.blockchain}
- onNewTokenSubmitted={this._onNewTokenSubmitted.bind(this)}
- tokenByAddress={this.props.tokenByAddress}
- />
- )}
- {this.state.assetView === AssetViews.ConfirmTrackToken && this._renderConfirmTrackToken()}
- </Dialog>
- );
- }
- private _renderConfirmTrackToken(): React.ReactNode {
- const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress];
- return (
- <TrackTokenConfirmation
- tokens={[token]}
- tokenByAddress={this.props.tokenByAddress}
- networkId={this.props.networkId}
- isAddingTokenToTracked={this.state.isAddingTokenToTracked}
- />
- );
- }
- private _renderAssetPicker(): React.ReactNode {
- return (
- <div
- className="flex flex-wrap"
- style={{
- maxWidth: 1000,
- maxHeight: 600,
- marginBottom: 10,
- }}
- >
- {this._renderGridTiles()}
- </div>
- );
- }
- private _renderGridTiles(): React.ReactNode {
- let isHovered;
- let tileStyles;
- const allTokens = _.values(this.props.tokenByAddress);
- // filter tokens based on visibility specified in props, do not show ZRX or ETHER as tracked or untracked
- const filteredTokens =
- this.props.tokenVisibility === TokenVisibility.All
- ? allTokens
- : _.filter(allTokens, token => {
- return (
- token.symbol !== constants.ZRX_TOKEN_SYMBOL &&
- token.symbol !== constants.ETHER_TOKEN_SYMBOL &&
- ((this.props.tokenVisibility === TokenVisibility.Tracked && utils.isTokenTracked(token)) ||
- (this.props.tokenVisibility === TokenVisibility.Untracked &&
- !utils.isTokenTracked(token)))
- );
- });
- // if we are showing tracked tokens, sort by date added, otherwise sort by symbol
- const sortKey = this.props.tokenVisibility === TokenVisibility.Tracked ? 'trackedTimestamp' : 'symbol';
- const sortedTokens = filteredTokens.sort(firstBy(sortKey));
- if (_.isEmpty(sortedTokens)) {
- return <div className="mx-auto p4 h2">No tokens to remove.</div>;
- }
- const gridTiles = _.map(sortedTokens, token => {
- const address = token.address;
- isHovered = this.state.hoveredAddress === address;
- tileStyles = {
- cursor: 'pointer',
- opacity: isHovered ? 0.6 : 1,
- };
- return (
- <div
- key={address}
- style={{
- width: TILE_DIMENSION,
- height: TILE_DIMENSION,
- ...tileStyles,
- }}
- className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto"
- onClick={this._onChooseToken.bind(this, address)}
- onMouseEnter={this._onToggleHover.bind(this, address, true)}
- onMouseLeave={this._onToggleHover.bind(this, address, false)}
- >
- <div className="p1">
- <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} />
- </div>
- <div className="center">{token.symbol}</div>
- </div>
- );
- });
- const otherTokenKey = 'otherToken';
- isHovered = this.state.hoveredAddress === otherTokenKey;
- tileStyles = {
- cursor: 'pointer',
- opacity: isHovered ? 0.6 : 1,
- };
- if (this.props.tokenVisibility !== TokenVisibility.Tracked) {
- gridTiles.push(
- <div
- key={otherTokenKey}
- style={{
- width: TILE_DIMENSION,
- height: TILE_DIMENSION,
- ...tileStyles,
- }}
- className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto"
- onClick={this._onCustomAssetChosen.bind(this)}
- onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)}
- onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)}
- >
- <div className="p1 center">
- <i
- style={{ fontSize: 105, paddingLeft: 1, paddingRight: 1 }}
- className="zmdi zmdi-plus-circle"
- />
- </div>
- <div className="center">Other ERC20 Token</div>
- </div>,
- );
- }
- return gridTiles;
- }
- private _onToggleHover(address: string, isHovered: boolean): void {
- const hoveredAddress = isHovered ? address : undefined;
- this.setState({
- hoveredAddress,
- });
- }
- private _onCloseDialog(): void {
- this.setState({
- assetView: AssetViews.AssetPicker,
- });
- this.props.onTokenChosen(this.props.currentTokenAddress);
- }
- private _onChooseToken(tokenAddress: string): void {
- const token = this.props.tokenByAddress[tokenAddress];
- if (utils.isTokenTracked(token)) {
- this.props.onTokenChosen(tokenAddress);
- } else {
- this.setState({
- assetView: AssetViews.ConfirmTrackToken,
- chosenTrackTokenAddress: tokenAddress,
- });
- }
- }
- private _onCustomAssetChosen(): void {
- this.setState({
- assetView: AssetViews.NewTokenForm,
- });
- }
- private _onNewTokenSubmitted(newToken: Token): void {
- trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newToken);
- this.props.dispatcher.addTokenToTokenByAddress(newToken);
- this.setState({
- assetView: AssetViews.AssetPicker,
- });
- this.props.onTokenChosen(newToken.address);
- }
- private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean): Promise<void> {
- const resetState: AssetPickerState = {
- ...this.state,
- isAddingTokenToTracked: false,
- assetView: AssetViews.AssetPicker,
- chosenTrackTokenAddress: undefined,
- };
- if (!didUserAcceptTracking) {
- this.setState(resetState);
- this._onCloseDialog();
- return;
- }
- this.setState({
- isAddingTokenToTracked: true,
- });
- const tokenAddress = this.state.chosenTrackTokenAddress;
- const token = this.props.tokenByAddress[tokenAddress];
- if (_.isUndefined(tokenAddress)) {
- this.setState(resetState);
- return;
- }
- const newTokenEntry = {
- ...token,
- trackedTimestamp: moment().unix(),
- };
- trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry);
-
- this.props.dispatcher.updateTokenByAddress([newTokenEntry]);
- this.setState(resetState);
- this.props.onTokenChosen(tokenAddress);
- }
-}
diff --git a/packages/website/ts/components/generate_order/generate_order_form.tsx b/packages/website/ts/components/generate_order/generate_order_form.tsx
deleted file mode 100644
index 0f70aa18f..000000000
--- a/packages/website/ts/components/generate_order/generate_order_form.tsx
+++ /dev/null
@@ -1,385 +0,0 @@
-import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils';
-import { colors } from '@0x/react-shared';
-import { Order as ZeroExOrder } from '@0x/types';
-import { BigNumber, logUtils } from '@0x/utils';
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import Divider from 'material-ui/Divider';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { ExpirationInput } from 'ts/components/inputs/expiration_input';
-import { HashInput } from 'ts/components/inputs/hash_input';
-import { IdenticonAddressInput } from 'ts/components/inputs/identicon_address_input';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { TokenInput } from 'ts/components/inputs/token_input';
-import { OrderJSON } from 'ts/components/order_json';
-import { Alert } from 'ts/components/ui/alert';
-import { HelpTooltip } from 'ts/components/ui/help_tooltip';
-import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
-import { SwapIcon } from 'ts/components/ui/swap_icon';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
-import { validator } from 'ts/schemas/validator';
-import {
- AlertTypes,
- BlockchainErrs,
- HashData,
- PortalOrder,
- Side,
- SideToAssetToken,
- Token,
- TokenByAddress,
-} from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-enum SigningState {
- Unsigned,
- Signing,
- Signed,
-}
-
-interface GenerateOrderFormProps {
- blockchain: Blockchain;
- blockchainErr: BlockchainErrs;
- blockchainIsLoaded: boolean;
- dispatcher: Dispatcher;
- hashData: HashData;
- orderExpiryTimestamp: BigNumber;
- networkId: number;
- userAddress: string;
- orderSignature: string;
- orderTakerAddress: string;
- orderSalt: BigNumber;
- sideToAssetToken: SideToAssetToken;
- tokenByAddress: TokenByAddress;
- lastForceTokenStateRefetch: number;
- isFullWidth?: boolean;
- shouldHideHeader?: boolean;
-}
-
-interface GenerateOrderFormState {
- globalErrMsg: string;
- shouldShowIncompleteErrs: boolean;
- signingState: SigningState;
-}
-
-export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> {
- public static defaultProps: Partial<GenerateOrderFormProps> = {
- isFullWidth: false,
- shouldHideHeader: false,
- };
- constructor(props: GenerateOrderFormProps) {
- super(props);
- this.state = {
- globalErrMsg: '',
- shouldShowIncompleteErrs: false,
- signingState: SigningState.Unsigned,
- };
- }
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- }
- public render(): React.ReactNode {
- const dispatcher = this.props.dispatcher;
- const depositTokenAddress = this.props.sideToAssetToken[Side.Deposit].address;
- const depositToken = this.props.tokenByAddress[depositTokenAddress];
- const receiveTokenAddress = this.props.sideToAssetToken[Side.Receive].address;
- const receiveToken = this.props.tokenByAddress[receiveTokenAddress];
- const takerExplanation =
- 'If a taker is specified, only they are<br> \
- allowed to fill this order. If no taker is<br> \
- specified, anyone is able to fill it.';
- const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists();
- const initialTakerAddress =
- this.props.orderTakerAddress === constants.NULL_ADDRESS ? '' : this.props.orderTakerAddress;
- const rootClassName = this.props.isFullWidth ? 'clearfix mb2' : 'clearfix mb2 lg-px4 md-px4 sm-px2';
- return (
- <div className={rootClassName}>
- {!this.props.shouldHideHeader && (
- <div>
- <h3>Generate an order</h3>
- <Divider />
- </div>
- )}
- <div className="mx-auto" style={{ maxWidth: 580 }}>
- <div className="pt3">
- <div className="mx-auto clearfix">
- <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2">
- <TokenInput
- userAddress={this.props.userAddress}
- blockchain={this.props.blockchain}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- label="Selling"
- side={Side.Deposit}
- networkId={this.props.networkId}
- assetToken={this.props.sideToAssetToken[Side.Deposit]}
- updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)}
- tokenByAddress={this.props.tokenByAddress}
- />
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- label="Sell amount"
- token={depositToken}
- amount={this.props.sideToAssetToken[Side.Deposit].amount}
- onChange={this._onTokenAmountChange.bind(this, depositToken, Side.Deposit)}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={true}
- shouldCheckAllowance={true}
- />
- </div>
- <div className="lg-col md-col lg-col-2 md-col-2 sm-col sm-col-2 xs-hide">
- <div className="p1">
- <SwapIcon swapTokensFn={dispatcher.swapAssetTokenSymbols.bind(dispatcher)} />
- </div>
- </div>
- <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2">
- <TokenInput
- userAddress={this.props.userAddress}
- blockchain={this.props.blockchain}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- label="Buying"
- side={Side.Receive}
- networkId={this.props.networkId}
- assetToken={this.props.sideToAssetToken[Side.Receive]}
- updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)}
- tokenByAddress={this.props.tokenByAddress}
- />
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- label="Receive amount"
- token={receiveToken}
- amount={this.props.sideToAssetToken[Side.Receive].amount}
- onChange={this._onTokenAmountChange.bind(this, receiveToken, Side.Receive)}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={false}
- shouldCheckAllowance={false}
- />
- </div>
- </div>
- </div>
- <div className="pt1 sm-pb2 lg-px4 md-px4">
- <div className="lg-px3 md-px3">
- <div style={{ fontSize: 12, color: colors.grey }}>Expiration</div>
- <ExpirationInput
- orderExpiryTimestamp={this.props.orderExpiryTimestamp}
- updateOrderExpiry={dispatcher.updateOrderExpiry.bind(dispatcher)}
- />
- </div>
- </div>
- <div className="pt1 flex mx-auto">
- <IdenticonAddressInput
- label="Taker"
- initialAddress={initialTakerAddress}
- updateOrderAddress={this._updateOrderAddress.bind(this)}
- />
- <div className="pt3">
- <div className="pl1">
- <HelpTooltip explanation={takerExplanation} />
- </div>
- </div>
- </div>
- <div>
- <HashInput
- blockchain={this.props.blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- hashData={this.props.hashData}
- label="Order Hash"
- />
- </div>
- <div className="pt2">
- <div className="center">
- <LifeCycleRaisedButton
- labelReady="Sign hash"
- labelLoading="Signing..."
- labelComplete="Hash signed!"
- onClickAsyncFn={this._onSignClickedAsync.bind(this)}
- />
- </div>
- {this.state.globalErrMsg !== '' && (
- <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} />
- )}
- </div>
- </div>
- <Dialog
- title="Order JSON"
- titleStyle={{ fontWeight: 100 }}
- modal={false}
- open={this.state.signingState === SigningState.Signed}
- onRequestClose={this._onCloseOrderJSONDialog.bind(this)}
- >
- <OrderJSON
- exchangeContractIfExists={exchangeContractIfExists}
- orderExpiryTimestamp={this.props.orderExpiryTimestamp}
- orderSignature={this.props.orderSignature}
- orderTakerAddress={this.props.orderTakerAddress}
- orderMakerAddress={this.props.userAddress}
- orderSalt={this.props.orderSalt}
- orderMakerFee={this.props.hashData.makerFee}
- orderTakerFee={this.props.hashData.takerFee}
- orderFeeRecipient={this.props.hashData.feeRecipientAddress}
- sideToAssetToken={this.props.sideToAssetToken}
- tokenByAddress={this.props.tokenByAddress}
- />
- </Dialog>
- </div>
- );
- }
- private _onTokenAmountChange(token: Token, side: Side, _isValid: boolean, amount?: BigNumber): void {
- this.props.dispatcher.updateChosenAssetToken(side, {
- address: token.address,
- amount,
- });
- }
- private _onCloseOrderJSONDialog(): void {
- // Upon closing the order JSON dialog, we update the orderSalt stored in the Redux store
- // with a new value so that if a user signs the identical order again, the newly signed
- // orderHash will not collide with the previously generated orderHash.
- this.props.dispatcher.updateOrderSalt(generatePseudoRandomSalt());
- this.setState({
- signingState: SigningState.Unsigned,
- });
- }
- private async _onSignClickedAsync(): Promise<boolean> {
- if (this.props.blockchainErr !== BlockchainErrs.NoError) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return false;
- }
-
- // Check if all required inputs were supplied
- const debitToken = this.props.sideToAssetToken[Side.Deposit];
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const [debitBalance, debitAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- debitToken.address,
- );
- const receiveToken = this.props.sideToAssetToken[Side.Receive];
- const receiveAmount = receiveToken.amount;
- if (
- !_.isUndefined(debitToken.amount) &&
- !_.isUndefined(receiveAmount) &&
- debitToken.amount.gt(0) &&
- receiveAmount.gt(0) &&
- this.props.userAddress !== '' &&
- debitBalance.gte(debitToken.amount) &&
- debitAllowance.gte(debitToken.amount)
- ) {
- const signedOrder = await this._signTransactionAsync();
- const doesSignedOrderExist = !_.isUndefined(signedOrder);
- if (doesSignedOrderExist) {
- analytics.trackOrderEvent('Sign Order Success', signedOrder);
- this.setState({
- globalErrMsg: '',
- shouldShowIncompleteErrs: false,
- });
- }
- return doesSignedOrderExist;
- } else {
- let globalErrMsg = 'You must fix the above errors in order to generate a valid order';
- if (this.props.userAddress === '') {
- globalErrMsg = 'You must enable wallet communication';
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- }
- analytics.track('Sign Order Failure', {
- makerTokenAmount: debitToken.amount.toString(),
- makerToken: this.props.tokenByAddress[debitToken.address].symbol,
- takerTokenAmount: receiveToken.amount.toString(),
- takerToken: this.props.tokenByAddress[receiveToken.address].symbol,
- });
- this.setState({
- globalErrMsg,
- shouldShowIncompleteErrs: true,
- });
- return false;
- }
- }
- private async _signTransactionAsync(): Promise<PortalOrder | undefined> {
- this.setState({
- signingState: SigningState.Signing,
- });
- const exchangeAddress = this.props.blockchain.getExchangeContractAddressIfExists();
- if (_.isUndefined(exchangeAddress)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- this.setState({
- signingState: SigningState.Unsigned,
- });
- return undefined;
- }
- const hashData = this.props.hashData;
-
- const makerAssetData = assetDataUtils.encodeERC20AssetData(hashData.depositTokenContractAddr);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(hashData.receiveTokenContractAddr);
- const zeroExOrder: ZeroExOrder = {
- senderAddress: constants.NULL_ADDRESS,
- exchangeAddress,
- expirationTimeSeconds: hashData.orderExpiryTimestamp,
- feeRecipientAddress: hashData.feeRecipientAddress,
- makerAddress: hashData.orderMakerAddress,
- makerFee: hashData.makerFee,
- makerAssetData,
- makerAssetAmount: hashData.depositAmount,
- salt: hashData.orderSalt,
- takerAddress: hashData.orderTakerAddress,
- takerFee: hashData.takerFee,
- takerAssetData,
- takerAssetAmount: hashData.receiveAmount,
- };
- const orderHash = orderHashUtils.getOrderHashHex(zeroExOrder);
-
- let globalErrMsg = '';
- let order;
- try {
- const signature = await this.props.blockchain.signOrderHashAsync(orderHash);
- order = utils.generateOrder(
- exchangeAddress,
- this.props.sideToAssetToken,
- hashData.orderExpiryTimestamp,
- this.props.orderTakerAddress,
- this.props.userAddress,
- hashData.makerFee,
- hashData.takerFee,
- hashData.feeRecipientAddress,
- signature,
- this.props.tokenByAddress,
- hashData.orderSalt,
- );
- const validationResult = validator.validate(order, portalOrderSchema);
- if (validationResult.errors.length > 0) {
- globalErrMsg = 'Order signing failed. Please refresh and try again';
- logUtils.log(`Unexpected error occured: Order validation failed:
- ${validationResult.errors}`);
- }
- } catch (err) {
- const errMsg = `${err}`;
- if (utils.didUserDenyWeb3Request(errMsg)) {
- globalErrMsg = 'User denied sign request';
- } else {
- globalErrMsg = 'An unexpected error occured. Please try refreshing the page';
- logUtils.log(`Unexpected error occured: ${err}`);
- logUtils.log(err.stack);
- errorReporter.report(err);
- }
- }
- this.setState({
- signingState: globalErrMsg === '' ? SigningState.Signed : SigningState.Unsigned,
- globalErrMsg,
- });
- return order;
- }
- private _updateOrderAddress(address?: string): void {
- if (!_.isUndefined(address)) {
- const normalizedAddress = _.isEmpty(address) ? constants.NULL_ADDRESS : address;
- this.props.dispatcher.updateOrderTakerAddress(normalizedAddress);
- }
- }
-}
diff --git a/packages/website/ts/components/generate_order/new_token_form.tsx b/packages/website/ts/components/generate_order/new_token_form.tsx
deleted file mode 100644
index ce684d177..000000000
--- a/packages/website/ts/components/generate_order/new_token_form.tsx
+++ /dev/null
@@ -1,229 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import TextField from 'material-ui/TextField';
-import * as moment from 'moment';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { AddressInput } from 'ts/components/inputs/address_input';
-import { Alert } from 'ts/components/ui/alert';
-import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
-import { RequiredLabel } from 'ts/components/ui/required_label';
-import { AlertTypes, Token, TokenByAddress } from 'ts/types';
-
-interface NewTokenFormProps {
- blockchain: Blockchain;
- tokenByAddress: TokenByAddress;
- onNewTokenSubmitted: (token: Token) => void;
-}
-
-interface NewTokenFormState {
- globalErrMsg: string;
- name: string;
- nameErrText: string;
- symbol: string;
- symbolErrText: string;
- address: string;
- shouldShowAddressIncompleteErr: boolean;
- decimals: string;
- decimalsErrText: string;
-}
-
-export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFormState> {
- constructor(props: NewTokenFormProps) {
- super(props);
- this.state = {
- address: '',
- globalErrMsg: '',
- name: '',
- nameErrText: '',
- shouldShowAddressIncompleteErr: false,
- symbol: '',
- symbolErrText: '',
- decimals: '18',
- decimalsErrText: '',
- };
- }
- public render(): React.ReactNode {
- return (
- <div className="mx-auto pb2" style={{ width: 256 }}>
- <div>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText={<RequiredLabel label="Name" />}
- value={this.state.name}
- errorText={this.state.nameErrText}
- onChange={this._onTokenNameChanged.bind(this)}
- />
- </div>
- <div>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText={<RequiredLabel label="Symbol" />}
- value={this.state.symbol}
- errorText={this.state.symbolErrText}
- onChange={this._onTokenSymbolChanged.bind(this)}
- />
- </div>
- <div>
- <AddressInput
- isRequired={true}
- label="Contract address"
- initialAddress=""
- shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr}
- updateAddress={this._onTokenAddressChanged.bind(this)}
- />
- </div>
- <div>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText={<RequiredLabel label="Decimals" />}
- value={this.state.decimals}
- errorText={this.state.decimalsErrText}
- onChange={this._onTokenDecimalsChanged.bind(this)}
- />
- </div>
- <div className="pt2 mx-auto" style={{ width: 120 }}>
- <LifeCycleRaisedButton
- labelReady="Add"
- labelLoading="Adding..."
- labelComplete="Added!"
- onClickAsyncFn={this._onAddNewTokenClickAsync.bind(this)}
- />
- </div>
- {this.state.globalErrMsg !== '' && <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} />}
- </div>
- );
- }
- private async _onAddNewTokenClickAsync(): Promise<void> {
- // Trigger validation of name and symbol
- this._onTokenNameChanged(undefined, this.state.name);
- this._onTokenSymbolChanged(undefined, this.state.symbol);
- this._onTokenDecimalsChanged(undefined, this.state.decimals);
-
- const isAddressIncomplete = this.state.address === '';
- let doesContractExist = false;
- if (!isAddressIncomplete) {
- doesContractExist = await this.props.blockchain.doesContractExistAtAddressAsync(this.state.address);
- }
-
- let hasBalanceAllowanceErr = false;
- if (doesContractExist) {
- try {
- await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync(this.state.address);
- } catch (err) {
- hasBalanceAllowanceErr = true;
- }
- }
-
- let globalErrMsg = '';
- if (
- this.state.nameErrText !== '' ||
- this.state.symbolErrText !== '' ||
- this.state.decimalsErrText !== '' ||
- isAddressIncomplete
- ) {
- globalErrMsg = 'Please fix the above issues';
- } else if (!doesContractExist) {
- globalErrMsg = 'No contract found at supplied address';
- } else if (hasBalanceAllowanceErr) {
- globalErrMsg = 'Unsuccessful call to `balanceOf` and/or `allowance` on supplied contract address';
- } else if (!isAddressIncomplete && !_.isUndefined(this.props.tokenByAddress[this.state.address])) {
- globalErrMsg = 'A token already exists with this address';
- }
-
- if (globalErrMsg !== '') {
- this.setState({
- globalErrMsg,
- shouldShowAddressIncompleteErr: isAddressIncomplete,
- });
- return;
- }
-
- const newToken: Token = {
- address: this.state.address,
- decimals: _.parseInt(this.state.decimals),
- iconUrl: undefined,
- name: this.state.name,
- symbol: this.state.symbol.toUpperCase(),
- trackedTimestamp: moment().unix(),
- isRegistered: false,
- };
- this.props.onNewTokenSubmitted(newToken);
- }
- private _onTokenNameChanged(_event: any, name: string): void {
- let nameErrText = '';
- const maxLength = 30;
- const tokens = _.values(this.props.tokenByAddress);
- const tokenWithNameIfExists = _.find(tokens, { name });
- const doesTokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
- if (name === '') {
- nameErrText = 'Name is required';
- } else if (!this._isValidName(name)) {
- nameErrText = 'Name should only contain letters, digits and spaces';
- } else if (name.length > maxLength) {
- nameErrText = `Max length is ${maxLength}`;
- } else if (doesTokenWithNameExists) {
- nameErrText = 'Token with this name already exists';
- }
-
- this.setState({
- name,
- nameErrText,
- });
- }
- private _onTokenSymbolChanged(_event: any, symbol: string): void {
- let symbolErrText = '';
- const maxLength = 5;
- const tokens = _.values(this.props.tokenByAddress);
- const doesTokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol }));
- if (symbol === '') {
- symbolErrText = 'Symbol is required';
- } else if (!this._isAlphanumeric(symbol)) {
- symbolErrText = 'Can only include alphanumeric characters';
- } else if (symbol.length > maxLength) {
- symbolErrText = `Max length is ${maxLength}`;
- } else if (doesTokenWithSymbolExists) {
- symbolErrText = 'Token with symbol already exists';
- }
-
- this.setState({
- symbol,
- symbolErrText,
- });
- }
- private _onTokenDecimalsChanged(_event: any, decimals: string): void {
- let decimalsErrText = '';
- const maxLength = 2;
- if (decimals === '') {
- decimalsErrText = 'Decimals is required';
- } else if (!this._isInteger(decimals)) {
- decimalsErrText = 'Must be an integer';
- } else if (decimals.length > maxLength) {
- decimalsErrText = `Max length is ${maxLength}`;
- }
-
- this.setState({
- decimals,
- decimalsErrText,
- });
- }
- private _onTokenAddressChanged(address?: string): void {
- if (!_.isUndefined(address)) {
- this.setState({
- address,
- });
- }
- }
- private _isValidName(input: string): boolean {
- return /^[a-z0-9 ]+$/i.test(input);
- }
- private _isInteger(input: string): boolean {
- return /^[0-9]+$/i.test(input);
- }
- private _isAlphanumeric(input: string): boolean {
- return /^[a-zA-Z0-9]+$/i.test(input);
- }
-}
diff --git a/packages/website/ts/components/hamburger.tsx b/packages/website/ts/components/hamburger.tsx
deleted file mode 100644
index 34d4ccc46..000000000
--- a/packages/website/ts/components/hamburger.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-interface Props {
- isOpen: boolean;
- onClick?: () => void;
-}
-
-export const Hamburger: React.FunctionComponent<Props> = (props: Props) => {
- return (
- <StyledHamburger isOpen={props.isOpen} onClick={props.onClick}>
- <span />
- <span />
- <span />
- </StyledHamburger>
- );
-};
-
-const StyledHamburger = styled.button<Props>`
- background: none;
- border: 0;
- width: 22px;
- height: 16px;
- position: relative;
- z-index: 25;
- padding: 0;
- outline: none;
- user-select: none;
-
- @media (min-width: 800px) {
- display: none;
- }
-
- span {
- display: block;
- background-color: ${props => props.theme.textColor};
- width: 100%;
- height: 2px;
- margin-bottom: 5px;
- transform-origin: 4px 0px;
- transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1),
- background-color 0.5s cubic-bezier(0.77, 0.2, 0.05, 1), opacity 0.55s ease;
-
- &:first-child {
- //transform-origin: 0% 0%;
- }
-
- &:last-child {
- //transform-origin: 0% 100%;
- }
-
- ${props =>
- props.isOpen &&
- `
- opacity: 1;
- transform: rotate(45deg) translate(0, 1px);
-
- &:nth-child(2) {
- opacity: 0;
- transform: rotate(0deg) scale(0.2, 0.2);
- }
-
- &:last-child {
- transform: rotate(-45deg) translate(1px, -4px);
- }
- `}
- }
-`;
diff --git a/packages/website/ts/components/header.tsx b/packages/website/ts/components/header.tsx
deleted file mode 100644
index 088f41048..000000000
--- a/packages/website/ts/components/header.tsx
+++ /dev/null
@@ -1,249 +0,0 @@
-import { Link } from '@0x/react-shared';
-import _ from 'lodash';
-import * as React from 'react';
-import MediaQuery from 'react-responsive';
-import styled, { css, withTheme } from 'styled-components';
-
-import Headroom from 'react-headroom';
-
-import { Button } from 'ts/components/button';
-import { DropdownDevelopers } from 'ts/components/dropdowns/dropdown_developers';
-import { DropdownProducts } from 'ts/components/dropdowns/dropdown_products';
-import { Hamburger } from 'ts/components/hamburger';
-import { Logo } from 'ts/components/logo';
-import { MobileNav } from 'ts/components/mobileNav';
-import { FlexWrap } from 'ts/components/newLayout';
-import { ThemeValuesInterface } from 'ts/components/siteWrap';
-import { WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-interface HeaderProps {
- location?: Location;
- isNavToggled?: boolean;
- toggleMobileNav?: () => void;
- theme: ThemeValuesInterface;
-}
-
-interface NavItemProps {
- url?: string;
- id?: string;
- text?: string;
- dropdownWidth?: number;
- dropdownComponent?: React.FunctionComponent<any>;
- shouldOpenInNewTab?: boolean;
-}
-
-interface DropdownWrapInterface {
- width?: number;
-}
-
-const navItems: NavItemProps[] = [
- {
- id: 'why',
- url: WebsitePaths.Why,
- text: 'Why 0x',
- },
- {
- id: 'products',
- text: 'Products',
- dropdownComponent: DropdownProducts,
- dropdownWidth: 280,
- },
- {
- id: 'developers',
- text: 'Developers',
- dropdownComponent: DropdownDevelopers,
- dropdownWidth: 480,
- },
- {
- id: 'about',
- url: WebsitePaths.AboutMission,
- text: 'About',
- },
- {
- id: 'blog',
- url: constants.URL_BLOG,
- shouldOpenInNewTab: true,
- text: 'Blog',
- },
-];
-
-class HeaderBase extends React.Component<HeaderProps> {
- public onUnpin = () => {
- if (this.props.isNavToggled) {
- this.props.toggleMobileNav();
- }
- };
-
- public render(): React.ReactNode {
- const { isNavToggled, toggleMobileNav, theme } = this.props;
-
- return (
- <Headroom onUnpin={this.onUnpin} downTolerance={4} upTolerance={10}>
- <StyledHeader isNavToggled={isNavToggled}>
- <HeaderWrap>
- <Link to={WebsitePaths.Home}>
- <Logo />
- </Link>
-
- <NavLinks>
- {_.map(navItems, (link, index) => (
- <NavItem key={`navlink-${index}`} link={link} />
- ))}
- </NavLinks>
-
- <MediaQuery minWidth={990}>
- <TradeButton bgColor={theme.headerButtonBg} color="#ffffff" href="/portal">
- Trade on 0x
- </TradeButton>
- </MediaQuery>
-
- <Hamburger isOpen={isNavToggled} onClick={toggleMobileNav} />
- <MobileNav isToggled={isNavToggled} toggleMobileNav={toggleMobileNav} />
- </HeaderWrap>
- </StyledHeader>
- </Headroom>
- );
- }
-}
-
-export const Header = withTheme(HeaderBase);
-
-const NavItem = (props: { link: NavItemProps; key: string }) => {
- const { link } = props;
- const Subnav = link.dropdownComponent;
- const linkElement = _.isUndefined(link.url) ? (
- <StyledAnchor href="#">{link.text}</StyledAnchor>
- ) : (
- <StyledNavLink to={link.url} shouldOpenInNewTab={link.shouldOpenInNewTab}>
- {link.text}
- </StyledNavLink>
- );
- return (
- <LinkWrap>
- {linkElement}
-
- {link.dropdownComponent && (
- <DropdownWrap width={link.dropdownWidth}>
- <Subnav />
- </DropdownWrap>
- )}
- </LinkWrap>
- );
-};
-
-const StyledHeader = styled.header<HeaderProps>`
- padding: 30px;
- background-color: ${props => props.theme.bgColor};
-`;
-
-const LinkWrap = styled.li`
- position: relative;
-
- a {
- display: block;
- }
-
- @media (min-width: 800px) {
- &:hover > div {
- display: block;
- visibility: visible;
- opacity: 1;
- transform: translate3d(0, 0, 0);
- transition: opacity 0.35s, transform 0.35s, visibility 0s;
- }
- }
-`;
-
-const linkStyles = css`
- color: ${props => props.theme.textColor};
- opacity: 0.5;
- transition: opacity 0.35s;
- padding: 15px 0;
- margin: 0 30px;
-
- &:hover {
- opacity: 1;
- }
-`;
-
-const StyledNavLink = styled(Link).attrs({
- activeStyle: { opacity: 1 },
-})`
- ${linkStyles};
-`;
-
-const StyledAnchor = styled.a`
- ${linkStyles};
- cursor: default;
-`;
-
-const HeaderWrap = styled(FlexWrap)`
- justify-content: space-between;
- align-items: center;
-
- @media (max-width: 800px) {
- padding-top: 0;
- display: flex;
- padding-bottom: 0;
- }
-`;
-
-const NavLinks = styled.ul`
- display: flex;
- align-items: center;
- justify-content: space-between;
-
- @media (max-width: 800px) {
- display: none;
- }
-`;
-
-const DropdownWrap = styled.div<DropdownWrapInterface>`
- width: ${props => props.width || 280}px;
- padding: 15px 0;
- border: 1px solid transparent;
- border-color: ${props => props.theme.dropdownBorderColor};
- background-color: ${props => props.theme.dropdownBg};
- color: ${props => props.theme.dropdownColor};
- position: absolute;
- top: 100%;
- left: calc(50% - ${props => (props.width || 280) / 2}px);
- visibility: hidden;
- opacity: 0;
- transform: translate3d(0, -10px, 0);
- transition: opacity 0.35s, transform 0.35s, visibility 0s 0.35s;
- z-index: 20;
-
- &:after,
- &:before {
- bottom: 100%;
- left: 50%;
- border: solid transparent;
- content: ' ';
- height: 0;
- width: 0;
- position: absolute;
- pointer-events: none;
- }
- &:after {
- border-color: rgba(255, 255, 255, 0);
- border-bottom-color: ${props => props.theme.dropdownBg};
- border-width: 10px;
- margin-left: -10px;
- }
- &:before {
- border-color: rgba(255, 0, 0, 0);
- border-bottom-color: ${props => props.theme.dropdownBorderColor};
- border-width: 11px;
- margin-left: -11px;
- }
-
- @media (max-width: 768px) {
- display: none;
- }
-`;
-
-const TradeButton = styled(Button)`
- padding: 14px 22px !important;
-`;
diff --git a/packages/website/ts/components/hero.tsx b/packages/website/ts/components/hero.tsx
deleted file mode 100644
index c326e0292..000000000
--- a/packages/website/ts/components/hero.tsx
+++ /dev/null
@@ -1,143 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { addFadeInAnimation } from 'ts/constants/animations';
-
-interface Props {
- title: string;
- maxWidth?: string;
- maxWidthHeading?: string;
- isLargeTitle?: boolean;
- isFullWidth?: boolean;
- isCenteredMobile?: boolean;
- description: string;
- figure?: React.ReactNode;
- actions?: React.ReactNode;
-}
-
-const Section = styled.section`
- padding: 120px 0;
-
- @media (max-width: 768px) {
- padding: 60px 0;
- }
-`;
-
-interface WrapProps {
- isCentered?: boolean;
- isFullWidth?: boolean;
- isCenteredMobile?: boolean;
-}
-const Wrap = styled.div<WrapProps>`
- width: calc(100% - 60px);
- margin: 0 auto;
-
- @media (min-width: 768px) {
- max-width: ${props => (!props.isFullWidth ? '895px' : '1136px')};
- flex-direction: row-reverse;
- display: flex;
- align-items: center;
- text-align: ${props => props.isCentered && 'center'};
- justify-content: ${props => (props.isCentered ? 'center' : 'space-between')};
- }
-
- @media (max-width: 768px) {
- text-align: ${props => (props.isCenteredMobile ? `center` : 'left')};
- }
-`;
-
-interface TitleProps {
- isLarge?: any;
- maxWidth?: string;
-}
-const Title = styled.h1<TitleProps>`
- font-size: ${props => (props.isLarge ? '80px' : '50px')};
- font-weight: 300;
- line-height: 1.1;
- margin-left: auto;
- margin-right: auto;
- margin-bottom: 30px;
- max-width: ${props => props.maxWidth};
- ${addFadeInAnimation('0.5s')}
-
- @media (max-width: 1024px) {
- font-size: 60px;
- }
-
- @media (max-width: 768px) {
- font-size: 46px;
- }
-`;
-
-const Description = styled.p`
- font-size: 22px;
- line-height: 31px;
- font-weight: 300;
- padding: 0;
- margin-bottom: 50px;
- color: ${props => props.theme.introTextColor};
- ${addFadeInAnimation('0.5s', '0.15s')} @media (max-width: 1024px) {
- margin-bottom: 30px;
- }
-`;
-
-const Content = styled.div<{ width: string }>`
- width: 100%;
-
- @media (min-width: 768px) {
- max-width: ${props => props.width};
- }
-`;
-
-const ButtonWrap = styled.div`
- display: inline-flex;
- align-items: center;
-
- * + * {
- margin-left: 12px;
- }
-
- > *:nth-child(1) {
- ${addFadeInAnimation('0.6s', '0.3s')};
- }
- > *:nth-child(2) {
- ${addFadeInAnimation('0.6s', '0.4s')};
- }
-
- @media (max-width: 500px) {
- flex-direction: column;
- justify-content: center;
-
- * {
- padding-left: 20px;
- padding-right: 20px;
- }
-
- * + * {
- margin-left: 0;
- margin-top: 12px;
- }
- }
-`;
-
-export const Hero: React.StatelessComponent<Props> = (props: Props) => (
- <Section>
- <Wrap isCentered={!props.figure} isFullWidth={props.isFullWidth} isCenteredMobile={props.isCenteredMobile}>
- {props.figure && <Content width="400px">{props.figure}</Content>}
-
- <Content width={props.maxWidth ? props.maxWidth : props.figure ? '546px' : '678px'}>
- <Title isLarge={props.isLargeTitle} maxWidth={props.maxWidthHeading}>
- {props.title}
- </Title>
-
- <Description>{props.description}</Description>
-
- {props.actions && <ButtonWrap>{props.actions}</ButtonWrap>}
- </Content>
- </Wrap>
- </Section>
-);
-
-Hero.defaultProps = {
- isCenteredMobile: true,
-};
diff --git a/packages/website/ts/components/heroAnimation.tsx b/packages/website/ts/components/heroAnimation.tsx
deleted file mode 100644
index 42956fb6a..000000000
--- a/packages/website/ts/components/heroAnimation.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import * as React from 'react';
-import styled, { keyframes } from 'styled-components';
-
-export const HeroAnimation = () => (
- <Image width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg">
- <mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="404" height="404">
- <circle cx="202" cy="202" r="200" fill="#00AE99" stroke="#00AE99" stroke-width="3" />
- </mask>
- <g mask="url(#mask0)">
- <circle cx="202" cy="202" r="200" stroke="#00AE99" strokeWidth="3" />
- <TopCircle
- vector-effect="non-scaling-stroke"
- cx="201.667"
- cy="68.6667"
- r="66.6667"
- stroke="#00AE99"
- strokeWidth="3"
- />
- <LeftCircle
- vector-effect="non-scaling-stroke"
- cx="68.6667"
- cy="202.667"
- r="66.6667"
- stroke="#00AE99"
- strokeWidth="3"
- />
- <Logo
- vector-effect="non-scaling-stroke"
- d="M168.17 260.29L167.271 259.089L165.46 260.444L167.413 261.585L168.17 260.29ZM197.32 269.2L197.219 270.696L197.226 270.697L197.32 269.2ZM237.414 258.856L238.22 260.12L238.225 260.117L237.414 258.856ZM252.653 245.439L253.801 246.405L254.55 245.515L253.874 244.568L252.653 245.439ZM241.096 229.872L242.285 228.958L242.281 228.952L242.276 228.946L241.096 229.872ZM237.72 225.571L238.901 224.645L237.582 222.965L236.449 224.775L237.72 225.571ZM219.719 241.445L218.672 242.519L219.418 243.246L220.36 242.801L219.719 241.445ZM208.264 230.282L209.311 229.207L208.392 228.312L207.365 229.081L208.264 230.282ZM143.827 169.549L145.02 168.64L143.647 166.838L142.524 168.806L143.827 169.549ZM135.133 198.43L133.637 198.329L133.636 198.337L135.133 198.43ZM145.464 238.577L144.201 239.388L145.464 238.577ZM158.862 253.837L157.895 254.984L158.786 255.736L159.735 255.057L158.862 253.837ZM174.409 242.264L175.324 243.453L175.33 243.448L175.336 243.443L174.409 242.264ZM178.705 238.885L179.632 240.064L181.287 238.761L179.516 237.623L178.705 238.885ZM162.851 220.757L161.78 219.707L161.049 220.452L161.495 221.397L162.851 220.757ZM174.102 209.286L175.173 210.337L176.082 209.41L175.295 208.377L174.102 209.286ZM235.163 145.072L236.036 146.292L237.92 144.945L235.92 143.777L235.163 145.072ZM206.014 136.162L205.91 137.658L205.913 137.658L206.014 136.162ZM165.817 146.506L166.629 147.767L166.632 147.765L165.817 146.506ZM150.578 159.922L149.43 158.956L148.681 159.846L149.357 160.793L150.578 159.922ZM162.135 175.489L160.946 176.403L160.951 176.409L160.955 176.415L162.135 175.489ZM165.511 179.791L164.331 180.717L165.634 182.378L166.773 180.6L165.511 179.791ZM183.614 163.916L184.655 162.836L183.913 162.122L182.98 162.557L183.614 163.916ZM194.354 174.26L193.313 175.341L194.212 176.206L195.226 175.48L194.354 174.26ZM259.608 235.505L258.411 236.409L259.789 238.233L260.914 236.243L259.608 235.505ZM268.2 206.931L269.696 207.033L269.697 207.024L268.2 206.931ZM257.87 166.784L259.135 165.979L259.132 165.974L257.87 166.784ZM244.471 151.524L245.439 150.378L244.547 149.625L243.598 150.304L244.471 151.524ZM228.924 163.097L228.009 161.909L228.003 161.913L227.997 161.918L228.924 163.097ZM224.629 166.477L223.701 165.298L222.034 166.609L223.826 167.744L224.629 166.477ZM240.584 184.604L239.228 185.244L239.235 185.259L239.242 185.274L240.584 184.604ZM240.687 184.809L241.767 185.849L242.502 185.086L242.029 184.139L240.687 184.809ZM229.845 196.075L228.764 195.035L227.877 195.957L228.648 196.979L229.845 196.075ZM167.413 261.585C176.201 266.718 186.346 269.964 197.219 270.696L197.421 267.703C187.019 267.002 177.321 263.898 168.926 258.994L167.413 261.585ZM197.226 270.697C212.283 271.639 226.405 267.659 238.22 260.12L236.607 257.591C225.307 264.8 211.813 268.604 197.413 267.703L197.226 270.697ZM238.225 260.117C244.08 256.348 249.307 251.742 253.801 246.405L251.506 244.473C247.204 249.583 242.203 253.989 236.602 257.594L238.225 260.117ZM253.874 244.568C250.283 239.533 246.385 234.295 242.285 228.958L239.906 230.786C243.989 236.1 247.864 241.309 251.432 246.31L253.874 244.568ZM242.276 228.946C241.713 228.229 241.151 227.512 240.588 226.795C240.026 226.078 239.463 225.362 238.901 224.645L236.54 226.497C237.103 227.213 237.665 227.93 238.228 228.647C238.791 229.364 239.353 230.081 239.916 230.798L242.276 228.946ZM236.449 224.775C232.311 231.384 226.193 236.725 219.078 240.089L220.36 242.801C227.974 239.201 234.538 233.481 238.992 226.367L236.449 224.775ZM220.766 240.371L209.311 229.207L207.217 231.356L218.672 242.519L220.766 240.371ZM207.365 229.081L167.271 259.089L169.069 261.49L209.163 231.483L207.365 229.081ZM142.524 168.806C137.505 177.601 134.368 187.549 133.637 198.329L136.63 198.532C137.33 188.214 140.33 178.703 145.13 170.293L142.524 168.806ZM133.636 198.337C132.696 213.409 136.668 227.654 144.201 239.388L146.726 237.767C139.531 226.56 135.73 212.947 136.63 198.524L133.636 198.337ZM144.201 239.388C147.965 245.25 152.565 250.484 157.895 254.984L159.83 252.691C154.727 248.383 150.327 243.376 146.726 237.767L144.201 239.388ZM159.735 255.057C164.764 251.461 169.994 247.558 175.324 243.453L173.494 241.076C168.187 245.164 162.985 249.045 157.99 252.617L159.735 255.057ZM175.336 243.443C176.768 242.317 178.2 241.19 179.632 240.064L177.777 237.706C176.345 238.832 174.913 239.959 173.481 241.086L175.336 243.443ZM179.516 237.623C172.904 233.374 167.568 227.241 164.208 220.117L161.495 221.397C165.09 229.021 170.8 235.588 177.894 240.147L179.516 237.623ZM163.922 221.807L175.173 210.337L173.031 208.236L161.78 219.707L163.922 221.807ZM175.295 208.377L145.02 168.64L142.634 170.458L172.909 210.196L175.295 208.377ZM235.92 143.777C227.132 138.643 216.987 135.398 206.114 134.665L205.913 137.658C216.315 138.359 226.012 141.463 234.407 146.367L235.92 143.777ZM206.118 134.665C191.055 133.618 176.824 137.599 165.003 145.246L166.632 147.765C177.926 140.459 191.515 136.657 205.91 137.658L206.118 134.665ZM165.006 145.244C159.151 149.013 153.924 153.619 149.43 158.956L151.725 160.888C156.027 155.779 161.028 151.372 166.629 147.767L165.006 145.244ZM149.357 160.793C152.948 165.828 156.846 171.066 160.946 176.403L163.325 174.575C159.242 169.261 155.367 164.052 151.799 159.051L149.357 160.793ZM160.955 176.415C161.518 177.132 162.08 177.849 162.643 178.566C163.205 179.283 163.768 180 164.331 180.717L166.691 178.865C166.128 178.148 165.566 177.431 165.003 176.714C164.441 175.997 163.878 175.28 163.315 174.563L160.955 176.415ZM166.773 180.6C171.021 173.973 177.044 168.635 184.248 165.276L182.98 162.557C175.251 166.161 168.796 171.885 164.248 178.981L166.773 180.6ZM182.574 164.997L193.313 175.341L195.394 173.18L184.655 162.836L182.574 164.997ZM195.226 175.48L236.036 146.292L234.291 143.852L193.481 173.04L195.226 175.48ZM260.914 236.243C265.827 227.556 268.964 217.713 269.696 207.033L266.703 206.828C266.003 217.042 263.004 226.453 258.303 234.767L260.914 236.243ZM269.697 207.024C270.638 191.949 266.663 177.81 259.135 165.979L256.604 167.589C263.804 178.904 267.603 192.417 266.703 206.837L269.697 207.024ZM259.132 165.974C255.368 160.111 250.769 154.878 245.439 150.378L243.503 152.67C248.606 156.978 253.007 161.986 256.607 167.594L259.132 165.974ZM243.598 150.304C238.57 153.901 233.339 157.803 228.009 161.909L229.84 164.285C235.147 160.197 240.349 156.316 245.344 152.744L243.598 150.304ZM227.997 161.918C227.281 162.481 226.565 163.045 225.849 163.608C225.133 164.171 224.417 164.734 223.701 165.298L225.556 167.656C226.272 167.092 226.988 166.529 227.704 165.966C228.42 165.402 229.136 164.839 229.852 164.276L227.997 161.918ZM223.826 167.744C230.535 171.992 235.869 178.121 239.228 185.244L241.941 183.964C238.345 176.339 232.632 169.769 225.431 165.209L223.826 167.744ZM239.242 185.274L239.345 185.479L242.029 184.139L241.926 183.934L239.242 185.274ZM239.606 183.769L228.764 195.035L230.926 197.115L241.767 185.849L239.606 183.769ZM228.648 196.979L258.411 236.409L260.806 234.601L231.042 195.171L228.648 196.979Z"
- fill="#00AE99"
- />
- <Rectangle
- vector-effect="non-scaling-stroke"
- d="M269 135V268.333H442V135H269Z"
- stroke="#00AE99"
- strokeWidth="3"
- />
- <Square
- vector-effect="non-scaling-stroke"
- d="M339.64 269.64L270 339.281L343.913 413.194L413.554 343.554L339.64 269.64Z"
- stroke="#00AE99"
- strokeWidth="3"
- />
- <Oblong
- vector-effect="non-scaling-stroke"
- d="M202.5 269C202.5 269 269 269 269 335.5C269 402 202.5 402 202.5 402H-6.5C-6.5 402 -77 402 -77 335.5C-77 269 -6.5 269 -6.5 269H202.5Z"
- stroke="#00AE99"
- strokeWidth="3"
- />
- </g>
- </Image>
-);
-
-const moveUp = keyframes`
- 0% { transform: translate3d(0, 0, 0) }
- 45% { transform: translate3d(0, 0, 0) }
- 55% { transform: translate3d(0, -7%, 0) }
- 85% { transform: translate3d(0, -7%, 0) }
- 100% { transform: translate3d(0, 0, 0) }
-`;
-
-const moveLeft = keyframes`
- 0% { transform: translate3d(0, 0, 0) }
- 45% { transform: translate3d(0, 0, 0) }
- 55% { transform: translate3d(-7%, 0, 0) }
- 85% { transform: translate3d(-7%, 0, 0) }
- 100% { transform: translate3d(0, 0, 0) }
-`;
-
-const moveDiag = keyframes`
- 0% { transform: translate3d(0, 0, 0) }
- 45% { transform: translate3d(0, 0, 0) }
- 55% { transform: translate3d(5%, 5%, 0) }
- 85% { transform: translate3d(5%, 5%, 0) }
- 100% { transform: translate3d(0, 0, 0) }
-`;
-
-const moveRight = keyframes`
- 0% { transform: translate3d(0, 0, 0) }
- 45% { transform: translate3d(0, 0, 0) }
- 55% { transform: translate3d(7%, 0, 0) }
- 85% { transform: translate3d(7%, 0, 0) }
- 100% { transform: translate3d(0, 0, 0) }
-`;
-
-const spin = keyframes`
- 0% { transform: rotate(0deg) }
- 65% { transform: rotate(0deg) }
- 85% { transform: rotate(90deg) }
- 100% { transform: rotate(90deg) }
-`;
-
-const moveIn = keyframes`
- 0% { opacity: 0; transform: scale(1.7) rotate(-30deg) }
- 100% { opacity: 1; transform: scale(1) rotate(0deg) }
-`;
-
-const Image = styled.svg`
- opacity: 0;
- transform: scale(1.5) rotate(-30deg);
- animation: ${moveIn} 2s forwards;
-`;
-
-const TopCircle = styled.circle`
- animation: ${moveUp} 4s -2.85s infinite;
-`;
-const LeftCircle = styled.circle`
- animation: ${moveLeft} 4s -2.85s infinite;
-`;
-const Oblong = styled.path`
- animation: ${moveLeft} 4s -2.85s infinite;
-`;
-const Square = styled.path`
- animation: ${moveDiag} 4s -2.85s infinite;
-`;
-const Rectangle = styled.path`
- animation: ${moveRight} 4s -2.85s infinite;
-`;
-
-const Logo = styled.path`
- animation: ${spin} 4s -2.8s infinite;
- transform-origin: 202px 202.7px;
-`;
diff --git a/packages/website/ts/components/heroImage.tsx b/packages/website/ts/components/heroImage.tsx
deleted file mode 100644
index af7c055ac..000000000
--- a/packages/website/ts/components/heroImage.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-interface Props {
- image: React.ReactNode;
-}
-
-export const LandingAnimation = (props: Props) => <Wrap>{props.image}</Wrap>;
-
-const Wrap = styled.figure`
- display: inline-block;
-
- svg {
- width: 100%;
- height: auto;
- }
-
- @media (min-width: 768px) {
- width: 100%;
- max-width: 400px;
- }
-
- @media (max-width: 768px) {
- width: 180px;
- margin-bottom: 40px;
- }
-`;
diff --git a/packages/website/ts/components/icon.tsx b/packages/website/ts/components/icon.tsx
deleted file mode 100644
index 60e4d04ee..000000000
--- a/packages/website/ts/components/icon.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as React from 'react';
-import Loadable from 'react-loadable';
-import styled from 'styled-components';
-
-import { Paragraph } from 'ts/components/text';
-import { getCSSPadding, PaddingInterface } from 'ts/constants/utilities';
-
-interface IconProps extends PaddingInterface {
- name?: string;
- component?: React.ReactNode;
- size?: 'small' | 'medium' | 'large' | 'hero' | number;
-}
-
-export const Icon: React.FunctionComponent<IconProps> = (props: IconProps) => {
- if (props.name && !props.component) {
- const IconSVG = Loadable({
- loader: async () => import(/* webpackChunkName: "icon" */ `ts/icons/illustrations/${props.name}.svg`),
- loading: () => <Paragraph>Loading</Paragraph>,
- });
-
- return (
- <StyledIcon {...props}>
- <IconSVG />
- </StyledIcon>
- );
- }
-
- if (props.component) {
- return <StyledIcon {...props}>{props.component}</StyledIcon>;
- }
-
- return null;
-};
-
-export const InlineIconWrap = styled.div<PaddingInterface>`
- margin: ${props => getCSSPadding(props.margin)};
- display: flex;
- align-items: center;
- justify-content: center;
-
- > figure {
- margin: 0 5px;
- }
-`;
-
-const _getSize = (size: string | number = 'small'): string => {
- if (typeof size === 'string') {
- return `var(--${size}Icon)`;
- }
-
- return `${size}px`;
-};
-
-const StyledIcon = styled.figure<IconProps>`
- width: ${props => _getSize(props.size)};
- height: ${props => _getSize(props.size)};
- margin: ${props => getCSSPadding(props.margin)};
- display: inline-block;
- flex-shrink: 0;
-
- svg {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
-`;
diff --git a/packages/website/ts/components/image.tsx b/packages/website/ts/components/image.tsx
deleted file mode 100644
index 0137cfc97..000000000
--- a/packages/website/ts/components/image.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-interface Props {
- alt?: string;
- src?: any;
- srcset?: any;
- isCentered?: boolean;
-}
-
-const ImageClass: React.FunctionComponent<Props> = (props: Props) => {
- return <img {...props} />;
-};
-
-export const Image = styled(ImageClass)<Props>`
- margin: ${props => props.isCentered && `0 auto`};
-`;
diff --git a/packages/website/ts/components/inputs/address_input.tsx b/packages/website/ts/components/inputs/address_input.tsx
deleted file mode 100644
index 1a71f8081..000000000
--- a/packages/website/ts/components/inputs/address_input.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { addressUtils } from '@0x/utils';
-import * as _ from 'lodash';
-import TextField from 'material-ui/TextField';
-import * as React from 'react';
-import { RequiredLabel } from 'ts/components/ui/required_label';
-
-interface AddressInputProps {
- disabled?: boolean;
- initialAddress: string;
- isRequired?: boolean;
- hintText?: string;
- shouldHideLabel?: boolean;
- label?: string;
- shouldShowIncompleteErrs?: boolean;
- updateAddress: (address?: string) => void;
-}
-
-interface AddressInputState {
- address: string;
- errMsg: string;
-}
-
-export class AddressInput extends React.Component<AddressInputProps, AddressInputState> {
- constructor(props: AddressInputProps) {
- super(props);
- this.state = {
- address: this.props.initialAddress,
- errMsg: '',
- };
- }
- public componentWillReceiveProps(nextProps: AddressInputProps): void {
- if (nextProps.shouldShowIncompleteErrs && this.props.isRequired && this.state.address === '') {
- this.setState({
- errMsg: 'Address is required',
- });
- }
- }
- public render(): React.ReactNode {
- const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : this.props.label;
- const labelDisplay = this.props.shouldHideLabel ? 'hidden' : 'block';
- const hintText = this.props.hintText ? this.props.hintText : '';
- return (
- <div className="overflow-hidden">
- <TextField
- id={`address-field-${this.props.label}`}
- disabled={_.isUndefined(this.props.disabled) ? false : this.props.disabled}
- fullWidth={true}
- hintText={hintText}
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey, display: labelDisplay }}
- floatingLabelText={label}
- errorText={this.state.errMsg}
- value={this.state.address}
- onChange={this._onOrderTakerAddressUpdated.bind(this)}
- />
- </div>
- );
- }
- private _onOrderTakerAddressUpdated(e: any): void {
- const address = e.target.value.toLowerCase();
- const isValidAddress = addressUtils.isAddress(address) || address === '';
- const errMsg = isValidAddress ? '' : 'Invalid ethereum address';
- this.setState({
- address,
- errMsg,
- });
- const addressIfValid = isValidAddress ? address : undefined;
- this.props.updateAddress(addressIfValid);
- }
-}
diff --git a/packages/website/ts/components/inputs/allowance_state_toggle.tsx b/packages/website/ts/components/inputs/allowance_state_toggle.tsx
deleted file mode 100644
index 3a78d32f3..000000000
--- a/packages/website/ts/components/inputs/allowance_state_toggle.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { BigNumber, logUtils } from '@0x/utils';
-import * as _ from 'lodash';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-import { Blockchain } from 'ts/blockchain';
-import { AllowanceState, AllowanceStateView } from 'ts/components/ui/allowance_state_view';
-import { Container } from 'ts/components/ui/container';
-import { PointerDirection } from 'ts/components/ui/pointer';
-import { Text } from 'ts/components/ui/text';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { BalanceErrs, Token, TokenState } from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-export interface AllowanceStateToggleProps {
- networkId: number;
- blockchain: Blockchain;
- dispatcher: Dispatcher;
- token: Token;
- tokenState: TokenState;
- userAddress: string;
- onErrorOccurred?: (errType: BalanceErrs) => void;
- refetchTokenStateAsync: () => Promise<void>;
- tooltipDirection?: PointerDirection;
-}
-
-export interface AllowanceStateToggleState {
- allowanceState: AllowanceState;
- prevTokenState: TokenState;
- loadingMessage?: string;
-}
-
-const DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS = new BigNumber(2).pow(256).minus(1);
-
-export class AllowanceStateToggle extends React.Component<AllowanceStateToggleProps, AllowanceStateToggleState> {
- public static defaultProps = {
- onErrorOccurred: _.noop.bind(_),
- tooltipDirection: PointerDirection.Right,
- };
- private static _getAllowanceState(tokenState: TokenState): AllowanceState {
- if (!tokenState.isLoaded) {
- return AllowanceState.Loading;
- }
- if (tokenState.allowance.gt(0)) {
- return AllowanceState.Unlocked;
- }
- return AllowanceState.Locked;
- }
- constructor(props: AllowanceStateToggleProps) {
- super(props);
- const tokenState = props.tokenState;
- this.state = {
- allowanceState: AllowanceStateToggle._getAllowanceState(tokenState),
- prevTokenState: tokenState,
- };
- }
-
- public render(): React.ReactNode {
- const tooltipId = `tooltip-id-${this.props.token.symbol}`;
- return (
- <Container cursor="pointer">
- <ReactTooltip id={tooltipId} effect="solid" offset={{ top: 3 }}>
- {this._getTooltipContent()}
- </ReactTooltip>
- <div
- data-tip={true}
- data-for={tooltipId}
- data-place={this.props.tooltipDirection}
- onClick={this._onToggleAllowanceAsync.bind(this)}
- >
- <AllowanceStateView allowanceState={this.state.allowanceState} />
- </div>
- </Container>
- );
- }
- public componentWillReceiveProps(nextProps: AllowanceStateToggleProps): void {
- const nextTokenState = nextProps.tokenState;
- const prevTokenState = this.state.prevTokenState;
- if (
- !nextTokenState.allowance.eq(prevTokenState.allowance) ||
- nextTokenState.isLoaded !== prevTokenState.isLoaded
- ) {
- const tokenState = nextProps.tokenState;
- this.setState({
- prevTokenState: tokenState,
- allowanceState: AllowanceStateToggle._getAllowanceState(nextTokenState),
- });
- }
- }
- private _getTooltipContent(): React.ReactNode {
- const symbol = this.props.token.symbol;
- switch (this.state.allowanceState) {
- case AllowanceState.Loading:
- return (
- <Text noWrap={true} fontColor={colors.white}>
- {this.state.loadingMessage || 'Loading...'}
- </Text>
- );
- case AllowanceState.Locked:
- return (
- <Text noWrap={true} fontColor={colors.white}>
- Click to enable <b>{symbol}</b> for trading
- </Text>
- );
- case AllowanceState.Unlocked:
- return (
- <Text noWrap={true} fontColor={colors.white}>
- <b>{symbol}</b> is available for trading
- </Text>
- );
- default:
- return null;
- }
- }
- private async _onToggleAllowanceAsync(): Promise<void> {
- // Close all tooltips
- ReactTooltip.hide();
- if (this.props.userAddress === '') {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return;
- }
-
- let newAllowanceAmountInBaseUnits = new BigNumber(0);
- if (!this._isAllowanceSet()) {
- newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
- }
- const isUnlockingToken = newAllowanceAmountInBaseUnits.gt(0);
- this.setState({
- allowanceState: AllowanceState.Loading,
- loadingMessage: `${isUnlockingToken ? 'Unlocking' : 'Locking'} ${this.props.token.symbol}`,
- });
- const logData = {
- tokenSymbol: this.props.token.symbol,
- newAllowance: newAllowanceAmountInBaseUnits.toNumber(),
- };
- try {
- await this.props.blockchain.setProxyAllowanceAsync(this.props.token, newAllowanceAmountInBaseUnits);
- analytics.track('Set Allowances Success', logData);
- await this.props.refetchTokenStateAsync();
- } catch (err) {
- analytics.track('Set Allowance Failure', logData);
- this.setState({
- allowanceState: AllowanceStateToggle._getAllowanceState(this.state.prevTokenState),
- });
- const errMsg = `${err}`;
- if (utils.didUserDenyWeb3Request(errMsg)) {
- return;
- }
- logUtils.log(`Unexpected error encountered: ${err}`);
- logUtils.log(err.stack);
- this.props.onErrorOccurred(BalanceErrs.AllowanceSettingFailed);
- errorReporter.report(err);
- }
- }
- private _isAllowanceSet(): boolean {
- return !this.props.tokenState.allowance.eq(0);
- }
-}
diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx
deleted file mode 100644
index 83f263842..000000000
--- a/packages/website/ts/components/inputs/balance_bounded_input.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-import TextField from 'material-ui/TextField';
-import * as React from 'react';
-import { RequiredLabel } from 'ts/components/ui/required_label';
-import { ValidatedBigNumberCallback } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-interface BalanceBoundedInputProps {
- label?: string;
- balance: BigNumber;
- amount?: BigNumber;
- hintText?: string;
- onChange: ValidatedBigNumberCallback;
- onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
- shouldShowIncompleteErrs?: boolean;
- shouldCheckBalance: boolean;
- validate?: (amount: BigNumber) => React.ReactNode;
- isDisabled?: boolean;
- shouldShowErrs?: boolean;
- shouldShowUnderline?: boolean;
- inputStyle?: React.CSSProperties;
- inputHintStyle?: React.CSSProperties;
-}
-
-interface BalanceBoundedInputState {
- errMsg: React.ReactNode;
- amountString: string;
-}
-
-export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> {
- public static defaultProps: Partial<BalanceBoundedInputProps> = {
- shouldShowIncompleteErrs: false,
- isDisabled: false,
- shouldShowErrs: true,
- hintText: 'amount',
- onErrorMsgChange: _.noop.bind(_),
- shouldShowUnderline: true,
- };
- constructor(props: BalanceBoundedInputProps) {
- super(props);
- const amountString = this.props.amount ? this.props.amount.toString() : '';
- this.state = {
- errMsg: this._validate(amountString, props.balance),
- amountString,
- };
- }
- public componentWillReceiveProps(nextProps: BalanceBoundedInputProps): void {
- if (nextProps === this.props) {
- return;
- }
- const isCurrentAmountNumeric = utils.isNumeric(this.state.amountString);
- if (!_.isUndefined(nextProps.amount)) {
- let shouldResetState = false;
- if (!isCurrentAmountNumeric) {
- shouldResetState = true;
- } else {
- const currentAmount = new BigNumber(this.state.amountString);
- if (!currentAmount.eq(nextProps.amount) || !nextProps.balance.eq(this.props.balance)) {
- shouldResetState = true;
- }
- }
- if (shouldResetState) {
- const amountString = nextProps.amount.toString();
- this._setAmountState(amountString, nextProps.balance);
- }
- } else if (isCurrentAmountNumeric) {
- const amountString = '';
- this._setAmountState(amountString, nextProps.balance);
- }
- }
- public render(): React.ReactNode {
- let errorText;
- if (this.props.shouldShowErrs) {
- errorText =
- this.props.shouldShowIncompleteErrs && this.state.amountString === ''
- ? 'This field is required'
- : this.state.errMsg;
- }
- let label: React.ReactNode | string = '';
- if (!_.isUndefined(this.props.label)) {
- label = <RequiredLabel label={this.props.label} />;
- }
- return (
- <TextField
- fullWidth={true}
- floatingLabelText={label}
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey, width: 206 }}
- errorText={errorText}
- value={this.state.amountString}
- hintText={<span style={{ textTransform: 'capitalize' }}>{this.props.hintText}</span>}
- onChange={this._onValueChange.bind(this)}
- underlineStyle={{ width: 'calc(100% + 50px)' }}
- inputStyle={this.props.inputStyle}
- hintStyle={this.props.inputHintStyle}
- underlineShow={this.props.shouldShowUnderline}
- disabled={this.props.isDisabled}
- />
- );
- }
- private _onValueChange(_event: any, amountString: string): void {
- this._setAmountState(amountString, this.props.balance, () => {
- const isValid = _.isUndefined(this._validate(amountString, this.props.balance));
- const isPositiveNumber = utils.isNumeric(amountString) && !_.includes(amountString, '-');
- if (isPositiveNumber) {
- this.props.onChange(isValid, new BigNumber(amountString));
- } else {
- this.props.onChange(isValid);
- }
- });
- }
- private _validate(amountString: string, balance: BigNumber): React.ReactNode {
- if (!utils.isNumeric(amountString)) {
- return amountString !== '' ? 'Must be a number' : '';
- }
- const amount = new BigNumber(amountString);
- if (amount.eq(0)) {
- return 'Cannot be zero';
- }
- if (this.props.shouldCheckBalance && amount.gt(balance)) {
- return <span>Insufficient balance.</span>;
- }
- const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
- return errMsg;
- }
- private _setAmountState(amount: string, balance: BigNumber, callback: () => void = _.noop.bind(_)): void {
- const errorMsg = this._validate(amount, balance);
- this.props.onErrorMsgChange(errorMsg);
- this.setState(
- {
- amountString: amount,
- errMsg: errorMsg,
- },
- callback,
- );
- }
-}
diff --git a/packages/website/ts/components/inputs/eth_amount_input.tsx b/packages/website/ts/components/inputs/eth_amount_input.tsx
deleted file mode 100644
index 6799e54bf..000000000
--- a/packages/website/ts/components/inputs/eth_amount_input.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input';
-import { ValidatedBigNumberCallback } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-interface EthAmountInputProps {
- label?: string;
- balance: BigNumber;
- amount?: BigNumber;
- hintText?: string;
- onChange: ValidatedBigNumberCallback;
- onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
- shouldShowIncompleteErrs: boolean;
- shouldCheckBalance: boolean;
- shouldShowErrs?: boolean;
- shouldShowUnderline?: boolean;
- style?: React.CSSProperties;
- labelStyle?: React.CSSProperties;
- inputHintStyle?: React.CSSProperties;
-}
-
-interface EthAmountInputState {}
-
-export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmountInputState> {
- public static defaultProps: Partial<EthAmountInputProps> = {
- shouldShowErrs: true,
- shouldShowUnderline: true,
- };
- public render(): React.ReactNode {
- const amount = this.props.amount
- ? Web3Wrapper.toUnitAmount(this.props.amount, constants.DECIMAL_PLACES_ETH)
- : undefined;
- return (
- <div className="flex" style={this.props.style}>
- <BalanceBoundedInput
- label={this.props.label}
- balance={this.props.balance}
- amount={amount}
- onChange={this._onChange.bind(this)}
- onErrorMsgChange={this.props.onErrorMsgChange}
- shouldCheckBalance={this.props.shouldCheckBalance}
- shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
- hintText={this.props.hintText}
- shouldShowErrs={this.props.shouldShowErrs}
- shouldShowUnderline={this.props.shouldShowUnderline}
- inputStyle={this.props.style}
- inputHintStyle={this.props.inputHintStyle}
- />
- <div style={this._getLabelStyle()}>ETH</div>
- </div>
- );
- }
- private _onChange(isValid: boolean, amount?: BigNumber): void {
- const baseUnitAmountIfExists = _.isUndefined(amount)
- ? undefined
- : Web3Wrapper.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH);
- this.props.onChange(isValid, baseUnitAmountIfExists);
- }
- private _getLabelStyle(): React.CSSProperties {
- return this.props.labelStyle || { paddingTop: _.isUndefined(this.props.label) ? 15 : 40 };
- }
-}
diff --git a/packages/website/ts/components/inputs/expiration_input.tsx b/packages/website/ts/components/inputs/expiration_input.tsx
deleted file mode 100644
index 3e43c1c07..000000000
--- a/packages/website/ts/components/inputs/expiration_input.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-import DatePicker from 'material-ui/DatePicker';
-import TimePicker from 'material-ui/TimePicker';
-import * as moment from 'moment';
-import * as React from 'react';
-import { utils } from 'ts/utils/utils';
-
-interface ExpirationInputProps {
- orderExpiryTimestamp: BigNumber;
- updateOrderExpiry: (unixTimestampSec: BigNumber) => void;
-}
-
-interface ExpirationInputState {
- dateMoment: moment.Moment;
- timeMoment: moment.Moment;
-}
-
-export class ExpirationInput extends React.Component<ExpirationInputProps, ExpirationInputState> {
- private readonly _earliestPickableMoment: moment.Moment;
- constructor(props: ExpirationInputProps) {
- super(props);
- // Set the earliest pickable date to today at 00:00, so users can only pick the current or later dates
- this._earliestPickableMoment = moment().startOf('day');
- const expirationMoment = utils.convertToMomentFromUnixTimestamp(props.orderExpiryTimestamp);
- const initialOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec();
- const didUserSetExpiry = !initialOrderExpiryTimestamp.eq(props.orderExpiryTimestamp);
- this.state = {
- dateMoment: didUserSetExpiry ? expirationMoment : undefined,
- timeMoment: didUserSetExpiry ? expirationMoment : undefined,
- };
- }
- public render(): React.ReactNode {
- const date = this.state.dateMoment ? this.state.dateMoment.toDate() : undefined;
- const time = this.state.timeMoment ? this.state.timeMoment.toDate() : undefined;
- return (
- <div className="clearfix">
- <div className="col col-6 overflow-hidden pr3 flex relative">
- <DatePicker
- className="overflow-hidden"
- hintText="Date"
- mode="landscape"
- autoOk={true}
- value={date}
- onChange={this._onDateChanged.bind(this)}
- shouldDisableDate={this._shouldDisableDate.bind(this)}
- />
- <div className="absolute" style={{ fontSize: 20, right: 40, top: 13, pointerEvents: 'none' }}>
- <i className="zmdi zmdi-calendar" />
- </div>
- </div>
- <div className="col col-5 overflow-hidden flex relative">
- <TimePicker
- className="overflow-hidden"
- hintText="Time"
- autoOk={true}
- value={time}
- onChange={this._onTimeChanged.bind(this)}
- />
- <div className="absolute" style={{ fontSize: 20, right: 9, top: 13, pointerEvents: 'none' }}>
- <i className="zmdi zmdi-time" />
- </div>
- </div>
- <div onClick={this._clearDates.bind(this)} className="col col-1 pt2" style={{ textAlign: 'right' }}>
- <i style={{ fontSize: 16, cursor: 'pointer' }} className="zmdi zmdi-close" />
- </div>
- </div>
- );
- }
- private _shouldDisableDate(date: Date): boolean {
- return moment(date)
- .startOf('day')
- .isBefore(this._earliestPickableMoment);
- }
- private _clearDates(): void {
- this.setState({
- dateMoment: undefined,
- timeMoment: undefined,
- });
- const defaultDateTime = utils.initialOrderExpiryUnixTimestampSec();
- this.props.updateOrderExpiry(defaultDateTime);
- }
- private _onDateChanged(_event: any, date: Date): void {
- const dateMoment = moment(date);
- this.setState({
- dateMoment,
- });
- const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, this.state.timeMoment);
- this.props.updateOrderExpiry(timestamp);
- }
- private _onTimeChanged(_event: any, time: Date): void {
- const timeMoment = moment(time);
- this.setState({
- timeMoment,
- });
- const dateMoment = _.isUndefined(this.state.dateMoment) ? moment() : this.state.dateMoment;
- const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, timeMoment);
- this.props.updateOrderExpiry(timestamp);
- }
-}
diff --git a/packages/website/ts/components/inputs/hash_input.tsx b/packages/website/ts/components/inputs/hash_input.tsx
deleted file mode 100644
index 7688ffe21..000000000
--- a/packages/website/ts/components/inputs/hash_input.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { Styles } from '@0x/react-shared';
-import { Order } from '@0x/types';
-import * as _ from 'lodash';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-
-import { Blockchain } from 'ts/blockchain';
-import { FakeTextField } from 'ts/components/ui/fake_text_field';
-import { HashData } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-const styles: Styles = {
- textField: {
- overflow: 'hidden',
- paddingTop: 8,
- textOverflow: 'ellipsis',
- whiteSpace: 'nowrap',
- },
-};
-
-interface HashInputProps {
- blockchain: Blockchain;
- blockchainIsLoaded: boolean;
- hashData: HashData;
- label: string;
-}
-
-interface HashInputState {}
-
-export class HashInput extends React.Component<HashInputProps, HashInputState> {
- public render(): React.ReactNode {
- const msgHashHex = this.props.blockchainIsLoaded ? this._generateMessageHashHex() : '';
- return (
- <div>
- <FakeTextField label={this.props.label}>
- <div style={styles.textField} data-tip={true} data-for="hashTooltip">
- {msgHashHex}
- </div>
- </FakeTextField>
- <ReactTooltip id="hashTooltip">{msgHashHex}</ReactTooltip>
- </div>
- );
- }
- private _generateMessageHashHex(): string {
- const exchangeAddress = this.props.blockchain.getExchangeContractAddressIfExists();
- const hashData = this.props.hashData;
- const makerAssetData = assetDataUtils.encodeERC20AssetData(hashData.depositTokenContractAddr);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(hashData.receiveTokenContractAddr);
- const order: Order = {
- senderAddress: constants.NULL_ADDRESS,
- exchangeAddress,
- expirationTimeSeconds: hashData.orderExpiryTimestamp,
- feeRecipientAddress: hashData.feeRecipientAddress,
- makerAddress: _.isEmpty(hashData.orderMakerAddress) ? constants.NULL_ADDRESS : hashData.orderMakerAddress,
- makerFee: hashData.makerFee,
- makerAssetData,
- makerAssetAmount: hashData.depositAmount,
- salt: hashData.orderSalt,
- takerAddress: hashData.orderTakerAddress,
- takerFee: hashData.takerFee,
- takerAssetData,
- takerAssetAmount: hashData.receiveAmount,
- };
- const orderHash = orderHashUtils.getOrderHashHex(order);
- return orderHash;
- }
-}
diff --git a/packages/website/ts/components/inputs/identicon_address_input.tsx b/packages/website/ts/components/inputs/identicon_address_input.tsx
deleted file mode 100644
index 6ba7584a7..000000000
--- a/packages/website/ts/components/inputs/identicon_address_input.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import * as React from 'react';
-import { AddressInput } from 'ts/components/inputs/address_input';
-import { Identicon } from 'ts/components/ui/identicon';
-import { InputLabel } from 'ts/components/ui/input_label';
-import { RequiredLabel } from 'ts/components/ui/required_label';
-
-interface IdenticonAddressInputProps {
- initialAddress: string;
- isRequired?: boolean;
- label: string;
- updateOrderAddress: (address?: string) => void;
-}
-
-interface IdenticonAddressInputState {
- address: string;
-}
-
-export class IdenticonAddressInput extends React.Component<IdenticonAddressInputProps, IdenticonAddressInputState> {
- constructor(props: IdenticonAddressInputProps) {
- super(props);
- this.state = {
- address: props.initialAddress,
- };
- }
- public render(): React.ReactNode {
- const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : this.props.label;
- return (
- <div className="relative" style={{ width: '100%' }}>
- <InputLabel text={label} />
- <div className="flex">
- <div className="col col-1 pb1 pr1" style={{ paddingTop: 13 }}>
- <Identicon address={this.state.address} diameter={26} />
- </div>
- <div className="col col-11 pb1 pl1" style={{ height: 65 }}>
- <AddressInput
- hintText="e.g 0x75bE4F78AA3699B3A348c84bDB2a96c3Db..."
- shouldHideLabel={true}
- initialAddress={this.props.initialAddress}
- updateAddress={this._updateAddress.bind(this)}
- />
- </div>
- </div>
- </div>
- );
- }
- private _updateAddress(address?: string): void {
- this.setState({
- address,
- });
- this.props.updateOrderAddress(address);
- }
-}
diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx
deleted file mode 100644
index fded3a9dd..000000000
--- a/packages/website/ts/components/inputs/token_amount_input.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-import { colors, Link } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input';
-import { Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types';
-
-interface TokenAmountInputProps {
- userAddress: string;
- networkId: number;
- blockchain: Blockchain;
- token: Token;
- label?: string;
- amount?: BigNumber;
- hintText?: string;
- shouldShowIncompleteErrs: boolean;
- shouldCheckBalance: boolean;
- shouldCheckAllowance: boolean;
- onChange: ValidatedBigNumberCallback;
- onErrorMsgChange?: (errorMsg: React.ReactNode) => void;
- lastForceTokenStateRefetch: number;
- shouldShowErrs?: boolean;
- shouldShowUnderline?: boolean;
- style?: React.CSSProperties;
- labelStyle?: React.CSSProperties;
- inputHintStyle?: React.CSSProperties;
-}
-
-interface TokenAmountInputState {
- balance: BigNumber;
- allowance: BigNumber;
- isBalanceAndAllowanceLoaded: boolean;
-}
-
-const HEIGHT_WITH_LABEL = 84;
-const HEIGHT_WITHOUT_LABEL = 62;
-
-export class TokenAmountInput extends React.Component<TokenAmountInputProps, TokenAmountInputState> {
- public static defaultProps: Partial<TokenAmountInputProps> = {
- shouldShowErrs: true,
- shouldShowUnderline: true,
- };
- private _isUnmounted: boolean;
- constructor(props: TokenAmountInputProps) {
- super(props);
- this._isUnmounted = false;
- const defaultAmount = new BigNumber(0);
- this.state = {
- balance: defaultAmount,
- allowance: defaultAmount,
- isBalanceAndAllowanceLoaded: false,
- };
- }
- public componentWillMount(): void {
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalanceAndAllowanceAsync(this.props.token.address, this.props.userAddress);
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public componentWillReceiveProps(nextProps: TokenAmountInputProps): void {
- if (
- nextProps.userAddress !== this.props.userAddress ||
- nextProps.networkId !== this.props.networkId ||
- nextProps.token.address !== this.props.token.address ||
- nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
- ) {
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalanceAndAllowanceAsync(nextProps.token.address, nextProps.userAddress);
- }
- }
- public render(): React.ReactNode {
- const amount = this.props.amount
- ? Web3Wrapper.toUnitAmount(this.props.amount, this.props.token.decimals)
- : undefined;
- return (
- <div className="flex overflow-hidden" style={this._getStyle()}>
- <BalanceBoundedInput
- label={this.props.label}
- amount={amount}
- balance={Web3Wrapper.toUnitAmount(this.state.balance, this.props.token.decimals)}
- onChange={this._onChange.bind(this)}
- onErrorMsgChange={this.props.onErrorMsgChange}
- validate={this._validate.bind(this)}
- shouldCheckBalance={this.props.shouldCheckBalance}
- shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
- isDisabled={!this.state.isBalanceAndAllowanceLoaded}
- hintText={this.props.hintText}
- shouldShowErrs={this.props.shouldShowErrs}
- shouldShowUnderline={this.props.shouldShowUnderline}
- inputStyle={this.props.style}
- inputHintStyle={this.props.inputHintStyle}
- />
- <div style={this._getLabelStyle()}>{this.props.token.symbol}</div>
- </div>
- );
- }
- private _onChange(isValid: boolean, amount?: BigNumber): void {
- let baseUnitAmount;
- if (!_.isUndefined(amount)) {
- baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amount, this.props.token.decimals);
- }
- this.props.onChange(isValid, baseUnitAmount);
- }
- private _validate(amount: BigNumber): React.ReactNode {
- if (this.props.shouldCheckAllowance && amount.gt(this.state.allowance)) {
- return (
- <span>
- Insufficient allowance.{' '}
- <Link
- to={`${WebsitePaths.Portal}/account`}
- textDecoration="underline"
- fontColor={colors.darkestGrey}
- >
- Set allowance
- </Link>
- </span>
- );
- } else {
- return undefined;
- }
- }
- private async _fetchBalanceAndAllowanceAsync(tokenAddress: string, userAddress: string): Promise<void> {
- this.setState({
- isBalanceAndAllowanceLoaded: false,
- });
- const userAddressIfExists = _.isEmpty(userAddress) ? undefined : userAddress;
- const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- tokenAddress,
- );
- if (!this._isUnmounted) {
- this.setState({
- balance,
- allowance,
- isBalanceAndAllowanceLoaded: true,
- });
- }
- }
- private _getStyle(): React.CSSProperties {
- const hasLabel = !_.isUndefined(this.props.label);
- return !_.isUndefined(this.props.style)
- ? this.props.style
- : { height: hasLabel ? HEIGHT_WITH_LABEL : HEIGHT_WITHOUT_LABEL };
- }
- private _getLabelStyle(): React.CSSProperties {
- const hasLabel = !_.isUndefined(this.props.label);
- return this.props.labelStyle || { paddingTop: hasLabel ? 39 : 14 };
- }
-}
diff --git a/packages/website/ts/components/inputs/token_input.tsx b/packages/website/ts/components/inputs/token_input.tsx
deleted file mode 100644
index c3c2d8b37..000000000
--- a/packages/website/ts/components/inputs/token_input.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { colors } from '@0x/react-shared';
-import Paper from 'material-ui/Paper';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { AssetPicker } from 'ts/components/generate_order/asset_picker';
-import { InputLabel } from 'ts/components/ui/input_label';
-import { TokenIcon } from 'ts/components/ui/token_icon';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { AssetToken, BlockchainErrs, Side, Token, TokenByAddress } from 'ts/types';
-
-const TOKEN_ICON_DIMENSION = 80;
-
-interface TokenInputProps {
- blockchain: Blockchain;
- blockchainErr: BlockchainErrs;
- dispatcher: Dispatcher;
- label: string;
- side: Side;
- networkId: number;
- assetToken: AssetToken;
- updateChosenAssetToken: (side: Side, token: AssetToken) => void;
- tokenByAddress: TokenByAddress;
- userAddress: string;
-}
-
-interface TokenInputState {
- isHoveringIcon: boolean;
- isPickerOpen: boolean;
- trackCandidateTokenIfExists?: Token;
-}
-
-export class TokenInput extends React.Component<TokenInputProps, TokenInputState> {
- constructor(props: TokenInputProps) {
- super(props);
- this.state = {
- isHoveringIcon: false,
- isPickerOpen: false,
- };
- }
- public render(): React.ReactNode {
- const token = this.props.tokenByAddress[this.props.assetToken.address];
- const iconStyles = {
- cursor: 'pointer',
- opacity: this.state.isHoveringIcon ? 0.5 : 1,
- };
- return (
- <div className="relative">
- <div className="pb1">
- <InputLabel text={this.props.label} />
- </div>
- <Paper
- zDepth={1}
- style={{ cursor: 'pointer' }}
- onMouseEnter={this._onToggleHover.bind(this, true)}
- onMouseLeave={this._onToggleHover.bind(this, false)}
- onClick={this._onAssetClicked.bind(this)}
- >
- <div className="mx-auto pt2" style={{ width: TOKEN_ICON_DIMENSION, ...iconStyles }}>
- <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} />
- </div>
- <div className="py1 center" style={{ color: colors.grey }}>
- {token.name}
- </div>
- </Paper>
- <AssetPicker
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- isOpen={this.state.isPickerOpen}
- currentTokenAddress={this.props.assetToken.address}
- onTokenChosen={this._onTokenChosen.bind(this)}
- tokenByAddress={this.props.tokenByAddress}
- />
- </div>
- );
- }
- private _onTokenChosen(tokenAddress: string): void {
- const assetToken: AssetToken = {
- address: tokenAddress,
- amount: this.props.assetToken.amount,
- };
- this.props.updateChosenAssetToken(this.props.side, assetToken);
- this.setState({
- isPickerOpen: false,
- });
- }
- private _onToggleHover(isHoveringIcon: boolean): void {
- this.setState({
- isHoveringIcon,
- });
- }
- private _onAssetClicked(): void {
- if (this.props.blockchainErr !== BlockchainErrs.NoError) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return;
- }
-
- this.setState({
- isPickerOpen: true,
- });
- }
-}
diff --git a/packages/website/ts/components/link.tsx b/packages/website/ts/components/link.tsx
deleted file mode 100644
index a66985acc..000000000
--- a/packages/website/ts/components/link.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { Link as SmartLink } from '@0x/react-shared';
-import * as React from 'react';
-import styled from 'styled-components';
-
-interface LinkInterface {
- color?: string;
- children?: React.ReactNode | string;
- isNoArrow?: boolean;
- hasIcon?: boolean | string;
- isBlock?: boolean;
- isCentered?: boolean;
- href?: string;
- theme?: {
- textColor: string;
- };
- shouldOpenInNewTab?: boolean;
- target?: string;
-}
-
-export const Link = (props: LinkInterface) => {
- const { children, isNoArrow, href } = props;
-
- return (
- <StyledLink to={href} {...props}>
- {children}
- {!isNoArrow && (
- <svg width="25" height="25" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M8.484 5.246l.023 1.411 8.147.053L4.817 18.547l.996.996L17.65 7.706l.052 8.146 1.411.024-.068-10.561-10.561-.069z"
- fill="currentColor"
- />
- </svg>
- )}
- </StyledLink>
- );
-};
-
-// Added this, & + & doesnt really work since we switch with element types...
-export const LinkWrap = styled.div`
- a + a,
- a + button,
- button + a {
- margin-left: 20px;
- }
-`;
-
-const StyledLink = styled(SmartLink)<LinkInterface>`
- display: ${props => !props.isBlock && 'inline-flex'};
- color: ${props => props.color || props.theme.linkColor};
- text-align: center;
- font-size: 18px;
- text-decoration: none;
- align-items: center;
-
- @media (max-width: 768px) {
- }
-
- svg {
- margin-left: 3px;
- }
-`;
diff --git a/packages/website/ts/components/logo.tsx b/packages/website/ts/components/logo.tsx
deleted file mode 100644
index f89be0711..000000000
--- a/packages/website/ts/components/logo.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { ThemeInterface } from 'ts/components/siteWrap';
-import LogoIcon from 'ts/icons/logo-with-type.svg';
-
-interface LogoInterface {
- theme?: ThemeInterface;
-}
-
-// Note let's refactor this
-// is it absolutely necessary to have a stateless component
-// to pass props down into the styled icon?
-const StyledLogo = styled.div`
- text-align: left;
- position: relative;
- z-index: 25;
-
- @media (max-width: 800px) {
- svg {
- width: 60px;
- }
- }
-`;
-
-const Icon = styled(LogoIcon)<LogoInterface>`
- flex-shrink: 0;
-
- path {
- fill: ${props => props.theme.textColor};
- }
-`;
-
-export const Logo: React.StatelessComponent<LogoInterface> = (props: LogoInterface) => (
- <StyledLogo>
- <Icon {...props} />
- </StyledLogo>
-);
diff --git a/packages/website/ts/components/meta_tags.tsx b/packages/website/ts/components/meta_tags.tsx
deleted file mode 100644
index f6c43d23f..000000000
--- a/packages/website/ts/components/meta_tags.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import * as React from 'react';
-import { Helmet } from 'react-helmet';
-
-export interface MetaTagsProps {
- title: string;
- description: string;
- imgSrc?: string;
-}
-
-export const MetaTags: React.StatelessComponent<MetaTagsProps> = ({ title, description, imgSrc }) => (
- <Helmet>
- <title>{title}</title>
- <meta name="description" content={description} />
- <meta property="og:title" content={title} />
- <meta property="og:description" content={description} />
- <meta property="og:type" content="website" />
- <meta property="og:image" content={imgSrc} />
- <meta name="twitter:site" content="@0xproject" />
- <meta name="twitter:image" content={imgSrc} />
- </Helmet>
-);
-
-MetaTags.defaultProps = {
- imgSrc: '/images/og_image.png',
-};
diff --git a/packages/website/ts/components/mobileNav.tsx b/packages/website/ts/components/mobileNav.tsx
deleted file mode 100644
index d43bbe50e..000000000
--- a/packages/website/ts/components/mobileNav.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-import * as React from 'react';
-import MediaQuery from 'react-responsive';
-import styled from 'styled-components';
-
-import { Link } from 'react-router-dom';
-
-import { WrapGrid, WrapProps } from 'ts/components/newLayout';
-import { WebsitePaths } from 'ts/types';
-
-interface Props {
- isToggled: boolean;
- toggleMobileNav: () => void;
-}
-
-export class MobileNav extends React.PureComponent<Props> {
- public render(): React.ReactNode {
- const { isToggled, toggleMobileNav } = this.props;
-
- return (
- <MediaQuery maxWidth={800}>
- <Wrap isToggled={isToggled}>
- <Section>
- <h4>Products</h4>
-
- <ul>
- <li>
- <Link to={WebsitePaths.Instant}>0x Instant</Link>
- </li>
- <li>
- <Link to={WebsitePaths.LaunchKit}>0x Launch Kit</Link>
- </li>
- </ul>
- </Section>
-
- <Section isDark={true}>
- <Grid as="ul" isFullWidth={true} isWrapped={true}>
- <li>
- <Link to={WebsitePaths.Why}>Why 0x</Link>
- </li>
- <li>
- <Link to={WebsitePaths.AboutMission}>About</Link>
- </li>
- <li>
- <a href="https://blog.0xproject.com/latest" target="_blank">
- Blog
- </a>
- </li>
- </Grid>
- </Section>
-
- {isToggled && <Overlay onClick={toggleMobileNav} />}
- </Wrap>
- </MediaQuery>
- );
- }
-}
-
-const Wrap = styled.nav<{ isToggled: boolean }>`
- width: 100%;
- height: 357px;
- background-color: ${props => props.theme.mobileNavBgUpper};
- color: ${props => props.theme.mobileNavColor};
- transition: ${props => (props.isToggled ? 'visibility 0s, transform 0.5s' : 'visibility 0s 0.5s, transform 0.5s')};
- transform: translate3d(0, ${props => (props.isToggled ? 0 : '-100%')}, 0);
- visibility: ${props => !props.isToggled && 'hidden'};
- position: fixed;
- display: flex;
- flex-direction: column;
- justify-content: flex-end;
- z-index: 20;
- top: 0;
- left: 0;
- font-size: 20px;
-
- a {
- padding: 15px 0;
- display: block;
- color: inherit;
- }
-
- h4 {
- font-size: 14px;
- opacity: 0.5;
- }
-`;
-
-const Overlay = styled.div`
- position: absolute;
- width: 100vw;
- height: 100vh;
- top: 100%;
- background: transparent;
- cursor: pointer;
-`;
-
-interface SectionProps {
- isDark?: boolean;
-}
-const Section = styled.div<SectionProps>`
- width: 100%;
- padding: 15px 30px;
- background-color: ${props => (props.isDark ? props.theme.mobileNavBgLower : 'transparent')};
-`;
-
-const Grid = styled(WrapGrid)<WrapProps>`
- justify-content: flex-start;
-
- li {
- width: 50%;
- flex-shrink: 0;
- }
-`;
diff --git a/packages/website/ts/components/modals/input.tsx b/packages/website/ts/components/modals/input.tsx
deleted file mode 100644
index c72e53aa0..000000000
--- a/packages/website/ts/components/modals/input.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-export enum InputWidth {
- Half,
- Full,
-}
-
-interface InputProps {
- name: string;
- width?: InputWidth;
- label: string;
- type?: string;
- errors?: ErrorProps;
- isErrors?: boolean;
- required?: boolean;
-}
-
-interface ErrorProps {
- [key: string]: string;
-}
-
-export const Input = React.forwardRef((props: InputProps, ref?: React.Ref<HTMLInputElement>) => {
- const { name, label, type, errors } = props;
- const id = `input-${name}`;
- const componentType = type === 'textarea' ? 'textarea' : 'input';
- const isErrors = errors.hasOwnProperty(name) && errors[name] !== null;
- const errorMessage = isErrors ? errors[name] : null;
-
- return (
- <InputWrapper {...props}>
- <Label htmlFor={id}>{label}</Label>
- <StyledInput as={componentType} ref={ref} id={id} isErrors={isErrors} {...props} />
- {isErrors && <Error>{errorMessage}</Error>}
- </InputWrapper>
- );
-});
-
-Input.defaultProps = {
- width: InputWidth.Full,
- errors: {},
-};
-
-const StyledInput = styled.input`
- appearance: none;
- background-color: #fff;
- border: 1px solid #d5d5d5;
- color: #000;
- font-size: 1.294117647rem;
- padding: 16px 15px 14px;
- outline: none;
- width: 100%;
- min-height: ${props => props.type === 'textarea' && `120px`};
-
- background-color: ${(props: InputProps) => props.isErrors && `#FDEDED`};
- border-color: ${(props: InputProps) => props.isErrors && `#FD0000`};
-
- &::placeholder {
- color: #c3c3c3;
- }
-`;
-
-const InputWrapper = styled.div<InputProps>`
- position: relative;
- flex-grow: ${props => props.width === InputWidth.Full && 1};
- width: ${props => props.width === InputWidth.Half && `calc(50% - 15px)`};
-
- @media (max-width: 768px) {
- width: 100%;
- margin-bottom: 30px;
- }
-`;
-
-const Label = styled.label`
- color: #000;
- font-size: 1.111111111rem;
- line-height: 1.4em;
- margin-bottom: 10px;
- display: inline-block;
-`;
-
-const Error = styled.span`
- color: #fd0000;
- font-size: 0.833333333rem;
- line-height: 1em;
- display: inline-block;
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- transform: translateY(24px);
-`;
diff --git a/packages/website/ts/components/modals/modal_contact.tsx b/packages/website/ts/components/modals/modal_contact.tsx
deleted file mode 100644
index 62c1062a3..000000000
--- a/packages/website/ts/components/modals/modal_contact.tsx
+++ /dev/null
@@ -1,390 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { colors } from 'ts/style/colors';
-
-import { DialogContent, DialogOverlay } from '@reach/dialog';
-import '@reach/dialog/styles.css';
-
-import { Button } from 'ts/components/button';
-import { Icon } from 'ts/components/icon';
-import { Input, InputWidth } from 'ts/components/modals/input';
-import { Heading, Paragraph } from 'ts/components/text';
-import { GlobalStyle } from 'ts/constants/globalStyle';
-import { utils } from 'ts/utils/utils';
-
-export enum ModalContactType {
- General = 'GENERAL',
- MarketMaker = 'MARKET_MAKER',
-}
-
-interface Props {
- theme?: GlobalStyle;
- isOpen?: boolean;
- onDismiss?: () => void;
- modalContactType: ModalContactType;
-}
-
-interface FormProps {
- isSuccessful?: boolean;
- isSubmitting?: boolean;
-}
-
-interface ErrorResponseProps {
- param: string;
- location: string;
- msg: string;
-}
-
-interface ErrorResponse {
- errors: ErrorResponseProps[];
-}
-
-interface ErrorProps {
- [key: string]: string;
-}
-
-export class ModalContact extends React.Component<Props> {
- public static defaultProps = {
- modalContactType: ModalContactType.General,
- };
- public state = {
- isSubmitting: false,
- isSuccessful: false,
- errors: {},
- };
- // shared fields
- public nameRef: React.RefObject<HTMLInputElement> = React.createRef();
- public emailRef: React.RefObject<HTMLInputElement> = React.createRef();
- public companyProjectRef: React.RefObject<HTMLInputElement> = React.createRef();
- public commentsRef: React.RefObject<HTMLInputElement> = React.createRef();
- // general lead fields
- public linkRef: React.RefObject<HTMLInputElement> = React.createRef();
- // market maker lead fields
- public countryRef: React.RefObject<HTMLInputElement> = React.createRef();
- public fundSizeRef: React.RefObject<HTMLInputElement> = React.createRef();
- public constructor(props: Props) {
- super(props);
- }
- public render(): React.ReactNode {
- const { isOpen, onDismiss } = this.props;
- const { isSuccessful, errors } = this.state;
- return (
- <>
- <DialogOverlay
- style={{ background: 'rgba(0, 0, 0, 0.75)', zIndex: 30 }}
- isOpen={isOpen}
- onDismiss={onDismiss}
- >
- <StyledDialogContent>
- <Form onSubmit={this._onSubmitAsync.bind(this)} isSuccessful={isSuccessful}>
- <Heading color={colors.textDarkPrimary} size={34} asElement="h2">
- Contact the 0x Core Team
- </Heading>
- {this._renderFormContent(errors)}
- <ButtonRow>
- <Button
- color="#5C5C5C"
- isNoBorder={true}
- isTransparent={true}
- type="button"
- onClick={this.props.onDismiss}
- >
- Back
- </Button>
- <Button>Submit</Button>
- </ButtonRow>
- </Form>
- <Confirmation isSuccessful={isSuccessful}>
- <Icon name="rocketship" size="large" margin={[0, 0, 'default', 0]} />
- <Heading color={colors.textDarkPrimary} size={34} asElement="h2">
- Thanks for contacting us.
- </Heading>
- <Paragraph isMuted={true} color={colors.textDarkPrimary}>
- We'll get back to you soon. If you need quick support in the meantime, reach out to the
- 0x team on Discord.
- </Paragraph>
- <Button onClick={this.props.onDismiss}>Done</Button>
- </Confirmation>
- </StyledDialogContent>
- </DialogOverlay>
- </>
- );
- }
- public _renderFormContent(errors: ErrorProps): React.ReactNode {
- switch (this.props.modalContactType) {
- case ModalContactType.MarketMaker:
- return this._renderMarketMakerFormContent(errors);
- case ModalContactType.General:
- default:
- return this._renderGeneralFormContent(errors);
- }
- }
- private _renderMarketMakerFormContent(errors: ErrorProps): React.ReactNode {
- return (
- <>
- <Paragraph isMuted={true} color={colors.textDarkPrimary}>
- If you’re considering market making on 0x, we’re happy to answer your questions. Fill out the form
- so we can connect you with the right person to help you get started.
- </Paragraph>
- <InputRow>
- <Input
- name="name"
- label="Your name"
- type="text"
- width={InputWidth.Half}
- ref={this.nameRef}
- required={true}
- errors={errors}
- />
- <Input
- name="email"
- label="Your email"
- type="email"
- ref={this.emailRef}
- required={true}
- errors={errors}
- width={InputWidth.Half}
- />
- </InputRow>
- <InputRow>
- <Input
- name="country"
- label="Country of Location"
- type="text"
- ref={this.countryRef}
- required={true}
- errors={errors}
- />
- </InputRow>
- <InputRow>
- <Input
- name="fundSize"
- label="Fund Size"
- type="text"
- ref={this.fundSizeRef}
- required={true}
- errors={errors}
- />
- </InputRow>
- <InputRow>
- <Input
- name="companyOrProject"
- label="Name of your project / company"
- type="text"
- ref={this.companyProjectRef}
- required={false}
- errors={errors}
- />
- </InputRow>
- <InputRow>
- <Input
- name="comments"
- label="What is prompting you to reach out?"
- type="textarea"
- ref={this.commentsRef}
- required={false}
- errors={errors}
- />
- </InputRow>
- </>
- );
- }
- private _renderGeneralFormContent(errors: ErrorProps): React.ReactNode {
- return (
- <>
- <Paragraph isMuted={true} color={colors.textDarkPrimary}>
- If you're considering building on 0x, we're happy to answer your questions. Fill out the form so we
- can connect you with the right person to help you get started.
- </Paragraph>
- <InputRow>
- <Input
- name="name"
- label="Your name"
- type="text"
- width={InputWidth.Half}
- ref={this.nameRef}
- required={true}
- errors={errors}
- />
- <Input
- name="email"
- label="Your email"
- type="email"
- ref={this.emailRef}
- required={true}
- errors={errors}
- width={InputWidth.Half}
- />
- </InputRow>
- <InputRow>
- <Input
- name="companyOrProject"
- label="Name of your project / company"
- type="text"
- ref={this.companyProjectRef}
- required={true}
- errors={errors}
- />
- </InputRow>
- <InputRow>
- <Input
- name="link"
- label="Do you have any documentation or a website?"
- type="text"
- ref={this.linkRef}
- errors={errors}
- />
- </InputRow>
- <InputRow>
- <Input
- name="comments"
- label="Anything else?"
- type="textarea"
- ref={this.commentsRef}
- errors={errors}
- />
- </InputRow>
- </>
- );
- }
- private async _onSubmitAsync(e: Event): Promise<void> {
- e.preventDefault();
-
- let jsonBody;
- if (this.props.modalContactType === ModalContactType.MarketMaker) {
- jsonBody = {
- name: this.nameRef.current.value,
- email: this.emailRef.current.value,
- country: this.countryRef.current.value,
- fundSize: this.fundSizeRef.current.value,
- projectOrCompany: this.companyProjectRef.current.value,
- comments: this.commentsRef.current.value,
- };
- } else {
- jsonBody = {
- name: this.nameRef.current.value,
- email: this.emailRef.current.value,
- projectOrCompany: this.companyProjectRef.current.value,
- link: this.linkRef.current.value,
- comments: this.commentsRef.current.value,
- };
- }
-
- this.setState({ ...this.state, errors: [], isSubmitting: true });
-
- const endpoint =
- this.props.modalContactType === ModalContactType.MarketMaker ? '/market_maker_leads' : '/leads';
-
- try {
- // Disabling no-unbound method b/c no reason for _.isEmpty to be bound
- // tslint:disable:no-unbound-method
- const response = await fetch(`${utils.getBackendBaseUrl()}${endpoint}`, {
- method: 'post',
- mode: 'cors',
- credentials: 'same-origin',
- headers: {
- 'content-type': 'application/json; charset=utf-8',
- },
- body: JSON.stringify(_.omitBy(jsonBody, _.isEmpty)),
- });
-
- if (!response.ok) {
- const errorResponse: ErrorResponse = await response.json();
- const errors = this._parseErrors(errorResponse.errors);
- this.setState({ ...this.state, isSubmitting: false, errors });
-
- throw new Error('Request failed');
- }
-
- this.setState({ ...this.state, isSuccessful: true });
- } catch (e) {
- // Empty block
- }
- }
- private _parseErrors(errors: ErrorResponseProps[]): ErrorProps {
- const initialValue: {} = {};
- return _.reduce(
- errors,
- (hash: ErrorProps, error: ErrorResponseProps) => {
- const { param, msg } = error;
- const key = param;
- hash[key] = msg;
-
- return hash;
- },
- initialValue,
- );
- }
-}
-
-// Handle errors: {"errors":[{"location":"body","param":"name","msg":"Invalid value"},{"location":"body","param":"email","msg":"Invalid value"}]}
-
-const InputRow = styled.div`
- width: 100%;
- flex: 0 0 auto;
-
- @media (min-width: 768px) {
- display: flex;
- justify-content: space-between;
- margin-bottom: 30px;
- }
-`;
-
-const ButtonRow = styled(InputRow)`
- @media (max-width: 768px) {
- display: flex;
- flex-direction: column;
-
- button:nth-child(1) {
- order: 2;
- }
-
- button:nth-child(2) {
- order: 1;
- margin-bottom: 10px;
- }
- }
-`;
-
-const StyledDialogContent = styled(DialogContent)`
- position: relative;
- max-width: 800px;
- background-color: #f6f6f6 !important;
- padding: 60px 60px !important;
-
- @media (max-width: 768px) {
- width: calc(100vw - 40px) !important;
- margin: 40px auto !important;
- padding: 30px 30px !important;
- }
-`;
-
-const Form = styled.form<FormProps>`
- position: relative;
- transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
-
- opacity: ${props => props.isSuccessful && `0`};
- visibility: ${props => props.isSuccessful && `hidden`};
-`;
-
-const Confirmation = styled.div<FormProps>`
- position: absolute;
- top: 50%;
- text-align: center;
- width: 100%;
- left: 0;
- transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
- transition-delay: 0.4s;
- padding: 60px 60px;
- transform: translateY(-50%);
- opacity: ${props => (props.isSuccessful ? `1` : `0`)};
- visibility: ${props => (props.isSuccessful ? 'visible' : `hidden`)};
-
- p {
- max-width: 492px;
- margin-left: auto;
- margin-right: auto;
- }
-`;
diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx
deleted file mode 100644
index 56df880f3..000000000
--- a/packages/website/ts/components/nested_sidebar_menu.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { ALink, colors, Link, utils as sharedUtils } from '@0x/react-shared';
-import { ObjectMap } from '@0x/types';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Button } from 'ts/components/ui/button';
-import { Text } from 'ts/components/ui/text';
-import { ScreenWidths } from 'ts/types';
-
-export interface NestedSidebarMenuProps {
- sectionNameToLinks: ObjectMap<ALink[]>;
- sidebarHeader?: React.ReactNode;
- shouldReformatMenuItemNames?: boolean;
- screenWidth: ScreenWidths;
-}
-
-export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => {
- const navigation = _.map(props.sectionNameToLinks, (links: ALink[], sectionName: string) => {
- const finalSectionName = sharedUtils.convertCamelCaseToSpaces(sectionName);
- const menuItems = _.map(links, (link, i) => {
- const menuItemTitle = props.shouldReformatMenuItemNames
- ? _.capitalize(sharedUtils.convertDashesToSpaces(link.title))
- : link.title;
- const finalLink = {
- ...link,
- title: menuItemTitle,
- };
- return <MenuItem key={`menu-item-${menuItemTitle}`} link={finalLink} screenWidth={props.screenWidth} />;
- });
- // tslint:disable-next-line:no-unused-variable
- return (
- <div key={`section-${sectionName}`} className="py1" style={{ color: colors.greyTheme }}>
- <Text fontSize="14px" letterSpacing="0.5" className="py1 pl1">
- {finalSectionName.toUpperCase()}
- </Text>
- {menuItems}
- </div>
- );
- });
- return (
- <div>
- {props.sidebarHeader}
- <div>{navigation}</div>
- </div>
- );
-};
-
-export interface MenuItemProps {
- link: ALink;
- screenWidth: ScreenWidths;
-}
-
-export interface MenuItemState {
- isActive: boolean;
-}
-
-export class MenuItem extends React.Component<MenuItemProps, MenuItemState> {
- constructor(props: MenuItemProps) {
- super(props);
- const isActive = window.location.hash.slice(1) === props.link.to;
- this.state = {
- isActive,
- };
- }
- public render(): React.ReactNode {
- const isActive = this.state.isActive;
- return (
- <Link
- to={this.props.link.to}
- shouldOpenInNewTab={this.props.link.shouldOpenInNewTab}
- onActivityChanged={this._onActivityChanged.bind(this)}
- >
- <Button
- borderRadius="4px"
- padding="0.4em 0.375em"
- width="100%"
- backgroundColor={
- isActive
- ? colors.lightLinkBlue
- : this.props.screenWidth === ScreenWidths.Sm
- ? 'white'
- : colors.grey100
- }
- fontSize="14px"
- textAlign="left"
- >
- <Text
- fontWeight={isActive ? 'bold' : 'normal'}
- fontColor={isActive ? colors.white : colors.grey800}
- >
- {this.props.link.title}
- </Text>
- </Button>
- </Link>
- );
- }
- private _onActivityChanged(isActive: boolean): void {
- this.setState({
- isActive,
- });
- }
-}
diff --git a/packages/website/ts/components/newLayout.tsx b/packages/website/ts/components/newLayout.tsx
deleted file mode 100644
index 07691a02a..000000000
--- a/packages/website/ts/components/newLayout.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-export interface WrapProps {
- bgColor?: string;
- id?: string;
- offsetTop?: string;
- maxWidth?: string;
- wrapWidth?: string;
- isFullWidth?: boolean;
- isTextCentered?: boolean;
- isCentered?: boolean;
- isWrapped?: boolean;
-}
-
-export interface WrapGridProps {
- isWrapped?: boolean;
- isCentered?: boolean;
-}
-
-export interface WrapStickyProps {
- offsetTop?: string;
-}
-
-export interface SectionProps extends WrapProps {
- isPadded?: boolean;
- isFullWidth?: boolean;
- isFlex?: boolean;
- padding?: string;
- paddingMobile?: string;
- flexBreakpoint?: string;
- maxWidth?: string;
- bgColor?: 'dark' | 'light' | string;
- children: any;
-}
-
-export interface FlexProps {
- padding?: string;
- isFlex?: boolean;
- flexBreakpoint?: string;
-}
-
-export interface ColumnProps {
- padding?: string;
- width?: string;
- maxWidth?: string;
-}
-
-export const Section: React.FunctionComponent<SectionProps> = (props: SectionProps) => {
- return (
- <SectionBase {...props}>
- <Wrap {...props}>{props.children}</Wrap>
- </SectionBase>
- );
-};
-
-export const Column = styled.div<ColumnProps>`
- width: ${props => props.width};
- max-width: ${props => props.maxWidth};
- padding: ${props => props.padding};
-
- @media (max-width: 768px) {
- width: 100%;
-
- & + & {
- margin-top: 60px;
- }
- }
-`;
-
-export const FlexWrap = styled.div<FlexProps>`
- max-width: 1500px;
- margin: 0 auto;
- padding: ${props => props.padding};
-
- @media (min-width: ${props => props.flexBreakpoint || '768px'}) {
- display: ${props => props.isFlex && 'flex'};
- justify-content: ${props => props.isFlex && 'space-between'};
- }
-`;
-
-export const WrapSticky = styled.div<WrapProps>`
- position: sticky;
- top: ${props => props.offsetTop || '60px'};
-`;
-
-const SectionBase = styled.section<SectionProps>`
- width: ${props => !props.isFullWidth && 'calc(100% - 60px)'};
- max-width: 1500px;
- margin: 0 auto;
- padding: ${props => props.isPadded && '120px 0'};
- background-color: ${props => props.theme[`${props.bgColor}BgColor`] || props.bgColor};
- position: relative;
- overflow: ${props => !props.isFullWidth && 'hidden'};
-
- @media (max-width: 768px) {
- padding: ${props => props.isPadded && (props.paddingMobile || '40px 0')};
- }
-`;
-
-const Wrap = styled(FlexWrap)<WrapProps>`
- width: ${props => props.wrapWidth || 'calc(100% - 60px)'};
- width: ${props => props.bgColor && 'calc(100% - 60px)'};
- max-width: ${props => !props.isFullWidth && (props.maxWidth || '895px')};
- text-align: ${props => props.isTextCentered && 'center'};
- margin: 0 auto;
-`;
-
-export const WrapGrid = styled(Wrap)<WrapProps>`
- display: flex;
- flex-wrap: ${props => props.isWrapped && `wrap`};
- justify-content: ${props => (props.isCentered ? `center` : 'space-between')};
-
- @media (max-width: 768px) {
- width: 100%;
- }
-`;
-
-Section.defaultProps = {
- isPadded: true,
-};
-
-FlexWrap.defaultProps = {
- isFlex: true,
-};
-
-WrapGrid.defaultProps = {
- isCentered: true,
- isFullWidth: true,
-};
-
-Wrap.defaultProps = {
- isFlex: false,
-};
diff --git a/packages/website/ts/components/newsletter_form.tsx b/packages/website/ts/components/newsletter_form.tsx
deleted file mode 100644
index e5fd95646..000000000
--- a/packages/website/ts/components/newsletter_form.tsx
+++ /dev/null
@@ -1,191 +0,0 @@
-import * as React from 'react';
-import styled, { withTheme } from 'styled-components';
-
-import { ThemeValuesInterface } from 'ts/components/siteWrap';
-import { colors } from 'ts/style/colors';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-interface FormProps {
- theme: ThemeValuesInterface;
-}
-
-interface InputProps {
- isSubmitted: boolean;
- name: string;
- type: string;
- label: string;
- textColor: string;
- required?: boolean;
-}
-
-interface ArrowProps {
- isSubmitted: boolean;
-}
-
-const Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputElement>) => {
- const { name, label, type } = props;
- const id = `input-${name}`;
-
- return (
- <InnerInputWrapper {...props}>
- <label className="visuallyHidden" htmlFor={id}>
- {label}
- </label>
- <StyledInput ref={ref} id={id} placeholder={label} type={type || 'text'} {...props} />
- </InnerInputWrapper>
- );
-});
-
-class Form extends React.Component<FormProps> {
- public emailInput = React.createRef<HTMLInputElement>();
- public state = {
- isSubmitted: false,
- };
- public render(): React.ReactNode {
- const { isSubmitted } = this.state;
- const { theme } = this.props;
-
- return (
- <StyledForm onSubmit={this._onSubmitAsync.bind(this)}>
- <InputWrapper>
- <Input
- isSubmitted={isSubmitted}
- name="email"
- type="email"
- label="Email Address"
- ref={this.emailInput}
- required={true}
- textColor={theme.textColor}
- />
-
- <SubmitButton>
- <Arrow
- isSubmitted={isSubmitted}
- width="22"
- height="17"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M13.066 0l-1.068 1.147 6.232 6.557H0v1.592h18.23l-6.232 6.557L13.066 17l8.08-8.5-8.08-8.5z"
- fill="#CBCBCB"
- />
- </Arrow>
- </SubmitButton>
- <SuccessText isSubmitted={isSubmitted}>🎉 Thank you for signing up!</SuccessText>
- </InputWrapper>
- <Text>Subscribe to our newsletter for updates in the 0x ecosystem</Text>
- </StyledForm>
- );
- }
-
- private async _onSubmitAsync(e: React.FormEvent<HTMLFormElement>): Promise<void> {
- e.preventDefault();
-
- const email = this.emailInput.current.value;
- const referrer = 'https://0x.org/';
-
- this.setState({ isSubmitted: true });
-
- if (email === 'triggererror@0xproject.org') {
- throw new Error('Manually triggered error');
- }
-
- try {
- await fetch(`${utils.getBackendBaseUrl()}/newsletter_subscriber/substack`, {
- method: 'post',
- mode: 'cors',
- headers: {
- 'content-type': 'application/json; charset=utf-8',
- },
- body: JSON.stringify({ email, referrer }),
- });
- } catch (e) {
- errorReporter.report(e);
- }
- }
-}
-
-export const NewsletterForm = withTheme(Form);
-
-const StyledForm = styled.form`
- appearance: none;
- border: 0;
- color: ${colors.white};
- padding: 13px 0 14px;
- margin-top: 27px;
-`;
-
-const StyledInput = styled.input<InputProps>`
- appearance: none;
- background-color: transparent;
- border: 0;
- border-bottom: 1px solid #393939;
- color: ${props => props.textColor || '#fff'};
- font-size: 1.294117647rem;
- padding: 15px 0;
- outline: none;
- width: 100%;
-
- &::placeholder {
- color: #b1b1b1; // #9D9D9D on light theme
- }
-`;
-
-const InputWrapper = styled.div`
- position: relative;
-`;
-
-const InnerInputWrapper = styled.div<ArrowProps>`
- opacity: ${props => props.isSubmitted && 0};
- visibility: ${props => props.isSubmitted && 'hidden'};
- transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out;
- transition-delay: 0.3s;
-`;
-
-const SubmitButton = styled.button`
- width: 44px;
- height: 44px;
- background-color: transparent;
- border: 0;
- position: absolute;
- right: 0;
- top: calc(50% - 22px);
- overflow: hidden;
- outline: 0;
-
- &:focus-within {
- //background-color: #eee;
- }
-`;
-
-const Text = styled.p`
- color: #656565;
- font-size: 0.833333333rem;
- font-weight: 300;
- line-height: 1.2em;
- margin-top: 15px;
-`;
-
-const SuccessText = styled.p<ArrowProps>`
- color: #b1b1b1;
- font-size: 1rem;
- font-weight: 300;
- line-height: 1.2em;
- padding-top: 25px;
- position: absolute;
- left: 0;
- top: 0;
- text-align: left;
- right: 50px;
- opacity: ${props => (props.isSubmitted ? 1 : 0)};
- visibility: ${props => (props.isSubmitted ? 'visible' : 'hidden')};
- transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out;
- transition-delay: 0.55s;
-`;
-
-const Arrow = styled.svg<ArrowProps>`
- transform: ${props => props.isSubmitted && `translateX(44px)`};
- transition: transform 0.25s ease-in-out;
-`;
diff --git a/packages/website/ts/components/old_footer.tsx b/packages/website/ts/components/old_footer.tsx
deleted file mode 100644
index 6366bf4ea..000000000
--- a/packages/website/ts/components/old_footer.tsx
+++ /dev/null
@@ -1,228 +0,0 @@
-import { ALink, colors, Link } from '@0x/react-shared';
-import { ObjectMap } from '@0x/types';
-import * as _ from 'lodash';
-import DropDownMenu from 'material-ui/DropDownMenu';
-import MenuItem from 'material-ui/MenuItem';
-import * as React from 'react';
-
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { Deco, Key, Language, WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-
-const ICON_DIMENSION = 16;
-
-const languageToMenuTitle = {
- [Language.English]: 'English',
- [Language.Russian]: 'Русский',
- [Language.Spanish]: 'Español',
- [Language.Korean]: '한국어',
- [Language.Chinese]: '中文',
-};
-
-export interface FooterProps {
- translate: Translate;
- dispatcher: Dispatcher;
- backgroundColor?: string;
-}
-
-interface FooterState {
- selectedLanguage: Language;
-}
-
-export class Footer extends React.Component<FooterProps, FooterState> {
- public static defaultProps = {
- backgroundColor: colors.darkerGrey,
- };
- constructor(props: FooterProps) {
- super(props);
- this.state = {
- selectedLanguage: props.translate.getLanguage(),
- };
- }
- public render(): React.ReactNode {
- const sectionNameToLinks: ObjectMap<ALink[]> = {
- [Key.Documentation]: [
- {
- title: 'Developer Home',
- to: WebsitePaths.Docs,
- },
- {
- title: '0x.js',
- to: WebsitePaths.ZeroExJs,
- },
- {
- title: this.props.translate.get(Key.SmartContracts, Deco.Cap),
- to: WebsitePaths.SmartContracts,
- },
- {
- title: this.props.translate.get(Key.Connect, Deco.Cap),
- to: WebsitePaths.Connect,
- },
- {
- title: this.props.translate.get(Key.Whitepaper, Deco.Cap),
- to: WebsitePaths.Whitepaper,
- shouldOpenInNewTab: true,
- },
- {
- title: this.props.translate.get(Key.Wiki, Deco.Cap),
- to: WebsitePaths.Wiki,
- },
- ],
- [Key.Community]: [
- {
- title: this.props.translate.get(Key.Discord, Deco.Cap),
- to: constants.URL_ZEROEX_CHAT,
- shouldOpenInNewTab: true,
- },
- {
- title: this.props.translate.get(Key.Blog, Deco.Cap),
- to: constants.URL_BLOG,
- shouldOpenInNewTab: true,
- },
- {
- title: 'Twitter',
- to: constants.URL_TWITTER,
- shouldOpenInNewTab: true,
- },
- {
- title: 'Reddit',
- to: constants.URL_REDDIT,
- shouldOpenInNewTab: true,
- },
- {
- title: this.props.translate.get(Key.Forum, Deco.Cap),
- to: constants.URL_DISCOURSE_FORUM,
- shouldOpenInNewTab: true,
- },
- ],
- [Key.Organization]: [
- {
- title: this.props.translate.get(Key.About, Deco.Cap),
- to: WebsitePaths.About,
- },
- {
- title: this.props.translate.get(Key.Careers, Deco.Cap),
- to: WebsitePaths.Careers,
- },
- {
- title: this.props.translate.get(Key.Contact, Deco.Cap),
- to: 'mailto:team@0x.org',
- shouldOpenInNewTab: true,
- },
- ],
- };
- const languageMenuItems = _.map(languageToMenuTitle, (menuTitle: string, language: Language) => {
- return <MenuItem key={menuTitle} value={language} primaryText={menuTitle} />;
- });
- return (
- <div className="relative pb4 pt2" style={{ backgroundColor: this.props.backgroundColor }}>
- <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{ color: colors.white }}>
- <div className="col lg-col-4 md-col-4 col-12 left">
- <div className="sm-mx-auto" style={{ width: 148 }}>
- <div>
- <img src="/images/protocol_logo_white.png" height="30" />
- </div>
- <div
- style={{
- fontSize: 11,
- color: colors.grey,
- paddingLeft: 37,
- paddingTop: 2,
- }}
- >
- © ZeroEx, Intl.
- </div>
- <div className="pt4 center">
- <DropDownMenu
- labelStyle={{ color: colors.white }}
- value={this.state.selectedLanguage}
- onChange={this._updateLanguage.bind(this)}
- >
- {languageMenuItems}
- </DropDownMenu>
- </div>
- </div>
- </div>
- <div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4">
- <div className="col lg-col-4 md-col-4 col-12">
- <div className="lg-right md-right sm-center">
- {this._renderHeader(Key.Documentation)}
- {_.map(sectionNameToLinks[Key.Documentation], this._renderMenuItem.bind(this))}
- </div>
- </div>
- <div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
- <div className="lg-right md-right sm-center">
- {this._renderHeader(Key.Community)}
- {_.map(sectionNameToLinks[Key.Community], this._renderMenuItem.bind(this))}
- </div>
- </div>
- <div className="col lg-col-4 md-col-4 col-12">
- <div className="lg-right md-right sm-center">
- {this._renderHeader(Key.Organization)}
- {_.map(sectionNameToLinks[Key.Organization], this._renderMenuItem.bind(this))}
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- }
- private _renderIcon(fileName: string): React.ReactNode {
- return (
- <div style={{ height: ICON_DIMENSION, width: ICON_DIMENSION }}>
- <img src={`/images/social/${fileName}`} style={{ width: ICON_DIMENSION }} />
- </div>
- );
- }
- private _renderMenuItem(link: ALink): React.ReactNode {
- const titleToIcon: { [title: string]: string } = {
- [this.props.translate.get(Key.Discord, Deco.Cap)]: 'discord.png',
- [this.props.translate.get(Key.Blog, Deco.Cap)]: 'medium.png',
- Twitter: 'twitter.png',
- Reddit: 'reddit.png',
- [this.props.translate.get(Key.Forum, Deco.Cap)]: 'discourse.png',
- };
- const iconIfExists = titleToIcon[link.title];
- return (
- <div key={link.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}>
- <Link
- to={link.to}
- shouldOpenInNewTab={link.shouldOpenInNewTab}
- fontColor={colors.white}
- className="text-decoration-none"
- >
- <div>
- {!_.isUndefined(iconIfExists) ? (
- <div className="inline-block">
- <div className="pr1 table-cell">{this._renderIcon(iconIfExists)}</div>
- <div className="table-cell">{link.title}</div>
- </div>
- ) : (
- link.title
- )}
- </div>
- </Link>
- </div>
- );
- }
- private _renderHeader(key: Key): React.ReactNode {
- const headerStyle = {
- color: colors.grey400,
- letterSpacing: 2,
- fontFamily: 'Roboto Mono',
- fontSize: 13,
- };
- return (
- <div className="lg-pb2 md-pb2 sm-pt4" style={headerStyle}>
- {this.props.translate.get(key, Deco.Upper)}
- </div>
- );
- }
- private _updateLanguage(_event: any, _index: number, value: Language): void {
- this.setState({
- selectedLanguage: value,
- });
- this.props.dispatcher.updateSelectedLanguage(value);
- }
-}
diff --git a/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx b/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx
deleted file mode 100644
index 1d21e5a85..000000000
--- a/packages/website/ts/components/onboarding/add_eth_onboarding_step.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as React from 'react';
-import { Balance } from 'ts/components/ui/balance';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Text } from 'ts/components/ui/text';
-import { constants } from 'ts/utils/constants';
-
-export interface AddEthOnboardingStepProps {
- userEthBalanceInWei: BigNumber;
-}
-
-export const AddEthOnboardingStep: React.StatelessComponent<AddEthOnboardingStepProps> = props =>
- props.userEthBalanceInWei.gt(0) ? (
- <div className="flex items-center flex-column">
- <Text>
- Great! Looks like you already have{' '}
- <Balance
- amount={props.userEthBalanceInWei}
- decimals={constants.DECIMAL_PLACES_ETH}
- symbol={constants.ETHER_SYMBOL}
- />{' '}
- in your wallet.
- </Text>
- <Container marginTop="15px" marginBottom="15px">
- <Image src="/images/ether_alt.svg" height="50px" width="50px" />
- </Container>
- </div>
- ) : (
- <div className="flex items-center flex-column">
- <Text> Before you begin you will need to send some ETH to your wallet.</Text>
- <Container marginTop="15px" marginBottom="15px">
- <Image src="/images/ether_alt.svg" height="50px" width="50px" />
- </Container>
- <Text className="xs-hide">
- Click on the <Image src="/images/metamask_icon.png" height="20px" width="20px" /> MetaMask extension in
- your browser and click either <b>BUY</b> or <b>DEPOSIT</b>.
- </Text>
- </div>
- );
diff --git a/packages/website/ts/components/onboarding/congrats_onboarding_step.tsx b/packages/website/ts/components/onboarding/congrats_onboarding_step.tsx
deleted file mode 100644
index 8100fd2c0..000000000
--- a/packages/website/ts/components/onboarding/congrats_onboarding_step.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-
-export interface CongratsOnboardingStepProps {}
-
-export const CongratsOnboardingStep: React.StatelessComponent<CongratsOnboardingStepProps> = () => (
- <div className="flex items-center flex-column">
- <Text>Your wallet is now set up for trading. Use it on any relayer in the 0x ecosystem.</Text>
- <Container marginTop="25px" marginBottom="15px" className="flex justify-center">
- <img src="/images/zrx_ecosystem.svg" height="150px" />
- </Container>
- <Text>No need to log in. Each relayer automatically detects and connects to your wallet.</Text>
- </div>
-);
diff --git a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
deleted file mode 100644
index 173ba9a97..000000000
--- a/packages/website/ts/components/onboarding/install_wallet_onboarding_step.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { colors } from '@0x/react-shared';
-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 { utils } from 'ts/utils/utils';
-
-export interface InstallWalletOnboardingStepProps {}
-
-export const InstallWalletOnboardingStep: React.StatelessComponent<InstallWalletOnboardingStepProps> = () => {
- const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile();
- const followupText = isOnMobile
- ? `Please revisit this site in your mobile dApp browser to continue!`
- : `Please refresh the page once you've done this to continue!`;
- const downloadText = isOnMobile ? 'Get Coinbase Wallet' : 'Get the MetaMask extension';
- return (
- <div className="flex items-center flex-column">
- <Text>First, you need to connect to a wallet. This will be used across all 0x relayers and dApps.</Text>
- <Container className="flex items-center" marginTop="15px" marginBottom="15px">
- <Image
- height="50px"
- width="50px"
- borderRadius="22%"
- src={isOnMobile ? '/images/coinbase_wallet_logo.png' : '/images/metamask_icon.png'}
- />
- <Container marginLeft="10px">
- <a href={downloadLink} target="_blank">
- <Text
- fontWeight={700}
- fontSize="18px"
- fontColor={colors.mediumBlue}
- textDecorationLine="underline"
- >
- {downloadText}
- </Text>
- </a>
- </Container>
- </Container>
- <Text>{followupText}</Text>
- </div>
- );
-};
diff --git a/packages/website/ts/components/onboarding/intro_onboarding_step.tsx b/packages/website/ts/components/onboarding/intro_onboarding_step.tsx
deleted file mode 100644
index f9ced7315..000000000
--- a/packages/website/ts/components/onboarding/intro_onboarding_step.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-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';
-
-export interface IntroOnboardingStepProps {}
-
-export const IntroOnboardingStep: React.StatelessComponent<IntroOnboardingStepProps> = () => (
- <div className="flex items-center flex-column">
- <Text>
- In order to start trading on any 0x relayer in the 0x ecosystem, you need to complete three simple steps.
- </Text>
- <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-around">
- <div className="flex flex-column items-center">
- <Image src="/images/ether.png" height="50px" width="50px" />
- <Text> Add ETH </Text>
- </div>
- <div className="flex flex-column items-center">
- <Image src="/images/eth_token.svg" height="50px" width="50x" />
- <Text> Wrap ETH </Text>
- </div>
- <div className="flex flex-column items-center">
- <Container marginBottom="9px">
- <Image src="/images/lock_icon.svg" height="35px" width="35x" />
- </Container>
- <Text> Unlock tokens </Text>
- </div>
- </Container>
- </div>
-);
diff --git a/packages/website/ts/components/onboarding/onboarding_card.tsx b/packages/website/ts/components/onboarding/onboarding_card.tsx
deleted file mode 100644
index 384bf7154..000000000
--- a/packages/website/ts/components/onboarding/onboarding_card.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-
-import * as _ from 'lodash';
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { IconButton } from 'ts/components/ui/icon_button';
-import { Island } from 'ts/components/ui/island';
-import { Text, Title } from 'ts/components/ui/text';
-
-export type ContinueButtonDisplay = 'enabled' | 'disabled';
-
-export interface OnboardingCardProps {
- title?: string;
- shouldCenterTitle?: boolean;
- content: React.ReactNode;
- isLastStep: boolean;
- onClose: () => void;
- onClickNext: () => void;
- onClickBack: () => void;
- onContinueButtonClick?: () => void;
- continueButtonDisplay?: ContinueButtonDisplay;
- shouldHideBackButton?: boolean;
- shouldHideNextButton?: boolean;
- continueButtonText?: string;
- borderRadius?: string;
- // Used for super-custom content.
- shouldRemoveExtraSpacing?: boolean;
-}
-
-export const OnboardingCard: React.StatelessComponent<OnboardingCardProps> = ({
- title,
- shouldCenterTitle,
- content,
- continueButtonDisplay,
- continueButtonText,
- onContinueButtonClick,
- onClickNext,
- onClickBack,
- onClose,
- shouldHideBackButton,
- shouldHideNextButton,
- borderRadius,
- shouldRemoveExtraSpacing,
-}) => {
- const padding = shouldRemoveExtraSpacing
- ? {}
- : {
- paddingRight: '30px',
- paddingLeft: '30px',
- paddingTop: '15px',
- paddingBottom: '15px',
- };
- const closeIconPositioning = shouldRemoveExtraSpacing
- ? { right: '15px', bottom: '3px' }
- : { bottom: '20px', left: '15px' };
- return (
- <Island borderRadius={borderRadius}>
- <Container {...padding}>
- <div className="flex flex-column">
- <Container className="flex justify-between">
- <Container width="100%">
- <Title center={shouldCenterTitle}>{title}</Title>
- </Container>
- <Container position="relative" {...closeIconPositioning}>
- <IconButton color={colors.grey} iconName="zmdi-close" onClick={onClose}>
- Close
- </IconButton>
- </Container>
- </Container>
- <Container marginBottom={shouldRemoveExtraSpacing ? undefined : '15px'}>
- <Text>{content}</Text>
- </Container>
- {continueButtonDisplay && (
- <Button
- isDisabled={continueButtonDisplay === 'disabled'}
- onClick={!_.isUndefined(onContinueButtonClick) ? onContinueButtonClick : onClickNext}
- fontColor={colors.white}
- fontSize="15px"
- backgroundColor={colors.mediumBlue}
- >
- {continueButtonText}
- </Button>
- )}
- {!(shouldHideBackButton && shouldHideNextButton) && (
- <Container className="clearfix" marginTop="15px">
- <div className="left">
- {!shouldHideBackButton && (
- <Text fontColor={colors.grey} onClick={onClickBack}>
- Back
- </Text>
- )}
- </div>
- <div className="right">
- {!shouldHideNextButton && (
- <Text fontColor={colors.grey} onClick={onClickNext}>
- Skip
- </Text>
- )}
- </div>
- </Container>
- )}
- </div>
- </Container>
- </Island>
- );
-};
-
-OnboardingCard.defaultProps = {
- continueButtonText: 'Continue',
- shouldCenterTitle: false,
- shouldRemoveExtraSpacing: false,
-};
-
-OnboardingCard.displayName = 'OnboardingCard';
diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx
deleted file mode 100644
index ec1b5bc42..000000000
--- a/packages/website/ts/components/onboarding/onboarding_flow.tsx
+++ /dev/null
@@ -1,182 +0,0 @@
-import * as React from 'react';
-import { Placement, Popper, PopperChildrenProps } from 'react-popper';
-
-import { OnboardingCard } from 'ts/components/onboarding/onboarding_card';
-import {
- ContinueButtonDisplay,
- OnboardingTooltip,
- TooltipPointerDisplay,
-} from 'ts/components/onboarding/onboarding_tooltip';
-import { Container } from 'ts/components/ui/container';
-import { EaseUpFromBottomAnimation } from 'ts/components/ui/ease_up_from_bottom_animation';
-import { Overlay } from 'ts/components/ui/overlay';
-import { zIndex } from 'ts/style/z_index';
-
-export interface FixedPositionSettings {
- type: 'fixed';
- top?: string;
- bottom?: string;
- left?: string;
- right?: string;
- tooltipPointerDisplay?: TooltipPointerDisplay;
-}
-
-export interface TargetPositionSettings {
- type: 'target';
- target: string;
- placement: Placement;
-}
-
-export interface Step {
- // Provide either a CSS selector, or fixed position settings. Only applies to desktop.
- position: TargetPositionSettings | FixedPositionSettings;
- title?: string;
- shouldCenterTitle?: boolean;
- content: React.ReactNode;
- shouldHideBackButton?: boolean;
- shouldHideNextButton?: boolean;
- continueButtonDisplay?: ContinueButtonDisplay;
- continueButtonText?: string;
- onContinueButtonClick?: () => void;
- // Only used for very custom steps.
- shouldRemoveExtraSpacing?: boolean;
-}
-
-export interface OnboardingFlowProps {
- steps: Step[];
- stepIndex: number;
- isRunning: boolean;
- onClose: () => void;
- updateOnboardingStep: (stepIndex: number) => void;
- disableOverlay?: boolean;
- isMobile: boolean;
- disableCloseOnClickOutside?: boolean;
-}
-
-export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
- public static defaultProps = {
- disableOverlay: false,
- isMobile: false,
- disableCloseOnClickOutside: false,
- };
- public render(): React.ReactNode {
- if (!this.props.isRunning) {
- return null;
- }
- let onboardingElement = null;
- const currentStep = this._getCurrentStep();
- if (this.props.isMobile) {
- onboardingElement = <EaseUpFromBottomAnimation>{this._renderOnboardingCard()}</EaseUpFromBottomAnimation>;
- } else if (currentStep.position.type === 'target') {
- const { placement, target } = currentStep.position;
- onboardingElement = (
- <Popper referenceElement={document.querySelector(target)} placement={placement} positionFixed={true}>
- {this._renderPopperChildren.bind(this)}
- </Popper>
- );
- } else if (currentStep.position.type === 'fixed') {
- const { top, right, bottom, left, tooltipPointerDisplay } = currentStep.position;
- onboardingElement = (
- <Container
- position="fixed"
- zIndex={zIndex.aboveOverlay}
- top={top}
- right={right}
- bottom={bottom}
- left={left}
- >
- {this._renderToolTip(tooltipPointerDisplay)}
- </Container>
- );
- }
- if (this.props.disableOverlay) {
- return onboardingElement;
- }
- return (
- <div>
- <Overlay onClick={this.props.disableCloseOnClickOutside ? undefined : this.props.onClose} />
- {onboardingElement}
- </div>
- );
- }
- private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode {
- const customStyles = { zIndex: zIndex.aboveOverlay };
- // On re-render, we want to re-center the popper.
- props.scheduleUpdate();
- return (
- <div ref={props.ref} style={{ ...props.style, ...customStyles }} data-placement={props.placement}>
- {this._renderToolTip()}
- </div>
- );
- }
- private _renderToolTip(tooltipPointerDisplay?: TooltipPointerDisplay): React.ReactNode {
- const { steps, stepIndex } = this.props;
- const step = steps[stepIndex];
- const isLastStep = steps.length - 1 === stepIndex;
- return (
- <Container marginLeft="30px" width="400px">
- <OnboardingTooltip
- title={step.title}
- shouldCenterTitle={step.shouldCenterTitle}
- content={step.content}
- isLastStep={isLastStep}
- shouldHideBackButton={step.shouldHideBackButton}
- shouldHideNextButton={step.shouldHideNextButton}
- onClose={this.props.onClose}
- onClickNext={this._goToNextStep.bind(this)}
- onClickBack={this._goToPrevStep.bind(this)}
- continueButtonDisplay={step.continueButtonDisplay}
- continueButtonText={step.continueButtonText}
- onContinueButtonClick={step.onContinueButtonClick}
- pointerDisplay={tooltipPointerDisplay}
- shouldRemoveExtraSpacing={step.shouldRemoveExtraSpacing}
- />
- </Container>
- );
- }
-
- private _renderOnboardingCard(): React.ReactNode {
- const { steps, stepIndex } = this.props;
- const step = steps[stepIndex];
- const isLastStep = steps.length - 1 === stepIndex;
- return (
- <Container position="relative" zIndex={1}>
- <OnboardingCard
- title={step.title}
- shouldCenterTitle={step.shouldCenterTitle}
- content={step.content}
- isLastStep={isLastStep}
- shouldHideBackButton={step.shouldHideBackButton}
- shouldHideNextButton={step.shouldHideNextButton}
- onClose={this.props.onClose}
- onClickNext={this._goToNextStep.bind(this)}
- onClickBack={this._goToPrevStep.bind(this)}
- continueButtonDisplay={step.continueButtonDisplay}
- continueButtonText={step.continueButtonText}
- onContinueButtonClick={step.onContinueButtonClick}
- borderRadius="10px 10px 0px 0px"
- shouldRemoveExtraSpacing={step.shouldRemoveExtraSpacing}
- />
- </Container>
- );
- }
- private _getCurrentStep(): Step {
- return this.props.steps[this.props.stepIndex];
- }
- private _goToNextStep(): void {
- const nextStep = this.props.stepIndex + 1;
- if (nextStep < this.props.steps.length) {
- this.props.updateOnboardingStep(nextStep);
- } else {
- this.props.onClose();
- }
- }
- private _goToPrevStep(): void {
- const nextStep = this.props.stepIndex - 1;
- if (nextStep >= 0) {
- this.props.updateOnboardingStep(nextStep);
- } else {
- this.props.onClose();
- }
- }
-}
diff --git a/packages/website/ts/components/onboarding/onboarding_tooltip.tsx b/packages/website/ts/components/onboarding/onboarding_tooltip.tsx
deleted file mode 100644
index ff5f0bab6..000000000
--- a/packages/website/ts/components/onboarding/onboarding_tooltip.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as React from 'react';
-
-import { OnboardingCard, OnboardingCardProps } from 'ts/components/onboarding/onboarding_card';
-import { Pointer, PointerDirection } from 'ts/components/ui/pointer';
-
-export type ContinueButtonDisplay = 'enabled' | 'disabled';
-export type TooltipPointerDisplay = PointerDirection | 'none';
-
-export interface OnboardingTooltipProps extends OnboardingCardProps {
- className?: string;
- pointerDisplay?: TooltipPointerDisplay;
-}
-
-export const OnboardingTooltip: React.StatelessComponent<OnboardingTooltipProps> = props => {
- const { pointerDisplay, className, ...cardProps } = props;
- const card = <OnboardingCard {...cardProps} />;
- if (pointerDisplay === 'none') {
- return card;
- }
- return (
- <Pointer className={className} direction={pointerDisplay}>
- <OnboardingCard {...cardProps} />
- </Pointer>
- );
-};
-OnboardingTooltip.defaultProps = {
- pointerDisplay: PointerDirection.Left,
-};
-
-OnboardingTooltip.displayName = 'OnboardingTooltip';
diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
deleted file mode 100644
index 6adcec0b1..000000000
--- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
+++ /dev/null
@@ -1,281 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import { RouteComponentProps, withRouter } from 'react-router';
-
-import { BigNumber } from '@0x/utils';
-import { Blockchain } from 'ts/blockchain';
-import { AddEthOnboardingStep } from 'ts/components/onboarding/add_eth_onboarding_step';
-import { CongratsOnboardingStep } from 'ts/components/onboarding/congrats_onboarding_step';
-import { InstallWalletOnboardingStep } from 'ts/components/onboarding/install_wallet_onboarding_step';
-import { IntroOnboardingStep } from 'ts/components/onboarding/intro_onboarding_step';
-import {
- FixedPositionSettings,
- OnboardingFlow,
- Step,
- TargetPositionSettings,
-} from 'ts/components/onboarding/onboarding_flow';
-import { SetAllowancesOnboardingStep } from 'ts/components/onboarding/set_allowances_onboarding_step';
-import { UnlockWalletOnboardingStep } from 'ts/components/onboarding/unlock_wallet_onboarding_step';
-import {
- WrapEthOnboardingStep1,
- WrapEthOnboardingStep2,
- WrapEthOnboardingStep3,
-} from 'ts/components/onboarding/wrap_eth_onboarding_step';
-import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle';
-import { BrowserType, ProviderType, ScreenWidths, Token, TokenByAddress, TokenStateByAddress } from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { utils } from 'ts/utils/utils';
-
-export interface PortalOnboardingFlowProps extends RouteComponentProps<any> {
- networkId: number;
- blockchain: Blockchain;
- stepIndex: number;
- isRunning: boolean;
- userAddress: string;
- hasBeenClosed: boolean;
- providerType: ProviderType;
- injectedProviderName: string;
- blockchainIsLoaded: boolean;
- userEtherBalanceInWei?: BigNumber;
- tokenByAddress: TokenByAddress;
- trackedTokenStateByAddress: TokenStateByAddress;
- updateIsRunning: (isRunning: boolean) => void;
- updateOnboardingStep: (stepIndex: number) => void;
- refetchTokenStateAsync: (tokenAddress: string) => Promise<void>;
- screenWidth: ScreenWidths;
-}
-
-class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProps> {
- private _unlisten: () => void;
- public componentDidMount(): void {
- this._adjustStepIfShould();
- // If there is a route change, just close onboarding.
- this._unlisten = this.props.history.listen(() => this.props.updateIsRunning(false));
- }
- public componentWillUnmount(): void {
- this._unlisten();
- }
- public componentDidUpdate(prevProps: PortalOnboardingFlowProps): void {
- // Any one of steps 0-3 could be the starting step, and we only want to reset the scroll on the starting step.
- if (this.props.isRunning && utils.isMobileWidth(this.props.screenWidth) && this.props.stepIndex < 3) {
- // On mobile, make sure the wallet is completely visible.
- document.querySelector('.wallet').scrollIntoView();
- }
- this._adjustStepIfShould();
- if (!prevProps.blockchainIsLoaded && this.props.blockchainIsLoaded) {
- this._autoStartOnboardingIfShould();
- }
- }
- public render(): React.ReactNode {
- const browserType = utils.getBrowserType();
- return (
- <OnboardingFlow
- steps={this._getSteps()}
- stepIndex={this.props.stepIndex}
- isRunning={this.props.isRunning}
- onClose={this._closeOnboarding.bind(this)}
- updateOnboardingStep={this._updateOnboardingStep.bind(this)}
- disableOverlay={this.props.screenWidth === ScreenWidths.Sm}
- isMobile={this.props.screenWidth === ScreenWidths.Sm}
- // This is necessary to ensure onboarding stays open once the user unlocks metamask and clicks away
- disableCloseOnClickOutside={browserType === BrowserType.Firefox || browserType === BrowserType.Opera}
- />
- );
- }
- private _getSteps(): Step[] {
- const nextToWalletPosition: TargetPositionSettings = {
- type: 'target',
- target: '.wallet',
- placement: 'right',
- };
- const underMetamaskExtension: FixedPositionSettings = {
- type: 'fixed',
- top: '10px',
- right: '10px',
- tooltipPointerDisplay: 'none',
- };
- const steps: Step[] = [
- {
- position: nextToWalletPosition,
- title: '0x Ecosystem Setup',
- content: <InstallWalletOnboardingStep />,
- shouldHideBackButton: true,
- shouldHideNextButton: true,
- },
- {
- position: underMetamaskExtension,
- title: 'Please Unlock Metamask...',
- content: <UnlockWalletOnboardingStep />,
- shouldHideBackButton: true,
- shouldHideNextButton: true,
- shouldCenterTitle: true,
- shouldRemoveExtraSpacing: true,
- },
- {
- position: nextToWalletPosition,
- title: '0x Ecosystem Account Setup',
- content: <IntroOnboardingStep />,
- shouldHideBackButton: true,
- continueButtonDisplay: 'enabled',
- },
- {
- position: nextToWalletPosition,
- title: 'Step 1: Add ETH',
- content: (
- <AddEthOnboardingStep userEthBalanceInWei={this.props.userEtherBalanceInWei || new BigNumber(0)} />
- ),
- continueButtonDisplay: this._userHasVisibleEth() ? 'enabled' : 'disabled',
- },
- {
- position: nextToWalletPosition,
- title: 'Step 2: Wrap ETH',
- content: <WrapEthOnboardingStep1 />,
- continueButtonDisplay: 'enabled',
- },
- {
- position: nextToWalletPosition,
- title: 'Step 2: Wrap ETH',
- content: <WrapEthOnboardingStep2 />,
- continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled',
- },
- {
- position: nextToWalletPosition,
- title: 'Step 2: Wrap ETH',
- content: <WrapEthOnboardingStep3 wethAmount={this._getWethBalance()} />,
- continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled',
- },
- {
- position: nextToWalletPosition,
- title: 'Step 3: Unlock Tokens',
- content: (
- <SetAllowancesOnboardingStep
- zrxAllowanceToggle={this._renderZrxAllowanceStateToggle()}
- ethAllowanceToggle={this._renderEthAllowanceStateToggle()}
- doesUserHaveAllowancesForWethAndZrx={this._doesUserHaveAllowancesForWethAndZrx()}
- />
- ),
- continueButtonDisplay: this._doesUserHaveAllowancesForWethAndZrx() ? 'enabled' : 'disabled',
- },
- {
- position: nextToWalletPosition,
- title: '🎉 The Ecosystem Awaits',
- content: <CongratsOnboardingStep />,
- continueButtonDisplay: 'enabled',
- shouldHideNextButton: true,
- continueButtonText: 'Enter the 0x Ecosystem',
- onContinueButtonClick: this._handleFinalStepContinueClick.bind(this),
- },
- ];
- return steps;
- }
- private _isAddressAvailable(): boolean {
- return !_.isEmpty(this.props.userAddress);
- }
- private _userHasVisibleEth(): boolean {
- return this.props.userEtherBalanceInWei > new BigNumber(0);
- }
- private _getWethBalance(): BigNumber {
- const ethToken = utils.getEthToken(this.props.tokenByAddress);
- if (!ethToken) {
- return new BigNumber(0);
- }
- const ethTokenState = this.props.trackedTokenStateByAddress[ethToken.address];
- return ethTokenState.balance;
- }
- private _userHasVisibleWeth(): boolean {
- return this._getWethBalance() > new BigNumber(0);
- }
- private _doesUserHaveAllowancesForWethAndZrx(): boolean {
- const ethToken = utils.getEthToken(this.props.tokenByAddress);
- const zrxToken = utils.getZrxToken(this.props.tokenByAddress);
- if (ethToken && zrxToken) {
- const ethTokenState = this.props.trackedTokenStateByAddress[ethToken.address];
- const zrxTokenState = this.props.trackedTokenStateByAddress[zrxToken.address];
- if (ethTokenState && zrxTokenState) {
- return ethTokenState.allowance.gt(0) && zrxTokenState.allowance.gt(0);
- }
- }
- return false;
- }
- private _adjustStepIfShould(): void {
- const stepIndex = this.props.stepIndex;
- if (this._isAddressAvailable()) {
- if (stepIndex < 2) {
- this.props.updateOnboardingStep(2);
- }
- return;
- }
- const isExternallyInjected = utils.isExternallyInjected(
- this.props.providerType,
- this.props.injectedProviderName,
- );
- if (isExternallyInjected) {
- if (stepIndex !== 1) {
- this.props.updateOnboardingStep(1);
- }
- return;
- }
- if (stepIndex !== 0) {
- this.props.updateOnboardingStep(0);
- }
- }
- private _autoStartOnboardingIfShould(): void {
- if (
- (this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) ||
- (!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded)
- ) {
- analytics.track('Onboarding Started', {
- reason: 'automatic',
- stepIndex: this.props.stepIndex,
- });
- this.props.updateIsRunning(true);
- }
- }
- private _updateOnboardingStep(stepIndex: number): void {
- this.props.updateOnboardingStep(stepIndex);
- analytics.track('Update Onboarding Step', {
- stepIndex,
- });
- }
- private _closeOnboarding(): void {
- this.props.updateIsRunning(false);
- analytics.track('Onboarding Closed', {
- stepIndex: this.props.stepIndex,
- });
- }
- private _renderZrxAllowanceStateToggle(): React.ReactNode {
- const zrxToken = utils.getZrxToken(this.props.tokenByAddress);
- return this._renderAllowanceStateToggle(zrxToken);
- }
- private _renderEthAllowanceStateToggle(): React.ReactNode {
- const ethToken = utils.getEthToken(this.props.tokenByAddress);
- return this._renderAllowanceStateToggle(ethToken);
- }
- private _renderAllowanceStateToggle(token: Token): React.ReactNode {
- if (!token) {
- return null;
- }
- const tokenStateIfExists = this.props.trackedTokenStateByAddress[token.address];
- if (_.isUndefined(tokenStateIfExists)) {
- return null;
- }
- return (
- <AllowanceStateToggle
- token={token}
- tokenState={tokenStateIfExists}
- blockchain={this.props.blockchain}
- // tslint:disable-next-line:jsx-no-lambda
- refetchTokenStateAsync={async () => this.props.refetchTokenStateAsync(token.address)}
- />
- );
- }
- private _handleFinalStepContinueClick(): void {
- if (utils.isMobileWidth(this.props.screenWidth)) {
- window.scrollTo(0, 0);
- this.props.history.push('/portal');
- }
- this._closeOnboarding();
- }
-}
-
-export const PortalOnboardingFlow = withRouter(PlainPortalOnboardingFlow);
diff --git a/packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx b/packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx
deleted file mode 100644
index 5ddfe38d7..000000000
--- a/packages/website/ts/components/onboarding/set_allowances_onboarding_step.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-
-export interface SetAllowancesOnboardingStepProps {
- zrxAllowanceToggle: React.ReactNode;
- ethAllowanceToggle: React.ReactNode;
- doesUserHaveAllowancesForWethAndZrx: boolean;
-}
-
-export const SetAllowancesOnboardingStep: React.StatelessComponent<SetAllowancesOnboardingStepProps> = ({
- ethAllowanceToggle,
- zrxAllowanceToggle,
- doesUserHaveAllowancesForWethAndZrx,
-}) => (
- <div className="flex items-center flex-column">
- <Text>Unlock your tokens for trading. You only need to do this once for each token.</Text>
- <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-around">
- <div className="flex flex-column items-center">
- <Text fontWeight={700}> Enable WETH </Text>
- <Container marginTop="10px">{ethAllowanceToggle}</Container>
- </div>
- <div className="flex flex-column items-center">
- <Text fontWeight={700}> Enable ZRX </Text>
- <Container marginTop="10px">{zrxAllowanceToggle}</Container>
- </div>
- </Container>
- {doesUserHaveAllowancesForWethAndZrx && <Text>Perfect! Both your ZRX and WETH tokens are unlocked.</Text>}
- </div>
-);
diff --git a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
deleted file mode 100644
index 358141520..000000000
--- a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as React from 'react';
-import { Image } from 'ts/components/ui/image';
-
-export interface UnlockWalletOnboardingStepProps {}
-
-export const UnlockWalletOnboardingStep: React.StatelessComponent<UnlockWalletOnboardingStepProps> = () => (
- <Image src="/images/unlock-mm.png" />
-);
diff --git a/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx b/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx
deleted file mode 100644
index 37eef867b..000000000
--- a/packages/website/ts/components/onboarding/wrap_eth_onboarding_step.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import * as React from 'react';
-import { Balance } from 'ts/components/ui/balance';
-import { Container } from 'ts/components/ui/container';
-import { IconButton } from 'ts/components/ui/icon_button';
-import { Text } from 'ts/components/ui/text';
-import { constants } from 'ts/utils/constants';
-
-export interface WrapEthOnboardingStep1Props {}
-
-export const WrapEthOnboardingStep1: React.StatelessComponent<WrapEthOnboardingStep1Props> = () => (
- <div className="flex items-center flex-column">
- <Text>
- You need to convert some of your ETH into tradeable <b>Wrapped ETH (WETH)</b>.
- </Text>
- <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-center">
- <div className="flex flex-column items-center">
- <Text fontWeight={700}> 1 ETH </Text>
- <img src="/images/eth_dollar.svg" height="75px" width="75x" />
- </div>
- <Container marginRight="25px" marginLeft="25px" position="relative" top="20px">
- <Text fontSize="36px">=</Text>
- </Container>
- <div className="flex flex-column items-center">
- <Text fontWeight={700}> 1 WETH </Text>
- <img src="/images/eth_token_erc20.svg" height="75px" width="75px" />
- </div>
- </Container>
- <Text>
- Think of it like the coin version of a paper note. It has the same value, but some machines only take coins.
- </Text>
- </div>
-);
-
-export interface WrapEthOnboardingStep2Props {}
-
-export const WrapEthOnboardingStep2: React.StatelessComponent<WrapEthOnboardingStep2Props> = () => (
- <div className="flex items-center flex-column">
- <Text>Wrapping your ETH is a reversable transaction, so don't worry about losing your ETH.</Text>
- <Text>
- Click
- <Container display="inline-block" marginLeft="10px" marginRight="10px">
- <IconButton
- iconName="zmdi-long-arrow-down"
- color={colors.mediumBlue}
- labelText="wrap"
- display="inline-flex"
- />
- </Container>
- to wrap your ETH.
- </Text>
- </div>
-);
-
-export interface WrapEthOnboardingStep3Props {
- wethAmount: BigNumber;
-}
-
-export const WrapEthOnboardingStep3: React.StatelessComponent<WrapEthOnboardingStep3Props> = ({ wethAmount }) => (
- <div className="flex items-center flex-column">
- <Text>
- You have{' '}
- <Balance
- amount={wethAmount}
- decimals={constants.DECIMAL_PLACES_ETH}
- symbol={constants.ETHER_TOKEN_SYMBOL}
- />{' '}
- in your wallet.
- {wethAmount.gt(0) && ' Great!'}
- </Text>
- <Container width="100%" marginTop="25px" marginBottom="15px" className="flex justify-center">
- <div className="flex flex-column items-center">
- <Text fontWeight={700}> 1 ETH </Text>
- <img src="/images/eth_dollar.svg" height="75px" width="75x" />
- </div>
- <Container marginRight="25px" marginLeft="25px" position="relative" top="20px">
- <Text fontSize="25px">
- <i className="zmdi zmdi-long-arrow-right" />
- </Text>
- </Container>
- <div className="flex flex-column items-center">
- <Text fontWeight={700}> 1 WETH </Text>
- <img src="/images/eth_token_erc20.svg" height="75px" width="75px" />
- </div>
- </Container>
- </div>
-);
diff --git a/packages/website/ts/components/order_json.tsx b/packages/website/ts/components/order_json.tsx
deleted file mode 100644
index f33681835..000000000
--- a/packages/website/ts/components/order_json.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-import { BigNumber, fetchAsync, logUtils } from '@0x/utils';
-import * as _ from 'lodash';
-import Paper from 'material-ui/Paper';
-import TextField from 'material-ui/TextField';
-import * as React from 'react';
-import { CopyIcon } from 'ts/components/ui/copy_icon';
-import { SideToAssetToken, TokenByAddress, WebsitePaths } from 'ts/types';
-import { configs } from 'ts/utils/configs';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-interface OrderJSONProps {
- exchangeContractIfExists: string;
- orderExpiryTimestamp: BigNumber;
- orderSignature: string;
- orderTakerAddress: string;
- orderMakerAddress: string;
- orderSalt: BigNumber;
- orderMakerFee: BigNumber;
- orderTakerFee: BigNumber;
- orderFeeRecipient: string;
- sideToAssetToken: SideToAssetToken;
- tokenByAddress: TokenByAddress;
-}
-
-interface OrderJSONState {
- shareLink: string;
-}
-
-export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
- constructor(props: OrderJSONProps) {
- super(props);
- this.state = {
- shareLink: '',
- };
- // tslint:disable-next-line:no-floating-promises
- this._setShareLinkAsync();
- }
- public render(): React.ReactNode {
- const order = utils.generateOrder(
- this.props.exchangeContractIfExists,
- this.props.sideToAssetToken,
- this.props.orderExpiryTimestamp,
- this.props.orderTakerAddress,
- this.props.orderMakerAddress,
- this.props.orderMakerFee,
- this.props.orderTakerFee,
- this.props.orderFeeRecipient,
- this.props.orderSignature,
- this.props.tokenByAddress,
- this.props.orderSalt,
- );
- const orderJSON = JSON.stringify(order);
- return (
- <div>
- <div className="pb2">
- You have successfully generated and cryptographically signed an order! The following JSON contains
- the order parameters and cryptographic signature that your counterparty will need to execute a trade
- with you.
- </div>
- <div className="pb2 flex">
- <div className="inline-block pl1" style={{ top: 1 }}>
- <CopyIcon data={orderJSON} callToAction="Copy" />
- </div>
- </div>
- <Paper className="center overflow-hidden">
- <TextField
- id="orderJSON"
- style={{ width: 710 }}
- value={JSON.stringify(order, null, '\t')}
- multiLine={true}
- rows={2}
- rowsMax={8}
- underlineStyle={{ display: 'none' }}
- />
- </Paper>
- <div className="pt3 pb2 center">
- <div>Share your signed order!</div>
- <div>
- <div className="mx-auto overflow-hidden" style={{ width: 152 }}>
- <TextField id={`${this.state.shareLink}-bitly`} value={this.state.shareLink} />
- </div>
- </div>
- <div className="mx-auto pt1 flex" style={{ width: 91 }}>
- <div>
- <i
- style={{ cursor: 'pointer', fontSize: 29 }}
- onClick={this._shareViaFacebook.bind(this)}
- className="zmdi zmdi-facebook-box"
- />
- </div>
- <div className="pl1" style={{ position: 'relative', width: 28 }}>
- <i
- style={{
- cursor: 'pointer',
- fontSize: 32,
- position: 'absolute',
- top: -2,
- left: 8,
- }}
- onClick={this._shareViaEmailAsync.bind(this)}
- className="zmdi zmdi-email"
- />
- </div>
- <div className="pl1">
- <i
- style={{ cursor: 'pointer', fontSize: 29 }}
- onClick={this._shareViaTwitterAsync.bind(this)}
- className="zmdi zmdi-twitter-box"
- />
- </div>
- </div>
- </div>
- </div>
- );
- }
- private _shareViaTwitterAsync(): void {
- const tweetText = encodeURIComponent(`Fill my order using the 0x protocol: ${this.state.shareLink}`);
- window.open(`https://twitter.com/intent/tweet?text=${tweetText}`, 'Share your order', 'width=500,height=400');
- }
- private _shareViaFacebook(): void {
- (window as any).FB.ui(
- {
- display: 'popup',
- href: this.state.shareLink,
- method: 'share',
- },
- _.noop.bind(_),
- );
- }
- private _shareViaEmailAsync(): void {
- const encodedSubject = encodeURIComponent("Let's trade using the 0x protocol");
- const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol.
-You can see and fill it here: ${this.state.shareLink}`);
- const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`;
- window.open(mailToLink, '_blank');
- }
- private async _setShareLinkAsync(): Promise<void> {
- const shareLink = await this._generateShareLinkAsync();
- this.setState({
- shareLink,
- });
- }
- private async _generateShareLinkAsync(): Promise<string> {
- const longUrl = encodeURIComponent(this._getOrderUrl());
- const bitlyRequestUrl = `${constants.URL_BITLY_API}/v3/shorten?access_token=${
- configs.BITLY_ACCESS_TOKEN
- }&longUrl=${longUrl}`;
- const response = await fetchAsync(bitlyRequestUrl);
- const responseBody = await response.text();
- const bodyObj = JSON.parse(responseBody);
- if (response.status !== 200 || bodyObj.status_code !== 200) {
- // TODO: Show error message in UI
- logUtils.log(`Unexpected status code: ${response.status} -> ${responseBody}`);
- errorReporter.report(new Error(`Bitly returned non-200: ${JSON.stringify(response)}`));
- return '';
- }
- return bodyObj.data.url;
- }
- private _getOrderUrl(): string {
- const order = utils.generateOrder(
- this.props.exchangeContractIfExists,
- this.props.sideToAssetToken,
- this.props.orderExpiryTimestamp,
- this.props.orderTakerAddress,
- this.props.orderMakerAddress,
- this.props.orderMakerFee,
- this.props.orderTakerFee,
- this.props.orderFeeRecipient,
- this.props.orderSignature,
- this.props.tokenByAddress,
- this.props.orderSalt,
- );
- const orderJSONString = JSON.stringify(order);
- const orderUrl = `${configs.BASE_URL}${WebsitePaths.Portal}/fill?order=${orderJSONString}`;
- return orderUrl;
- }
-}
diff --git a/packages/website/ts/components/portal/back_button.tsx b/packages/website/ts/components/portal/back_button.tsx
deleted file mode 100644
index bea69bb95..000000000
--- a/packages/website/ts/components/portal/back_button.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Link, Styles } from '@0x/react-shared';
-import * as React from 'react';
-import { Island } from 'ts/components/ui/island';
-import { colors } from 'ts/style/colors';
-
-export interface BackButtonProps {
- to: string;
- labelText: string;
-}
-
-const BACK_BUTTON_HEIGHT = 28;
-
-const styles: Styles = {
- backButton: {
- height: BACK_BUTTON_HEIGHT,
- paddingTop: 10,
- borderRadius: BACK_BUTTON_HEIGHT,
- },
- backButtonIcon: {
- color: colors.mediumBlue,
- fontSize: 20,
- },
-};
-
-export const BackButton = (props: BackButtonProps) => {
- return (
- <div style={{ height: 65, paddingTop: 25 }}>
- <Link to={props.to}>
- <Island className="flex right" style={styles.backButton}>
- <div style={{ marginLeft: 12 }}>
- <i style={styles.backButtonIcon} className={`zmdi zmdi-arrow-left`} />
- </div>
- <div style={{ marginLeft: 12, marginRight: 12 }}>
- <div style={{ fontSize: 16, color: colors.lightGrey }}>{props.labelText}</div>
- </div>
- </Island>
- </Link>
- </div>
- );
-};
diff --git a/packages/website/ts/components/portal/drawer_menu.tsx b/packages/website/ts/components/portal/drawer_menu.tsx
deleted file mode 100644
index 7280a6102..000000000
--- a/packages/website/ts/components/portal/drawer_menu.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Blockchain } from 'ts/blockchain';
-import { defaultMenuItemEntries, Menu } from 'ts/components/portal/menu';
-import { Identicon } from 'ts/components/ui/identicon';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { ProviderType, WebsitePaths } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-const IDENTICON_DIAMETER = 45;
-const BORDER_RADIUS = '50%';
-
-const styles: Styles = {
- root: {
- backgroundColor: colors.drawerMenuBackground,
- width: '100%',
- height: '100%',
- },
- identicon: {
- borderWidth: 3,
- borderStyle: 'solid',
- borderColor: colors.white,
- borderRadius: BORDER_RADIUS,
- MozBorderRadius: BORDER_RADIUS,
- WebkitBorderRadius: BORDER_RADIUS,
- },
-};
-
-export interface DrawerMenuProps {
- selectedPath?: string;
- userAddress?: string;
- injectedProviderName: string;
- providerType: ProviderType;
- blockchain?: Blockchain;
- blockchainIsLoaded: boolean;
-}
-export const DrawerMenu = (props: DrawerMenuProps) => {
- const relayerItemEntry = {
- to: WebsitePaths.Portal,
- labelText: 'Relayer ecosystem',
- iconName: 'zmdi-portable-wifi',
- };
- const menuItemEntries = _.concat(relayerItemEntry, defaultMenuItemEntries);
- const accountState = utils.getAccountState(
- props.blockchainIsLoaded && !_.isUndefined(props.blockchain),
- props.providerType,
- props.injectedProviderName,
- props.userAddress,
- );
- const displayMessage = utils.getReadableAccountState(accountState, props.userAddress);
- return (
- <div style={styles.root}>
- <Header userAddress={props.userAddress} displayMessage={displayMessage} />
- <Menu selectedPath={props.selectedPath} menuItemEntries={menuItemEntries} />
- </div>
- );
-};
-
-interface HeaderProps {
- userAddress?: string;
- displayMessage: string;
-}
-const Header = (props: HeaderProps) => {
- return (
- <div className="flex flex-center py4">
- <div className="flex flex-column mx-auto items-center">
- <Identicon address={props.userAddress} diameter={IDENTICON_DIAMETER} style={styles.identicon} />
- <Text className="pt2" fontColor={colors.white}>
- {props.displayMessage}
- </Text>
- </div>
- </div>
- );
-};
diff --git a/packages/website/ts/components/portal/loading.tsx b/packages/website/ts/components/portal/loading.tsx
deleted file mode 100644
index d804dd1b8..000000000
--- a/packages/website/ts/components/portal/loading.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import CircularProgress from 'material-ui/CircularProgress';
-import * as React from 'react';
-
-const CIRCULAR_PROGRESS_SIZE = 40;
-const CIRCULAR_PROGRESS_THICKNESS = 5;
-
-export interface LoadingProps {
- isLoading: boolean;
- content: React.ReactNode;
-}
-export const Loading = (props: LoadingProps) => {
- if (props.isLoading) {
- return (
- <div className="center">
- <CircularProgress size={CIRCULAR_PROGRESS_SIZE} thickness={CIRCULAR_PROGRESS_THICKNESS} />
- </div>
- );
- } else {
- return <div>{props.content}</div>;
- }
-};
diff --git a/packages/website/ts/components/portal/menu.tsx b/packages/website/ts/components/portal/menu.tsx
deleted file mode 100644
index d59101686..000000000
--- a/packages/website/ts/components/portal/menu.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { CustomMenuItem } from 'ts/components/ui/custom_menu_item';
-import { colors } from 'ts/style/colors';
-import { WebsitePaths } from 'ts/types';
-
-export interface MenuTheme {
- paddingLeft: number;
- textColor: string;
- iconColor: string;
- selectedIconColor: string;
- selectedBackgroundColor: string;
-}
-
-export interface MenuItemEntry {
- to: string;
- labelText: string;
- iconName: string;
-}
-
-export interface MenuProps {
- selectedPath?: string;
- theme?: MenuTheme;
- menuItemEntries?: MenuItemEntry[];
-}
-
-export const defaultMenuItemEntries: MenuItemEntry[] = [
- {
- to: `${WebsitePaths.Portal}/account`,
- labelText: 'Account overview',
- iconName: 'zmdi-balance-wallet',
- },
- {
- to: `${WebsitePaths.Portal}/trades`,
- labelText: 'Trade history',
- iconName: 'zmdi-format-list-bulleted',
- },
- {
- to: `${WebsitePaths.Portal}/weth`,
- labelText: 'Wrapped ETH',
- iconName: 'zmdi-circle-o',
- },
- {
- to: `${WebsitePaths.Portal}/generate`,
- labelText: 'Generate order',
- iconName: 'zmdi-arrow-right-top',
- },
- {
- to: `${WebsitePaths.Portal}/fill`,
- labelText: 'Fill order',
- iconName: 'zmdi-arrow-left-bottom',
- },
-];
-
-const DEFAULT_MENU_THEME: MenuTheme = {
- paddingLeft: 30,
- textColor: colors.white,
- iconColor: colors.white,
- selectedIconColor: colors.white,
- selectedBackgroundColor: colors.menuItemDefaultSelectedBackground,
-};
-
-export const Menu: React.StatelessComponent<MenuProps> = (props: MenuProps) => {
- return (
- <div>
- {_.map(props.menuItemEntries, entry => {
- const isSelected = entry.to === props.selectedPath;
- return (
- <CustomMenuItem key={entry.to} to={entry.to}>
- <MenuItemLabel
- title={entry.labelText}
- iconName={entry.iconName}
- selected={isSelected}
- theme={props.theme}
- />
- </CustomMenuItem>
- );
- })}
- </div>
- );
-};
-Menu.defaultProps = {
- theme: DEFAULT_MENU_THEME,
- menuItemEntries: defaultMenuItemEntries,
-};
-
-interface MenuItemLabelProps {
- title: string;
- iconName: string;
- selected: boolean;
- theme: MenuTheme;
-}
-const MenuItemLabel: React.StatelessComponent<MenuItemLabelProps> = (props: MenuItemLabelProps) => {
- const styles: Styles = {
- root: {
- backgroundColor: props.selected ? props.theme.selectedBackgroundColor : undefined,
- paddingLeft: props.theme.paddingLeft,
- },
- icon: {
- color: props.selected ? props.theme.selectedIconColor : props.theme.iconColor,
- fontSize: 20,
- },
- text: {
- color: props.theme.textColor,
- fontWeight: props.selected ? 'bold' : 'normal',
- fontSize: 16,
- },
- };
- return (
- <div className="flex py2" style={styles.root}>
- <div className="pr1">
- <i style={styles.icon} className={`zmdi ${props.iconName}`} />
- </div>
- <div className="pl1" style={styles.text}>
- {props.title}
- </div>
- </div>
- );
-};
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
deleted file mode 100644
index 59cf2db71..000000000
--- a/packages/website/ts/components/portal/portal.tsx
+++ /dev/null
@@ -1,749 +0,0 @@
-import { colors, Link } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-import * as React from 'react';
-import * as DocumentTitle from 'react-document-title';
-import { Route, RouteComponentProps, Switch } from 'react-router-dom';
-
-import { Blockchain } from 'ts/blockchain';
-import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog';
-import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog';
-import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog';
-import { EthWrappers } from 'ts/components/eth_wrappers';
-import { FillOrder } from 'ts/components/fill_order';
-import { AssetPicker } from 'ts/components/generate_order/asset_picker';
-import { MetaTags } from 'ts/components/meta_tags';
-import { BackButton } from 'ts/components/portal/back_button';
-import { Loading } from 'ts/components/portal/loading';
-import { Menu, MenuTheme } from 'ts/components/portal/menu';
-import { Section } from 'ts/components/portal/section';
-import { TextHeader } from 'ts/components/portal/text_header';
-import { RelayerIndex, RelayerIndexCellStyle } from 'ts/components/relayer_index/relayer_index';
-import { TokenBalances } from 'ts/components/token_balances';
-import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar';
-import { TradeHistory } from 'ts/components/trade_history/trade_history';
-import { Container } from 'ts/components/ui/container';
-import { FlashMessage } from 'ts/components/ui/flash_message';
-import { Image } from 'ts/components/ui/image';
-import { PointerDirection } from 'ts/components/ui/pointer';
-import { Text } from 'ts/components/ui/text';
-import { Wallet } from 'ts/components/wallet/wallet';
-import { GenerateOrderForm } from 'ts/containers/generate_order_form';
-import { PortalOnboardingFlow } from 'ts/containers/portal_onboarding_flow';
-import { localStorage } from 'ts/local_storage/local_storage';
-import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
-import { FullscreenMessage } from 'ts/pages/fullscreen_message';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { zIndex } from 'ts/style/z_index';
-import {
- BlockchainErrs,
- HashData,
- ItemByAddress,
- PortalOrder,
- ProviderType,
- ScreenWidths,
- Token,
- TokenByAddress,
- TokenStateByAddress,
- TokenVisibility,
- WebsitePaths,
-} from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { backendClient } from 'ts/utils/backend_client';
-import { configs } from 'ts/utils/configs';
-import { constants } from 'ts/utils/constants';
-import { orderParser } from 'ts/utils/order_parser';
-import { Translate } from 'ts/utils/translate';
-import { utils } from 'ts/utils/utils';
-
-export interface PortalProps {
- blockchainErr: BlockchainErrs;
- blockchainIsLoaded: boolean;
- dispatcher: Dispatcher;
- hashData: HashData;
- injectedProviderName: string;
- networkId: number;
- nodeVersion: string;
- orderFillAmount: BigNumber;
- providerType: ProviderType;
- screenWidth: ScreenWidths;
- tokenByAddress: TokenByAddress;
- userEtherBalanceInWei?: BigNumber;
- userAddress: string;
- shouldBlockchainErrDialogBeOpen: boolean;
- userSuppliedOrderCache: PortalOrder;
- location: Location;
- flashMessage?: string | React.ReactNode;
- lastForceTokenStateRefetch: number;
- translate: Translate;
- isPortalOnboardingShowing: boolean;
- portalOnboardingStep: number;
-}
-
-interface PortalState {
- prevNetworkId: number;
- prevNodeVersion: string;
- prevUserAddress: string;
- prevPathname: string;
- isDisclaimerDialogOpen: boolean;
- isLedgerDialogOpen: boolean;
- tokenManagementState: TokenManagementState;
- trackedTokenStateByAddress: TokenStateByAddress;
-}
-
-interface AccountManagementItem {
- pathName: string;
- headerText?: string;
- render: () => React.ReactNode;
-}
-
-enum TokenManagementState {
- Add = 'Add',
- Remove = 'Remove',
- None = 'None',
-}
-
-const THROTTLE_TIMEOUT = 100;
-const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded);
-const LEFT_COLUMN_WIDTH = 346;
-const MENU_PADDING_LEFT = 185;
-const LARGE_LAYOUT_MAX_WIDTH = 1200;
-const SIDE_PADDING = 20;
-const DOCUMENT_TITLE = '0x Portal';
-const DOCUMENT_DESCRIPTION = 'Learn about and trade on 0x Relayers';
-
-export class Portal extends React.Component<PortalProps, PortalState> {
- private _blockchain: Blockchain;
- private readonly _sharedOrderIfExists: PortalOrder;
- private readonly _throttledScreenWidthUpdate: () => void;
- constructor(props: PortalProps) {
- super(props);
- this._sharedOrderIfExists = orderParser.parseQueryString(window.location.search);
- this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
- const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
- const hasAcceptedDisclaimer =
- !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer);
- const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(
- this._getCurrentTrackedTokens(),
- );
- this.state = {
- prevNetworkId: this.props.networkId,
- prevNodeVersion: this.props.nodeVersion,
- prevUserAddress: this.props.userAddress,
- prevPathname: this.props.location.pathname,
- isDisclaimerDialogOpen: !hasAcceptedDisclaimer,
- tokenManagementState: TokenManagementState.None,
- isLedgerDialogOpen: false,
- trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
- };
- }
- public componentDidMount(): void {
- window.addEventListener('resize', this._throttledScreenWidthUpdate);
- window.scrollTo(0, 0);
- }
- public componentWillMount(): void {
- this._blockchain = new Blockchain(this.props.dispatcher);
- }
- public componentWillUnmount(): void {
- this._blockchain.destroy();
- window.removeEventListener('resize', this._throttledScreenWidthUpdate);
- // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered
- // the initialization process always occurs from the same base state. This helps avoid
- // initialization inconsistencies (i.e While the portal was unrendered, the user might have
- // become disconnected from their backing Ethereum node, changed user accounts, etc...)
- this.props.dispatcher.resetState();
- }
- public componentDidUpdate(prevProps: PortalProps): void {
- if (!prevProps.blockchainIsLoaded && this.props.blockchainIsLoaded) {
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(this._getCurrentTrackedTokensAddresses());
- }
- }
- public componentWillReceiveProps(nextProps: PortalProps): void {
- if (nextProps.networkId !== this.state.prevNetworkId) {
- // tslint:disable-next-line:no-floating-promises
- this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
- this.setState({
- prevNetworkId: nextProps.networkId,
- });
- }
- if (nextProps.userAddress !== this.state.prevUserAddress) {
- const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress;
- // tslint:disable-next-line:no-floating-promises
- this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress);
- this.setState({
- prevUserAddress: nextProps.userAddress,
- });
- }
- if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
- // tslint:disable-next-line:no-floating-promises
- this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
- }
- if (nextProps.location.pathname !== this.state.prevPathname) {
- this.setState({
- prevPathname: nextProps.location.pathname,
- });
- }
-
- // If the address changed, but the network did not, we can just refetch the currently tracked tokens.
- if (
- (nextProps.userAddress !== this.props.userAddress && nextProps.networkId === this.props.networkId) ||
- nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
- ) {
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(this._getCurrentTrackedTokensAddresses());
- }
-
- const nextTrackedTokens = utils.getTrackedTokens(nextProps.tokenByAddress);
- const trackedTokens = this._getCurrentTrackedTokens();
-
- if (!_.isEqual(nextTrackedTokens, trackedTokens)) {
- const newTokens = _.difference(nextTrackedTokens, trackedTokens);
- const newTokenAddresses = _.map(newTokens, token => token.address);
- // Add placeholder entry for this token to the state, since fetching the
- // balance/allowance is asynchronous
- const trackedTokenStateByAddress = { ...this.state.trackedTokenStateByAddress };
- for (const tokenAddress of newTokenAddresses) {
- trackedTokenStateByAddress[tokenAddress] = {
- balance: new BigNumber(0),
- allowance: new BigNumber(0),
- isLoaded: false,
- };
- }
- this.setState(
- {
- trackedTokenStateByAddress,
- },
- () => {
- // Fetch the actual balance/allowance.
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(newTokenAddresses);
- },
- );
- }
- }
- public render(): React.ReactNode {
- const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
- this.props.dispatcher,
- );
- const isAssetPickerDialogOpen = this.state.tokenManagementState !== TokenManagementState.None;
- const tokenVisibility =
- this.state.tokenManagementState === TokenManagementState.Add
- ? TokenVisibility.Untracked
- : TokenVisibility.Tracked;
- return (
- <Container>
- <MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} />
- <DocumentTitle title={DOCUMENT_TITLE} />
- <TopBar
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- injectedProviderName={this.props.injectedProviderName}
- onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
- dispatcher={this.props.dispatcher}
- providerType={this.props.providerType}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- location={this.props.location}
- blockchain={this._blockchain}
- translate={this.props.translate}
- displayType={TopBarDisplayType.Expanded}
- style={{
- backgroundColor: colors.lightestGrey,
- position: 'fixed',
- zIndex: zIndex.topBar,
- }}
- maxWidth={LARGE_LAYOUT_MAX_WIDTH}
- />
- <Container marginTop={TOP_BAR_HEIGHT} minHeight="100vh" backgroundColor={colors.lightestGrey}>
- <Switch>
- <Route path={`${WebsitePaths.Portal}/:route`} render={this._renderOtherRoutes.bind(this)} />
- <Route
- exact={true}
- path={`${WebsitePaths.Portal}/`}
- render={this._renderMainRoute.bind(this)}
- />
- </Switch>
- <BlockchainErrDialog
- blockchain={this._blockchain}
- blockchainErr={this.props.blockchainErr}
- isOpen={this.props.shouldBlockchainErrDialogBeOpen}
- userAddress={this.props.userAddress}
- toggleDialogFn={updateShouldBlockchainErrDialogBeOpen}
- networkId={this.props.networkId}
- />
- <FlashMessage dispatcher={this.props.dispatcher} flashMessage={this.props.flashMessage} />
-
- <LedgerConfigDialog
- providerType={this.props.providerType}
- networkId={this.props.networkId}
- blockchain={this._blockchain}
- dispatcher={this.props.dispatcher}
- toggleDialogFn={this._onToggleLedgerDialog.bind(this)}
- isOpen={this.state.isLedgerDialogOpen}
- />
-
- <AssetPicker
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this._blockchain}
- dispatcher={this.props.dispatcher}
- isOpen={isAssetPickerDialogOpen}
- currentTokenAddress={''}
- onTokenChosen={this._onTokenChosen.bind(this)}
- tokenByAddress={this.props.tokenByAddress}
- tokenVisibility={tokenVisibility}
- />
- </Container>
- </Container>
- );
- }
- private _renderMainRoute(): React.ReactNode {
- if (this._isSmallScreen()) {
- return <SmallLayout content={this._renderRelayerIndexSection()} />;
- } else {
- return <LargeLayout left={this._renderWalletSection()} right={this._renderRelayerIndexSection()} />;
- }
- }
- private _renderOtherRoutes(routeComponentProps: RouteComponentProps<any>): React.ReactNode {
- if (this._isSmallScreen()) {
- return <SmallLayout content={this._renderAccountManagement()} />;
- } else {
- return <LargeLayout left={this._renderMenu(routeComponentProps)} right={this._renderAccountManagement()} />;
- }
- }
- private _renderMenu(routeComponentProps: RouteComponentProps<any>): React.ReactNode {
- const menuTheme: MenuTheme = {
- paddingLeft: MENU_PADDING_LEFT,
- textColor: colors.darkerGrey,
- iconColor: colors.darkerGrey,
- selectedIconColor: colors.yellow800,
- selectedBackgroundColor: 'transparent',
- };
- return (
- <Section
- header={<BackButton to={WebsitePaths.Portal} labelText="back to Relayers" />}
- body={<Menu selectedPath={routeComponentProps.location.pathname} theme={menuTheme} />}
- />
- );
- }
- private _renderWallet(): React.ReactNode {
- const isMobile = utils.isMobileWidth(this.props.screenWidth);
- // We need room to scroll down for mobile onboarding
- const marginBottom = isMobile ? '250px' : '15px';
- return (
- <div>
- <Container className="flex flex-column items-center">
- {isMobile && (
- <Container marginTop="20px" marginBottom="20px">
- {this._renderStartOnboarding()}
- </Container>
- )}
- <Container marginBottom={marginBottom} width="100%">
- <Wallet
- style={
- !isMobile && this.props.isPortalOnboardingShowing
- ? { zIndex: zIndex.aboveOverlay, position: 'relative' }
- : undefined
- }
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this._blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- tokenByAddress={this.props.tokenByAddress}
- trackedTokens={this._getCurrentTrackedTokens()}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- screenWidth={this.props.screenWidth}
- location={this.props.location}
- trackedTokenStateByAddress={this.state.trackedTokenStateByAddress}
- onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
- onAddToken={this._onAddToken.bind(this)}
- onRemoveToken={this._onRemoveToken.bind(this)}
- refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)}
- toggleTooltipDirection={
- this.props.isPortalOnboardingShowing ? PointerDirection.Left : PointerDirection.Right
- }
- />
- </Container>
- {!isMobile && <Container marginTop="8px">{this._renderStartOnboarding()}</Container>}
- </Container>
- <PortalOnboardingFlow
- blockchain={this._blockchain}
- trackedTokenStateByAddress={this.state.trackedTokenStateByAddress}
- refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)}
- />
- </div>
- );
- }
- private _renderStartOnboarding(): React.ReactNode {
- const isMobile = utils.isMobileWidth(this.props.screenWidth);
- const shouldStartOnboarding = !isMobile || this.props.location.pathname === `${WebsitePaths.Portal}/account`;
- const startOnboarding = (
- <Container className="flex items-center center">
- <Text fontColor={colors.mediumBlue} fontSize="16px" onClick={this._startOnboarding.bind(this)}>
- Set up your account to start trading
- </Text>
- <Container marginLeft="8px" paddingTop="3px">
- <Image src="/images/setup_account_icon.svg" height="20px" width="20x" />
- </Container>
- </Container>
- );
- return !shouldStartOnboarding ? (
- <Link to={`${WebsitePaths.Portal}/account`}>{startOnboarding}</Link>
- ) : (
- startOnboarding
- );
- }
- private _startOnboarding(): void {
- analytics.track('Onboarding Started', {
- reason: 'manual',
- stepIndex: this.props.portalOnboardingStep,
- });
- this.props.dispatcher.updatePortalOnboardingShowing(true);
- }
- private _renderWalletSection(): React.ReactNode {
- return <Section header={<TextHeader labelText="Your Account" />} body={this._renderWallet()} />;
- }
- private _renderAccountManagement(): React.ReactNode {
- const accountManagementItems: AccountManagementItem[] = [
- {
- pathName: `${WebsitePaths.Portal}/weth`,
- headerText: 'Wrapped ETH',
- render: this._renderEthWrapper.bind(this),
- },
- {
- pathName: `${WebsitePaths.Portal}/account`,
- headerText: this._isSmallScreen() ? undefined : 'Your Account',
- render: this._isSmallScreen() ? this._renderWallet.bind(this) : this._renderTokenBalances.bind(this),
- },
- {
- pathName: `${WebsitePaths.Portal}/trades`,
- headerText: 'Trade History',
- render: this._renderTradeHistory.bind(this),
- },
- {
- pathName: `${WebsitePaths.Portal}/generate`,
- headerText: 'Generate Order',
- render: this._renderGenerateOrderForm.bind(this),
- },
- {
- pathName: `${WebsitePaths.Portal}/fill`,
- headerText: 'Fill Order',
- render: this._renderFillOrder.bind(this),
- },
- ];
- return (
- <div>
- <Switch>
- {_.map(accountManagementItems, item => {
- return (
- <Route
- key={item.pathName}
- path={item.pathName}
- render={this._renderAccountManagementItem.bind(this, item)}
- />
- );
- })}
- }
- <Route render={this._renderNotFoundMessage.bind(this)} />
- </Switch>
- <PortalDisclaimerDialog
- isOpen={this.state.isDisclaimerDialogOpen}
- onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
- />
- </div>
- );
- }
- private _renderAccountManagementItem(item: AccountManagementItem): React.ReactNode {
- return (
- <Section
- header={!_.isUndefined(item.headerText) && <TextHeader labelText={item.headerText} />}
- body={<Loading isLoading={!this.props.blockchainIsLoaded} content={item.render()} />}
- />
- );
- }
- private _renderEthWrapper(): React.ReactNode {
- return (
- <EthWrappers
- networkId={this.props.networkId}
- blockchain={this._blockchain}
- dispatcher={this.props.dispatcher}
- tokenByAddress={this.props.tokenByAddress}
- userAddress={this.props.userAddress}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- isFullWidth={true}
- />
- );
- }
- private _renderTradeHistory(): React.ReactNode {
- return (
- <TradeHistory
- tokenByAddress={this.props.tokenByAddress}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- isFullWidth={true}
- shouldHideHeader={true}
- isScrollable={false}
- />
- );
- }
- private _renderGenerateOrderForm(): React.ReactNode {
- return (
- <GenerateOrderForm
- blockchain={this._blockchain}
- hashData={this.props.hashData}
- dispatcher={this.props.dispatcher}
- isFullWidth={true}
- shouldHideHeader={true}
- />
- );
- }
- private _renderFillOrder(): React.ReactNode {
- const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache)
- ? this.props.userSuppliedOrderCache
- : this._sharedOrderIfExists;
- return (
- <FillOrder
- blockchain={this._blockchain}
- blockchainErr={this.props.blockchainErr}
- initialOrder={initialFillOrder}
- isOrderInUrl={!_.isUndefined(this._sharedOrderIfExists)}
- orderFillAmount={this.props.orderFillAmount}
- networkId={this.props.networkId}
- userAddress={this.props.userAddress}
- tokenByAddress={this.props.tokenByAddress}
- dispatcher={this.props.dispatcher}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- isFullWidth={true}
- shouldHideHeader={true}
- />
- );
- }
- private _renderTokenBalances(): React.ReactNode {
- return (
- <TokenBalances
- blockchain={this._blockchain}
- blockchainErr={this.props.blockchainErr}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- dispatcher={this.props.dispatcher}
- screenWidth={this.props.screenWidth}
- tokenByAddress={this.props.tokenByAddress}
- trackedTokens={this._getCurrentTrackedTokens()}
- userAddress={this.props.userAddress}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- networkId={this.props.networkId}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- isFullWidth={true}
- />
- );
- }
- private _renderRelayerIndexSection(): React.ReactNode {
- const isMobile = utils.isMobileWidth(this.props.screenWidth);
- // TODO(bmillman): revert RelayerIndex cellStyle to Expanded once data pipeline is tracking v2 volume
- return (
- <Section
- header={!isMobile && <TextHeader labelText="0x Relayers" />}
- body={
- <Container className="flex flex-column">
- {isMobile && (
- <Container marginTop="20px" marginBottom="20px">
- {this._renderStartOnboarding()}
- </Container>
- )}
- <RelayerIndex
- networkId={this.props.networkId}
- screenWidth={this.props.screenWidth}
- cellStyle={RelayerIndexCellStyle.Minimized}
- />
- </Container>
- }
- />
- );
- }
- private _renderNotFoundMessage(): React.ReactNode {
- return (
- <FullscreenMessage
- headerText="404 Not Found"
- bodyText="Hm... looks like we couldn't find what you are looking for."
- />
- );
- }
- private _onTokenChosen(tokenAddress: string): void {
- if (_.isEmpty(tokenAddress)) {
- this.setState({
- tokenManagementState: TokenManagementState.None,
- });
- return;
- }
- const token = this.props.tokenByAddress[tokenAddress];
- const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol);
- if (this.state.tokenManagementState === TokenManagementState.Remove && !isDefaultTrackedToken) {
- if (token.isRegistered) {
- // Remove the token from tracked tokens
- const newToken: Token = {
- ...token,
- trackedTimestamp: undefined,
- };
- this.props.dispatcher.updateTokenByAddress([newToken]);
- } else {
- this.props.dispatcher.removeTokenToTokenByAddress(token);
- }
- trackedTokenStorage.removeTrackedToken(this.props.userAddress, this.props.networkId, tokenAddress);
- } else if (isDefaultTrackedToken) {
- this.props.dispatcher.showFlashMessage(`Cannot remove ${token.name} because it's a default token`);
- }
- this.setState({
- tokenManagementState: TokenManagementState.None,
- });
- }
- private _onToggleLedgerDialog(): void {
- this.setState({
- isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
- });
- }
- private _onAddToken(): void {
- this.setState({
- tokenManagementState: TokenManagementState.Add,
- });
- }
- private _onRemoveToken(): void {
- this.setState({
- tokenManagementState: TokenManagementState.Remove,
- });
- }
- private _onPortalDisclaimerAccepted(): void {
- localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
- this.setState({
- isDisclaimerDialogOpen: false,
- });
- }
- private _updateScreenWidth(): void {
- const newScreenWidth = utils.getScreenWidth();
- this.props.dispatcher.updateScreenWidth(newScreenWidth);
- }
- private _isSmallScreen(): boolean {
- const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
- return isSmallScreen;
- }
- private _getCurrentTrackedTokens(): Token[] {
- return utils.getTrackedTokens(this.props.tokenByAddress);
- }
- private _getCurrentTrackedTokensAddresses(): string[] {
- return _.map(this._getCurrentTrackedTokens(), token => token.address);
- }
- private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]): TokenStateByAddress {
- const trackedTokenStateByAddress: TokenStateByAddress = {};
- _.each(trackedTokens, token => {
- trackedTokenStateByAddress[token.address] = {
- balance: new BigNumber(0),
- allowance: new BigNumber(0),
- isLoaded: false,
- };
- });
- return trackedTokenStateByAddress;
- }
-
- private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise<void> {
- if (_.isEmpty(tokenAddresses)) {
- return;
- }
- const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const balancesAndAllowances = await Promise.all(
- tokenAddresses.map(async tokenAddress => {
- return this._blockchain.getTokenBalanceAndAllowanceAsync(userAddressIfExists, tokenAddress);
- }),
- );
- const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses);
- for (let i = 0; i < tokenAddresses.length; i++) {
- // Order is preserved in Promise.all
- const [balance, allowance] = balancesAndAllowances[i];
- const tokenAddress = tokenAddresses[i];
- trackedTokenStateByAddress[tokenAddress] = {
- balance,
- allowance,
- isLoaded: true,
- price: priceByAddress[tokenAddress],
- };
- }
- this.setState({
- trackedTokenStateByAddress,
- });
- }
-
- private async _getPriceByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> {
- if (_.isEmpty(tokenAddresses)) {
- return {};
- }
- // for each input token address, search for the corresponding symbol in this.props.tokenByAddress, if it exists
- // create a mapping from existing symbols -> address
- const tokenAddressBySymbol: { [symbol: string]: string } = {};
- _.each(tokenAddresses, address => {
- const tokenIfExists = _.get(this.props.tokenByAddress, address);
- if (!_.isUndefined(tokenIfExists)) {
- const symbol = tokenIfExists.symbol;
- tokenAddressBySymbol[symbol] = address;
- }
- });
- const tokenSymbols = _.keys(tokenAddressBySymbol);
- try {
- const priceBySymbol = await backendClient.getPriceInfoAsync(tokenSymbols);
- const priceByAddress = _.mapKeys(priceBySymbol, (_value, symbol) => _.get(tokenAddressBySymbol, symbol));
- const result = _.mapValues(priceByAddress, price => {
- const priceBigNumber = new BigNumber(price);
- return priceBigNumber;
- });
- return result;
- } catch (err) {
- return {};
- }
- }
-
- private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> {
- await this._fetchBalancesAndAllowancesAsync([tokenAddress]);
- }
-}
-
-interface LargeLayoutProps {
- left: React.ReactNode;
- right: React.ReactNode;
-}
-const LargeLayout = (props: LargeLayoutProps) => {
- return (
- <Container
- className="mx-auto flex flex-center"
- maxWidth={LARGE_LAYOUT_MAX_WIDTH}
- paddingLeft={SIDE_PADDING}
- paddingRight={SIDE_PADDING}
- >
- <div className="flex-last">
- <Container width={LEFT_COLUMN_WIDTH} position="fixed" zIndex={zIndex.aboveTopBar}>
- {props.left}
- </Container>
- </div>
- <Container className="flex-auto" marginLeft={LEFT_COLUMN_WIDTH}>
- <Container className="flex-auto" marginLeft={SIDE_PADDING}>
- {props.right}
- </Container>
- </Container>
- </Container>
- );
-};
-
-interface SmallLayoutProps {
- content: React.ReactNode;
-}
-const SmallLayout = (props: SmallLayoutProps) => {
- return (
- <div className="flex flex-center">
- <Container className="flex-auto" paddingLeft={SIDE_PADDING} paddingRight={SIDE_PADDING}>
- {props.content}
- </Container>
- </div>
- );
-}; // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/portal/section.tsx b/packages/website/ts/components/portal/section.tsx
deleted file mode 100644
index b6c9fd098..000000000
--- a/packages/website/ts/components/portal/section.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import * as React from 'react';
-
-export interface SectionProps {
- header: React.ReactNode;
- body: React.ReactNode;
-}
-export const Section = (props: SectionProps) => {
- return (
- <div className="flex flex-column">
- {props.header}
- {props.body}
- </div>
- );
-};
diff --git a/packages/website/ts/components/portal/text_header.tsx b/packages/website/ts/components/portal/text_header.tsx
deleted file mode 100644
index b6045b832..000000000
--- a/packages/website/ts/components/portal/text_header.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-
-import { Text } from 'ts/components/ui/text';
-
-export interface TextHeaderProps {
- labelText: string;
-}
-
-export const TextHeader = (props: TextHeaderProps) => {
- return (
- <Text className="pt3 pb2" fontWeight="bold" fontSize="16px" fontColor={colors.darkestGrey}>
- {props.labelText}
- </Text>
- );
-};
diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
deleted file mode 100644
index 7f1b4ebb4..000000000
--- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import * as _ from 'lodash';
-import { GridTile as PlainGridTile } from 'material-ui/GridList';
-import * as React from 'react';
-import { analytics } from 'ts/utils/analytics';
-
-import { TopTokens } from 'ts/components/relayer_index/relayer_top_tokens';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Island } from 'ts/components/ui/island';
-import { colors } from 'ts/style/colors';
-import { media } from 'ts/style/media';
-import { styled } from 'ts/style/theme';
-import { WebsiteBackendRelayerInfo } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-export enum RelayerGridTileStyle {
- Expanded = 0,
- Minimized,
-}
-
-export interface RelayerGridTileProps {
- relayerInfo: WebsiteBackendRelayerInfo;
- networkId: number;
- style: RelayerGridTileStyle;
-}
-
-const styles: Styles = {
- root: {
- boxSizing: 'border-box',
- // All material UI components have position: relative
- // which creates a new stacking context and makes z-index stuff impossible. So reset.
- position: 'static',
- },
- innerDiv: {
- height: '100%',
- boxSizing: 'border-box',
- },
- expandedHeader: {
- height: '50%',
- width: '100%',
- },
- minimizedHeader: {
- height: '100%',
- width: '100%',
- },
- body: {
- height: '50%',
- width: '100%',
- boxSizing: 'border-box',
- padding: 12,
- },
- weeklyTradeVolumeLabel: {
- fontSize: 14,
- color: colors.mediumBlue,
- },
- subLabel: {
- fontSize: 12,
- color: colors.lightGrey,
- },
- relayerNameLabel: {
- fontSize: 16,
- fontWeight: 'bold',
- color: colors.black,
- },
-};
-
-const FALLBACK_IMG_SRC = '/images/relayer_fallback.png';
-const FALLBACK_PRIMARY_COLOR = colors.grey300;
-const NO_CONTENT_MESSAGE = '--';
-const RELAYER_ICON_HEIGHT = '110px';
-
-export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => {
- const link = props.relayerInfo.appUrl || props.relayerInfo.url;
- const topTokens = props.relayerInfo.topTokens;
- const weeklyTxnVolume = props.relayerInfo.weeklyTxnVolume;
- const onClick = () => {
- analytics.track('Relayer Click', {
- name: props.relayerInfo.name,
- });
- utils.openUrl(link);
- };
- const headerImageUrl = props.relayerInfo.logoImgUrl;
- const headerBackgroundColor =
- !_.isUndefined(headerImageUrl) && !_.isUndefined(props.relayerInfo.primaryColor)
- ? props.relayerInfo.primaryColor
- : FALLBACK_PRIMARY_COLOR;
- const isExpanded = props.style === RelayerGridTileStyle.Expanded;
- const headerStyle = isExpanded ? styles.expandedHeader : styles.minimizedHeader;
- return (
- <Island style={styles.root} Component={GridTile}>
- <div style={styles.innerDiv} onClick={onClick}>
- <div className="flex items-center" style={{ ...headerStyle, backgroundColor: headerBackgroundColor }}>
- <Image
- className="mx-auto"
- src={props.relayerInfo.logoImgUrl}
- fallbackSrc={FALLBACK_IMG_SRC}
- height={RELAYER_ICON_HEIGHT}
- />
- </div>
- {isExpanded && (
- <div style={styles.body}>
- <div className="pb1" style={styles.relayerNameLabel}>
- {props.relayerInfo.name}
- </div>
- <Section titleText="Weekly Trade Volume">
- {!_.isUndefined(weeklyTxnVolume) && (
- <div style={styles.weeklyTradeVolumeLabel}>{props.relayerInfo.weeklyTxnVolume}</div>
- )}
- </Section>
- <Container marginTop="10px">
- <Section titleText="Top Tokens">
- {!_.isEmpty(topTokens) && <TopTokens tokens={topTokens} networkId={props.networkId} />}
- </Section>
- </Container>
- </div>
- )}
- </div>
- </Island>
- );
-};
-
-const GridTile = styled(PlainGridTile)`
- cursor: pointer;
- &:hover {
- transition: transform 0.2s ease;
- transform: translate(0px, -3px);
- }
- ${media.small`
- transform: none !important;
- transition: none !important;
- `};
-`;
-
-interface SectionProps {
- titleText: string;
- children?: React.ReactNode;
-}
-const Section = (props: SectionProps) => {
- return (
- <div>
- <div style={styles.subLabel}>{props.titleText}</div>
- <Container marginTop="6px">{props.children || <NoContent />}</Container>
- </div>
- );
-};
-
-const NoContent = () => <div style={styles.subLabel}>{NO_CONTENT_MESSAGE}</div>;
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx
deleted file mode 100644
index e88c20d7e..000000000
--- a/packages/website/ts/components/relayer_index/relayer_index.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import * as _ from 'lodash';
-import CircularProgress from 'material-ui/CircularProgress';
-import { GridList } from 'material-ui/GridList';
-import * as React from 'react';
-
-import { RelayerGridTile, RelayerGridTileStyle } from 'ts/components/relayer_index/relayer_grid_tile';
-import { Retry } from 'ts/components/ui/retry';
-import { ScreenWidths, WebsiteBackendRelayerInfo } from 'ts/types';
-import { backendClient } from 'ts/utils/backend_client';
-
-export enum RelayerIndexCellStyle {
- Expanded = 0,
- Minimized,
-}
-
-export interface RelayerIndexProps {
- networkId: number;
- screenWidth: ScreenWidths;
- cellStyle: RelayerIndexCellStyle;
-}
-
-interface RelayerIndexState {
- relayerInfos?: WebsiteBackendRelayerInfo[];
- error?: Error;
-}
-
-const CELL_HEIGHT_EXPANDED = 290;
-const CELL_HEIGHT_MINIMIZED = 225;
-const NUMBER_OF_COLUMNS_LARGE = 3;
-const NUMBER_OF_COLUMNS_MEDIUM = 2;
-const NUMBER_OF_COLUMNS_SMALL = 2;
-const GRID_PADDING = 20;
-
-export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerIndexState> {
- private _isUnmounted: boolean;
- constructor(props: RelayerIndexProps) {
- super(props);
- this._isUnmounted = false;
- this.state = {
- relayerInfos: undefined,
- error: undefined,
- };
- }
- public componentWillMount(): void {
- // tslint:disable-next-line:no-floating-promises
- this._fetchRelayerInfosAsync();
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public render(): React.ReactNode {
- const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
- if (!isReadyToRender) {
- return (
- // TODO: consolidate this loading component with the one in portal and OpenPositions
- // TODO: possibly refactor into a generic loading container with spinner and retry UI
- <div className="center">
- {_.isUndefined(this.state.error) ? (
- <CircularProgress size={40} thickness={5} />
- ) : (
- <Retry onRetry={this._fetchRelayerInfosAsync.bind(this)} />
- )}
- </div>
- );
- } else {
- const numberOfRelayers = this.state.relayerInfos.length;
- const numberOfColumns = Math.min(
- numberOfRelayers,
- this._numberOfColumnsForScreenWidth(this.props.screenWidth),
- );
- const isExpanded = this.props.cellStyle === RelayerIndexCellStyle.Expanded;
- const cellHeight = isExpanded ? CELL_HEIGHT_EXPANDED : CELL_HEIGHT_MINIMIZED;
- const gridTileStyle = isExpanded ? RelayerGridTileStyle.Expanded : RelayerGridTileStyle.Minimized;
- return (
- <GridList
- cellHeight={cellHeight}
- cols={numberOfColumns}
- padding={GRID_PADDING}
- style={{ marginTop: -10, marginBottom: 0 }}
- >
- {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => (
- <RelayerGridTile
- key={index}
- relayerInfo={relayerInfo}
- networkId={this.props.networkId}
- style={gridTileStyle}
- />
- ))}
- </GridList>
- );
- }
- }
- private async _fetchRelayerInfosAsync(): Promise<void> {
- try {
- if (!this._isUnmounted) {
- this.setState({
- relayerInfos: undefined,
- error: undefined,
- });
- }
- const relayerInfos = await backendClient.getRelayerInfosAsync();
- if (!this._isUnmounted) {
- this.setState({
- relayerInfos,
- });
- }
- } catch (error) {
- if (!this._isUnmounted) {
- this.setState({
- error,
- });
- }
- }
- }
- private _numberOfColumnsForScreenWidth(screenWidth: ScreenWidths): number {
- switch (screenWidth) {
- case ScreenWidths.Md:
- return NUMBER_OF_COLUMNS_MEDIUM;
- case ScreenWidths.Sm:
- return NUMBER_OF_COLUMNS_SMALL;
- case ScreenWidths.Lg:
- default:
- return NUMBER_OF_COLUMNS_LARGE;
- }
- }
-}
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
deleted file mode 100644
index 558d99855..000000000
--- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { WebsiteBackendTokenInfo } from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { utils } from 'ts/utils/utils';
-
-export interface TopTokensProps {
- tokens: WebsiteBackendTokenInfo[];
- networkId: number;
-}
-
-export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => {
- return (
- <div className="flex">
- {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo) => {
- return (
- <Container key={tokenInfo.address} marginRight="16px">
- <TokenLink tokenInfo={tokenInfo} networkId={props.networkId} />
- </Container>
- );
- })}
- </div>
- );
-};
-
-interface TokenLinkProps {
- tokenInfo: WebsiteBackendTokenInfo;
- networkId: number;
-}
-interface TokenLinkState {}
-
-class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> {
- constructor(props: TokenLinkProps) {
- super(props);
- this.state = {
- isHovering: false,
- };
- }
- public render(): React.ReactNode {
- const onClick = (event: React.MouseEvent<HTMLElement>) => {
- event.stopPropagation();
- analytics.track('Token Click', {
- tokenSymbol: this.props.tokenInfo.symbol,
- });
- const tokenLink = this._tokenLinkFromToken(this.props.tokenInfo, this.props.networkId);
- utils.openUrl(tokenLink);
- };
- return (
- <Text fontSize="14px" fontColor={colors.mediumBlue} onClick={onClick}>
- {this.props.tokenInfo.symbol}
- </Text>
- );
- }
- private _tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number): string {
- return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address);
- }
-}
diff --git a/packages/website/ts/components/sections/landing/about.tsx b/packages/website/ts/components/sections/landing/about.tsx
deleted file mode 100644
index 9c369d83a..000000000
--- a/packages/website/ts/components/sections/landing/about.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-import { Button } from 'ts/components/button';
-import { Icon, InlineIconWrap } from 'ts/components/icon';
-import { Column, FlexWrap, Section } from 'ts/components/newLayout';
-import { Paragraph } from 'ts/components/text';
-import { WebsitePaths } from 'ts/types';
-
-interface FigureProps {
- value: string;
- description: string;
-}
-
-export const SectionLandingAbout = () => (
- <Section bgColor="dark" isTextCentered={true}>
- <InlineIconWrap>
- <Icon name="descriptionCoin" size="small" />
- <Icon name="descriptionCopy" size="small" />
- <Icon name="descriptionFlask" size="small" />
- <Icon name="descriptionBolt" size="small" />
- </InlineIconWrap>
-
- <Paragraph size="large" isCentered={true} isMuted={1} padding={['large', 0, 'default', 0]}>
- Anyone in the world can use 0x to service a wide variety of markets ranging from gaming items to financial
- instruments to assets that could have never existed before.
- </Paragraph>
-
- <DeveloperLink href={`${WebsitePaths.Why}#cases`} isWithArrow={true} isAccentColor={true}>
- Discover how developers use 0x
- </DeveloperLink>
-
- <hr
- style={{
- width: '100%',
- maxWidth: '340px',
- borderColor: '#3C4746',
- margin: '60px auto',
- }}
- />
-
- <FlexWrap as="dl">
- <Figure value="353K" description="Total Transactions" />
-
- <Figure value="$447M" description="Total Volume" />
-
- <Figure value="30+" description="Total Projects" />
- </FlexWrap>
- </Section>
-);
-
-const Figure = (props: FigureProps) => (
- <Column padding="0 30px">
- <FigureValue>{props.value}</FigureValue>
- <FigureDescription>{props.description}</FigureDescription>
- </Column>
-);
-
-const DeveloperLink = styled(Button)`
- @media (max-width: 500px) {
- && {
- white-space: pre-wrap;
- line-height: 1.3;
- }
- }
-`;
-
-const FigureValue = styled.dt`
- font-size: 50px;
- font-weight: 300;
- margin-bottom: 15px;
-
- @media (max-width: 768px) {
- font-size: 40px;
- }
-`;
-
-const FigureDescription = styled.dd`
- font-size: 18px;
- color: #999999;
-`;
diff --git a/packages/website/ts/components/sections/landing/clients.tsx b/packages/website/ts/components/sections/landing/clients.tsx
deleted file mode 100644
index 4d83a1d2f..000000000
--- a/packages/website/ts/components/sections/landing/clients.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import styled from 'styled-components';
-import { Heading } from 'ts/components/text';
-
-import { Section, WrapGrid } from 'ts/components/newLayout';
-
-interface ProjectLogo {
- name: string;
- imageUrl?: string;
- persistOnMobile?: boolean;
-}
-
-interface StyledProjectInterface {
- isOnMobile?: boolean;
-}
-
-const projects: ProjectLogo[] = [
- {
- name: 'Radar Relay',
- imageUrl: 'images/clients/radar-relay.svg',
- persistOnMobile: true,
- },
- {
- name: 'Paradex',
- imageUrl: 'images/clients/paradex.svg',
- persistOnMobile: true,
- },
- {
- name: 'Star Bit Ex',
- imageUrl: 'images/clients/starbitex.svg',
- },
- {
- name: 'LedgerDex',
- imageUrl: 'images/clients/ledgerdex.svg',
- },
- {
- name: 'OpenRelay',
- imageUrl: 'images/clients/openrelay.svg',
- persistOnMobile: true,
- },
- {
- name: 'Bamboo Relay',
- imageUrl: 'images/clients/bamboo.svg',
- persistOnMobile: true,
- },
- {
- name: 'dEX',
- imageUrl: 'images/clients/ercdex.svg',
- persistOnMobile: true,
- },
- {
- name: 'emoon',
- imageUrl: 'images/clients/emoon.svg',
- persistOnMobile: true,
- },
- {
- name: 'Gods Unchained',
- imageUrl: 'images/clients/godsUnchained.svg',
- },
- {
- name: 'Instex',
- imageUrl: 'images/clients/instex.svg',
- },
- {
- name: 'Lake Trade',
- imageUrl: 'images/clients/laketrade.svg',
- },
- {
- name: 'Veil',
- imageUrl: 'images/clients/veil.svg',
- },
-];
-
-export const SectionLandingClients = () => (
- <Section isTextCentered={true}>
- <Heading size="small">Join the growing number of projects developing on 0x</Heading>
-
- <WrapGrid isWrapped={true}>
- {_.map(projects, (item: ProjectLogo, index) => (
- <StyledProject key={`client-${index}`} isOnMobile={item.persistOnMobile}>
- <img src={item.imageUrl} alt={item.name} />
- </StyledProject>
- ))}
- </WrapGrid>
- </Section>
-);
-
-const StyledProject = styled.div<StyledProjectInterface>`
- flex-shrink: 0;
-
- img {
- object-fit: contain;
- width: 100%;
- height: 100%;
- }
-
- @media (min-width: 768px) {
- width: auto;
- height: 50px;
- margin: 30px;
- }
-
- @media (max-width: 768px) {
- width: auto;
- height: 42px;
- margin: 15px;
- display: ${props => !props.isOnMobile && 'none'};
- }
-`;
diff --git a/packages/website/ts/components/sections/landing/cta.tsx b/packages/website/ts/components/sections/landing/cta.tsx
deleted file mode 100644
index ec5a58a58..000000000
--- a/packages/website/ts/components/sections/landing/cta.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as React from 'react';
-
-import { BlockIconLink } from 'ts/components/blockIconLink';
-import { Section } from 'ts/components/newLayout';
-
-import { AnimatedChatIcon } from 'ts/components/animatedChatIcon';
-import { AnimatedCompassIcon } from 'ts/components/animatedCompassIcon';
-import { WebsitePaths } from 'ts/types';
-
-interface Props {
- onContactClick?: () => void;
-}
-
-export const SectionLandingCta = (props: Props) => (
- <Section isPadded={false} isFlex={true} maxWidth="auto" wrapWidth="100%" flexBreakpoint="900px">
- <BlockIconLink
- iconComponent={<AnimatedCompassIcon />}
- title="Ready to build on 0x?"
- linkLabel="Get Started"
- linkUrl={WebsitePaths.Docs}
- />
- <BlockIconLink
- iconComponent={<AnimatedChatIcon />}
- title="Want help from the 0x team?"
- linkLabel="Get in Touch"
- linkAction={props.onContactClick}
- />
- </Section>
-);
diff --git a/packages/website/ts/components/sections/landing/hero.tsx b/packages/website/ts/components/sections/landing/hero.tsx
deleted file mode 100644
index 489757286..000000000
--- a/packages/website/ts/components/sections/landing/hero.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as React from 'react';
-
-import { Button } from 'ts/components/button';
-import { Hero } from 'ts/components/hero';
-import { LandingAnimation } from 'ts/components/heroImage';
-
-import { HeroAnimation } from 'ts/components/heroAnimation';
-import { WebsitePaths } from 'ts/types';
-
-export const SectionLandingHero = () => (
- <Hero
- title="Powering Decentralized Exchange"
- isLargeTitle={true}
- isFullWidth={true}
- description="0x is an open protocol that enables the peer-to-peer exchange of assets on the Ethereum blockchain."
- figure={<LandingAnimation image={<HeroAnimation />} />}
- actions={<HeroActions />}
- />
-);
-
-const HeroActions = () => (
- <>
- <Button href="https://0x.org/docs" isInline={true}>
- Get Started
- </Button>
-
- <Button to={WebsitePaths.Why} isTransparent={true} isInline={true}>
- Learn More
- </Button>
- </>
-);
diff --git a/packages/website/ts/components/send_button.tsx b/packages/website/ts/components/send_button.tsx
deleted file mode 100644
index 27438e5d5..000000000
--- a/packages/website/ts/components/send_button.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { BigNumber, logUtils } from '@0x/utils';
-import * as _ from 'lodash';
-import RaisedButton from 'material-ui/RaisedButton';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { SendDialog } from 'ts/components/dialogs/send_dialog';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { BlockchainCallErrs, Token } from 'ts/types';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-interface SendButtonProps {
- userAddress: string;
- networkId: number;
- asset: Token | 'ETH';
- dispatcher: Dispatcher;
- blockchain: Blockchain;
- onError: () => void;
- lastForceTokenStateRefetch: number;
- refetchTokenStateAsync: (tokenAddress: string) => Promise<void>;
-}
-
-interface SendButtonState {
- isSendDialogVisible: boolean;
- isSending: boolean;
-}
-
-export class SendButton extends React.Component<SendButtonProps, SendButtonState> {
- public constructor(props: SendButtonProps) {
- super(props);
- this.state = {
- isSendDialogVisible: false,
- isSending: false,
- };
- }
- public render(): React.ReactNode {
- const labelStyle = this.state.isSending ? { fontSize: 10 } : {};
- return (
- <div>
- <RaisedButton
- style={{ width: '100%' }}
- labelStyle={labelStyle}
- disabled={this.state.isSending}
- label={this.state.isSending ? 'Sending...' : 'Send'}
- onClick={this._toggleSendDialog.bind(this)}
- />
- <SendDialog
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- isOpen={this.state.isSendDialogVisible}
- onComplete={this._onSendAmountSelectedAsync.bind(this)}
- onCancelled={this._toggleSendDialog.bind(this)}
- asset={this.props.asset}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- />
- </div>
- );
- }
- private _toggleSendDialog(): void {
- this.setState({
- isSendDialogVisible: !this.state.isSendDialogVisible,
- });
- }
- private async _onSendAmountSelectedAsync(recipient: string, value: BigNumber): Promise<void> {
- this.setState({
- isSending: true,
- });
- this._toggleSendDialog();
- try {
- if (this.props.asset === 'ETH') {
- await this.props.blockchain.sendAsync(recipient, value);
- } else {
- const token = this.props.asset;
- await this.props.blockchain.transferAsync(token, recipient, value);
- await this.props.refetchTokenStateAsync(token.address);
- }
- } catch (err) {
- const errMsg = `${err}`;
- if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return;
- } else if (!utils.didUserDenyWeb3Request(errMsg)) {
- logUtils.log(`Unexpected error encountered: ${err}`);
- logUtils.log(err.stack);
- this.props.onError();
- errorReporter.report(err);
- }
- }
- this.setState({
- isSending: false,
- });
- }
-}
diff --git a/packages/website/ts/components/siteWrap.tsx b/packages/website/ts/components/siteWrap.tsx
deleted file mode 100644
index 1f0902105..000000000
--- a/packages/website/ts/components/siteWrap.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import * as React from 'react';
-import styled, { ThemeProvider } from 'styled-components';
-
-import { colors } from 'ts/style/colors';
-
-import { Footer } from 'ts/components/footer';
-import { Header } from 'ts/components/header';
-import { GlobalStyles } from 'ts/constants/globalStyle';
-
-interface Props {
- theme?: 'dark' | 'light' | 'gray';
- children: any;
-}
-
-interface State {
- isMobileNavOpen: boolean;
-}
-
-interface MainProps {
- isNavToggled: boolean;
-}
-
-export interface ThemeValuesInterface {
- bgColor: string;
- darkBgColor?: string;
- lightBgColor: string;
- introTextColor: string;
- textColor: string;
- paragraphColor: string;
- linkColor: string;
- mobileNavBgUpper: string;
- mobileNavBgLower: string;
- mobileNavColor: string;
- dropdownBg: string;
- dropdownButtonBg: string;
- dropdownBorderColor?: string;
- dropdownColor: string;
- headerButtonBg: string;
- footerBg: string;
- footerColor: string;
-}
-
-export interface ThemeInterface {
- [key: string]: ThemeValuesInterface;
-}
-
-const GLOBAL_THEMES: ThemeInterface = {
- dark: {
- bgColor: '#000000',
- darkBgColor: '#111A19',
- lightBgColor: '#003831',
- introTextColor: 'rgba(255, 255, 255, 0.75)',
- textColor: '#FFFFFF',
- paragraphColor: '#FFFFFF',
- linkColor: colors.brandLight,
- mobileNavBgUpper: '#003831',
- mobileNavBgLower: '#022924',
- mobileNavColor: '#FFFFFF',
- dropdownBg: '#111A19',
- dropdownButtonBg: '#003831',
- dropdownColor: '#FFFFFF',
- headerButtonBg: '#00AE99',
- footerBg: '#181818',
- footerColor: '#FFFFFF',
- },
- light: {
- bgColor: '#FFFFFF',
- lightBgColor: '#F3F6F4',
- darkBgColor: '#003831',
- introTextColor: 'rgba(92, 92, 92, 0.87)',
- textColor: '#000000',
- paragraphColor: '#474747',
- linkColor: colors.brandDark,
- mobileNavBgUpper: '#FFFFFF',
- mobileNavBgLower: '#F3F6F4',
- mobileNavColor: '#000000',
- dropdownBg: '#FBFBFB',
- dropdownButtonBg: '#F3F6F4',
- dropdownColor: '#003831',
- dropdownBorderColor: '#E4E4E4',
- headerButtonBg: '#003831',
- footerBg: '#F2F2F2',
- footerColor: '#000000',
- },
- gray: {
- bgColor: '#e0e0e0',
- lightBgColor: '#003831',
- introTextColor: 'rgba(92, 92, 92, 0.87)',
- textColor: '#000000',
- paragraphColor: '#777777',
- linkColor: colors.brandDark,
- mobileNavBgUpper: '#FFFFFF',
- mobileNavBgLower: '#F3F6F4',
- mobileNavColor: '#000000',
- dropdownBg: '#FFFFFF',
- dropdownButtonBg: '#F3F6F4',
- dropdownColor: '#003831',
- headerButtonBg: '#003831',
- footerBg: '#181818',
- footerColor: '#FFFFFF',
- },
-};
-
-export class SiteWrap extends React.Component<Props, State> {
- public state = {
- isMobileNavOpen: false,
- };
-
- public componentDidMount(): void {
- document.documentElement.style.overflowY = 'auto';
- window.scrollTo(0, 0);
- }
-
- public toggleMobileNav = () => {
- this.setState({
- isMobileNavOpen: !this.state.isMobileNavOpen,
- });
- };
-
- public render(): React.ReactNode {
- const { children, theme = 'dark' } = this.props;
- const { isMobileNavOpen } = this.state;
- const currentTheme = GLOBAL_THEMES[theme];
-
- return (
- <>
- <ThemeProvider theme={currentTheme}>
- <>
- <GlobalStyles />
-
- <Header isNavToggled={isMobileNavOpen} toggleMobileNav={this.toggleMobileNav} />
-
- <Main isNavToggled={isMobileNavOpen}>{children}</Main>
-
- <Footer />
- </>
- </ThemeProvider>
- </>
- );
- }
-}
-
-const Main = styled.main<MainProps>`
- transition: transform 0.5s, opacity 0.5s;
- opacity: ${props => props.isNavToggled && '0.5'};
-`;
diff --git a/packages/website/ts/components/slider/slider.tsx b/packages/website/ts/components/slider/slider.tsx
deleted file mode 100644
index f0a29f894..000000000
--- a/packages/website/ts/components/slider/slider.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-import * as React from 'react';
-import Flickity from 'react-flickity-component';
-import styled from 'styled-components';
-
-import { colors } from 'ts/style/colors';
-
-import { Icon } from 'ts/components/icon';
-import { Heading, Paragraph } from 'ts/components/text';
-
-interface SliderProps {}
-
-interface SlideProps {
- icon: string;
- heading: string;
- text: string;
- href?: string;
-}
-
-const flickityOptions = {
- initialIndex: 0,
- cellAlign: 'left',
- arrowShape:
- 'M0 50.766L42.467 93.58l5.791-5.839-32.346-32.61H100V46.84H15.48L50.2 11.838 44.409 6 5.794 44.93l-.003-.003z',
- prevNextButtons: true,
-};
-
-export const Slide: React.StatelessComponent<SlideProps> = (props: SlideProps) => {
- const { heading, text, icon } = props;
-
- return (
- <StyledSlide>
- <SlideHead>
- <Icon name={icon} size="large" />
- </SlideHead>
- <SlideContent>
- <Heading asElement="h4" size="small" marginBottom="15px">
- {heading}
- </Heading>
- <Paragraph isMuted={true}>{text}</Paragraph>
- </SlideContent>
- </StyledSlide>
- );
-};
-
-export const Slider: React.StatelessComponent<SliderProps> = props => {
- return (
- <StyledSlider>
- <Flickity
- className={'carousel'} // default ''
- elementType={'div'} // default 'div'
- options={flickityOptions} // takes flickity options {}
- disableImagesLoaded={false} // default false
- >
- {props.children}
- </Flickity>
- </StyledSlider>
- );
-};
-
-const StyledSlider = styled.div`
- //overflow: hidden;
- width: 100%;
- height: 520px;
-
- @media (max-width: 500px) {
- height: 450px;
- }
-
- .carousel {
- display: block;
- user-select: none;
- touch-action: pan-y;
- -webkit-tap-highlight-color: transparent;
- outline: none;
-
- @media (max-width: 500px) {
- overflow: hidden;
- margin-left: -20px;
- width: calc(100vw - 20px);
- }
- }
-
- .flickity-viewport {
- outline: none;
- }
-
- .flickity-button {
- cursor: pointer;
- position: absolute;
- width: 74px;
- height: 74px;
- background-color: #000;
- display: flex;
- outline: 0;
- top: calc(50% - 37px);
- border: 0;
- padding: 0;
- transition: background-color 0.4s ease-in-out, visibility 0.4s ease-in-out, opacity 0.4s ease-in-out;
-
- &:disabled {
- opacity: 0;
- visibility: hidden;
- }
-
- &:hover {
- background-color: hsla(0, 0%, 10%, 1);
- }
-
- &.previous {
- left: 0;
- }
-
- &.next {
- right: 0;
- }
-
- svg {
- margin: auto;
- width: 28px;
- height: auto;
- }
-
- path {
- fill: #fff;
- }
- }
-`;
-
-const StyledSlide = styled.div`
- background-color: ${colors.backgroundDark};
- width: 560px;
- height: 520px;
- flex: 0 0 auto;
- opacity: 0.3;
- transition: opacity 0.4s ease-in-out;
-
- & + & {
- margin-left: 30px;
- }
-
- @media (max-width: 1200px) {
- width: 100%;
- }
-
- @media (max-width: 500px) {
- width: calc(100vw - 10px - 30px);
- height: 450px;
-
- & + & {
- margin-left: 10px;
- }
- }
-
- &.is-selected {
- opacity: 1;
- }
-`;
-
-const SlideHead = styled.div`
- background-color: ${colors.brandDark};
- height: 300px;
- display: flex;
- justify-content: center;
- align-items: center;
-
- @media (max-width: 500px) {
- height: 240px;
- }
-`;
-
-const SlideContent = styled.div`
- padding: 30px;
-
- @media (max-width: 500px) {
- padding: 20px;
- }
-`;
diff --git a/packages/website/ts/components/text.tsx b/packages/website/ts/components/text.tsx
deleted file mode 100644
index a47e61ef3..000000000
--- a/packages/website/ts/components/text.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-import { getCSSPadding, PaddingInterface } from 'ts/constants/utilities';
-
-interface BaseTextInterface extends PaddingInterface {
- size?: 'default' | 'medium' | 'large' | 'small' | number;
- isCentered?: boolean;
- textAlign?: string;
-}
-
-interface HeadingProps extends BaseTextInterface {
- asElement?: 'h1' | 'h2' | 'h3' | 'h4';
- maxWidth?: string;
- fontWeight?: string;
- isCentered?: boolean;
- isFlex?: boolean;
- isNoMargin?: boolean;
- isMuted?: boolean | number;
- marginBottom?: string;
- color?: string;
-}
-
-interface ParagraphProps extends BaseTextInterface {
- isNoMargin?: boolean;
- marginBottom?: string; // maybe we should remove isNoMargin
- isMuted?: boolean | number;
- fontWeight?: string | number;
-}
-
-const StyledHeading = styled.h1<HeadingProps>`
- max-width: ${props => props.maxWidth};
- color: ${props => props.color || props.theme.textColor};
- display: ${props => props.isFlex && `inline-flex`};
- align-items: center;
- justify-content: ${props => props.isFlex && `space-between`};
- font-size: ${props =>
- typeof props.size === 'string' ? `var(--${props.size || 'default'}Heading)` : `${props.size}px`};
- line-height: ${props => `var(--${props.size || 'default'}HeadingHeight)`};
- text-align: ${props => props.isCentered && 'center'};
- padding: ${props => props.padding && getCSSPadding(props.padding)};
- margin-left: ${props => props.isCentered && 'auto'};
- margin-right: ${props => props.isCentered && 'auto'};
- margin-bottom: ${props => !props.isNoMargin && (props.marginBottom || '30px')};
- opacity: ${props => (typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted)};
- font-weight: ${props => (props.fontWeight ? props.fontWeight : ['h4'].includes(props.asElement) ? 400 : 300)};
- width: ${props => props.isFlex && `100%`};
-`;
-
-export const Heading: React.StatelessComponent<HeadingProps> = props => {
- const { asElement = 'h1', children } = props;
- const Component = StyledHeading.withComponent(asElement);
-
- return <Component {...props}>{children}</Component>;
-};
-
-Heading.defaultProps = {
- size: 'default',
-};
-
-// No need to declare it twice as Styled then rewrap as a stateless comp
-// Note: this would be useful to be implemented the same way was "Heading"
-// and be more generic. e.g. <Text /> with a props asElement so we can use it
-// for literally anything =
-export const Paragraph = styled.p<ParagraphProps>`
- font-size: ${props => `var(--${props.size || 'default'}Paragraph)`};
- font-weight: ${props => props.fontWeight || 300};
- margin-bottom: ${props => !props.isNoMargin && (props.marginBottom || '30px')};
- padding: ${props => props.padding && getCSSPadding(props.padding)};
- color: ${props => props.color || props.theme.paragraphColor};
- opacity: ${props => (typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted)};
- text-align: ${props => (props.textAlign ? props.textAlign : props.isCentered && 'center')};
- line-height: 1.4;
-`;
-
-Paragraph.defaultProps = {
- isMuted: true,
-};
diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx
deleted file mode 100644
index e8f2a6461..000000000
--- a/packages/website/ts/components/token_balances.tsx
+++ /dev/null
@@ -1,658 +0,0 @@
-import {
- constants as sharedConstants,
- EtherscanLinkSuffixes,
- Networks,
- Styles,
- utils as sharedUtils,
-} from '@0x/react-shared';
-import { BigNumber, errorUtils, fetchAsync, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import Divider from 'material-ui/Divider';
-import FlatButton from 'material-ui/FlatButton';
-import FloatingActionButton from 'material-ui/FloatingActionButton';
-import ContentAdd from 'material-ui/svg-icons/content/add';
-import ContentRemove from 'material-ui/svg-icons/content/remove';
-import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-import firstBy from 'thenby';
-import { Blockchain } from 'ts/blockchain';
-import { AssetPicker } from 'ts/components/generate_order/asset_picker';
-import { SendButton } from 'ts/components/send_button';
-import { HelpTooltip } from 'ts/components/ui/help_tooltip';
-import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
-import { TokenIcon } from 'ts/components/ui/token_icon';
-import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle';
-import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import {
- BalanceErrs,
- BlockchainCallErrs,
- BlockchainErrs,
- ScreenWidths,
- Token,
- TokenByAddress,
- TokenStateByAddress,
- TokenVisibility,
-} from 'ts/types';
-import { configs } from 'ts/utils/configs';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-const ETHER_ICON_PATH = '/images/ether.png';
-const ETHER_TOKEN_SYMBOL = 'WETH';
-const ZRX_TOKEN_SYMBOL = 'ZRX';
-
-const ICON_DIMENSION = 40;
-const ARTIFICIAL_FAUCET_REQUEST_DELAY = 1000;
-const TOKEN_TABLE_ROW_HEIGHT = 60;
-const MAX_TOKEN_TABLE_HEIGHT = 420;
-const TOKEN_COL_SPAN_LG = 2;
-const TOKEN_COL_SPAN_SM = 1;
-
-const styles: Styles = {
- bgColor: {
- backgroundColor: 'transparent',
- },
-};
-
-interface TokenBalancesProps {
- blockchain: Blockchain;
- blockchainErr: BlockchainErrs;
- blockchainIsLoaded: boolean;
- dispatcher: Dispatcher;
- screenWidth: ScreenWidths;
- tokenByAddress: TokenByAddress;
- trackedTokens: Token[];
- userAddress: string;
- userEtherBalanceInWei: BigNumber;
- networkId: number;
- lastForceTokenStateRefetch: number;
- isFullWidth?: boolean;
-}
-
-interface TokenBalancesState {
- errorType: BalanceErrs;
- trackedTokenStateByAddress: TokenStateByAddress;
- isBalanceSpinnerVisible: boolean;
- isZRXSpinnerVisible: boolean;
- isTokenPickerOpen: boolean;
- isAddingToken: boolean;
-}
-
-export class TokenBalances extends React.Component<TokenBalancesProps, TokenBalancesState> {
- public static defaultProps: Partial<TokenBalancesProps> = {
- userEtherBalanceInWei: new BigNumber(0),
- isFullWidth: false,
- };
- private _isUnmounted: boolean;
- public constructor(props: TokenBalancesProps) {
- super(props);
- this._isUnmounted = false;
- const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens);
- this.state = {
- errorType: undefined,
- isBalanceSpinnerVisible: false,
- isZRXSpinnerVisible: false,
- isTokenPickerOpen: false,
- isAddingToken: false,
- trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
- };
- }
- public componentWillMount(): void {
- const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public componentWillReceiveProps(nextProps: TokenBalancesProps): void {
- if (nextProps.userEtherBalanceInWei !== this.props.userEtherBalanceInWei) {
- if (this.state.isBalanceSpinnerVisible) {
- const receivedAmountInWei = nextProps.userEtherBalanceInWei.minus(this.props.userEtherBalanceInWei);
- const receivedAmountInEth = Web3Wrapper.toUnitAmount(receivedAmountInWei, constants.DECIMAL_PLACES_ETH);
- const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
- this.props.dispatcher.showFlashMessage(
- `Received ${receivedAmountInEth.toString(10)} ${networkName} Ether`,
- );
- }
- this.setState({
- isBalanceSpinnerVisible: false,
- });
- }
-
- if (
- nextProps.userAddress !== this.props.userAddress ||
- nextProps.networkId !== this.props.networkId ||
- nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
- ) {
- const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
- }
-
- if (!_.isEqual(nextProps.trackedTokens, this.props.trackedTokens)) {
- const newTokens = _.difference(nextProps.trackedTokens, this.props.trackedTokens);
- const newTokenAddresses = _.map(newTokens, token => token.address);
- // Add placeholder entry for this token to the state, since fetching the
- // balance/allowance is asynchronous
- const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
- for (const tokenAddress of newTokenAddresses) {
- trackedTokenStateByAddress[tokenAddress] = {
- balance: new BigNumber(0),
- allowance: new BigNumber(0),
- isLoaded: false,
- };
- }
- this.setState({
- trackedTokenStateByAddress,
- });
- // Fetch the actual balance/allowance.
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(newTokenAddresses);
- }
- }
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- }
- public render(): React.ReactNode {
- const errorDialogActions = [
- <FlatButton
- key="errorOkBtn"
- label="Ok"
- primary={true}
- onClick={this._onErrorDialogToggle.bind(this, false)}
- />,
- ];
- const isTestNetwork = utils.isTestNetwork(this.props.networkId);
- const stubColumnStyle = {
- display: isTestNetwork ? 'none' : 'table-cell',
- };
- const allTokenRowHeight = _.size(this.props.tokenByAddress) * TOKEN_TABLE_ROW_HEIGHT;
- const tokenTableHeight =
- allTokenRowHeight < MAX_TOKEN_TABLE_HEIGHT ? allTokenRowHeight : MAX_TOKEN_TABLE_HEIGHT;
- const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
- const tokenColSpan = isSmallScreen ? TOKEN_COL_SPAN_SM : TOKEN_COL_SPAN_LG;
- const allowanceExplanation =
- '0x smart contracts require access to your<br> \
- token balances in order to execute trades.<br> \
- Toggling sets an allowance for the<br> \
- smart contract so you can start trading that token.';
- const userEtherBalanceInEth = Web3Wrapper.toUnitAmount(
- this.props.userEtherBalanceInWei,
- constants.DECIMAL_PLACES_ETH,
- );
- const rootClassName = this.props.isFullWidth ? 'pb2' : 'lg-px4 md-px4 sm-px1 pb2';
- return (
- <div className={rootClassName}>
- <h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3>
- <Divider />
- <div className="pt2 pb2">
- {isTestNetwork
- ? 'In order to try out the 0x Portal Dapp, request some test ether to pay for \
- gas costs. It might take a bit of time for the test ether to show up.'
- : 'Ether must be converted to Ether Tokens in order to be tradable via 0x. \
- You can convert between Ether and Ether Tokens from the "Wrap ETH" tab.'}
- </div>
- <Table selectable={false} style={styles.bgColor}>
- <TableHeader displaySelectAll={false} adjustForCheckbox={false}>
- <TableRow>
- <TableHeaderColumn>Currency</TableHeaderColumn>
- <TableHeaderColumn>Balance</TableHeaderColumn>
- <TableRowColumn className="sm-hide xs-hide" style={stubColumnStyle} />
- {isTestNetwork && <TableHeaderColumn style={{ paddingLeft: 3 }}>Action</TableHeaderColumn>}
- <TableHeaderColumn>Send</TableHeaderColumn>
- </TableRow>
- </TableHeader>
- <TableBody displayRowCheckbox={false}>
- <TableRow key="ETH">
- <TableRowColumn className="py1">
- <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />
- </TableRowColumn>
- <TableRowColumn>
- {userEtherBalanceInEth.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} ETH
- {this.state.isBalanceSpinnerVisible && (
- <span className="pl1">
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- </span>
- )}
- </TableRowColumn>
- <TableRowColumn className="sm-hide xs-hide" style={stubColumnStyle} />
- {isTestNetwork && (
- <TableRowColumn style={{ paddingLeft: 3 }}>
- <LifeCycleRaisedButton
- labelReady="Request"
- labelLoading="Sending..."
- labelComplete="Sent!"
- onClickAsyncFn={this._faucetRequestAsync.bind(this, true)}
- />
- </TableRowColumn>
- )}
- <TableRowColumn>
- <SendButton
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- asset="ETH"
- onError={this._onSendFailed.bind(this)}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- // This is not necessary for ETH.
- // tslint:disable:jsx-no-lambda
- refetchTokenStateAsync={() => undefined}
- />
- </TableRowColumn>
- </TableRow>
- </TableBody>
- </Table>
- <div className="clearfix" style={{ paddingBottom: 1 }}>
- <div className="col col-10">
- <h3 className="pt2">{isTestNetwork ? 'Test tokens' : 'Tokens'}</h3>
- </div>
- <div className="col col-1 pt3 align-right">
- <FloatingActionButton mini={true} zDepth={0} onClick={this._onAddTokenClicked.bind(this)}>
- <ContentAdd />
- </FloatingActionButton>
- </div>
- <div className="col col-1 pt3 align-right">
- <FloatingActionButton mini={true} zDepth={0} onClick={this._onRemoveTokenClicked.bind(this)}>
- <ContentRemove />
- </FloatingActionButton>
- </div>
- </div>
- <Divider />
- <div className="pt2 pb2">
- {isTestNetwork
- ? "Mint some test tokens you'd like to use to generate or fill an order using 0x."
- : "Set trading permissions for a token you'd like to start trading."}
- </div>
- <Table selectable={false} bodyStyle={{ height: tokenTableHeight }} style={styles.bgColor}>
- <TableHeader displaySelectAll={false} adjustForCheckbox={false}>
- <TableRow>
- <TableHeaderColumn colSpan={tokenColSpan}>Token</TableHeaderColumn>
- <TableHeaderColumn style={{ paddingLeft: 3 }}>Balance</TableHeaderColumn>
- <TableHeaderColumn>
- <div className="inline-block">Allowance</div>
- <HelpTooltip style={{ paddingLeft: 4 }} explanation={allowanceExplanation} />
- </TableHeaderColumn>
- {isTestNetwork && <TableHeaderColumn>Action</TableHeaderColumn>}
- {this.props.screenWidth !== ScreenWidths.Sm && <TableHeaderColumn>Send</TableHeaderColumn>}
- </TableRow>
- </TableHeader>
- <TableBody displayRowCheckbox={false}>{this._renderTokenTableRows()}</TableBody>
- </Table>
- <Dialog
- title="Oh oh"
- titleStyle={{ fontWeight: 100 }}
- actions={errorDialogActions}
- open={!_.isUndefined(this.state.errorType)}
- onRequestClose={this._onErrorDialogToggle.bind(this, false)}
- >
- {this._renderErrorDialogBody()}
- </Dialog>
- <AssetPicker
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- isOpen={this.state.isTokenPickerOpen}
- currentTokenAddress={''}
- onTokenChosen={this._onAssetTokenPicked.bind(this)}
- tokenByAddress={this.props.tokenByAddress}
- tokenVisibility={this.state.isAddingToken ? TokenVisibility.Untracked : TokenVisibility.Tracked}
- />
- </div>
- );
- }
- private _renderTokenTableRows(): React.ReactNode {
- if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== BlockchainErrs.NoError) {
- return '';
- }
- const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
- const tokenColSpan = isSmallScreen ? TOKEN_COL_SPAN_SM : TOKEN_COL_SPAN_LG;
- const actionPaddingX = isSmallScreen ? 2 : 24;
- const trackedTokens = this.props.trackedTokens;
- const trackedTokensStartingWithEtherToken = trackedTokens.sort(
- firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL)
- .thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL)
- .thenBy('trackedTimestamp'),
- );
- const tableRows = _.map(
- trackedTokensStartingWithEtherToken,
- this._renderTokenRow.bind(this, tokenColSpan, actionPaddingX),
- );
- return tableRows;
- }
- private _renderTokenRow(tokenColSpan: number, actionPaddingX: number, token: Token): React.ReactNode {
- const tokenState = this.state.trackedTokenStateByAddress[token.address];
- const tokenLink = sharedUtils.getEtherScanLinkIfExists(
- token.address,
- this.props.networkId,
- EtherscanLinkSuffixes.Address,
- );
- const isMintable =
- (_.includes(configs.SYMBOLS_OF_MINTABLE_KOVAN_TOKENS, token.symbol) &&
- this.props.networkId === sharedConstants.NETWORK_ID_BY_NAME[Networks.Kovan]) ||
- (_.includes(configs.SYMBOLS_OF_MINTABLE_ROPSTEN_TOKENS, token.symbol) &&
- this.props.networkId === sharedConstants.NETWORK_ID_BY_NAME[Networks.Ropsten]);
- return (
- <TableRow key={token.address} style={{ height: TOKEN_TABLE_ROW_HEIGHT }}>
- <TableRowColumn colSpan={tokenColSpan}>
- {_.isUndefined(tokenLink) ? (
- this._renderTokenName(token)
- ) : (
- <a href={tokenLink} target="_blank" style={{ textDecoration: 'none' }}>
- {this._renderTokenName(token)}
- </a>
- )}
- </TableRowColumn>
- <TableRowColumn style={{ paddingRight: 3, paddingLeft: 3 }}>
- {tokenState.isLoaded ? (
- <span>
- {this._renderAmount(tokenState.balance, token.decimals)} {token.symbol}
- {this.state.isZRXSpinnerVisible && token.symbol === ZRX_TOKEN_SYMBOL && (
- <span className="pl1">
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- </span>
- )}
- </span>
- ) : (
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- )}
- </TableRowColumn>
- <TableRowColumn>
- <div className="flex justify-center">
- <AllowanceStateToggle
- blockchain={this.props.blockchain}
- token={token}
- tokenState={tokenState}
- onErrorOccurred={this._onErrorOccurred.bind(this)}
- refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this, token.address)}
- />
- </div>
- </TableRowColumn>
- {utils.isTestNetwork(this.props.networkId) && (
- <TableRowColumn style={{ paddingLeft: actionPaddingX, paddingRight: actionPaddingX }}>
- {isMintable && (
- <LifeCycleRaisedButton
- labelReady="Mint"
- labelLoading={<span style={{ fontSize: 12 }}>Minting...</span>}
- labelComplete="Minted!"
- onClickAsyncFn={this._onMintTestTokensAsync.bind(this, token)}
- />
- )}
- </TableRowColumn>
- )}
- {this.props.screenWidth !== ScreenWidths.Sm && (
- <TableRowColumn
- style={{
- paddingLeft: actionPaddingX,
- paddingRight: actionPaddingX,
- }}
- >
- <SendButton
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- asset={token}
- onError={this._onSendFailed.bind(this)}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this, token.address)}
- />
- </TableRowColumn>
- )}
- </TableRow>
- );
- }
- private _onAssetTokenPicked(tokenAddress: string): void {
- if (_.isEmpty(tokenAddress)) {
- this.setState({
- isTokenPickerOpen: false,
- });
- return;
- }
- const token = this.props.tokenByAddress[tokenAddress];
- const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol);
- if (!this.state.isAddingToken && !isDefaultTrackedToken) {
- if (token.isRegistered) {
- // Remove the token from tracked tokens
- const newToken: Token = {
- ...token,
- trackedTimestamp: undefined,
- };
- this.props.dispatcher.updateTokenByAddress([newToken]);
- } else {
- this.props.dispatcher.removeTokenToTokenByAddress(token);
- }
- trackedTokenStorage.removeTrackedToken(this.props.userAddress, this.props.networkId, tokenAddress);
- } else if (isDefaultTrackedToken) {
- this.props.dispatcher.showFlashMessage(`Cannot remove ${token.name} because it's a default token`);
- }
- this.setState({
- isTokenPickerOpen: false,
- });
- }
- private _onSendFailed(): void {
- this.setState({
- errorType: BalanceErrs.SendFailed,
- });
- }
- private _renderAmount(amount: BigNumber, decimals: number): React.ReactNode {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- return unitAmount.toNumber().toFixed(configs.AMOUNT_DISPLAY_PRECSION);
- }
- private _renderTokenName(token: Token): React.ReactNode {
- const tooltipId = `tooltip-${token.address}`;
- return (
- <div className="flex">
- <TokenIcon token={token} diameter={ICON_DIMENSION} />
- <div data-tip={true} data-for={tooltipId} className="mt2 ml2 sm-hide xs-hide">
- {token.name}
- </div>
- <ReactTooltip id={tooltipId}>{token.address}</ReactTooltip>
- </div>
- );
- }
- private _renderErrorDialogBody(): React.ReactNode {
- switch (this.state.errorType) {
- case BalanceErrs.IncorrectNetworkForFaucet:
- return (
- <div>
- Our faucet can only send test Ether to addresses on testnets. Please make sure you are connected
- to a testnet and try requesting again.
- </div>
- );
-
- case BalanceErrs.FaucetRequestFailed:
- return (
- <div>
- An unexpected error occurred while trying to request test Ether from our faucet. Please refresh
- the page and try again.
- </div>
- );
-
- case BalanceErrs.FaucetQueueIsFull:
- return <div>Our test Ether faucet queue is full. Please try requesting test Ether again later.</div>;
-
- case BalanceErrs.MintingFailed:
- return <div>Minting your test tokens failed unexpectedly. Please refresh the page and try again.</div>;
-
- case BalanceErrs.AllowanceSettingFailed:
- return (
- <div>
- An unexpected error occurred while trying to set your test token allowance. Please refresh the
- page and try again.
- </div>
- );
-
- case undefined:
- return null; // No error to show
-
- default:
- throw errorUtils.spawnSwitchErr('errorType', this.state.errorType);
- }
- }
- private _onErrorOccurred(errorType: BalanceErrs): void {
- this.setState({
- errorType,
- });
- }
- private async _onMintTestTokensAsync(token: Token): Promise<boolean> {
- try {
- await this.props.blockchain.mintTestTokensAsync(token);
- await this._refetchTokenStateAsync(token.address);
- const amount = Web3Wrapper.toUnitAmount(constants.MINT_AMOUNT, token.decimals);
- this.props.dispatcher.showFlashMessage(`Successfully minted ${amount.toString(10)} ${token.symbol}`);
- return true;
- } catch (err) {
- const errMsg = `${err}`;
- if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return false;
- }
- if (utils.didUserDenyWeb3Request(errMsg)) {
- return false;
- }
- logUtils.log(`Unexpected error encountered: ${err}`);
- logUtils.log(err.stack);
- this.setState({
- errorType: BalanceErrs.MintingFailed,
- });
- errorReporter.report(err);
- return false;
- }
- }
- private async _faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> {
- if (this.props.userAddress === '') {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return false;
- }
-
- // If on another network other then the testnet our faucet serves test ether
- // from, we must show user an error message
- if (!utils.isTestNetwork(this.props.blockchain.networkId)) {
- this.setState({
- errorType: BalanceErrs.IncorrectNetworkForFaucet,
- });
- return false;
- }
-
- await utils.sleepAsync(ARTIFICIAL_FAUCET_REQUEST_DELAY);
-
- const segment = isEtherRequest ? 'ether' : 'zrx';
- const response = await fetchAsync(
- `${constants.URL_TESTNET_FAUCET}/${segment}/${this.props.userAddress}?networkId=${this.props.networkId}`,
- );
- const responseBody = await response.text();
- if (response.status !== constants.SUCCESS_STATUS) {
- logUtils.log(`Unexpected status code: ${response.status} -> ${responseBody}`);
- const errorType =
- response.status === constants.UNAVAILABLE_STATUS
- ? BalanceErrs.FaucetQueueIsFull
- : BalanceErrs.FaucetRequestFailed;
- this.setState({
- errorType,
- });
- errorReporter.report(new Error(`Faucet returned non-200: ${JSON.stringify(response)}`));
- return false;
- }
-
- if (isEtherRequest) {
- this.setState({
- isBalanceSpinnerVisible: true,
- });
- } else {
- this.setState({
- isZRXSpinnerVisible: true,
- });
- // tslint:disable-next-line:no-floating-promises
- this._startPollingZrxBalanceAsync();
- }
- return true;
- }
- private _onErrorDialogToggle(_isOpen: boolean): void {
- this.setState({
- errorType: undefined,
- });
- }
- private _onAddTokenClicked(): void {
- this.setState({
- isTokenPickerOpen: true,
- isAddingToken: true,
- });
- }
- private _onRemoveTokenClicked(): void {
- this.setState({
- isTokenPickerOpen: true,
- isAddingToken: false,
- });
- }
- private async _startPollingZrxBalanceAsync(): Promise<void> {
- const tokens = _.values(this.props.tokenByAddress);
- const zrxToken = _.find(tokens, t => t.symbol === ZRX_TOKEN_SYMBOL);
-
- // tslint:disable-next-line:no-floating-promises
- const balance = await this.props.blockchain.pollTokenBalanceAsync(zrxToken);
- const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
- trackedTokenStateByAddress[zrxToken.address] = {
- ...trackedTokenStateByAddress[zrxToken.address],
- balance,
- };
- this.setState({
- isZRXSpinnerVisible: false,
- });
- }
- private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise<void> {
- const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- for (const tokenAddress of tokenAddresses) {
- const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- tokenAddress,
- );
- trackedTokenStateByAddress[tokenAddress] = {
- balance,
- allowance,
- isLoaded: true,
- };
- }
- if (!this._isUnmounted) {
- this.setState({
- trackedTokenStateByAddress,
- });
- }
- }
- private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]): TokenStateByAddress {
- const trackedTokenStateByAddress: TokenStateByAddress = {};
- _.each(trackedTokens, token => {
- trackedTokenStateByAddress[token.address] = {
- balance: new BigNumber(0),
- allowance: new BigNumber(0),
- isLoaded: false,
- };
- });
- return trackedTokenStateByAddress;
- }
- private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> {
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- tokenAddress,
- );
- this.setState({
- trackedTokenStateByAddress: {
- ...this.state.trackedTokenStateByAddress,
- [tokenAddress]: {
- balance,
- allowance,
- isLoaded: true,
- },
- },
- });
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
deleted file mode 100644
index c88c29b8e..000000000
--- a/packages/website/ts/components/top_bar/provider_display.tsx
+++ /dev/null
@@ -1,154 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import * as _ from 'lodash';
-import CircularProgress from 'material-ui/CircularProgress';
-import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
-import * as React from 'react';
-
-import { Blockchain } from 'ts/blockchain';
-import { AccountConnection } from 'ts/components/ui/account_connection';
-import { Container } from 'ts/components/ui/container';
-import { DropDown } from 'ts/components/ui/drop_down';
-import { Identicon } from 'ts/components/ui/identicon';
-import { Image } from 'ts/components/ui/image';
-import { Island } from 'ts/components/ui/island';
-import {
- CopyAddressSimpleMenuItem,
- DifferentWalletSimpleMenuItem,
- GoToAccountManagementSimpleMenuItem,
- SimpleMenu,
-} from 'ts/components/ui/simple_menu';
-import { Text } from 'ts/components/ui/text';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import { AccountState, ProviderType } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-const ROOT_HEIGHT = 24;
-
-export interface ProviderDisplayProps {
- dispatcher: Dispatcher;
- userAddress: string;
- networkId: number;
- injectedProviderName: string;
- providerType: ProviderType;
- onToggleLedgerDialog: () => void;
- blockchain?: Blockchain;
- blockchainIsLoaded: boolean;
-}
-
-interface ProviderDisplayState {}
-
-const styles: Styles = {
- root: {
- height: ROOT_HEIGHT,
- borderRadius: ROOT_HEIGHT,
- },
-};
-
-export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
- public render(): React.ReactNode {
- const activeNode = (
- <Island className="flex items-center py1 px2" style={styles.root}>
- {this._renderIcon()}
- <Container marginLeft="12px" marginRight="12px">
- {this._renderDisplayMessage()}
- </Container>
- {this._renderInjectedProvider()}
- </Island>
- );
- return (
- <div style={{ width: 'fit-content', height: 48, float: 'right' }}>
- <DropDown
- activeNode={activeNode}
- popoverContent={this._renderPopoverContent()}
- anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }}
- targetOrigin={{ horizontal: 'middle', vertical: 'top' }}
- zDepth={1}
- />
- </div>
- );
- }
- private _renderPopoverContent(): React.ReactNode {
- const accountState = this._getAccountState();
- switch (accountState) {
- case AccountState.Ready:
- return (
- <SimpleMenu>
- <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} />
- <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} />
- <GoToAccountManagementSimpleMenuItem />
- </SimpleMenu>
- );
- case AccountState.Disconnected:
- case AccountState.Locked:
- case AccountState.Loading:
- default:
- return null;
- }
- }
- private _renderIcon(): React.ReactNode {
- const accountState = this._getAccountState();
- switch (accountState) {
- case AccountState.Ready:
- return <Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />;
- case AccountState.Loading:
- return <CircularProgress size={ROOT_HEIGHT} thickness={2} />;
- case AccountState.Locked:
- return <Image src="/images/lock_icon.svg" height="20px" width="20px" />;
- case AccountState.Disconnected:
- return <ActionAccountBalanceWallet color={colors.mediumBlue} />;
- default:
- return null;
- }
- }
- private _renderDisplayMessage(): React.ReactNode {
- const accountState = this._getAccountState();
- const displayMessage = utils.getReadableAccountState(accountState, this.props.userAddress);
- const fontColor = this._getDisplayMessageFontColor();
- return (
- <Text fontSize="16px" fontColor={fontColor} fontWeight={500}>
- {displayMessage}
- </Text>
- );
- }
- private _getDisplayMessageFontColor(): string {
- const accountState = this._getAccountState();
- switch (accountState) {
- case AccountState.Loading:
- return colors.darkGrey;
- case AccountState.Ready:
- case AccountState.Locked:
- case AccountState.Disconnected:
- default:
- return colors.black;
- }
- }
- private _renderInjectedProvider(): React.ReactNode {
- const accountState = this._getAccountState();
- switch (accountState) {
- case AccountState.Ready:
- case AccountState.Locked:
- return (
- <AccountConnection
- accountState={accountState}
- injectedProviderName={this.props.injectedProviderName}
- />
- );
- case AccountState.Disconnected:
- case AccountState.Loading:
- default:
- return null;
- }
- }
- private _isBlockchainReady(): boolean {
- return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain);
- }
- private _getAccountState(): AccountState {
- return utils.getAccountState(
- this._isBlockchainReady(),
- this.props.providerType,
- this.props.injectedProviderName,
- this.props.userAddress,
- );
- }
-}
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
deleted file mode 100644
index d5967cd1d..000000000
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ /dev/null
@@ -1,279 +0,0 @@
-import { DocsInfo } from '@0x/react-docs';
-import { ALink, colors, Link, Styles } from '@0x/react-shared';
-import { ObjectMap } from '@0x/types';
-import * as _ from 'lodash';
-import Drawer from 'material-ui/Drawer';
-import MenuItem from 'material-ui/MenuItem';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { DevelopersDropDown } from 'ts/components/dropdowns/developers_drop_down';
-import { DrawerMenu } from 'ts/components/portal/drawer_menu';
-import { ProviderDisplay } from 'ts/components/top_bar/provider_display';
-import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
-import { Container } from 'ts/components/ui/container';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { Deco, Key, ProviderType, WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-
-export enum TopBarDisplayType {
- Default,
- Expanded,
-}
-
-export interface TopBarProps {
- userAddress?: string;
- networkId?: number;
- injectedProviderName?: string;
- providerType?: ProviderType;
- onToggleLedgerDialog?: () => void;
- blockchain?: Blockchain;
- dispatcher?: Dispatcher;
- blockchainIsLoaded: boolean;
- location: Location;
- translate: Translate;
- docsVersion?: string;
- availableDocVersions?: string[];
- sectionNameToLinks?: ObjectMap<ALink[]>;
- displayType?: TopBarDisplayType;
- docsInfo?: DocsInfo;
- style?: React.CSSProperties;
- isNightVersion?: boolean;
- onVersionSelected?: (semver: string) => void;
- sidebarHeader?: React.ReactNode;
- maxWidth?: number;
- paddingLeft?: number;
- paddingRight?: number;
-}
-
-interface TopBarState {
- isDrawerOpen: boolean;
-}
-
-const styles: Styles = {
- topBar: {
- backgroundColor: colors.white,
- width: '100%',
- position: 'relative',
- top: 0,
- paddingBottom: 1,
- zIndex: 1,
- },
- bottomBar: {
- boxShadow: 'rgba(0, 0, 0, 0.187647) 0px 1px 3px',
- },
- menuItem: {
- fontSize: 14,
- color: colors.darkestGrey,
- paddingTop: 6,
- paddingBottom: 6,
- cursor: 'pointer',
- fontWeight: 400,
- },
-};
-
-const DEFAULT_HEIGHT = 68;
-const EXPANDED_HEIGHT = 75;
-
-export class TopBar extends React.Component<TopBarProps, TopBarState> {
- public static defaultProps: Partial<TopBarProps> = {
- displayType: TopBarDisplayType.Default,
- style: {},
- isNightVersion: false,
- paddingLeft: 20,
- paddingRight: 20,
- };
- public static heightForDisplayType(displayType: TopBarDisplayType): number {
- const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
- return result + 1;
- }
- constructor(props: TopBarProps) {
- super(props);
- this.state = {
- isDrawerOpen: false,
- };
- }
- public componentWillReceiveProps(nextProps: TopBarProps): void {
- if (nextProps.location.pathname !== this.props.location.pathname) {
- this.setState({
- isDrawerOpen: false,
- });
- }
- }
- public render(): React.ReactNode {
- const isNightVersion = this.props.isNightVersion;
- const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded;
- const parentClassNames = !isExpandedDisplayType
- ? 'flex mx-auto items-center max-width-4'
- : 'flex mx-auto items-center';
- const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
- const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
- const fullWidthClasses = isExpandedDisplayType ? 'pr4' : '';
- const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
- const menuClasses = `col col-${
- isExpandedDisplayType ? '4' : '6'
- } ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
- const menuIconStyle = {
- fontSize: 25,
- color: isNightVersion ? 'white' : 'black',
- cursor: 'pointer',
- };
- return (
- <div
- style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }}
- className="pb1 flex items-center"
- >
- <Container
- className={parentClassNames}
- width="100%"
- maxWidth={this.props.maxWidth}
- paddingLeft={this.props.paddingLeft}
- paddingRight={this.props.paddingRight}
- >
- <Link to={WebsitePaths.Home}>
- <img src={logoUrl} height="30" />
- </Link>
- <div className="flex-auto" />
- {!this._isViewingPortal() && (
- <div className={menuClasses}>
- <div className="flex items-center justify-between">
- <DevelopersDropDown
- location={this.props.location}
- menuItemStyles={{ ...styles.menuItem, paddingBottom: 12, paddingTop: 12 }}
- translate={this.props.translate}
- menuIconStyle={menuIconStyle}
- />
- <TopBarMenuItem
- title={this.props.translate.get(Key.Blog, Deco.Cap)}
- path={constants.URL_BLOG}
- style={styles.menuItem}
- isNightVersion={isNightVersion}
- shouldOpenInNewTab={true}
- />
- <TopBarMenuItem
- title={this.props.translate.get(Key.About, Deco.Cap)}
- path={WebsitePaths.About}
- style={styles.menuItem}
- isNightVersion={isNightVersion}
- />
- <TopBarMenuItem
- title={this.props.translate.get(Key.Careers, Deco.Cap)}
- path={WebsitePaths.Careers}
- style={styles.menuItem}
- isNightVersion={isNightVersion}
- />
- <TopBarMenuItem
- title={this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
- path={WebsitePaths.Portal}
- isPrimary={true}
- style={styles.menuItem}
- className={`${isExpandedDisplayType && 'md-hide'}`}
- isNightVersion={isNightVersion}
- />
- </div>
- </div>
- )}
- {this._isViewingPortal() && (
- <div className="sm-hide xs-hide">
- <ProviderDisplay
- dispatcher={this.props.dispatcher}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.props.onToggleLedgerDialog}
- blockchain={this.props.blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- />
- </div>
- )}
- <div className={'md-hide lg-hide'}>
- <div style={menuIconStyle}>
- <i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
- </div>
- </div>
- </Container>
- {this._isViewingPortal() ? this._renderPortalDrawer() : this._renderDrawer()}
- </div>
- );
- }
- private _renderPortalDrawer(): React.ReactNode {
- return (
- <Drawer
- open={this.state.isDrawerOpen}
- docked={false}
- openSecondary={true}
- onRequestChange={this._onMenuButtonClick.bind(this)}
- >
- <DrawerMenu
- selectedPath={this.props.location.pathname}
- userAddress={this.props.userAddress}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- blockchain={this.props.blockchain}
- />
- </Drawer>
- );
- }
- private _renderDrawer(): React.ReactNode {
- return (
- <Drawer
- open={this.state.isDrawerOpen}
- docked={false}
- openSecondary={true}
- onRequestChange={this._onMenuButtonClick.bind(this)}
- >
- <div className="clearfix">
- <div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}>
- {this.props.translate.get(Key.Website, Deco.Cap)}
- </div>
- <Link to={WebsitePaths.Home}>
- <MenuItem className="py2">{this.props.translate.get(Key.Home, Deco.Cap)}</MenuItem>
- </Link>
- <Link to={WebsitePaths.Docs}>
- <MenuItem className="py2">{this.props.translate.get(Key.Docs, Deco.Cap)}</MenuItem>
- </Link>
- {!this._isViewingPortal() && (
- <Link to={WebsitePaths.Portal}>
- <MenuItem className="py2">
- {this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
- </MenuItem>
- </Link>
- )}
- <Link to={WebsitePaths.Whitepaper} shouldOpenInNewTab={true}>
- <MenuItem className="py2">{this.props.translate.get(Key.Whitepaper, Deco.Cap)}</MenuItem>
- </Link>
- <Link to={WebsitePaths.About}>
- <MenuItem className="py2">{this.props.translate.get(Key.About, Deco.Cap)}</MenuItem>
- </Link>
- <Link to={WebsitePaths.Careers}>
- <MenuItem className="py2">{this.props.translate.get(Key.Careers, Deco.Cap)}</MenuItem>
- </Link>
- <Link to={constants.URL_BLOG} shouldOpenInNewTab={true}>
- <MenuItem className="py2">{this.props.translate.get(Key.Blog, Deco.Cap)}</MenuItem>
- </Link>
- <Link to={WebsitePaths.FAQ}>
- <MenuItem className="py2" onClick={this._onMenuButtonClick.bind(this)}>
- {this.props.translate.get(Key.Faq, Deco.Cap)}
- </MenuItem>
- </Link>
- </div>
- </Drawer>
- );
- }
- private _onMenuButtonClick(): void {
- this.setState({
- isDrawerOpen: !this.state.isDrawerOpen,
- });
- }
- private _isViewingPortal(): boolean {
- return _.includes(this.props.location.pathname, WebsitePaths.Portal);
- }
- private _isViewingFAQ(): boolean {
- return _.includes(this.props.location.pathname, WebsitePaths.FAQ);
- }
- private _shouldDisplayBottomBar(): boolean {
- return this._isViewingFAQ() || this._isViewingPortal();
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
deleted file mode 100644
index 9f15cffbb..000000000
--- a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { colors, Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { CallToAction } from 'ts/components/ui/button';
-
-const DEFAULT_STYLE = {
- color: colors.darkestGrey,
-};
-
-interface TopBarMenuItemProps {
- title: string;
- path?: string;
- isPrimary?: boolean;
- shouldOpenInNewTab?: boolean;
- style?: React.CSSProperties;
- className?: string;
- isNightVersion?: boolean;
-}
-
-interface TopBarMenuItemState {}
-
-export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarMenuItemState> {
- public static defaultProps: Partial<TopBarMenuItemProps> = {
- isPrimary: false,
- style: DEFAULT_STYLE,
- className: '',
- shouldOpenInNewTab: false,
- isNightVersion: false,
- };
- public render(): React.ReactNode {
- const menuItemColor = this.props.isNightVersion ? 'white' : this.props.style.color;
- const linkColor = _.isUndefined(menuItemColor) ? colors.darkestGrey : menuItemColor;
- const itemContent = this.props.isPrimary ? (
- <CallToAction padding="0.8em 1.5em">{this.props.title}</CallToAction>
- ) : (
- this.props.title
- );
- return (
- <div className={`center ${this.props.className}`} style={{ ...this.props.style, color: menuItemColor }}>
- <Link to={this.props.path} shouldOpenInNewTab={this.props.shouldOpenInNewTab} fontColor={linkColor}>
- {itemContent}
- </Link>
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/track_token_confirmation.tsx b/packages/website/ts/components/track_token_confirmation.tsx
deleted file mode 100644
index e701686b0..000000000
--- a/packages/website/ts/components/track_token_confirmation.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Party } from 'ts/components/ui/party';
-import { Token, TokenByAddress } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-interface TrackTokenConfirmationProps {
- tokens: Token[];
- tokenByAddress: TokenByAddress;
- networkId: number;
- isAddingTokenToTracked: boolean;
-}
-
-interface TrackTokenConfirmationState {}
-
-export class TrackTokenConfirmation extends React.Component<TrackTokenConfirmationProps, TrackTokenConfirmationState> {
- public render(): React.ReactNode {
- const isMultipleTokens = this.props.tokens.length > 1;
- const allTokens = _.values(this.props.tokenByAddress);
- return (
- <div style={{ color: colors.grey700 }}>
- {this.props.isAddingTokenToTracked ? (
- <div className="py4 my4 center">
- <span className="pr1">
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- </span>
- <span>Adding token{isMultipleTokens && 's'}...</span>
- </div>
- ) : (
- <div>
- <div>You do not currently track the following token{isMultipleTokens && 's'}:</div>
- <div className="py2 clearfix mx-auto center" style={{ width: 355 }}>
- {_.map(this.props.tokens, (token: Token) => (
- <div
- key={`token-profile-${token.name}`}
- className={`col col-${isMultipleTokens ? '6' : '12'} px2`}
- >
- <Party
- label={token.name}
- address={token.address}
- networkId={this.props.networkId}
- alternativeImage={token.iconUrl}
- isInTokenRegistry={token.isRegistered}
- hasUniqueNameAndSymbol={utils.hasUniqueNameAndSymbol(allTokens, token)}
- />
- </div>
- ))}
- </div>
- <div>
- Tracking a token adds it to the balances section of 0x Portal and allows you to
- generate/fill orders involving the token
- {isMultipleTokens && 's'}. Would you like to start tracking{' '}
- {isMultipleTokens ? 'these' : 'this'} token?
- </div>
- </div>
- )}
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/trade_history/trade_history.tsx b/packages/website/ts/components/trade_history/trade_history.tsx
deleted file mode 100644
index 84c0f70a8..000000000
--- a/packages/website/ts/components/trade_history/trade_history.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import * as _ from 'lodash';
-import Divider from 'material-ui/Divider';
-import Paper from 'material-ui/Paper';
-import * as React from 'react';
-import { TradeHistoryItem } from 'ts/components/trade_history/trade_history_item';
-import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
-import { Fill, TokenByAddress } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-const FILL_POLLING_INTERVAL = 1000;
-
-interface TradeHistoryProps {
- tokenByAddress: TokenByAddress;
- userAddress: string;
- networkId: number;
- isFullWidth?: boolean;
- shouldHideHeader?: boolean;
- isScrollable?: boolean;
-}
-
-interface TradeHistoryState {
- sortedFills: Fill[];
-}
-
-export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> {
- public static defaultProps: Partial<TradeHistoryProps> = {
- isFullWidth: false,
- shouldHideHeader: false,
- isScrollable: true,
- };
- private _fillPollingIntervalId: number;
- public constructor(props: TradeHistoryProps) {
- super(props);
- const sortedFills = this._getSortedFills();
- this.state = {
- sortedFills,
- };
- }
- public componentWillMount(): void {
- this._startPollingForFills();
- }
- public componentWillUnmount(): void {
- this._stopPollingForFills();
- }
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- }
- public render(): React.ReactNode {
- const rootClassName = !this.props.isFullWidth ? 'lg-px4 md-px4 sm-px2' : undefined;
- return (
- <div className={rootClassName}>
- {!this.props.shouldHideHeader && (
- <div>
- <h3>Trade history</h3>
- <Divider />
- </div>
- )}
- {this.props.isScrollable ? (
- <div className="pt2" style={{ height: 608, overflow: 'scroll' }}>
- {this._renderTrades()}
- </div>
- ) : (
- this._renderTrades()
- )}
- </div>
- );
- }
- private _renderTrades(): React.ReactNode {
- const numNonCustomFills = this._numFillsWithoutCustomERC20Tokens();
- if (numNonCustomFills === 0) {
- return this._renderEmptyNotice();
- }
-
- return _.map(this.state.sortedFills, (fill, index) => {
- return (
- <TradeHistoryItem
- key={`${fill.orderHash}-${fill.filledTakerTokenAmount}-${index}`}
- fill={fill}
- tokenByAddress={this.props.tokenByAddress}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- />
- );
- });
- }
- private _renderEmptyNotice(): React.ReactNode {
- return (
- <Paper className="mt1 p2 mx-auto center" style={{ width: '80%' }}>
- No filled orders yet.
- </Paper>
- );
- }
- private _numFillsWithoutCustomERC20Tokens(): number {
- let numNonCustomFills = 0;
- const tokens = _.values(this.props.tokenByAddress);
- _.each(this.state.sortedFills, fill => {
- const takerToken = _.find(tokens, token => {
- return token.address === fill.takerToken;
- });
- const makerToken = _.find(tokens, token => {
- return token.address === fill.makerToken;
- });
- // For now we don't show history items for orders using custom ERC20
- // tokens the client does not know how to display.
- // TODO: Try to retrieve the name/symbol of an unknown token in order to display it
- // Be sure to remove similar logic in trade_history_item.tsx
- if (!_.isUndefined(takerToken) && !_.isUndefined(makerToken)) {
- numNonCustomFills += 1;
- }
- });
- return numNonCustomFills;
- }
- private _startPollingForFills(): void {
- this._fillPollingIntervalId = window.setInterval(() => {
- const sortedFills = this._getSortedFills();
- if (!utils.deepEqual(sortedFills, this.state.sortedFills)) {
- this.setState({
- sortedFills,
- });
- }
- }, FILL_POLLING_INTERVAL);
- }
- private _stopPollingForFills(): void {
- clearInterval(this._fillPollingIntervalId);
- }
- private _getSortedFills(): Fill[] {
- const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId);
- const fills = _.values(fillsByHash);
- const sortedFills = _.sortBy(fills, [(fill: Fill) => fill.blockTimestamp * -1]);
- return sortedFills;
- }
-}
diff --git a/packages/website/ts/components/trade_history/trade_history_item.tsx b/packages/website/ts/components/trade_history/trade_history_item.tsx
deleted file mode 100644
index 667027dce..000000000
--- a/packages/website/ts/components/trade_history/trade_history_item.tsx
+++ /dev/null
@@ -1,176 +0,0 @@
-import { colors, EtherscanLinkSuffixes } from '@0x/react-shared';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import Paper from 'material-ui/Paper';
-import * as moment from 'moment';
-import * as React from 'react';
-import * as ReactTooltip from 'react-tooltip';
-import { EtherScanIcon } from 'ts/components/ui/etherscan_icon';
-import { Party } from 'ts/components/ui/party';
-import { Fill, Token, TokenByAddress } from 'ts/types';
-import { configs } from 'ts/utils/configs';
-
-const IDENTICON_DIAMETER = 40;
-
-interface TradeHistoryItemProps {
- fill: Fill;
- tokenByAddress: TokenByAddress;
- userAddress: string;
- networkId: number;
-}
-
-interface TradeHistoryItemState {}
-
-export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, TradeHistoryItemState> {
- public render(): React.ReactNode {
- const fill = this.props.fill;
- const tokens = _.values(this.props.tokenByAddress);
- const takerToken = _.find(tokens, token => {
- return token.address === fill.takerToken;
- });
- const makerToken = _.find(tokens, token => {
- return token.address === fill.makerToken;
- });
- // For now we don't show history items for orders using custom ERC20
- // tokens the client does not know how to display.
- // TODO: Try to retrieve the name/symbol of an unknown token in order to display it
- // Be sure to remove similar logic in trade_history.tsx
- if (_.isUndefined(takerToken) || _.isUndefined(makerToken)) {
- return null;
- }
-
- const amountColStyle: React.CSSProperties = {
- fontWeight: 100,
- display: 'inline-block',
- };
- const amountColClassNames =
- 'col col-12 lg-col-4 md-col-4 lg-py2 md-py2 sm-py1 lg-pr2 md-pr2 \
- lg-right-align md-right-align sm-center';
-
- return (
- <Paper className="py1" style={{ margin: '3px 3px 15px 3px' }}>
- <div className="clearfix">
- <div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3">{this._renderDate()}</div>
- <div
- className="col col-12 lg-col-6 md-col-6 lg-pl3 md-pl3"
- style={{ fontSize: 12, fontWeight: 100 }}
- >
- <div className="flex sm-mx-auto xs-mx-auto" style={{ paddingTop: 4, width: 224 }}>
- <Party
- label="Maker"
- address={fill.maker}
- identiconDiameter={IDENTICON_DIAMETER}
- networkId={this.props.networkId}
- />
- <i style={{ fontSize: 30 }} className="zmdi zmdi-swap py3" />
- <Party
- label="Taker"
- address={fill.taker}
- identiconDiameter={IDENTICON_DIAMETER}
- networkId={this.props.networkId}
- />
- </div>
- </div>
- <div className={amountColClassNames} style={amountColStyle}>
- {this._renderAmounts(makerToken, takerToken)}
- </div>
- <div className="col col-12 lg-col-1 md-col-1 lg-pr3 md-pr3 lg-py3 md-py3 sm-pb1 sm-center">
- <div className="pt1 lg-right md-right sm-mx-auto" style={{ width: 13 }}>
- <EtherScanIcon
- addressOrTxHash={fill.transactionHash}
- networkId={this.props.networkId}
- etherscanLinkSuffixes={EtherscanLinkSuffixes.Tx}
- />
- </div>
- </div>
- </div>
- </Paper>
- );
- }
- private _renderAmounts(makerToken: Token, takerToken: Token): React.ReactNode {
- const fill = this.props.fill;
- const filledTakerTokenAmountInUnits = Web3Wrapper.toUnitAmount(
- fill.filledTakerTokenAmount,
- takerToken.decimals,
- );
- const filledMakerTokenAmountInUnits = Web3Wrapper.toUnitAmount(
- fill.filledMakerTokenAmount,
- takerToken.decimals,
- );
- let exchangeRate = filledTakerTokenAmountInUnits.div(filledMakerTokenAmountInUnits);
- const fillMakerTokenAmount = Web3Wrapper.toBaseUnitAmount(filledMakerTokenAmountInUnits, makerToken.decimals);
-
- let receiveAmount;
- let receiveToken;
- let givenAmount;
- let givenToken;
- if (this.props.userAddress === fill.maker && this.props.userAddress === fill.taker) {
- receiveAmount = new BigNumber(0);
- givenAmount = new BigNumber(0);
- receiveToken = makerToken;
- givenToken = takerToken;
- } else if (this.props.userAddress === fill.maker) {
- receiveAmount = fill.filledTakerTokenAmount;
- givenAmount = fillMakerTokenAmount;
- receiveToken = takerToken;
- givenToken = makerToken;
- exchangeRate = new BigNumber(1).div(exchangeRate);
- } else if (this.props.userAddress === fill.taker) {
- receiveAmount = fillMakerTokenAmount;
- givenAmount = fill.filledTakerTokenAmount;
- receiveToken = makerToken;
- givenToken = takerToken;
- } else {
- // This condition should never be hit
- throw new Error("Found Fill that wasn't performed by this user");
- }
-
- return (
- <div>
- <div style={{ color: colors.green400, fontSize: 16 }}>
- <span>+ </span>
- {this._renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)}
- </div>
- <div className="pb1 inline-block" style={{ color: colors.red200, fontSize: 16 }}>
- <span>- </span>
- {this._renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)}
- </div>
- <div style={{ color: colors.grey400, fontSize: 14 }}>
- {exchangeRate.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {givenToken.symbol}/{receiveToken.symbol}
- </div>
- </div>
- );
- }
- private _renderDate(): React.ReactNode {
- const blockMoment = moment.unix(this.props.fill.blockTimestamp);
- if (!blockMoment.isValid()) {
- return null;
- }
-
- const dayOfMonth = blockMoment.format('D');
- const monthAbreviation = blockMoment.format('MMM');
- const formattedBlockDate = blockMoment.format('H:mmA - MMMM D, YYYY');
- const dateTooltipId = `${this.props.fill.transactionHash}-date`;
-
- return (
- <div data-tip={true} data-for={dateTooltipId}>
- <div className="center pt1" style={{ fontSize: 13 }}>
- {monthAbreviation}
- </div>
- <div className="center" style={{ fontSize: 24, fontWeight: 100 }}>
- {dayOfMonth}
- </div>
- <ReactTooltip id={dateTooltipId}>{formattedBlockDate}</ReactTooltip>
- </div>
- );
- }
- private _renderAmount(amount: BigNumber, symbol: string, decimals: number): React.ReactNode {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- return (
- <span>
- {unitAmount.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {symbol}
- </span>
- );
- }
-}
diff --git a/packages/website/ts/components/ui/account_connection.tsx b/packages/website/ts/components/ui/account_connection.tsx
deleted file mode 100644
index 6d0b90922..000000000
--- a/packages/website/ts/components/ui/account_connection.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import * as React from 'react';
-
-import { Circle } from 'ts/components/ui/circle';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { AccountState } from 'ts/types';
-
-export interface AccountConnectionProps {
- accountState: AccountState;
- injectedProviderName: string;
-}
-
-export const AccountConnection: React.StatelessComponent<AccountConnectionProps> = ({
- accountState,
- injectedProviderName,
-}) => {
- return (
- <Container className="flex items-center">
- <Circle diameter={6} fillColor={getInjectedProviderColor(accountState)} />
- <Container marginLeft="6px">
- <Text fontSize="12px" lineHeight="14px" fontColor={colors.darkGrey}>
- {injectedProviderName}
- </Text>
- </Container>
- </Container>
- );
-};
-
-const getInjectedProviderColor = (accountState: AccountState) => {
- switch (accountState) {
- case AccountState.Ready:
- return colors.limeGreen;
- case AccountState.Locked:
- case AccountState.Loading:
- case AccountState.Disconnected:
- default:
- return colors.red;
- }
-};
diff --git a/packages/website/ts/components/ui/alert.tsx b/packages/website/ts/components/ui/alert.tsx
deleted file mode 100644
index c7a5b9030..000000000
--- a/packages/website/ts/components/ui/alert.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-import { AlertTypes } from 'ts/types';
-
-interface AlertProps {
- type: AlertTypes;
- message: string | React.ReactNode;
-}
-
-export const Alert = (props: AlertProps) => {
- const isAlert = props.type === AlertTypes.Error;
- const errMsgStyles = {
- background: isAlert ? colors.red200 : colors.lightestGreen,
- color: colors.white,
- marginTop: 10,
- padding: 4,
- paddingLeft: 8,
- };
-
- return (
- <div className="rounded center" style={errMsgStyles}>
- {props.message}
- </div>
- );
-};
diff --git a/packages/website/ts/components/ui/allowance_state_view.tsx b/packages/website/ts/components/ui/allowance_state_view.tsx
deleted file mode 100644
index fc754421a..000000000
--- a/packages/website/ts/components/ui/allowance_state_view.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { Spinner } from 'ts/components/ui/spinner';
-
-export enum AllowanceState {
- Locked,
- Unlocked,
- Loading,
-}
-
-export interface AllowanceStateViewProps {
- allowanceState: AllowanceState;
-}
-
-export const AllowanceStateView: React.StatelessComponent<AllowanceStateViewProps> = ({ allowanceState }) => {
- switch (allowanceState) {
- case AllowanceState.Locked:
- return renderLock();
- case AllowanceState.Unlocked:
- return renderCheck();
- case AllowanceState.Loading:
- return (
- <Container position="relative" top="3px" left="5px">
- <Spinner size={18} strokeSize={2} />
- </Container>
- );
- default:
- return null;
- }
-};
-
-const renderCheck = (color: string = colors.lightGreen) => (
- <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
- <circle cx="8.5" cy="8.5" r="8.5" fill={color} />
- <path
- d="M2.5 4.5L1.79289 5.20711L2.5 5.91421L3.20711 5.20711L2.5 4.5ZM-0.707107 2.70711L1.79289 5.20711L3.20711 3.79289L0.707107 1.29289L-0.707107 2.70711ZM3.20711 5.20711L7.70711 0.707107L6.29289 -0.707107L1.79289 3.79289L3.20711 5.20711Z"
- transform="translate(5 6.5)"
- fill="white"
- />
- </svg>
-);
-
-const renderLock = () => (
- <svg width="12" height="15" viewBox="0 0 12 15" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M6 0C3.51604 0 1.48688 2.0495 1.48688 4.55837V5.86581C0.664723 5.86581 -3.33647e-08 6.53719 -3.33647e-08 7.36759V13.3217C-3.33647e-08 14.1521 0.664723 14.8235 1.48688 14.8235H10.5131C11.3353 14.8235 12 14.1521 12 13.3217V7.36759C12 6.53719 11.3353 5.86581 10.5131 5.86581V4.55837C10.5131 2.0495 8.48396 0 6 0ZM8.93878 5.86581H3.06122V4.55837C3.06122 2.9329 4.37318 1.59013 6 1.59013C7.62682 1.59013 8.93878 2.9329 8.93878 4.55837V5.86581Z"
- fill="black"
- />
- </svg>
-);
diff --git a/packages/website/ts/components/ui/balance.tsx b/packages/website/ts/components/ui/balance.tsx
deleted file mode 100644
index a1a8ff89b..000000000
--- a/packages/website/ts/components/ui/balance.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as React from 'react';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { utils } from 'ts/utils/utils';
-
-export interface BalanceProps {
- amount: BigNumber;
- decimals: number;
- symbol: string;
-}
-
-export const Balance: React.StatelessComponent<BalanceProps> = ({ amount, decimals, symbol }) => {
- const formattedAmout = utils.getFormattedAmount(amount, decimals);
- return (
- <span>
- <Text Tag="span" fontSize="16px" fontWeight="700" lineHeight="1em">
- {formattedAmout}
- </Text>
- <Container marginLeft="0.3em" Tag="span">
- <Text Tag="span" fontSize="12px" fontWeight="700" lineHeight="1em">
- {symbol}
- </Text>
- </Container>
- </span>
- );
-};
diff --git a/packages/website/ts/components/ui/button.tsx b/packages/website/ts/components/ui/button.tsx
deleted file mode 100644
index 92f927843..000000000
--- a/packages/website/ts/components/ui/button.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { darken, saturate } from 'polished';
-import * as React from 'react';
-import { styled } from 'ts/style/theme';
-
-export interface ButtonProps {
- className?: string;
- fontSize?: string;
- fontColor?: string;
- fontFamily?: string;
- backgroundColor?: string;
- borderColor?: string;
- borderRadius?: string;
- width?: string;
- padding?: string;
- type?: string;
- isDisabled?: boolean;
- onClick?: (event: React.MouseEvent<HTMLElement>) => void;
- textAlign?: string;
-}
-
-const PlainButton: React.StatelessComponent<ButtonProps> = ({ children, isDisabled, onClick, type, className }) => (
- <button type={type} className={className} onClick={isDisabled ? undefined : onClick} disabled={isDisabled}>
- {children}
- </button>
-);
-
-export const Button = styled(PlainButton)`
- cursor: ${props => (props.isDisabled ? 'default' : 'pointer')};
- font-size: ${props => props.fontSize};
- color: ${props => props.fontColor};
- transition: background-color, opacity 0.5s ease;
- padding: ${props => props.padding};
- border-radius: ${props => props.borderRadius};
- font-weight: 500;
- outline: none;
- font-family: ${props => props.fontFamily};
- width: ${props => props.width};
- text-align: ${props => props.textAlign};
- background-color: ${props => props.backgroundColor};
- border: ${props => (props.borderColor ? `1px solid ${props.borderColor}` : 'none')};
- &:hover {
- background-color: ${props => (!props.isDisabled ? darken(0.1, props.backgroundColor) : '')} !important;
- }
- &:active {
- background-color: ${props => (!props.isDisabled ? darken(0.2, props.backgroundColor) : '')};
- }
- &:disabled {
- opacity: 0.5;
- }
- &:focus {
- background-color: ${props => saturate(0.2, props.backgroundColor)};
- }
-`;
-
-Button.defaultProps = {
- fontSize: '12px',
- borderRadius: '6px',
- backgroundColor: colors.white,
- width: 'auto',
- fontFamily: 'Roboto',
- isDisabled: false,
- padding: '0.8em 2.2em',
- textAlign: 'center',
-};
-
-Button.displayName = 'Button';
-
-type CallToActionType = 'light' | 'dark';
-
-export interface CallToActionProps {
- type?: CallToActionType;
- fontSize?: string;
- width?: string;
- padding?: string;
-}
-
-export const CallToAction: React.StatelessComponent<CallToActionProps> = ({
- children,
- type,
- fontSize,
- padding,
- width,
-}) => {
- const isLight = type === 'light';
- const backgroundColor = isLight ? colors.white : colors.mediumBlue;
- const fontColor = isLight ? colors.heroGrey : colors.white;
- return (
- <Button
- fontSize={fontSize}
- padding={padding}
- backgroundColor={backgroundColor}
- fontColor={fontColor}
- width={width}
- >
- {children}
- </Button>
- );
-};
-
-CallToAction.defaultProps = {
- type: 'dark',
- fontSize: '14px',
- padding: '0.9em 1.6em',
-};
diff --git a/packages/website/ts/components/ui/check_mark.tsx b/packages/website/ts/components/ui/check_mark.tsx
deleted file mode 100644
index 86e427c8b..000000000
--- a/packages/website/ts/components/ui/check_mark.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as React from 'react';
-
-import { colors } from '@0x/react-shared';
-
-export interface CheckMarkProps {
- color?: string;
- isChecked?: boolean;
-}
-
-export const CheckMark: React.StatelessComponent<CheckMarkProps> = ({ color, isChecked }) => (
- <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
- <circle
- cx="8.5"
- cy="8.5"
- r="8.5"
- fill={isChecked ? color : 'white'}
- stroke={isChecked ? undefined : '#CCCCCC'}
- />
- <path
- d="M2.5 4.5L1.79289 5.20711L2.5 5.91421L3.20711 5.20711L2.5 4.5ZM-0.707107 2.70711L1.79289 5.20711L3.20711 3.79289L0.707107 1.29289L-0.707107 2.70711ZM3.20711 5.20711L7.70711 0.707107L6.29289 -0.707107L1.79289 3.79289L3.20711 5.20711Z"
- transform="translate(5 6.5)"
- fill="white"
- />
- </svg>
-);
-
-CheckMark.displayName = 'Check';
-
-CheckMark.defaultProps = {
- color: colors.mediumBlue,
-};
diff --git a/packages/website/ts/components/ui/circle.tsx b/packages/website/ts/components/ui/circle.tsx
deleted file mode 100644
index 75103d066..000000000
--- a/packages/website/ts/components/ui/circle.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import * as React from 'react';
-
-export interface CircleProps {
- className?: string;
- diameter: number;
- fillColor: string;
-}
-
-export const Circle: React.StatelessComponent<CircleProps> = ({ className, diameter, fillColor }) => {
- const radius = diameter / 2;
- return (
- <svg className={className} height={diameter} width={diameter}>
- <circle cx={radius} cy={radius} r={radius} fill={fillColor} />
- </svg>
- );
-};
diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx
deleted file mode 100644
index 778f59f27..000000000
--- a/packages/website/ts/components/ui/container.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-import { TextAlignProperty } from 'csstype';
-import { darken } from 'polished';
-import * as React from 'react';
-
-import { styled } from 'ts/style/theme';
-
-type StringOrNum = string | number;
-
-export type ContainerTag = 'div' | 'span';
-
-export interface ContainerProps {
- margin?: string;
- marginTop?: StringOrNum;
- marginBottom?: StringOrNum;
- marginRight?: StringOrNum;
- marginLeft?: StringOrNum;
- padding?: StringOrNum;
- paddingTop?: StringOrNum;
- paddingBottom?: StringOrNum;
- paddingRight?: StringOrNum;
- paddingLeft?: StringOrNum;
- backgroundColor?: string;
- background?: string;
- border?: string;
- borderTop?: string;
- borderRadius?: StringOrNum;
- borderBottomLeftRadius?: StringOrNum;
- borderBottomRightRadius?: StringOrNum;
- borderBottom?: StringOrNum;
- borderColor?: string;
- children?: React.ReactNode;
- maxWidth?: StringOrNum;
- maxHeight?: StringOrNum;
- width?: StringOrNum;
- height?: StringOrNum;
- minWidth?: StringOrNum;
- minHeight?: StringOrNum;
- textAlign?: TextAlignProperty;
- isHidden?: boolean;
- className?: string;
- position?: 'absolute' | 'fixed' | 'relative' | 'unset';
- display?: 'inline-block' | 'block' | 'inline-flex' | 'inline';
- top?: string;
- left?: string;
- right?: string;
- bottom?: string;
- zIndex?: number;
- float?: 'right' | 'left';
- Tag?: ContainerTag;
- cursor?: string;
- id?: string;
- onClick?: (event: React.MouseEvent<HTMLElement>) => void;
- overflowX?: 'scroll' | 'hidden' | 'auto' | 'visible';
- overflowY?: 'scroll' | 'hidden' | 'auto' | 'visible';
- shouldDarkenOnHover?: boolean;
- hasBoxShadow?: boolean;
- shouldAddBoxShadowOnHover?: boolean;
-}
-
-export const PlainContainer: React.StatelessComponent<ContainerProps> = props => {
- const {
- children,
- className,
- Tag,
- isHidden,
- id,
- onClick,
- shouldDarkenOnHover,
- shouldAddBoxShadowOnHover,
- hasBoxShadow,
- // tslint:disable-next-line:trailing-comma
- ...style
- } = props;
- const visibility = isHidden ? 'hidden' : undefined;
- return (
- <Tag id={id} style={{ ...style, visibility }} className={className} onClick={onClick}>
- {children}
- </Tag>
- );
-};
-
-const BOX_SHADOW = '0px 3px 10px rgba(0, 0, 0, 0.3)';
-
-export const Container = styled(PlainContainer)`
- box-sizing: border-box;
- ${props => (props.hasBoxShadow ? `box-shadow: ${BOX_SHADOW}` : '')};
- &:hover {
- ${props =>
- props.shouldDarkenOnHover
- ? `background-color: ${props.backgroundColor ? darken(0.05, props.backgroundColor) : 'none'} !important`
- : ''};
- ${props => (props.shouldAddBoxShadowOnHover ? `box-shadow: ${BOX_SHADOW}` : '')};
- }
-`;
-
-Container.defaultProps = {
- Tag: 'div',
-};
-
-Container.displayName = 'Container';
diff --git a/packages/website/ts/components/ui/copy_icon.tsx b/packages/website/ts/components/ui/copy_icon.tsx
deleted file mode 100644
index 403cd4607..000000000
--- a/packages/website/ts/components/ui/copy_icon.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-import * as CopyToClipboard from 'react-copy-to-clipboard';
-import * as ReactDOM from 'react-dom';
-import ReactTooltip from 'react-tooltip';
-
-interface CopyIconProps {
- data: string;
- callToAction?: string;
-}
-
-interface CopyIconState {
- isHovering: boolean;
-}
-
-export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
- private _copyTooltipTimeoutId: number;
- private _copyable: HTMLInputElement;
- constructor(props: CopyIconProps) {
- super(props);
- this.state = {
- isHovering: false,
- };
- }
- public componentDidUpdate(): void {
- // Remove tooltip if hover away
- if (!this.state.isHovering && this._copyTooltipTimeoutId) {
- clearInterval(this._copyTooltipTimeoutId);
- this._hideTooltip();
- }
- }
- public render(): React.ReactNode {
- return (
- <div className="inline-block">
- <CopyToClipboard text={this.props.data} onCopy={this._onCopy.bind(this)}>
- <div
- className="inline flex"
- style={{ cursor: 'pointer', color: colors.amber600 }}
- ref={this._setRefToProperty.bind(this)}
- data-tip={true}
- data-for="copy"
- data-event="click"
- data-iscapture={true} // This let's the click event continue to propogate
- onMouseOver={this._setHoverState.bind(this, true)}
- onMouseOut={this._setHoverState.bind(this, false)}
- >
- <div>
- <i style={{ fontSize: 15 }} className="zmdi zmdi-copy" />
- </div>
- {this.props.callToAction && <div className="pl1">{this.props.callToAction}</div>}
- </div>
- </CopyToClipboard>
- <ReactTooltip id="copy">Copied!</ReactTooltip>
- </div>
- );
- }
- private _setRefToProperty(el: HTMLInputElement): void {
- this._copyable = el;
- }
- private _setHoverState(isHovering: boolean): void {
- this.setState({
- isHovering,
- });
- }
- private _onCopy(): void {
- if (this._copyTooltipTimeoutId) {
- clearInterval(this._copyTooltipTimeoutId);
- }
-
- const tooltipLifespanMs = 1000;
- this._copyTooltipTimeoutId = window.setTimeout(() => {
- this._hideTooltip();
- }, tooltipLifespanMs);
- }
- private _hideTooltip(): void {
- ReactTooltip.hide(ReactDOM.findDOMNode(this._copyable));
- }
-}
diff --git a/packages/website/ts/components/ui/custom_menu_item.tsx b/packages/website/ts/components/ui/custom_menu_item.tsx
deleted file mode 100644
index 87ce32126..000000000
--- a/packages/website/ts/components/ui/custom_menu_item.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-interface CustomMenuItemProps {
- to: string;
- onClick?: () => void;
- className?: string;
-}
-
-interface CustomMenuItemState {
- isHovering: boolean;
-}
-
-export class CustomMenuItem extends React.Component<CustomMenuItemProps, CustomMenuItemState> {
- public static defaultProps: Partial<CustomMenuItemProps> = {
- onClick: _.noop.bind(_),
- className: '',
- };
- public constructor(props: CustomMenuItemProps) {
- super(props);
- this.state = {
- isHovering: false,
- };
- }
- public render(): React.ReactNode {
- const menuItemStyles = {
- cursor: 'pointer',
- opacity: this.state.isHovering ? 0.5 : 1,
- };
- return (
- <Link to={this.props.to}>
- <div
- onClick={this.props.onClick.bind(this)}
- className={`mx-auto ${this.props.className}`}
- style={menuItemStyles}
- onMouseEnter={this._onToggleHover.bind(this, true)}
- onMouseLeave={this._onToggleHover.bind(this, false)}
- >
- {this.props.children}
- </div>
- </Link>
- );
- }
- private _onToggleHover(isHovering: boolean): void {
- this.setState({
- isHovering,
- });
- }
-}
diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx
deleted file mode 100644
index 4138b3fe5..000000000
--- a/packages/website/ts/components/ui/drop_down.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import * as _ from 'lodash';
-import Popover from 'material-ui/Popover';
-import * as React from 'react';
-import { MaterialUIPosition } from 'ts/types';
-
-const CHECK_CLOSE_POPOVER_INTERVAL_MS = 300;
-const DEFAULT_STYLE = {
- fontSize: 14,
-};
-
-export enum DropdownMouseEvent {
- Hover = 'hover',
- Click = 'click',
-}
-
-export interface DropDownProps {
- activeNode: React.ReactNode;
- popoverContent: React.ReactNode;
- anchorOrigin: MaterialUIPosition;
- targetOrigin: MaterialUIPosition;
- style?: React.CSSProperties;
- zDepth?: number;
- activateEvent?: DropdownMouseEvent;
- closeEvent?: DropdownMouseEvent;
- popoverStyle?: React.CSSProperties;
-}
-
-interface DropDownState {
- isDropDownOpen: boolean;
- anchorEl?: HTMLInputElement;
-}
-
-export class DropDown extends React.Component<DropDownProps, DropDownState> {
- public static defaultProps: Partial<DropDownProps> = {
- style: DEFAULT_STYLE,
- zDepth: 1,
- activateEvent: DropdownMouseEvent.Hover,
- closeEvent: DropdownMouseEvent.Hover,
- popoverStyle: {},
- };
- private _isHovering: boolean;
- private _popoverCloseCheckIntervalId: number;
- constructor(props: DropDownProps) {
- super(props);
- this.state = {
- isDropDownOpen: false,
- };
- }
- public componentDidMount(): void {
- this._popoverCloseCheckIntervalId = window.setInterval(() => {
- this._checkIfShouldClosePopover();
- }, CHECK_CLOSE_POPOVER_INTERVAL_MS);
- }
- public componentWillUnmount(): void {
- window.clearInterval(this._popoverCloseCheckIntervalId);
- }
- public componentWillReceiveProps(_nextProps: DropDownProps): void {
- // HACK: If the popoverContent is updated to a different dimension and the users
- // mouse is no longer above it, the dropdown can enter an inconsistent state where
- // it believes the user is still hovering over it. In order to remedy this, we
- // call hoverOff whenever the dropdown receives updated props. This is a hack
- // because it will effectively close the dropdown on any prop update, barring
- // dropdowns from having dynamic content.
- this._onHoverOff();
- }
- public render(): React.ReactNode {
- return (
- <div
- style={{ ...this.props.style, width: 'fit-content', height: '100%' }}
- onMouseEnter={this._onHover.bind(this)}
- onMouseLeave={this._onHoverOff.bind(this)}
- >
- <div onClick={this._onActiveNodeClick.bind(this)}>{this.props.activeNode}</div>
- <Popover
- open={this.state.isDropDownOpen}
- anchorEl={this.state.anchorEl}
- anchorOrigin={this.props.anchorOrigin}
- targetOrigin={this.props.targetOrigin}
- onRequestClose={
- this.props.closeEvent === DropdownMouseEvent.Click
- ? this._closePopover.bind(this)
- : _.noop.bind(_)
- }
- useLayerForClickAway={this.props.closeEvent === DropdownMouseEvent.Click}
- animated={false}
- zDepth={this.props.zDepth}
- style={this.props.popoverStyle}
- >
- <div
- onMouseEnter={this._onHover.bind(this)}
- onMouseLeave={this._onHoverOff.bind(this)}
- onClick={this._closePopover.bind(this)}
- >
- {this.props.popoverContent}
- </div>
- </Popover>
- </div>
- );
- }
- private _onActiveNodeClick(event: React.FormEvent<HTMLInputElement>): void {
- if (this.props.activateEvent === DropdownMouseEvent.Click) {
- this.setState({
- isDropDownOpen: !this.state.isDropDownOpen,
- anchorEl: event.currentTarget,
- });
- }
- }
- private _onHover(event: React.FormEvent<HTMLInputElement>): void {
- this._isHovering = true;
- if (this.props.activateEvent === DropdownMouseEvent.Hover) {
- this._checkIfShouldOpenPopover(event);
- }
- }
- private _onHoverOff(): void {
- this._isHovering = false;
- }
- private _checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>): void {
- if (this.state.isDropDownOpen) {
- return; // noop
- }
- this.setState({
- isDropDownOpen: true,
- anchorEl: event.currentTarget,
- });
- }
- private _checkIfShouldClosePopover(): void {
- if (!this.state.isDropDownOpen) {
- return; // noop
- }
- if (this.props.closeEvent === DropdownMouseEvent.Hover && !this._isHovering) {
- this._closePopover();
- }
- }
- private _closePopover(): void {
- this.setState({
- isDropDownOpen: false,
- });
- }
-}
diff --git a/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx b/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx
deleted file mode 100644
index ba141c01e..000000000
--- a/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { css, keyframes, styled } from 'ts/style/theme';
-
-const appearFromBottomFrames = keyframes`
- from {
- position: fixed;
- bottom: -500px;
- left: 0px;
- right: 0px;
- }
-
- to {
- position: fixed;
- bottom: 0px;
- left: 0px;
- right: 0px;
- }
-`;
-
-const stylesForAnimation = css`
- position: fixed;
-`;
-const animations = css`
- animation: ${appearFromBottomFrames} 1s ease 0s 1 forwards;
-`;
-
-export const EaseUpFromBottomAnimation = styled.div`
- ${props => animations};
- ${props => stylesForAnimation};
-`;
-
-EaseUpFromBottomAnimation.displayName = 'EaseUpFromBottomAnimation';
diff --git a/packages/website/ts/components/ui/ethereum_address.tsx b/packages/website/ts/components/ui/ethereum_address.tsx
deleted file mode 100644
index 12f8636eb..000000000
--- a/packages/website/ts/components/ui/ethereum_address.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { EtherscanLinkSuffixes } from '@0x/react-shared';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-import { EtherScanIcon } from 'ts/components/ui/etherscan_icon';
-import { utils } from 'ts/utils/utils';
-
-interface EthereumAddressProps {
- address: string;
- networkId: number;
-}
-
-export const EthereumAddress = (props: EthereumAddressProps) => {
- const tooltipId = `${props.address}-ethereum-address`;
- const truncatedAddress = utils.getAddressBeginAndEnd(props.address);
- return (
- <div>
- <div className="inline" style={{ fontSize: 13 }} data-tip={true} data-for={tooltipId}>
- {truncatedAddress}
- </div>
- <div className="pl1 inline">
- <EtherScanIcon
- addressOrTxHash={props.address}
- networkId={props.networkId}
- etherscanLinkSuffixes={EtherscanLinkSuffixes.Address}
- />
- </div>
- <ReactTooltip id={tooltipId}>{props.address}</ReactTooltip>
- </div>
- );
-};
diff --git a/packages/website/ts/components/ui/etherscan_icon.tsx b/packages/website/ts/components/ui/etherscan_icon.tsx
deleted file mode 100644
index a7fba8a33..000000000
--- a/packages/website/ts/components/ui/etherscan_icon.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-
-interface EtherScanIconProps {
- addressOrTxHash: string;
- etherscanLinkSuffixes: EtherscanLinkSuffixes;
- networkId: number;
-}
-
-export const EtherScanIcon = (props: EtherScanIconProps) => {
- const etherscanLinkIfExists = sharedUtils.getEtherScanLinkIfExists(
- props.addressOrTxHash,
- props.networkId,
- props.etherscanLinkSuffixes,
- );
- const transactionTooltipId = `${props.addressOrTxHash}-etherscan-icon-tooltip`;
- return (
- <div className="inline">
- {!_.isUndefined(etherscanLinkIfExists) ? (
- <a href={etherscanLinkIfExists} target="_blank">
- {renderIcon()}
- </a>
- ) : (
- <div className="inline" data-tip={true} data-for={transactionTooltipId}>
- {renderIcon()}
- <ReactTooltip id={transactionTooltipId}>
- Your network (id: {props.networkId}) is not supported by Etherscan
- </ReactTooltip>
- </div>
- )}
- </div>
- );
-};
-
-function renderIcon(): React.ReactNode {
- return <i style={{ color: colors.amber600 }} className="zmdi zmdi-open-in-new" />;
-}
diff --git a/packages/website/ts/components/ui/fake_text_field.tsx b/packages/website/ts/components/ui/fake_text_field.tsx
deleted file mode 100644
index 7c3a482a4..000000000
--- a/packages/website/ts/components/ui/fake_text_field.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import * as React from 'react';
-import { InputLabel } from 'ts/components/ui/input_label';
-
-const styles: Styles = {
- hr: {
- borderBottom: '1px solid rgb(224, 224, 224)',
- borderLeft: 'none rgb(224, 224, 224)',
- borderRight: 'none rgb(224, 224, 224)',
- borderTop: 'none rgb(224, 224, 224)',
- bottom: 6,
- boxSizing: 'content-box',
- margin: 0,
- position: 'absolute',
- width: '100%',
- },
-};
-
-interface FakeTextFieldProps {
- label?: React.ReactNode | string;
- children?: any;
-}
-
-export const FakeTextField = (props: FakeTextFieldProps) => {
- return (
- <div className="relative">
- {props.label !== '' && <InputLabel text={props.label} />}
- <div className="pb2" style={{ height: 23 }}>
- {props.children}
- </div>
- <hr style={styles.hr} />
- </div>
- );
-};
diff --git a/packages/website/ts/components/ui/flash_message.tsx b/packages/website/ts/components/ui/flash_message.tsx
deleted file mode 100644
index 2b866676d..000000000
--- a/packages/website/ts/components/ui/flash_message.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import * as _ from 'lodash';
-import Snackbar from 'material-ui/Snackbar';
-import * as React from 'react';
-import { Dispatcher } from 'ts/redux/dispatcher';
-
-const SHOW_DURATION_MS = 4000;
-
-interface FlashMessageProps {
- dispatcher: Dispatcher;
- flashMessage?: string | React.ReactNode;
- showDurationMs?: number;
- bodyStyle?: React.CSSProperties;
-}
-
-interface FlashMessageState {}
-
-export class FlashMessage extends React.Component<FlashMessageProps, FlashMessageState> {
- public static defaultProps: Partial<FlashMessageProps> = {
- showDurationMs: SHOW_DURATION_MS,
- bodyStyle: {},
- };
- public render(): React.ReactNode {
- if (!_.isUndefined(this.props.flashMessage)) {
- return (
- <Snackbar
- open={true}
- message={this.props.flashMessage}
- autoHideDuration={this.props.showDurationMs}
- onRequestClose={this._onClose.bind(this)}
- bodyStyle={this.props.bodyStyle}
- />
- );
- } else {
- return null;
- }
- }
- private _onClose(): void {
- this.props.dispatcher.hideFlashMessage();
- }
-}
diff --git a/packages/website/ts/components/ui/help_tooltip.tsx b/packages/website/ts/components/ui/help_tooltip.tsx
deleted file mode 100644
index 831d888f5..000000000
--- a/packages/website/ts/components/ui/help_tooltip.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-
-interface HelpTooltipProps {
- style?: React.CSSProperties;
- explanation: React.ReactNode;
-}
-
-export const HelpTooltip = (props: HelpTooltipProps) => {
- return (
- <div
- style={{ ...props.style }}
- className="inline-block"
- data-tip={props.explanation}
- data-for="helpTooltip"
- data-multiline={true}
- >
- <i style={{ fontSize: 16 }} className="zmdi zmdi-help" />
- <ReactTooltip id="helpTooltip" />
- </div>
- );
-};
diff --git a/packages/website/ts/components/ui/icon_button.tsx b/packages/website/ts/components/ui/icon_button.tsx
deleted file mode 100644
index 9f469ec69..000000000
--- a/packages/website/ts/components/ui/icon_button.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { colors, Styles } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-export interface IconButtonProps {
- iconName: string;
- labelText?: string;
- onClick?: () => void;
- color?: string;
- display?: string;
-}
-interface IconButtonState {
- isHovering: boolean;
-}
-export class IconButton extends React.Component<IconButtonProps, IconButtonState> {
- public static defaultProps: Partial<IconButtonProps> = {
- labelText: '',
- color: colors.mediumBlue,
- };
- public constructor(props: IconButtonProps) {
- super(props);
- this.state = {
- isHovering: false,
- };
- }
- public render(): React.ReactNode {
- const styles: Styles = {
- root: {
- cursor: this.props.onClick ? 'pointer' : 'undefined',
- opacity: this.state.isHovering && this.props.onClick ? 0.5 : 1,
- display: this.props.display,
- },
- icon: {
- color: this.props.color,
- fontSize: 20,
- },
- label: {
- color: this.props.color,
- fontSize: 10,
- },
- };
- return (
- <div
- className="flex items-center py2"
- onClick={this.props.onClick}
- onMouseEnter={this._onToggleHover.bind(this, true)}
- onMouseLeave={this._onToggleHover.bind(this, false)}
- style={styles.root}
- >
- <i style={styles.icon} className={`zmdi ${this.props.iconName}`} />
- {!_.isEmpty(this.props.labelText) && (
- <div className="pl1" style={styles.label}>
- {this.props.labelText}
- </div>
- )}
- </div>
- );
- }
- private _onToggleHover(isHovering: boolean): void {
- this.setState({
- isHovering,
- });
- }
-}
diff --git a/packages/website/ts/components/ui/identicon.tsx b/packages/website/ts/components/ui/identicon.tsx
deleted file mode 100644
index 9eca04a5d..000000000
--- a/packages/website/ts/components/ui/identicon.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import blockies from 'blockies';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Circle } from 'ts/components/ui/circle';
-import { Image } from 'ts/components/ui/image';
-import { colors } from 'ts/style/colors';
-
-interface IdenticonProps {
- address: string;
- diameter: number;
- style?: React.CSSProperties;
-}
-
-interface IdenticonState {}
-
-export class Identicon extends React.Component<IdenticonProps, IdenticonState> {
- public static defaultProps: Partial<IdenticonProps> = {
- style: {},
- };
- public render(): React.ReactNode {
- const address = this.props.address;
- const diameter = this.props.diameter;
- return (
- <div
- className="circle relative transitionFix"
- style={{
- width: diameter,
- height: diameter,
- overflow: 'hidden',
- ...this.props.style,
- }}
- >
- {!_.isEmpty(address) ? (
- <Image
- src={blockies({
- seed: address.toLowerCase(),
- }).toDataURL()}
- height={diameter}
- width={diameter}
- />
- ) : (
- <Circle diameter={diameter} fillColor={colors.grey200} />
- )}
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx
deleted file mode 100644
index d698ddaa0..000000000
--- a/packages/website/ts/components/ui/image.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-export interface ImageProps {
- className?: string;
- src?: string;
- fallbackSrc?: string;
- borderRadius?: string;
- width?: string | number;
- height?: string | number;
- maxWidth?: string | number;
- maxHeight?: string | number;
- additionalStyle?: React.CSSProperties;
-}
-interface ImageState {
- imageLoadFailed: boolean;
-}
-export class Image extends React.Component<ImageProps, ImageState> {
- constructor(props: ImageProps) {
- super(props);
- this.state = {
- imageLoadFailed: false,
- };
- }
- public render(): React.ReactNode {
- const src =
- this.state.imageLoadFailed || _.isUndefined(this.props.src) ? this.props.fallbackSrc : this.props.src;
- return (
- <img
- className={this.props.className}
- onError={this._onError.bind(this)}
- src={src}
- style={{
- ...this.props.additionalStyle,
- borderRadius: this.props.borderRadius,
- maxWidth: this.props.maxWidth,
- maxHeight: this.props.maxHeight,
- }}
- height={this.props.height}
- width={this.props.width}
- />
- );
- }
- private _onError(): void {
- this.setState({
- imageLoadFailed: true,
- });
- }
-}
diff --git a/packages/website/ts/components/ui/input_label.tsx b/packages/website/ts/components/ui/input_label.tsx
deleted file mode 100644
index e7afb5a17..000000000
--- a/packages/website/ts/components/ui/input_label.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { colors, Styles } from '@0x/react-shared';
-import * as React from 'react';
-
-export interface InputLabelProps {
- text: string | Element | React.ReactNode;
-}
-
-const styles: Styles = {
- label: {
- color: colors.grey,
- fontSize: 12,
- pointerEvents: 'none',
- textAlign: 'left',
- transform: 'scale(0.75) translate(0px, -28px)',
- transformOrigin: 'left top 0px',
- transition: 'all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms',
- userSelect: 'none',
- width: 240,
- zIndex: 1,
- } as React.CSSProperties,
-};
-
-export const InputLabel = (props: InputLabelProps) => {
- return <label style={styles.label}>{props.text}</label>;
-};
diff --git a/packages/website/ts/components/ui/island.tsx b/packages/website/ts/components/ui/island.tsx
deleted file mode 100644
index c8abfb7e0..000000000
--- a/packages/website/ts/components/ui/island.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as React from 'react';
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-
-export interface IslandProps {
- style?: React.CSSProperties;
- className?: string;
- Component?: string | React.ComponentClass<any> | React.StatelessComponent<any>;
- borderRadius?: string;
-}
-
-const PlainIsland: React.StatelessComponent<IslandProps> = ({ Component, style, className, children }) => (
- <Component style={style} className={className} children={children} />
-);
-
-export const Island = styled(PlainIsland)`
- background-color: ${colors.white};
- border-radius: ${props => props.borderRadius};
- box-shadow: 0px 4px 6px ${colors.walletBoxShadow};
- overflow: hidden;
-`;
-
-Island.defaultProps = {
- Component: 'div',
- borderRadius: '10px',
- style: {},
-};
-
-Island.displayName = 'Island';
diff --git a/packages/website/ts/components/ui/lifecycle_raised_button.tsx b/packages/website/ts/components/ui/lifecycle_raised_button.tsx
deleted file mode 100644
index f004dd47f..000000000
--- a/packages/website/ts/components/ui/lifecycle_raised_button.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { errorUtils } from '@0x/utils';
-import RaisedButton from 'material-ui/RaisedButton';
-import * as React from 'react';
-
-const COMPLETE_STATE_SHOW_LENGTH_MS = 2000;
-
-enum ButtonState {
- Ready,
- Loading,
- Complete,
-}
-
-interface LifeCycleRaisedButtonProps {
- isHidden?: boolean;
- isDisabled?: boolean;
- isPrimary?: boolean;
- labelReady: React.ReactNode | string;
- labelLoading: React.ReactNode | string;
- labelComplete: React.ReactNode | string;
- onClickAsyncFn: () => Promise<boolean>;
- backgroundColor?: string;
- labelColor?: string;
-}
-
-interface LifeCycleRaisedButtonState {
- buttonState: ButtonState;
-}
-
-export class LifeCycleRaisedButton extends React.Component<LifeCycleRaisedButtonProps, LifeCycleRaisedButtonState> {
- public static defaultProps: Partial<LifeCycleRaisedButtonProps> = {
- isDisabled: false,
- backgroundColor: colors.white,
- labelColor: colors.darkGrey,
- };
- private _buttonTimeoutId: number;
- private _didUnmount: boolean;
- constructor(props: LifeCycleRaisedButtonProps) {
- super(props);
- this.state = {
- buttonState: ButtonState.Ready,
- };
- }
- public componentWillUnmount(): void {
- clearTimeout(this._buttonTimeoutId);
- this._didUnmount = true;
- }
- public render(): React.ReactNode {
- if (this.props.isHidden) {
- return <span />;
- }
-
- let label;
- switch (this.state.buttonState) {
- case ButtonState.Ready:
- label = this.props.labelReady;
- break;
- case ButtonState.Loading:
- label = this.props.labelLoading;
- break;
- case ButtonState.Complete:
- label = this.props.labelComplete;
- break;
- default:
- throw errorUtils.spawnSwitchErr('ButtonState', this.state.buttonState);
- }
- return (
- <RaisedButton
- primary={this.props.isPrimary}
- label={label}
- style={{ width: '100%' }}
- backgroundColor={this.props.backgroundColor}
- labelColor={this.props.labelColor}
- onClick={this.onClickAsync.bind(this)}
- disabled={this.props.isDisabled || this.state.buttonState !== ButtonState.Ready}
- />
- );
- }
- public async onClickAsync(): Promise<void> {
- this.setState({
- buttonState: ButtonState.Loading,
- });
- const didSucceed = await this.props.onClickAsyncFn();
- if (this._didUnmount) {
- return; // noop since unmount called before async callback returned.
- }
- if (didSucceed) {
- this.setState({
- buttonState: ButtonState.Complete,
- });
- this._buttonTimeoutId = window.setTimeout(() => {
- this.setState({
- buttonState: ButtonState.Ready,
- });
- }, COMPLETE_STATE_SHOW_LENGTH_MS);
- } else {
- this.setState({
- buttonState: ButtonState.Ready,
- });
- }
- }
-}
diff --git a/packages/website/ts/components/ui/multi_select.tsx b/packages/website/ts/components/ui/multi_select.tsx
deleted file mode 100644
index 2cf44cae1..000000000
--- a/packages/website/ts/components/ui/multi_select.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Container } from './container';
-
-export interface MultiSelectItemConfig {
- value: string;
- renderItemContent: (isSelected: boolean) => React.ReactNode;
- onClick?: () => void;
-}
-
-export interface MultiSelectProps {
- selectedValues?: string[];
- items: MultiSelectItemConfig[];
- backgroundColor?: string;
- height?: string;
-}
-
-export class MultiSelect extends React.Component<MultiSelectProps> {
- public static defaultProps = {
- backgroundColor: colors.white,
- };
- public render(): React.ReactNode {
- const { items, backgroundColor, selectedValues, height } = this.props;
- return (
- <Container
- backgroundColor={backgroundColor}
- borderRadius="4px"
- width="100%"
- height={height}
- overflowY="scroll"
- >
- {_.map(items, item => (
- <MultiSelectItem
- key={item.value}
- renderItemContent={item.renderItemContent}
- backgroundColor={backgroundColor}
- onClick={item.onClick}
- isSelected={_.isUndefined(selectedValues) || _.includes(selectedValues, item.value)}
- />
- ))}
- </Container>
- );
- }
-}
-
-export interface MultiSelectItemProps {
- renderItemContent: (isSelected: boolean) => React.ReactNode;
- isSelected?: boolean;
- onClick?: () => void;
- backgroundColor?: string;
-}
-
-export const MultiSelectItem: React.StatelessComponent<MultiSelectItemProps> = ({
- renderItemContent,
- isSelected,
- onClick,
- backgroundColor,
-}) => (
- <Container cursor="pointer" shouldDarkenOnHover={true} onClick={onClick} backgroundColor={backgroundColor}>
- <Container borderBottom={`1px solid ${colors.lightestGrey}`} margin="0px 15px" padding="10px 0px">
- {renderItemContent(isSelected)}
- </Container>
- </Container>
-);
diff --git a/packages/website/ts/components/ui/overlay.tsx b/packages/website/ts/components/ui/overlay.tsx
deleted file mode 100644
index fc7507475..000000000
--- a/packages/website/ts/components/ui/overlay.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { zIndex } from 'ts/style/z_index';
-
-export interface OverlayProps {
- style?: React.CSSProperties;
- onClick?: () => void;
-}
-
-const style: React.CSSProperties = {
- position: 'fixed',
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- zIndex: zIndex.overlay,
- backgroundColor: 'rgba(0, 0, 0, 0.6)',
-};
-
-export const Overlay: React.StatelessComponent<OverlayProps> = props => (
- <div style={{ ...style, ...props.style }} onClick={props.onClick}>
- {props.children}
- </div>
-);
-
-Overlay.defaultProps = {
- style: {},
- onClick: _.noop.bind(_),
-};
-
-Overlay.displayName = 'Overlay';
diff --git a/packages/website/ts/components/ui/party.tsx b/packages/website/ts/components/ui/party.tsx
deleted file mode 100644
index a14b94d8a..000000000
--- a/packages/website/ts/components/ui/party.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import ReactTooltip from 'react-tooltip';
-import { EthereumAddress } from 'ts/components/ui/ethereum_address';
-import { Identicon } from 'ts/components/ui/identicon';
-
-const IMAGE_DIMENSION = 100;
-const IDENTICON_DIAMETER = 95;
-
-interface PartyProps {
- label: string;
- address: string;
- networkId: number;
- alternativeImage?: string;
- identiconDiameter?: number;
- identiconStyle?: React.CSSProperties;
- isInTokenRegistry?: boolean;
- hasUniqueNameAndSymbol?: boolean;
-}
-
-interface PartyState {}
-
-export class Party extends React.Component<PartyProps, PartyState> {
- public static defaultProps: Partial<PartyProps> = {
- identiconStyle: {},
- identiconDiameter: IDENTICON_DIAMETER,
- };
- public render(): React.ReactNode {
- const label = this.props.label;
- const address = this.props.address;
- const identiconDiameter = this.props.identiconDiameter;
- const emptyIdenticonStyles = {
- width: identiconDiameter,
- height: identiconDiameter,
- backgroundColor: 'lightgray',
- marginTop: 13,
- marginBottom: 10,
- };
- const tokenImageStyle = {
- width: IMAGE_DIMENSION,
- height: IMAGE_DIMENSION,
- };
- const etherscanLinkIfExists = sharedUtils.getEtherScanLinkIfExists(
- this.props.address,
- this.props.networkId,
- EtherscanLinkSuffixes.Address,
- );
- const isRegistered = this.props.isInTokenRegistry;
- const registeredTooltipId = `${this.props.address}-${isRegistered}-registeredTooltip`;
- const uniqueNameAndSymbolTooltipId = `${this.props.address}-${isRegistered}-uniqueTooltip`;
- return (
- <div style={{ overflow: 'hidden' }}>
- <div className="pb1 center">{label}</div>
- {_.isEmpty(address) ? (
- <div className="circle mx-auto" style={emptyIdenticonStyles} />
- ) : (
- <a href={etherscanLinkIfExists} target="_blank">
- {isRegistered && !_.isUndefined(this.props.alternativeImage) ? (
- <img style={tokenImageStyle} src={this.props.alternativeImage} />
- ) : (
- <div className="mx-auto" style={{ height: identiconDiameter, width: identiconDiameter }}>
- <Identicon
- address={this.props.address}
- diameter={identiconDiameter}
- style={this.props.identiconStyle}
- />
- </div>
- )}
- </a>
- )}
- <div className="mx-auto center pt1">
- <div style={{ height: 25 }}>
- <EthereumAddress address={address} networkId={this.props.networkId} />
- </div>
- {!_.isUndefined(this.props.isInTokenRegistry) && (
- <div>
- <div
- data-tip={true}
- data-for={registeredTooltipId}
- className="mx-auto"
- style={{ fontSize: 13, width: 127 }}
- >
- <span
- style={{
- color: isRegistered ? colors.brightGreen : colors.red500,
- }}
- >
- <i
- className={`zmdi ${isRegistered ? 'zmdi-check-circle' : 'zmdi-alert-triangle'}`}
- />
- </span>{' '}
- <span>{isRegistered ? 'Registered' : 'Unregistered'} token</span>
- <ReactTooltip id={registeredTooltipId}>
- {isRegistered ? (
- <div>
- This token address was found in the token registry
- <br />
- smart contract and is therefore believed to be a<br />
- legitimate token.
- </div>
- ) : (
- <div>
- This token is not included in the token registry
- <br />
- smart contract. We cannot guarantee the legitimacy
- <br />
- of this token. Make sure to verify its address on Etherscan.
- </div>
- )}
- </ReactTooltip>
- </div>
- </div>
- )}
- {!_.isUndefined(this.props.hasUniqueNameAndSymbol) && !this.props.hasUniqueNameAndSymbol && (
- <div>
- <div
- data-tip={true}
- data-for={uniqueNameAndSymbolTooltipId}
- className="mx-auto"
- style={{ fontSize: 13, width: 127 }}
- >
- <span style={{ color: colors.red500 }}>
- <i className="zmdi zmdi-alert-octagon" />
- </span>{' '}
- <span>Suspicious token</span>
- <ReactTooltip id={uniqueNameAndSymbolTooltipId}>
- This token shares it's name, symbol or both with
- <br />
- a token in the 0x Token Registry but it has a different
- <br />
- smart contract address. This is most likely a scam token!
- </ReactTooltip>
- </div>
- </div>
- )}
- </div>
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/ui/pointer.tsx b/packages/website/ts/components/ui/pointer.tsx
deleted file mode 100644
index c97b1e700..000000000
--- a/packages/website/ts/components/ui/pointer.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-import { styled } from 'ts/style/theme';
-
-export enum PointerDirection {
- Top = 'top',
- Right = 'right',
- Bottom = 'bottom',
- Left = 'left',
-}
-
-export interface PointerProps {
- className?: string;
- color?: string;
- size?: number;
- direction: PointerDirection;
-}
-
-const PlainPointer: React.StatelessComponent<PointerProps> = props => <div {...props} />;
-
-const positionToCss = (props: PointerProps) => {
- const position = {
- top: `bottom: 100%; left: 50%;`,
- right: `left: 100%; top: 50%;`,
- bottom: `top: 100%; left: 50%;`,
- left: `right: 100%; top: 50%;`,
- }[props.direction];
-
- const borderColorSide = {
- top: 'border-bottom-color',
- right: 'border-left-color',
- bottom: 'border-top-color',
- left: 'border-right-color',
- }[props.direction];
- const border = `${borderColorSide}: ${props.color};`;
- const marginSide = {
- top: 'margin-left',
- right: 'margin-top',
- bottom: 'margin-left',
- left: 'margin-top',
- }[props.direction];
- const margin = `${marginSide}: -${props.size}px`;
- return {
- position,
- border,
- margin,
- };
-};
-
-export const Pointer = styled(PlainPointer)`
- position: relative;
- &:after {
- border: solid transparent;
- content: " ";
- height: 0;
- width: 0;
- position: absolute;
- pointer-events: none;
- border-color: rgba(136, 183, 213, 0);
- border-width: ${props => `${props.size}px`};
- ${props => positionToCss(props).position}
- ${props => positionToCss(props).border}
- ${props => positionToCss(props).margin}
- }
-`;
-
-Pointer.defaultProps = {
- color: colors.white,
- size: 16,
-};
-
-Pointer.displayName = 'Pointer';
diff --git a/packages/website/ts/components/ui/required_label.tsx b/packages/website/ts/components/ui/required_label.tsx
deleted file mode 100644
index 5080462fa..000000000
--- a/packages/website/ts/components/ui/required_label.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-
-export interface RequiredLabelProps {
- label: string | React.ReactNode;
-}
-
-export const RequiredLabel = (props: RequiredLabelProps) => {
- return (
- <span>
- {props.label}
- <span style={{ color: colors.red600 }}>*</span>
- </span>
- );
-};
diff --git a/packages/website/ts/components/ui/retry.tsx b/packages/website/ts/components/ui/retry.tsx
deleted file mode 100644
index 543b7df4b..000000000
--- a/packages/website/ts/components/ui/retry.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import * as React from 'react';
-
-import { Button } from 'ts/components/ui/button';
-import { colors } from 'ts/style/colors';
-
-const BUTTON_TEXT = 'reload';
-
-export interface RetryProps {
- onRetry: () => void;
-}
-export const Retry = (props: RetryProps) => (
- <div className="clearfix center" style={{ color: colors.black }}>
- <div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}>
- <div className="h2" style={{ fontFamily: 'Roboto Mono' }}>
- Something went wrong.
- </div>
- <div className="py3">
- <Button
- type="button"
- backgroundColor={colors.black}
- width="290px"
- fontColor={colors.white}
- fontSize="18px"
- fontFamily="Roboto Mono"
- onClick={props.onRetry}
- >
- {BUTTON_TEXT}
- </Button>
- </div>
- </div>
- </div>
-);
diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx
deleted file mode 100644
index 45ee752e3..000000000
--- a/packages/website/ts/components/ui/simple_menu.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import { Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import * as CopyToClipboard from 'react-copy-to-clipboard';
-
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { WebsitePaths } from 'ts/types';
-
-export interface SimpleMenuProps {
- minWidth?: number | string;
-}
-
-export const SimpleMenu: React.StatelessComponent<SimpleMenuProps> = ({ children, minWidth }) => {
- return (
- <Container
- marginLeft="16px"
- marginRight="16px"
- marginBottom="16px"
- minWidth={minWidth}
- className="flex flex-column"
- >
- {children}
- </Container>
- );
-};
-
-SimpleMenu.defaultProps = {
- minWidth: '220px',
-};
-
-export interface SimpleMenuItemProps {
- displayText: string;
- onClick?: () => void;
-}
-export const SimpleMenuItem: React.StatelessComponent<SimpleMenuItemProps> = ({ displayText, onClick }) => {
- // Falling back to _.noop for onclick retains the hovering effect
- return (
- <Container marginTop="16px" className="flex flex-column">
- <Text
- fontSize="14px"
- fontColor={colors.darkGrey}
- onClick={onClick || _.noop.bind(_)}
- hoverColor={colors.mediumBlue}
- >
- {displayText}
- </Text>
- </Container>
- );
-};
-
-export interface CopyAddressSimpleMenuItemProps {
- userAddress: string;
- onClick?: () => void;
-}
-export const CopyAddressSimpleMenuItem: React.StatelessComponent<CopyAddressSimpleMenuItemProps> = ({
- userAddress,
- onClick,
-}) => {
- return (
- <CopyToClipboard text={userAddress}>
- <SimpleMenuItem displayText="Copy Address to Clipboard" onClick={onClick} />
- </CopyToClipboard>
- );
-};
-
-export interface GoToAccountManagementSimpleMenuItemProps {
- onClick?: () => void;
-}
-export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent<
- GoToAccountManagementSimpleMenuItemProps
-> = ({ onClick }) => {
- return (
- <Link to={`${WebsitePaths.Portal}/account`}>
- <SimpleMenuItem displayText="Manage Account..." onClick={onClick} />
- </Link>
- );
-};
-
-export interface DifferentWalletSimpleMenuItemProps {
- onClick?: () => void;
-}
-export const DifferentWalletSimpleMenuItem: React.StatelessComponent<DifferentWalletSimpleMenuItemProps> = ({
- onClick,
-}) => {
- return <SimpleMenuItem displayText="Use Ledger Wallet..." onClick={onClick} />;
-};
diff --git a/packages/website/ts/components/ui/spinner.tsx b/packages/website/ts/components/ui/spinner.tsx
deleted file mode 100644
index dc73e74e3..000000000
--- a/packages/website/ts/components/ui/spinner.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-import { styled } from 'ts/style/theme';
-
-import { dash, rotate } from 'ts/style/keyframes';
-
-interface SpinnerSvgProps {
- color: string;
- size: number;
- viewBox?: string;
-}
-
-const SpinnerSvg: React.StatelessComponent<SpinnerSvgProps> = props => <svg {...props} />;
-
-const StyledSpinner = styled(SpinnerSvg)`
- animation: ${rotate} 3s linear infinite;
- margin: ${props => `-${props.size / 2}px 0 0 -${props.size / 2}px`};
- margin-top: ${props => `-${props.size / 2}px`};
- margin-left: ${props => `-${props.size / 2}px`};
- margin-bottom: 0px;
- margin-right: 0px;
- size: ${props => `${props.size}px`};
- height: ${props => `${props.size}px`};
-
- & .path {
- stroke: ${props => props.color};
- stroke-linecap: round;
- animation: ${dash} 2.5s ease-in-out infinite;
- }
-`;
-
-export interface SpinnerProps {
- size?: number;
- strokeSize?: number;
- color?: string;
-}
-
-export const Spinner: React.StatelessComponent<SpinnerProps> = ({ size, strokeSize, color }) => {
- const c = size / 2;
- const r = c - strokeSize;
- return (
- <StyledSpinner color={color} size={size} viewBox={`0 0 ${size} ${size}`}>
- <circle className="path" cx={c} cy={c} r={r} fill="none" strokeWidth={strokeSize} />
- </StyledSpinner>
- );
-};
-
-Spinner.defaultProps = {
- size: 50,
- color: colors.mediumBlue,
- strokeSize: 4,
-};
-
-Spinner.displayName = 'Spinner';
diff --git a/packages/website/ts/components/ui/swap_icon.tsx b/packages/website/ts/components/ui/swap_icon.tsx
deleted file mode 100644
index 406da8fe1..000000000
--- a/packages/website/ts/components/ui/swap_icon.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-
-interface SwapIconProps {
- swapTokensFn: () => void;
-}
-
-interface SwapIconState {
- isHovering: boolean;
-}
-
-export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> {
- public constructor(props: SwapIconProps) {
- super(props);
- this.state = {
- isHovering: false,
- };
- }
- public render(): React.ReactNode {
- const swapStyles = {
- color: this.state.isHovering ? colors.amber600 : colors.amber800,
- fontSize: 50,
- };
- return (
- <div
- className="mx-auto pt4"
- style={{ cursor: 'pointer', height: 50, width: 37.5 }}
- onClick={this.props.swapTokensFn}
- onMouseEnter={this._onToggleHover.bind(this, true)}
- onMouseLeave={this._onToggleHover.bind(this, false)}
- >
- <i style={swapStyles} className="zmdi zmdi-swap" />
- </div>
- );
- }
- private _onToggleHover(isHovering: boolean): void {
- this.setState({
- isHovering,
- });
- }
-}
diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx
deleted file mode 100644
index 046442ee5..000000000
--- a/packages/website/ts/components/ui/text.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { colors } from '@0x/react-shared';
-import { darken } from 'polished';
-import * as React from 'react';
-import { styled } from 'ts/style/theme';
-
-export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i' | 'span';
-
-export interface TextProps {
- className?: string;
- children?: any;
- Tag?: TextTag;
- fontSize?: string;
- fontFamily?: string;
- fontStyle?: string;
- fontColor?: string;
- lineHeight?: string;
- minHeight?: string;
- center?: boolean;
- fontWeight?: number | string;
- textDecorationLine?: string;
- onClick?: (event: React.MouseEvent<HTMLElement>) => void;
- hoverColor?: string;
- letterSpacing?: string | number;
- noWrap?: boolean;
- textAlign?: string;
- display?: string;
-}
-
-const PlainText: React.StatelessComponent<TextProps> = ({ children, className, onClick, Tag }) => (
- <Tag className={className} onClick={onClick}>
- {children}
- </Tag>
-);
-
-export const Text = styled(PlainText)`
- font-family: ${props => props.fontFamily};
- font-style: ${props => props.fontStyle};
- font-weight: ${props => props.fontWeight};
- font-size: ${props => props.fontSize};
- text-align: ${props => props.textAlign};
- letter-spacing: ${props => props.letterSpacing};
- text-decoration-line: ${props => props.textDecorationLine};
- ${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')};
- ${props => (props.center ? 'text-align: center' : '')};
- color: ${props => props.fontColor};
- ${props => (props.minHeight ? `min-height: ${props.minHeight}` : '')};
- ${props => (props.onClick ? 'cursor: pointer' : '')};
- transition: color 0.5s ease;
- ${props => (props.noWrap ? 'white-space: nowrap' : '')};
- ${props => (props.display ? `display: ${props.display}` : '')};
- &:hover {
- ${props => (props.onClick ? `color: ${props.hoverColor || darken(0.3, props.fontColor)}` : '')};
- }
-`;
-
-Text.defaultProps = {
- fontFamily: 'Roboto',
- fontStyle: 'normal',
- fontWeight: 400,
- fontColor: colors.black,
- fontSize: '15px',
- lineHeight: '1.5em',
- textDecorationLine: 'none',
- Tag: 'div',
- noWrap: false,
-};
-
-Text.displayName = 'Text';
-
-export const Title: React.StatelessComponent<TextProps> = props => <Text {...props} />;
-
-Title.defaultProps = {
- Tag: 'h2',
- fontSize: '20px',
- fontWeight: 600,
- fontColor: colors.black,
-};
-
-Title.displayName = 'Title';
diff --git a/packages/website/ts/components/ui/token_icon.tsx b/packages/website/ts/components/ui/token_icon.tsx
deleted file mode 100644
index 0875cc56b..000000000
--- a/packages/website/ts/components/ui/token_icon.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Identicon } from 'ts/components/ui/identicon';
-import { Token } from 'ts/types';
-
-interface TokenIconProps {
- token: Token;
- diameter: number;
- link?: string;
-}
-
-interface TokenIconState {}
-
-export class TokenIcon extends React.Component<TokenIconProps, TokenIconState> {
- public render(): React.ReactNode {
- const token = this.props.token;
- const diameter = this.props.diameter;
- const icon =
- token.isRegistered && !_.isUndefined(token.iconUrl) ? (
- <img style={{ width: diameter, height: diameter }} src={token.iconUrl} />
- ) : (
- <Identicon address={token.address} diameter={diameter} />
- );
- if (_.isEmpty(this.props.link)) {
- return icon;
- } else {
- return (
- <a href={this.props.link} target="_blank" style={{ textDecoration: 'none' }}>
- {icon}
- </a>
- );
- }
- }
-}
diff --git a/packages/website/ts/components/visual_order.tsx b/packages/website/ts/components/visual_order.tsx
deleted file mode 100644
index d723757d2..000000000
--- a/packages/website/ts/components/visual_order.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { Party } from 'ts/components/ui/party';
-import { AssetToken, Token, TokenByAddress } from 'ts/types';
-import { configs } from 'ts/utils/configs';
-import { utils } from 'ts/utils/utils';
-
-interface VisualOrderProps {
- makerAssetToken: AssetToken;
- takerAssetToken: AssetToken;
- makerToken: Token;
- takerToken: Token;
- networkId: number;
- tokenByAddress: TokenByAddress;
- isMakerTokenAddressInRegistry: boolean;
- isTakerTokenAddressInRegistry: boolean;
-}
-
-interface VisualOrderState {}
-
-export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderState> {
- public render(): React.ReactNode {
- const allTokens = _.values(this.props.tokenByAddress);
- const makerImage = this.props.makerToken.iconUrl;
- const takerImage = this.props.takerToken.iconUrl;
- return (
- <div>
- <div className="clearfix">
- <div className="col col-5 center">
- <Party
- label="Send"
- address={this.props.takerToken.address}
- alternativeImage={takerImage}
- networkId={this.props.networkId}
- isInTokenRegistry={this.props.isTakerTokenAddressInRegistry}
- hasUniqueNameAndSymbol={utils.hasUniqueNameAndSymbol(allTokens, this.props.takerToken)}
- />
- </div>
- <div className="col col-2 center pt1">
- <div className="pb1">
- {this._renderAmount(this.props.takerAssetToken, this.props.takerToken)}
- </div>
- <div className="lg-p2 md-p2 sm-p1">
- <img src="/images/trade_arrows.png" style={{ width: 47 }} />
- </div>
- <div className="pt1">
- {this._renderAmount(this.props.makerAssetToken, this.props.makerToken)}
- </div>
- </div>
- <div className="col col-5 center">
- <Party
- label="Receive"
- address={this.props.makerToken.address}
- alternativeImage={makerImage}
- networkId={this.props.networkId}
- isInTokenRegistry={this.props.isMakerTokenAddressInRegistry}
- hasUniqueNameAndSymbol={utils.hasUniqueNameAndSymbol(allTokens, this.props.makerToken)}
- />
- </div>
- </div>
- </div>
- );
- }
- private _renderAmount(assetToken: AssetToken, token: Token): React.ReactNode {
- const unitAmount = Web3Wrapper.toUnitAmount(assetToken.amount, token.decimals);
- return (
- <div style={{ fontSize: 13 }}>
- {unitAmount.toNumber().toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {token.symbol}
- </div>
- );
- }
-}
diff --git a/packages/website/ts/components/wallet/body_overlay.tsx b/packages/website/ts/components/wallet/body_overlay.tsx
deleted file mode 100644
index 3795f0eaa..000000000
--- a/packages/website/ts/components/wallet/body_overlay.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Blockchain } from 'ts/blockchain';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Island } from 'ts/components/ui/island';
-import { Text } from 'ts/components/ui/text';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-import { AccountState, ProviderType } from 'ts/types';
-import { utils } from 'ts/utils/utils';
-
-const METAMASK_IMG_SRC = '/images/metamask_icon.png';
-const COINBASE_WALLET_IMG_SRC = '/images/coinbase_wallet_logo.png';
-
-export interface BodyOverlayProps {
- dispatcher: Dispatcher;
- userAddress: string;
- injectedProviderName: string;
- providerType: ProviderType;
- onToggleLedgerDialog: () => void;
- blockchain?: Blockchain;
- blockchainIsLoaded: boolean;
-}
-
-interface BodyOverlayState {}
-
-export class BodyOverlay extends React.Component<BodyOverlayProps, BodyOverlayState> {
- public render(): React.ReactNode {
- const accountState = this._getAccountState();
- switch (accountState) {
- case AccountState.Locked:
- return <LockedOverlay onUseDifferentWalletClicked={this.props.onToggleLedgerDialog} />;
- case AccountState.Disconnected:
- return <DisconnectedOverlay onUseDifferentWalletClicked={this.props.onToggleLedgerDialog} />;
- case AccountState.Ready:
- case AccountState.Loading:
- default:
- return null;
- }
- }
- private _isBlockchainReady(): boolean {
- return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain);
- }
- private _getAccountState(): AccountState {
- return utils.getAccountState(
- this._isBlockchainReady(),
- this.props.providerType,
- this.props.injectedProviderName,
- this.props.userAddress,
- );
- }
-}
-
-interface LockedOverlayProps {
- className?: string;
- onUseDifferentWalletClicked?: () => void;
-}
-const PlainLockedOverlay: React.StatelessComponent<LockedOverlayProps> = ({
- className,
- onUseDifferentWalletClicked,
-}) => (
- <div className={className}>
- <Container
- className="flex flex-column items-center"
- marginBottom="24px"
- marginTop="24px"
- marginLeft="48px"
- marginRight="48px"
- >
- <Image src={METAMASK_IMG_SRC} height="70px" />
- <Container marginTop="12px">
- <Text fontColor={colors.metaMaskOrange} fontSize="16px" fontWeight="bold">
- Please Unlock MetaMask
- </Text>
- </Container>
- <UseDifferentWallet fontColor={colors.darkGrey} onClick={onUseDifferentWalletClicked} />
- </Container>
- </div>
-);
-const LockedOverlay = styled(PlainLockedOverlay)`
- background: ${colors.metaMaskTransparentOrange};
- border: 1px solid ${colors.metaMaskOrange};
- border-radius: 10px;
-`;
-
-interface DisconnectedOverlayProps {
- onUseDifferentWalletClicked?: () => void;
-}
-const DisconnectedOverlay = (props: DisconnectedOverlayProps) => {
- return (
- <div className="flex flex-column items-center">
- <GetWalletCallToAction />
- {!utils.isMobileOperatingSystem() && (
- <UseDifferentWallet fontColor={colors.mediumBlue} onClick={props.onUseDifferentWalletClicked} />
- )}
- </div>
- );
-};
-
-interface UseDifferentWallet {
- fontColor: string;
- onClick?: () => void;
-}
-const UseDifferentWallet = (props: UseDifferentWallet) => {
- return (
- <Container marginTop="12px">
- <Text fontColor={props.fontColor} fontSize="16px" textDecorationLine="underline" onClick={props.onClick}>
- Use a different wallet
- </Text>
- </Container>
- );
-};
-
-const GetWalletCallToAction = () => {
- const [downloadLink, isOnMobile] = utils.getBestWalletDownloadLinkAndIsMobile();
- const imageUrl = isOnMobile ? COINBASE_WALLET_IMG_SRC : METAMASK_IMG_SRC;
- const text = isOnMobile ? 'Get Coinbase Wallet' : 'Get MetaMask Wallet';
- return (
- <a href={downloadLink} target="_blank" style={{ textDecoration: 'none' }}>
- <Island
- className="flex items-center py1 px2"
- style={{ height: 28, borderRadius: 28, backgroundColor: colors.mediumBlue }}
- >
- <Image src={imageUrl} width="28px" borderRadius="22%" />
- <Container marginLeft="8px" marginRight="12px">
- <Text fontColor={colors.white} fontSize="16px" fontWeight={500}>
- {text}
- </Text>
- </Container>
- </Island>
- </a>
- );
-};
diff --git a/packages/website/ts/components/wallet/null_token_row.tsx b/packages/website/ts/components/wallet/null_token_row.tsx
deleted file mode 100644
index a1ec9871a..000000000
--- a/packages/website/ts/components/wallet/null_token_row.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as React from 'react';
-
-import { Circle } from 'ts/components/ui/circle';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { PlaceHolder } from 'ts/components/wallet/placeholder';
-import { StandardIconRow } from 'ts/components/wallet/standard_icon_row';
-import { colors } from 'ts/style/colors';
-
-export interface NullTokenRowProps {
- iconDimension: number;
- fillColor: string;
-}
-
-export const NullTokenRow: React.StatelessComponent<NullTokenRowProps> = ({ iconDimension, fillColor }) => {
- const icon = <Circle diameter={iconDimension} fillColor={fillColor} />;
- const main = (
- <div className="flex flex-column">
- <PlaceHolder hideChildren={true} fillColor={fillColor}>
- <Text fontSize="16px" fontWeight="bold" lineHeight="1em">
- 0.00 XXX
- </Text>
- </PlaceHolder>
- <Container marginTop="3px">
- <PlaceHolder hideChildren={true} fillColor={fillColor}>
- <Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em">
- $0.00
- </Text>
- </PlaceHolder>
- </Container>
- </div>
- );
- const accessory = (
- <Container marginRight="12px">
- <PlaceHolder hideChildren={true} fillColor={fillColor}>
- <Container width="20px" height="14px" />
- </PlaceHolder>
- </Container>
- );
- return <StandardIconRow icon={icon} main={main} accessory={accessory} />;
-};
diff --git a/packages/website/ts/components/wallet/placeholder.tsx b/packages/website/ts/components/wallet/placeholder.tsx
deleted file mode 100644
index bf40d2ea8..000000000
--- a/packages/website/ts/components/wallet/placeholder.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import * as React from 'react';
-
-import { styled } from 'ts/style/theme';
-
-export interface PlaceHolderProps {
- className?: string;
- hideChildren: React.ReactNode;
- fillColor: string;
-}
-
-const PlainPlaceHolder: React.StatelessComponent<PlaceHolderProps> = ({ className, hideChildren, children }) => {
- const childrenVisibility = hideChildren ? 'hidden' : 'visible';
- const childrenStyle: React.CSSProperties = { visibility: childrenVisibility };
- return (
- <div className={className}>
- <div style={childrenStyle}>{children}</div>
- </div>
- );
-};
-
-export const PlaceHolder = styled(PlainPlaceHolder)`
- background-color: ${props => (props.hideChildren ? props.fillColor : 'transparent')};
- display: inline-block;
- border-radius: 2px;
-`;
diff --git a/packages/website/ts/components/wallet/standard_icon_row.tsx b/packages/website/ts/components/wallet/standard_icon_row.tsx
deleted file mode 100644
index 1a2ec021b..000000000
--- a/packages/website/ts/components/wallet/standard_icon_row.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import * as React from 'react';
-
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-
-export interface StandardIconRowProps {
- className?: string;
- icon: React.ReactNode;
- main: React.ReactNode;
- accessory?: React.ReactNode;
- minHeight?: string;
- borderBottomColor?: string;
- borderBottomStyle?: string;
- borderWidth?: string;
- backgroundColor?: string;
-}
-const PlainStandardIconRow: React.StatelessComponent<StandardIconRowProps> = ({ className, icon, main, accessory }) => {
- return (
- <div className={`flex items-center ${className}`}>
- <div className="flex items-center px2">{icon}</div>
- <div className="flex-none pr2">{main}</div>
- <div className="flex-auto" />
- <div>{accessory}</div>
- </div>
- );
-};
-
-export const StandardIconRow = styled(PlainStandardIconRow)`
- min-height: ${props => props.minHeight};
- border-bottom-color: ${props => props.borderBottomColor};
- border-bottom-style: ${props => props.borderBottomStyle};
- border-width: ${props => props.borderWidth};
- background-color: ${props => props.backgroundColor};
-`;
-
-StandardIconRow.defaultProps = {
- minHeight: '85px',
- borderBottomColor: colors.walletBorder,
- borderBottomStyle: 'solid',
- borderWidth: '1px',
- backgroundColor: colors.walletDefaultItemBackground,
-};
-
-StandardIconRow.displayName = 'StandardIconRow';
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
deleted file mode 100644
index d9da0b9d5..000000000
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ /dev/null
@@ -1,527 +0,0 @@
-import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared';
-import { BigNumber, errorUtils } from '@0x/utils';
-import * as _ from 'lodash';
-
-import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet';
-import * as React from 'react';
-import firstBy from 'thenby';
-
-import { Blockchain } from 'ts/blockchain';
-import { AccountConnection } from 'ts/components/ui/account_connection';
-import { Balance } from 'ts/components/ui/balance';
-import { Container } from 'ts/components/ui/container';
-import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down';
-import { IconButton } from 'ts/components/ui/icon_button';
-import { Identicon } from 'ts/components/ui/identicon';
-import { Island } from 'ts/components/ui/island';
-import { PointerDirection } from 'ts/components/ui/pointer';
-import {
- CopyAddressSimpleMenuItem,
- DifferentWalletSimpleMenuItem,
- GoToAccountManagementSimpleMenuItem,
- SimpleMenu,
- SimpleMenuItem,
-} from 'ts/components/ui/simple_menu';
-import { Text } from 'ts/components/ui/text';
-import { TokenIcon } from 'ts/components/ui/token_icon';
-import { BodyOverlay } from 'ts/components/wallet/body_overlay';
-import { NullTokenRow } from 'ts/components/wallet/null_token_row';
-import { PlaceHolder } from 'ts/components/wallet/placeholder';
-import { StandardIconRow } from 'ts/components/wallet/standard_icon_row';
-import { WrapEtherItem } from 'ts/components/wallet/wrap_ether_item';
-import { AllowanceStateToggle } from 'ts/containers/inputs/allowance_state_toggle';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import {
- AccountState,
- BlockchainErrs,
- ProviderType,
- ScreenWidths,
- Side,
- Token,
- TokenByAddress,
- TokenState,
- TokenStateByAddress,
-} from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-export interface WalletProps {
- userAddress: string;
- networkId: number;
- blockchain: Blockchain;
- blockchainIsLoaded: boolean;
- blockchainErr: BlockchainErrs;
- dispatcher: Dispatcher;
- tokenByAddress: TokenByAddress;
- trackedTokens: Token[];
- userEtherBalanceInWei?: BigNumber;
- lastForceTokenStateRefetch: number;
- injectedProviderName: string;
- providerType: ProviderType;
- screenWidth: ScreenWidths;
- location: Location;
- trackedTokenStateByAddress: TokenStateByAddress;
- onToggleLedgerDialog: () => void;
- onAddToken: () => void;
- onRemoveToken: () => void;
- refetchTokenStateAsync: (tokenAddress: string) => Promise<void>;
- style: React.CSSProperties;
- toggleTooltipDirection?: PointerDirection;
-}
-
-interface WalletState {
- wrappedEtherDirection?: Side;
- isHoveringSidebar: boolean;
-}
-
-interface AllowanceStateToggleConfig {
- token: Token;
- tokenState: TokenState;
-}
-
-interface AccessoryItemConfig {
- wrappedEtherDirection?: Side;
- allowanceStateToggleConfig?: AllowanceStateToggleConfig;
-}
-
-const ETHER_ICON_PATH = '/images/ether.png';
-const ICON_DIMENSION = 28;
-const BODY_ITEM_KEY = 'BODY';
-const HEADER_ITEM_KEY = 'HEADER';
-const ETHER_ITEM_KEY = 'ETHER';
-const WRAP_ROW_ALLOWANCE_TOGGLE_WIDTH = 67;
-const ALLOWANCE_TOGGLE_WIDTH = 56;
-const PLACEHOLDER_COLOR = colors.grey300;
-const LOADING_ROWS_COUNT = 6;
-
-export class Wallet extends React.Component<WalletProps, WalletState> {
- public static defaultProps = {
- style: {},
- };
- constructor(props: WalletProps) {
- super(props);
- this.state = {
- wrappedEtherDirection: undefined,
- isHoveringSidebar: false,
- };
- }
- public componentDidUpdate(prevProps: WalletProps): void {
- const currentTrackedTokens = this.props.trackedTokens;
- const differentTrackedTokens = _.difference(currentTrackedTokens, prevProps.trackedTokens);
- const firstDifferentTrackedToken = _.head(differentTrackedTokens);
- // check if there is only one different token, and if that token is a member of the current tracked tokens
- // this means that the token was added, not removed
- if (
- !_.isUndefined(firstDifferentTrackedToken) &&
- _.size(differentTrackedTokens) === 1 &&
- _.includes(currentTrackedTokens, firstDifferentTrackedToken)
- ) {
- document.getElementById(firstDifferentTrackedToken.address).scrollIntoView();
- }
- }
- public render(): React.ReactNode {
- return (
- <Island className="flex flex-column wallet" style={this.props.style}>
- {this._isBlockchainReady() ? this._renderLoadedRows() : this._renderLoadingRows()}
- </Island>
- );
- }
- private _renderLoadingRows(): React.ReactNode {
- return _.concat(this._renderLoadingHeaderRows(), this._renderLoadingBodyRows());
- }
- private _renderLoadingHeaderRows(): React.ReactElement<{}> {
- return this._renderPlainHeaderRow('Loading...');
- }
- private _renderLoadingBodyRows(): React.ReactElement<{}> {
- const bodyStyle = this._getBodyStyle();
- const loadingRowsRange = _.range(LOADING_ROWS_COUNT);
- return (
- <div key={BODY_ITEM_KEY} className="flex flex-column" style={bodyStyle}>
- {_.map(loadingRowsRange, index => {
- return <NullTokenRow key={index} iconDimension={ICON_DIMENSION} fillColor={PLACEHOLDER_COLOR} />;
- })}
- <Container
- className="flex items-center"
- position="absolute"
- width="100%"
- height="100%"
- maxHeight={bodyStyle.maxHeight}
- >
- <div className="mx-auto">
- <BodyOverlay
- dispatcher={this.props.dispatcher}
- userAddress={this.props.userAddress}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.props.onToggleLedgerDialog}
- blockchain={this.props.blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- />
- </div>
- </Container>
- </div>
- );
- }
- private _renderLoadedRows(): React.ReactNode {
- const isAddressAvailable = !_.isEmpty(this.props.userAddress);
- return isAddressAvailable
- ? _.concat(this._renderConnectedHeaderRows(), this._renderBody())
- : _.concat(this._renderDisconnectedHeaderRows(), this._renderLoadingBodyRows());
- }
- private _renderDisconnectedHeaderRows(): React.ReactElement<{}> {
- const isExternallyInjectedProvider = utils.isExternallyInjected(
- this.props.providerType,
- this.props.injectedProviderName,
- );
- const text = isExternallyInjectedProvider ? 'Please unlock MetaMask...' : 'Please connect a wallet...';
- return this._renderPlainHeaderRow(text);
- }
- private _renderPlainHeaderRow(text: string): React.ReactElement<{}> {
- return (
- <StandardIconRow
- key={HEADER_ITEM_KEY}
- icon={<ActionAccountBalanceWallet color={colors.grey} />}
- main={
- <Text fontSize="16px" fontColor={colors.grey}>
- {text}
- </Text>
- // https://github.com/palantir/tslint-react/issues/140
- // tslint:disable-next-line:jsx-curly-spacing
- }
- minHeight="60px"
- backgroundColor={colors.white}
- />
- );
- }
- private _renderConnectedHeaderRows(): React.ReactElement<{}> {
- const isMobile = this.props.screenWidth === ScreenWidths.Sm;
- const userAddress = this.props.userAddress;
- const accountState = this._getAccountState();
- const main = (
- <div className="flex flex-column">
- <Text fontSize="16px" lineHeight="19px" fontWeight={500}>
- {utils.getAddressBeginAndEnd(userAddress)}
- </Text>
- <AccountConnection accountState={accountState} injectedProviderName={this.props.injectedProviderName} />
- </div>
- );
- const onClick = _.noop.bind(_);
- const accessory = (
- <DropDown
- activeNode={
- // this container gives the menu button more of a hover target for the drop down
- // it prevents accidentally closing the menu by moving off of the button
- <Container paddingLeft="100px" paddingRight="15px">
- <Text
- className="zmdi zmdi-more-horiz"
- Tag="i"
- fontSize="32px"
- fontFamily="Material-Design-Iconic-Font"
- fontColor={colors.darkGrey}
- onClick={onClick}
- hoverColor={colors.mediumBlue}
- />
- </Container>
- }
- popoverContent={
- <SimpleMenu minWidth="150px">
- <CopyAddressSimpleMenuItem userAddress={this.props.userAddress} />
- {!isMobile && <DifferentWalletSimpleMenuItem onClick={this.props.onToggleLedgerDialog} />}
- <SimpleMenuItem displayText="Add Tokens..." onClick={this.props.onAddToken} />
- <SimpleMenuItem displayText="Remove Tokens..." onClick={this.props.onRemoveToken} />
- {!isMobile && <GoToAccountManagementSimpleMenuItem />}
- </SimpleMenu>
- }
- anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
- targetOrigin={{ horizontal: 'right', vertical: 'top' }}
- zDepth={1}
- activateEvent={DropdownMouseEvent.Click}
- closeEvent={DropdownMouseEvent.Click}
- />
- );
- return (
- <StandardIconRow
- key={HEADER_ITEM_KEY}
- icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
- main={main}
- accessory={accessory}
- minHeight="60px"
- backgroundColor={colors.white}
- />
- );
- }
- private _renderBody(): React.ReactElement<{}> {
- const bodyStyle = this._getBodyStyle();
- return (
- <div
- style={bodyStyle}
- key={BODY_ITEM_KEY}
- onMouseEnter={this._onSidebarHover.bind(this)}
- onMouseLeave={this._onSidebarHoverOff.bind(this)}
- >
- {this._renderEthRows()}
- {this._renderTokenRows()}
- </div>
- );
- }
- private _getBodyStyle(): React.CSSProperties {
- return {
- overflow: 'auto',
- WebkitOverflowScrolling: 'touch',
- position: 'relative',
- overflowY: this.state.isHoveringSidebar ? 'scroll' : 'hidden',
- marginRight: this.state.isHoveringSidebar ? 0 : 4,
- minHeight: '250px',
- maxHeight: !utils.isMobileWidth(this.props.screenWidth) ? 'calc(90vh - 300px)' : undefined,
- };
- }
- private _onSidebarHover(_event: React.FormEvent<HTMLInputElement>): void {
- this.setState({
- isHoveringSidebar: true,
- });
- }
- private _onSidebarHoverOff(): void {
- this.setState({
- isHoveringSidebar: false,
- });
- }
- private _renderEthRows(): React.ReactNode {
- const icon = <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />;
- const primaryText = this._renderAmount(
- this.props.userEtherBalanceInWei || new BigNumber(0),
- constants.DECIMAL_PLACES_ETH,
- constants.ETHER_SYMBOL,
- _.isUndefined(this.props.userEtherBalanceInWei),
- );
- const etherToken = this._getEthToken();
- const etherTokenState = this.props.trackedTokenStateByAddress[etherToken.address];
- const etherPrice = etherTokenState.price;
- const secondaryText = this._renderValue(
- this.props.userEtherBalanceInWei || new BigNumber(0),
- constants.DECIMAL_PLACES_ETH,
- etherPrice,
- _.isUndefined(this.props.userEtherBalanceInWei) || !etherTokenState.isLoaded,
- );
- const accessoryItemConfig = {
- wrappedEtherDirection: Side.Deposit,
- };
- const key = ETHER_ITEM_KEY;
- return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
- }
- private _renderTokenRows(): React.ReactNode {
- const trackedTokens = this.props.trackedTokens;
- const trackedTokensStartingWithEtherToken = trackedTokens.sort(
- firstBy((t: Token) => t.symbol !== constants.ETHER_TOKEN_SYMBOL)
- .thenBy((t: Token) => t.symbol !== constants.ZRX_TOKEN_SYMBOL)
- .thenBy('trackedTimestamp'),
- );
- return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
- }
- private _renderTokenRow(token: Token): React.ReactNode {
- const tokenState = this.props.trackedTokenStateByAddress[token.address];
- if (_.isUndefined(tokenState)) {
- return null;
- }
- const tokenLink = sharedUtils.getEtherScanLinkIfExists(
- token.address,
- this.props.networkId,
- EtherscanLinkSuffixes.Address,
- );
- const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />;
- const isWeth = token.symbol === constants.ETHER_TOKEN_SYMBOL;
- const wrappedEtherDirection = isWeth ? Side.Receive : undefined;
- const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol, !tokenState.isLoaded);
- const secondaryText = this._renderValue(
- tokenState.balance,
- token.decimals,
- tokenState.price,
- !tokenState.isLoaded,
- );
- const accessoryItemConfig: AccessoryItemConfig = {
- wrappedEtherDirection,
- allowanceStateToggleConfig: {
- token,
- tokenState,
- },
- };
- const key = token.address;
- return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
- }
- private _renderBalanceRow(
- key: string,
- icon: React.ReactNode,
- primaryText: React.ReactNode,
- secondaryText: React.ReactNode,
- accessoryItemConfig: AccessoryItemConfig,
- className?: string,
- ): React.ReactNode {
- const shouldShowWrapEtherItem =
- !_.isUndefined(this.state.wrappedEtherDirection) &&
- this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection &&
- !_.isUndefined(this.props.userEtherBalanceInWei);
- const etherToken = this._getEthToken();
- const wrapEtherItem = shouldShowWrapEtherItem ? (
- <WrapEtherItem
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this.props.blockchain}
- dispatcher={this.props.dispatcher}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- direction={accessoryItemConfig.wrappedEtherDirection}
- etherToken={etherToken}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- onConversionSuccessful={this._closeWrappedEtherActionRow.bind(this)}
- // tslint:disable:jsx-no-lambda
- refetchEthTokenStateAsync={async () => this.props.refetchTokenStateAsync(etherToken.address)}
- />
- ) : null;
- return (
- <div id={key} key={key} className={`flex flex-column ${className || ''}`}>
- {this.state.wrappedEtherDirection === Side.Receive && wrapEtherItem}
- <StandardIconRow
- icon={icon}
- main={
- <div className="flex flex-column">
- {primaryText}
- <Container marginTop="3px">{secondaryText}</Container>
- </div>
- }
- accessory={this._renderAccessoryItems(accessoryItemConfig)}
- />
- {this.state.wrappedEtherDirection === Side.Deposit && wrapEtherItem}
- </div>
- );
- }
- private _renderAccessoryItems(config: AccessoryItemConfig): React.ReactElement<{}> {
- const shouldShowWrappedEtherAction = !_.isUndefined(config.wrappedEtherDirection);
- const shouldShowToggle = !_.isUndefined(config.allowanceStateToggleConfig);
- // if we don't have a toggle, we still want some space to the right of the "wrap" button so that it aligns with
- // the "unwrap" button in the row below
- const isWrapEtherRow = shouldShowWrappedEtherAction && config.wrappedEtherDirection === Side.Deposit;
- const width = isWrapEtherRow ? WRAP_ROW_ALLOWANCE_TOGGLE_WIDTH : ALLOWANCE_TOGGLE_WIDTH;
- const toggle = (
- <Container className="flex justify-center" width={width}>
- {shouldShowToggle && this._renderAllowanceToggle(config.allowanceStateToggleConfig)}
- </Container>
- );
- return (
- <div className="flex items-center">
- <div className="flex-auto">
- {shouldShowWrappedEtherAction && this._renderWrappedEtherButton(config.wrappedEtherDirection)}
- </div>
- <div className="flex-last pl2">{toggle}</div>
- </div>
- );
- }
- private _renderAllowanceToggle(config: AllowanceStateToggleConfig): React.ReactNode {
- // TODO: Error handling
- return (
- <AllowanceStateToggle
- blockchain={this.props.blockchain}
- token={config.token}
- tokenState={config.tokenState}
- tooltipDirection={this.props.toggleTooltipDirection}
- refetchTokenStateAsync={async () => this.props.refetchTokenStateAsync(config.token.address)}
- />
- );
- }
- private _renderAmount(
- amount: BigNumber,
- decimals: number,
- symbol: string,
- isLoading: boolean = false,
- ): React.ReactNode {
- if (isLoading) {
- return (
- <PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}>
- <Text fontSize="16px" fontWeight="bold" lineHeight="1em">
- 0.00 XXX
- </Text>
- </PlaceHolder>
- );
- } else {
- return <Balance amount={amount} decimals={decimals} symbol={symbol} />;
- }
- }
- private _renderValue(
- amount: BigNumber,
- decimals: number,
- price?: BigNumber,
- isLoading: boolean = false,
- ): React.ReactNode {
- const result = !isLoading
- ? _.isUndefined(price)
- ? '--'
- : utils.getUsdValueFormattedAmount(amount, decimals, price)
- : '$0.00';
- return (
- <PlaceHolder hideChildren={isLoading} fillColor={PLACEHOLDER_COLOR}>
- <Text fontSize="14px" fontColor={colors.darkGrey} lineHeight="1em">
- {result}
- </Text>
- </PlaceHolder>
- );
- }
- private _renderWrappedEtherButton(wrappedEtherDirection: Side): React.ReactNode {
- const isWrappedEtherDirectionOpen = this.state.wrappedEtherDirection === wrappedEtherDirection;
- let buttonLabel;
- let buttonIconName;
- if (isWrappedEtherDirectionOpen) {
- buttonLabel = 'cancel';
- buttonIconName = 'zmdi-close';
- } else {
- switch (wrappedEtherDirection) {
- case Side.Deposit:
- buttonLabel = 'wrap';
- buttonIconName = 'zmdi-long-arrow-down';
- break;
- case Side.Receive:
- buttonLabel = 'unwrap';
- buttonIconName = 'zmdi-long-arrow-up';
- break;
- default:
- throw errorUtils.spawnSwitchErr('wrappedEtherDirection', wrappedEtherDirection);
- }
- }
- const onClick = isWrappedEtherDirectionOpen
- ? this._closeWrappedEtherActionRow.bind(this, wrappedEtherDirection)
- : this._openWrappedEtherActionRow.bind(this, wrappedEtherDirection);
- return (
- <IconButton iconName={buttonIconName} labelText={buttonLabel} onClick={onClick} color={colors.mediumBlue} />
- );
- }
- private _openWrappedEtherActionRow(wrappedEtherDirection: Side): void {
- const action =
- wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Opened' : 'Wallet - Unwrap WETH Opened';
- analytics.track(action);
- this.setState({
- wrappedEtherDirection,
- });
- }
- private _closeWrappedEtherActionRow(wrappedEtherDirection: Side): void {
- const action =
- wrappedEtherDirection === Side.Deposit ? 'Wallet - Wrap ETH Closed' : 'Wallet - Unwrap WETH Closed';
- analytics.track(action);
- this.setState({
- wrappedEtherDirection: undefined,
- });
- }
- private _getEthToken(): Token {
- return utils.getEthToken(this.props.tokenByAddress);
- }
- private _isBlockchainReady(): boolean {
- return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain);
- }
- private _getAccountState(): AccountState {
- return utils.getAccountState(
- this._isBlockchainReady(),
- this.props.providerType,
- this.props.injectedProviderName,
- this.props.userAddress,
- );
- }
-}
-
-// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/wallet/wrap_ether_item.tsx b/packages/website/ts/components/wallet/wrap_ether_item.tsx
deleted file mode 100644
index 7de3afbf8..000000000
--- a/packages/website/ts/components/wallet/wrap_ether_item.tsx
+++ /dev/null
@@ -1,230 +0,0 @@
-import { Styles } from '@0x/react-shared';
-import { BigNumber, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-
-import { Blockchain } from 'ts/blockchain';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { Container } from 'ts/components/ui/container';
-import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { colors } from 'ts/style/colors';
-import { BlockchainCallErrs, Side, Token } from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-export interface WrapEtherItemProps {
- userAddress: string;
- networkId: number;
- blockchain: Blockchain;
- dispatcher: Dispatcher;
- userEtherBalanceInWei: BigNumber;
- direction: Side;
- etherToken: Token;
- lastForceTokenStateRefetch: number;
- onConversionSuccessful?: () => void;
- refetchEthTokenStateAsync: () => Promise<void>;
-}
-
-interface WrapEtherItemState {
- currentInputAmount?: BigNumber;
- isEthConversionHappening: boolean;
- errorMsg: React.ReactNode;
-}
-
-const styles: Styles = {
- topLabel: {
- color: colors.black,
- fontSize: 11,
- },
- inputContainer: {
- backgroundColor: colors.white,
- borderBottomRightRadius: 3,
- borderBottomLeftRadius: 3,
- borderTopRightRadius: 3,
- borderTopLeftRadius: 3,
- padding: 4,
- },
- amountInput: {
- height: 34,
- },
- amountInputLabel: {
- paddingTop: 10,
- paddingRight: 10,
- paddingLeft: 5,
- color: colors.grey,
- fontSize: 14,
- },
- amountInputHint: {
- bottom: 18,
- },
- wrapEtherConfirmationButtonLabel: {
- fontSize: 12,
- color: colors.white,
- },
- errorMsg: {
- fontSize: 12,
- marginTop: 4,
- color: colors.red,
- minHeight: 20,
- },
- conversionSpinner: {
- paddingTop: 26,
- },
-};
-
-export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEtherItemState> {
- constructor(props: WrapEtherItemProps) {
- super(props);
- this.state = {
- currentInputAmount: undefined,
- isEthConversionHappening: false,
- errorMsg: null,
- };
- }
- public render(): React.ReactNode {
- const isWrappingEth = this.props.direction === Side.Deposit;
- const topLabelText = isWrappingEth ? 'Convert ETH into WETH 1:1' : 'Convert WETH into ETH 1:1';
- return (
- <Container className="flex" backgroundColor={colors.walletFocusedItemBackground} paddingTop="25px">
- <div>{this._renderIsEthConversionHappeningSpinner()} </div>
- <div className="flex flex-column">
- <div style={styles.topLabel}>{topLabelText}</div>
- <div className="flex items-center">
- <div style={styles.inputContainer}>
- {isWrappingEth ? (
- <EthAmountInput
- amount={this.state.currentInputAmount}
- hintText="0.00"
- onChange={this._onValueChange.bind(this)}
- shouldCheckBalance={true}
- shouldShowIncompleteErrs={false}
- shouldShowErrs={false}
- shouldShowUnderline={false}
- style={styles.amountInput}
- labelStyle={styles.amountInputLabel}
- inputHintStyle={styles.amountInputHint}
- onErrorMsgChange={this._onErrorMsgChange.bind(this)}
- />
- ) : (
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- token={this.props.etherToken}
- shouldShowIncompleteErrs={false}
- shouldCheckBalance={true}
- shouldCheckAllowance={false}
- onChange={this._onValueChange.bind(this)}
- amount={this.state.currentInputAmount}
- hintText="0.00"
- shouldShowErrs={false}
- shouldShowUnderline={false}
- style={styles.amountInput}
- labelStyle={styles.amountInputLabel}
- inputHintStyle={styles.amountInputHint}
- onErrorMsgChange={this._onErrorMsgChange.bind(this)}
- />
- )}
- </div>
- <div>{this._renderWrapEtherConfirmationButton()}</div>
- </div>
-
- {this._renderErrorMsg()}
- </div>
- </Container>
- );
- }
- private _onValueChange(_isValid: boolean, amount?: BigNumber): void {
- this.setState({
- currentInputAmount: amount,
- });
- }
- private _onErrorMsgChange(errorMsg: React.ReactNode): void {
- this.setState({
- errorMsg,
- });
- }
- private _renderIsEthConversionHappeningSpinner(): React.ReactElement<{}> {
- const visibility = this.state.isEthConversionHappening ? 'visible' : 'hidden';
- const style: React.CSSProperties = { ...styles.conversionSpinner, visibility };
- return (
- <div className="pl3 pr2" style={style}>
- <i className="zmdi zmdi-spinner zmdi-hc-spin" />
- </div>
- );
- }
- private _renderWrapEtherConfirmationButton(): React.ReactElement<{}> {
- const isWrappingEth = this.props.direction === Side.Deposit;
- const labelText = isWrappingEth ? 'wrap' : 'unwrap';
- return (
- <div className="pl1 pr3">
- <FlatButton
- backgroundColor={colors.wrapEtherConfirmationButton}
- label={labelText}
- style={{ zIndex: 0 }}
- labelStyle={styles.wrapEtherConfirmationButtonLabel}
- onClick={this._wrapEtherConfirmationActionAsync.bind(this)}
- disabled={this.state.isEthConversionHappening}
- />
- </div>
- );
- }
- private _renderErrorMsg(): React.ReactNode {
- return <div style={styles.errorMsg}>{this.state.errorMsg}</div>;
- }
- private async _wrapEtherConfirmationActionAsync(): Promise<void> {
- this.setState({
- isEthConversionHappening: true,
- });
- const etherToken = this.props.etherToken;
- const amountToConvert = this.state.currentInputAmount;
- const ethAmount = Web3Wrapper.toUnitAmount(amountToConvert, constants.DECIMAL_PLACES_ETH).toString();
- const tokenAmount = Web3Wrapper.toUnitAmount(amountToConvert, etherToken.decimals).toString();
- try {
- if (this.props.direction === Side.Deposit) {
- await this.props.blockchain.convertEthToWrappedEthTokensAsync(etherToken.address, amountToConvert);
- this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount} ETH to WETH`);
- analytics.track('Wrap ETH Success', {
- amount: ethAmount,
- });
- } else {
- await this.props.blockchain.convertWrappedEthTokensToEthAsync(etherToken.address, amountToConvert);
- this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount} WETH to ETH`);
- analytics.track('Unwrap WETH Success', {
- amount: tokenAmount,
- });
- }
- await this.props.refetchEthTokenStateAsync();
- this.props.onConversionSuccessful();
- } catch (err) {
- const errMsg = `${err}`;
- if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- } else if (!utils.didUserDenyWeb3Request(errMsg)) {
- logUtils.log(`Unexpected error encountered: ${err}`);
- logUtils.log(err.stack);
- if (this.props.direction === Side.Deposit) {
- this.props.dispatcher.showFlashMessage('Failed to wrap your ETH. Please try again.');
- analytics.track('Wrap ETH Failure', {
- amount: ethAmount,
- });
- } else {
- this.props.dispatcher.showFlashMessage('Failed to unwrap your WETH. Please try again.');
- analytics.track('Unwrap WETH Failed', {
- amount: tokenAmount,
- });
- }
- errorReporter.report(err);
- }
- }
- this.setState({
- isEthConversionHappening: false,
- });
- }
-}