Commit 71376cf7 authored by Noah Zinsmeister's avatar Noah Zinsmeister

set up eslint and prettier; run prettier

parent da47f33b
{
"semi": false,
"singleQuote": true,
"printWidth": 120
}
......@@ -42,9 +42,18 @@
"build": "react-scripts build",
"build:rinkeby": "REACT_APP_NETWORK_ID=4 REACT_APP_NETWORK='Rinkeby Test Network' yarn build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"lint:base": "yarn eslint './src/**/*.{js,jsx}'",
"format:base": "yarn prettier './src/**/*.{js,jsx,scss}'",
"lint": "yarn lint:base --fix",
"format": "yarn format:base --write",
"check:lint": "yarn lint:base",
"check:format": "yarn format:base --check",
"check:all": "yarn check:lint && yarn check:format"
},
"devDependencies": {
"prettier": "^1.17.0"
},
"devDependencies": {},
"browserslist": [
">0.2%",
"not dead",
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import c from 'classnames';
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import c from 'classnames'
import QrCode from '../QrCode';
import './address-input-panel.scss';
import QrCode from '../QrCode'
import './address-input-panel.scss'
class AddressInputPanel extends Component {
static propTypes = {
title: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.string,
errorMessage: PropTypes.string,
};
errorMessage: PropTypes.string
}
static defaultProps = {
onChange() {},
value: '',
};
value: ''
}
render() {
const {
t,
title,
onChange,
value,
errorMessage,
} = this.props;
const { t, title, onChange, value, errorMessage } = this.props
return (
<div className="currency-input-panel">
<div className={c('currency-input-panel__container address-input-panel__recipient-row', {
'currency-input-panel__container--error': errorMessage,
})}>
<div
className={c('currency-input-panel__container address-input-panel__recipient-row', {
'currency-input-panel__container--error': errorMessage
})}
>
<div className="address-input-panel__input-container">
<div className="currency-input-panel__label-row">
<div className="currency-input-panel__label-container">
<span className="currency-input-panel__label">{title || t("recipientAddress")}</span>
<span className="currency-input-panel__label">{title || t('recipientAddress')}</span>
</div>
</div>
<div className="currency-input-panel__input-row">
<input
type="text"
className={c('address-input-panel__input',{
'address-input-panel__input--error': errorMessage,
className={c('address-input-panel__input', {
'address-input-panel__input--error': errorMessage
})}
placeholder="0x1234..."
onChange={e => onChange(e.target.value)}
......@@ -59,4 +55,4 @@ class AddressInputPanel extends Component {
}
}
export default AddressInputPanel;
export default AddressInputPanel
@import "../../variables.scss";
@import '../../variables.scss';
.contextual-info {
&__summary-wrapper {
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import c from 'classnames';
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import c from 'classnames'
import DropdownBlue from "../../assets/images/dropdown-blue.svg";
import DropupBlue from "../../assets/images/dropup-blue.svg";
import './contextual-info.scss';
import DropdownBlue from '../../assets/images/dropdown-blue.svg'
import DropupBlue from '../../assets/images/dropup-blue.svg'
import './contextual-info.scss'
class ContextualInfo extends Component {
static propTypes = {
openDetailsText: PropTypes.string,
renderTransactionDetails: PropTypes.func,
contextualInfo: PropTypes.string,
isError: PropTypes.bool,
};
isError: PropTypes.bool
}
static defaultProps = {
openDetailsText: 'Transaction Details',
closeDetailsText: 'Hide Details',
renderTransactionDetails() {},
contextualInfo: '',
isError: false,
};
isError: false
}
state = {
showDetails: false,
};
showDetails: false
}
renderDetails() {
if (!this.state.showDetails) {
return null;
return null
}
return (
<div className="contextual-info__details">
{this.props.renderTransactionDetails()}
</div>
);
return <div className="contextual-info__details">{this.props.renderTransactionDetails()}</div>
}
render() {
const {
openDetailsText,
closeDetailsText,
contextualInfo,
isError,
} = this.props;
const { openDetailsText, closeDetailsText, contextualInfo, isError } = this.props
if (contextualInfo) {
return (
<div className={c({ 'contextual-info--error': isError }, 'contextual-info__summary-wrapper')}>
<div>{contextualInfo}</div>
</div>
);
)
}
return [
<div
key="open-details"
className="contextual-info__summary-wrapper contextual-info__open-details-container"
onClick={() => this.setState((prevState) => {
onClick={() =>
this.setState(prevState => {
return { showDetails: !prevState.showDetails }
})}
})
}
>
{!this.state.showDetails ? (
<>
<span>{openDetailsText}</span>
<img src={DropdownBlue} alt='dropdown' />
<img src={DropdownBlue} alt="dropdown" />
</>
) : (
<>
<span>{closeDetailsText}</span>
<img src={DropupBlue} alt='dropup' />
<img src={DropupBlue} alt="dropup" />
</>
)}
</div>,
......@@ -79,4 +72,4 @@ class ContextualInfo extends Component {
}
}
export default ContextualInfo;
export default ContextualInfo
......@@ -9,20 +9,20 @@
&__container {
border-radius: 1.25rem;
box-shadow: 0 0 0 .5px $mercury-gray;
box-shadow: 0 0 0 0.5px $mercury-gray;
background-color: $white;
transition: box-shadow 200ms ease-in-out;
&--error {
box-shadow: 0 0 0 .5px $salmon-red;
box-shadow: 0 0 0 0.5px $salmon-red;
}
&:focus-within {
box-shadow: 0 0 .5px .5px $malibu-blue;
box-shadow: 0 0 0.5px 0.5px $malibu-blue;
}
&--error:focus-within {
box-shadow: 0 0 .5px .5px $salmon-red;
box-shadow: 0 0 0.5px 0.5px $salmon-red;
}
}
......@@ -30,9 +30,9 @@
@extend %row-nowrap;
align-items: center;
color: $dove-gray;
font-size: .75rem;
font-size: 0.75rem;
line-height: 1rem;
padding: .75rem 1rem;
padding: 0.75rem 1rem;
}
&__label-container {
......@@ -44,14 +44,14 @@
}
&__label-description {
opacity: .75;
margin-left: .25rem;
opacity: 0.75;
margin-left: 0.25rem;
}
&__input-row {
@extend %row-nowrap;
align-items: center;
padding: .25rem .85rem .75rem;
padding: 0.25rem 0.85rem 0.75rem;
}
&__input {
......@@ -62,7 +62,7 @@
}
&[type='number'] {
-moz-appearance:textfield;
-moz-appearance: textfield;
}
&::-webkit-outer-spin-button,
......@@ -92,14 +92,14 @@
user-select: none;
&:active {
background-color: rgba($zumthor-blue, .8);
background-color: rgba($zumthor-blue, 0.8);
}
&--selected {
background-color: $concrete-gray;
border-color: $mercury-gray;
color: $black;
padding: 0 .5rem;
padding: 0 0.5rem;
.currency-input-panel__dropdown-icon {
background-image: url(../../assets/images/dropdown.svg);
......@@ -128,18 +128,18 @@
user-select: none;
&--pending {
line-height: .9;
line-height: 0.9;
.loader {
height: .5rem;
width: .5rem;
height: 0.5rem;
width: 0.5rem;
}
}
}
&__dropdown-icon {
height: 1rem;
width: .75rem;
margin-left: .7rem;
width: 0.75rem;
margin-left: 0.7rem;
background-image: url(../../assets/images/dropdown-blue.svg);
background-repeat: no-repeat;
background-size: contain;
......@@ -147,13 +147,12 @@
}
&__selected-token-logo {
margin-right: .4rem;
margin-right: 0.4rem;
border-radius: 1rem;
object-fit: contain;
}
}
.token-modal {
background-color: $white;
position: relative;
......@@ -176,7 +175,7 @@
}
&__search-icon {
margin-right: .2rem;
margin-right: 0.2rem;
}
&__token-list {
......@@ -189,7 +188,7 @@
@extend %row-nowrap;
align-items: center;
padding: 1rem 1.5rem;
margin: .25rem .5rem;
margin: 0.25rem 0.5rem;
justify-content: space-between;
cursor: pointer;
user-select: none;
......@@ -235,7 +234,7 @@
justify-content: center;
background-color: $malibu-blue;
&:hover {
background-color: lighten($malibu-blue, 1)
background-color: lighten($malibu-blue, 1);
}
&:active {
......@@ -253,7 +252,7 @@
color: $dove-gray;
}
@media only screen and (min-width : 768px) {
@media only screen and (min-width: 768px) {
max-width: 560px;
max-height: 768px;
position: absolute;
......@@ -269,7 +268,6 @@
}
}
.token-modal-appear {
bottom: 0;
}
......
This diff is collapsed.
@import "../../variables.scss";
@import '../../variables.scss';
.header {
@extend %col-nowrap;
&__top {
@extend %row-nowrap;
padding: 1.25rem .75rem;
padding: 1.25rem 0.75rem;
align-items: center;
border-bottom: 1px solid $concrete-gray;
}
......@@ -28,22 +28,22 @@
}
&--inactive {
opacity: .5;
opacity: 0.5;
}
&__dialog {
@extend %col-nowrap;
border-radius: .875rem;
border-radius: 0.875rem;
border: 1px solid $mercury-gray;
margin: 1rem .75rem 0 .75rem;
margin: 1rem 0.75rem 0 0.75rem;
padding: 1.5rem 1rem;
text-align: center;
display: none;
&__description {
font-size: .75rem;
font-size: 0.75rem;
color: $dove-gray;
margin-top: .4rem;
margin-top: 0.4rem;
}
&--disconnected {
......@@ -68,7 +68,7 @@
}
}
@media only screen and (min-width : 768px) {
@media only screen and (min-width: 768px) {
//position: fixed;
top: 0px;
left: 0px;
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import classnames from 'classnames';
import UAParser from 'ua-parser-js';
import { withNamespaces } from 'react-i18next';
import Logo from '../Logo';
import CoinbaseWalletLogo from '../../assets/images/coinbase-wallet-logo.png';
import TrustLogo from '../../assets/images/trust-wallet-logo.svg';
import BraveLogo from '../../assets/images/brave-logo.svg';
import MetamaskLogo from '../../assets/images/metamask-logo.svg';
import Web3Status from '../Web3Status';
import "./header.scss";
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import classnames from 'classnames'
import UAParser from 'ua-parser-js'
import { withNamespaces } from 'react-i18next'
import Logo from '../Logo'
import CoinbaseWalletLogo from '../../assets/images/coinbase-wallet-logo.png'
import TrustLogo from '../../assets/images/trust-wallet-logo.svg'
import BraveLogo from '../../assets/images/brave-logo.svg'
import MetamaskLogo from '../../assets/images/metamask-logo.svg'
import Web3Status from '../Web3Status'
import './header.scss'
const links = {
coinbaseWallet: {
......@@ -19,135 +19,132 @@ const links = {
ios: 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455'
},
trust: {
android: 'https://links.trustwalletapp.com/a/key_live_lfvIpVeI9TFWxPCqwU8rZnogFqhnzs4D?&event=openURL&url=https://uniswap.exchange/swap',
ios: 'https://links.trustwalletapp.com/a/key_live_lfvIpVeI9TFWxPCqwU8rZnogFqhnzs4D?&event=openURL&url=https://uniswap.exchange/swap',
android:
'https://links.trustwalletapp.com/a/key_live_lfvIpVeI9TFWxPCqwU8rZnogFqhnzs4D?&event=openURL&url=https://uniswap.exchange/swap',
ios:
'https://links.trustwalletapp.com/a/key_live_lfvIpVeI9TFWxPCqwU8rZnogFqhnzs4D?&event=openURL&url=https://uniswap.exchange/swap'
},
metamask: {
chrome: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
chrome: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn'
},
brave: {
android: 'https://play.google.com/store/apps/details?id=com.brave.browser',
ios: 'https://itunes.apple.com/us/app/brave-browser-fast-adblocker/id1052879175',
},
};
ios: 'https://itunes.apple.com/us/app/brave-browser-fast-adblocker/id1052879175'
}
}
const ua = new UAParser(window.navigator.userAgent);
const ua = new UAParser(window.navigator.userAgent)
function getTrustLink() {
const os = ua.getOS();
const os = ua.getOS()
if (os.name === 'Android') {
return links.trust.android;
return links.trust.android
}
if (os.name === 'iOS') {
return links.trust.ios;
return links.trust.ios
}
}
function getCoinbaseWalletLink() {
const os = ua.getOS();
const os = ua.getOS()
if (os.name === 'Android') {
return links.coinbaseWallet.android;
return links.coinbaseWallet.android
}
if (os.name === 'iOS') {
return links.coinbaseWallet.ios;
return links.coinbaseWallet.ios
}
}
function getBraveLink() {
const os = ua.getOS();
const os = ua.getOS()
if (os.name === 'Mac OS') {
return links.brave.ios;
return links.brave.ios
}
return links.brave.android;
return links.brave.android
}
function getMetamaskLink() {
return links.metamask.chrome;
return links.metamask.chrome
}
function isMobile() {
return ua.getDevice().type === 'mobile';
return ua.getDevice().type === 'mobile'
}
class BlockingWarning extends Component {
render () {
const {
t,
isConnected,
initialized,
networkId,
} = this.props;
let content = [];
render() {
const { t, isConnected, initialized, networkId } = this.props
let content = []
const correctNetworkId = process.env.REACT_APP_NETWORK_ID || 1;
const correctNetwork = process.env.REACT_APP_NETWORK || 'Main Ethereum Network';
const correctNetworkId = process.env.REACT_APP_NETWORK_ID || 1
const correctNetwork = process.env.REACT_APP_NETWORK || 'Main Ethereum Network'
const wrongNetwork = networkId !== correctNetworkId;
const wrongNetwork = networkId !== correctNetworkId
if (wrongNetwork && initialized) {
content = [
<div key="warning-title">{t("wrongNetwork")}</div>,
<div key="warning-title">{t('wrongNetwork')}</div>,
<div key="warning-desc" className="header__dialog__description">
{t("switchNetwork", {correctNetwork})}
</div>,
];
{t('switchNetwork', { correctNetwork })}
</div>
]
}
if (!isConnected && initialized) {
content = [
<div key="warning-title">{t("noWallet")}</div>,
<div key="warning-title">{t('noWallet')}</div>,
<div key="warning-desc" className="header__dialog__description">
{
isMobile()
? t("installWeb3MobileBrowser")
: t("installMetamask")
}
{isMobile() ? t('installWeb3MobileBrowser') : t('installMetamask')}
</div>,
<div key="warning-logos" className="header__download">
{
isMobile()
? (
[
<img alt='coinbase' src={CoinbaseWalletLogo} key="coinbase-wallet" onClick={() => window.open(getCoinbaseWalletLink(), '_blank')} />,
<img alt='trust' src={TrustLogo} key="trust" onClick={() => window.open(getTrustLink(), '_blank')} />
{isMobile()
? [
<img
alt="coinbase"
src={CoinbaseWalletLogo}
key="coinbase-wallet"
onClick={() => window.open(getCoinbaseWalletLink(), '_blank')}
/>,
<img alt="trust" src={TrustLogo} key="trust" onClick={() => window.open(getTrustLink(), '_blank')} />
]
)
: (
[
<img alt='metamask' src={MetamaskLogo} key="metamask" onClick={() => window.open(getMetamaskLink(), '_blank')} />,
<img alt='brave' src={BraveLogo} key="brave" onClick={() => window.open(getBraveLink(), '_blank')} />
: [
<img
alt="metamask"
src={MetamaskLogo}
key="metamask"
onClick={() => window.open(getMetamaskLink(), '_blank')}
/>,
<img alt="brave" src={BraveLogo} key="brave" onClick={() => window.open(getBraveLink(), '_blank')} />
]}
</div>
]
)
}
</div>,
];
}
return (
<div
className={classnames('header__dialog', {
'header__dialog--disconnected': (!isConnected || wrongNetwork) && initialized,
'header__dialog--disconnected': (!isConnected || wrongNetwork) && initialized
})}
>
{content}
</div>
);
)
}
}
function Header (props) {
function Header(props) {
return (
<div className="header">
<BlockingWarning {...props} />
<div
className={classnames('header__top', {
'header--inactive': !props.isConnected,
'header--inactive': !props.isConnected
})}
>
<Logo />
......@@ -162,15 +159,13 @@ function Header (props) {
Header.propTypes = {
currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired,
};
isConnected: PropTypes.bool.isRequired
}
export default connect(
state => ({
export default connect(state => ({
currentAddress: state.web3connect.account,
initialized: state.web3connect.initialized,
isConnected: !!state.web3connect.account,
web3: state.web3connect.web3,
networkId: state.web3connect.networkId,
}),
)(withNamespaces()(Header));
networkId: state.web3connect.networkId
}))(withNamespaces()(Header))
import React from 'react';
import "./logo.scss";
import React from 'react'
import './logo.scss'
export default function Logo(props) {
return (
<div className="logo">
<span role="img" aria-label="logo">🦄</span>
<span role="img" aria-label="logo">
🦄
</span>
</div>
);
)
}
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { CSSTransitionGroup } from 'react-transition-group';
import './modal.scss';
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import { CSSTransitionGroup } from 'react-transition-group'
import './modal.scss'
const modalRoot = document.querySelector('#modal-root');
const modalRoot = document.querySelector('#modal-root')
export default class Modal extends Component {
static propTypes = {
onClose: PropTypes.func.isRequired,
};
onClose: PropTypes.func.isRequired
}
componentDidMount() {
// The portal element is inserted in the DOM tree after
......@@ -28,7 +28,7 @@ export default class Modal extends Component {
setTimeout(() => {
// modalRoot.style.display = 'none';
// modalRoot.removeChild(this.el);
}, 500);
}, 500)
}
render() {
......@@ -46,7 +46,7 @@ export default class Modal extends Component {
</CSSTransitionGroup>
{this.props.children}
</div>,
modalRoot,
);
modalRoot
)
}
}
......@@ -4,9 +4,8 @@
position: relative;
height: 100vh;
width: 100vw;
background-color: rgba($black, .6);
background-color: rgba($black, 0.6);
z-index: 1000;
}
.modal-container-appear {
......
@import "../../variables";
@import '../../variables';
.beta-message {
@extend %row-nowrap;
flex: 1 0 auto;
align-items: center;
position: relative;
padding: .5rem 1rem;
padding: 0.5rem 1rem;
margin-bottom: 1rem;
border: 1px solid rgba($wisteria-purple, .4);
background-color: rgba($wisteria-purple, .1);
border: 1px solid rgba($wisteria-purple, 0.4);
background-color: rgba($wisteria-purple, 0.1);
border-radius: 2rem;
font-size: .75rem;
font-size: 0.75rem;
line-height: 1rem;
text-align: center;
color: $wisteria-purple;
&:after {
content: '✕';
top: .5rem;
top: 0.5rem;
right: 1rem;
position: absolute;
color: $wisteria-purple;
......
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next';
import { dismissBetaMessage } from '../../ducks/app';
import {Tab, Tabs} from "../Tab";
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { withNamespaces } from 'react-i18next'
import { dismissBetaMessage } from '../../ducks/app'
import { Tab, Tabs } from '../Tab'
import './beta-message.scss';
import './beta-message.scss'
class NavigationTabs extends Component {
static propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
push: PropTypes.func.isRequired
}),
className: PropTypes.string,
dismissBetaMessage: PropTypes.func.isRequired,
showBetaMessage: PropTypes.bool.isRequired,
};
showBetaMessage: PropTypes.bool.isRequired
}
constructor(props) {
super(props);
super(props)
this.state = {
selectedPath: this.props.location.pathname,
className: '',
showWarning: true,
};
showWarning: true
}
}
renderTab(name, path, regex) {
const { push } = this.props.history;
return (
<Tab
text={name}
onClick={() => push(path)}
isSelected={regex.test(this.props.location.pathname)}
/>
)
const { push } = this.props.history
return <Tab text={name} onClick={() => push(path)} isSelected={regex.test(this.props.location.pathname)} />
}
render() {
const { t, showBetaMessage, className, dismissBetaMessage } = this.props;
const { t, showBetaMessage, className, dismissBetaMessage } = this.props
return (
<div>
<Tabs className={className}>
{ this.renderTab(t("swap"), '/swap', /swap/) }
{ this.renderTab(t("send"), '/send', /send/) }
{ this.renderTab(t("pool"), '/add-liquidity', /add-liquidity|remove-liquidity|create-exchange/) }
{this.renderTab(t('swap'), '/swap', /swap/)}
{this.renderTab(t('send'), '/send', /send/)}
{this.renderTab(t('pool'), '/add-liquidity', /add-liquidity|remove-liquidity|create-exchange/)}
</Tabs>
{
showBetaMessage && (
{showBetaMessage && (
<div className="beta-message" onClick={dismissBetaMessage}>
<span role='img' aria-label='warning'>💀</span> {t("betaWarning")}
<span role="img" aria-label="warning">
💀
</span>{' '}
{t('betaWarning')}
</div>
)
}
)}
</div>
);
)
}
}
export default withRouter(
connect(
state => ({
showBetaMessage: state.app.showBetaMessage,
showBetaMessage: state.app.showBetaMessage
}),
dispatch => ({
dismissBetaMessage: () => dispatch(dismissBetaMessage()),
}),
dismissBetaMessage: () => dispatch(dismissBetaMessage())
})
)(withNamespaces()(NavigationTabs))
);
)
import React from 'react';
import React from 'react'
import './oversized-panel.scss';
import './oversized-panel.scss'
export default function OversizedPanel(props) {
return (
<div className="oversized-panel">
{ props.hideTop || <div className="oversized-panel__top" /> }
{props.hideTop || <div className="oversized-panel__top" />}
{props.children}
{ props.hideBottom || <div className="oversized-panel__bottom" /> }
{props.hideBottom || <div className="oversized-panel__bottom" />}
</div>
);
)
}
......@@ -5,12 +5,12 @@
background-color: $concrete-gray;
width: calc(100% - 1rem);
margin: 0 auto;
border-radius: .625rem;
border-radius: 0.625rem;
&__top {
content: "";
content: '';
position: absolute;
top: -.5rem;
top: -0.5rem;
left: 0;
height: 1rem;
width: 100%;
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { CSSTransitionGroup } from "react-transition-group";
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { CSSTransitionGroup } from 'react-transition-group'
import Modal from '../Modal';
import QrCodeSVG from '../../assets/images/qr-code.svg';
import QrScanner from '../../libraries/qr-scanner';
import './qr-code.scss';
import Modal from '../Modal'
import QrCodeSVG from '../../assets/images/qr-code.svg'
import QrScanner from '../../libraries/qr-scanner'
import './qr-code.scss'
class QrCode extends Component {
static propTypes = {
onValueReceived: PropTypes.func,
};
onValueReceived: PropTypes.func
}
static defaultProps = {
onValueReceived() {},
};
onValueReceived() {}
}
state = {
videoOpen: false,
stream: null,
};
stream: null
}
componentDidUpdate() {
const { videoOpen, stream } = this.state;
const { videoOpen, stream } = this.state
if (videoOpen && !stream && this.videoRef) {
this.startStreamingVideo(this.videoRef)
} else if (!videoOpen && stream) {
this.setState({stream: null});
this.setState({ stream: null })
}
}
startStreamingVideo(videoRef) {
if (navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({video: { facingMode: 'user'}, audio: false})
.then((stream) => {
videoRef.srcObject = stream;
new QrScanner(videoRef, (val) => {
this.closeVideo();
this.props.onValueReceived(val);
navigator.mediaDevices
.getUserMedia({ video: { facingMode: 'user' }, audio: false })
.then(stream => {
videoRef.srcObject = stream
new QrScanner(videoRef, val => {
this.closeVideo()
this.props.onValueReceived(val)
})
this.setState({
stream: stream.getTracks()[0]
});
})
.catch((error) => {
this.closeVideo();
console.error(error);
});
})
.catch(error => {
this.closeVideo()
console.error(error)
})
}
}
openVideo = () => {
this.setState({videoOpen: true});
this.setState({ videoOpen: true })
}
closeVideo = () => {
if (this.state.stream) {
this.state.stream.stop();
this.state.stream.stop()
}
this.setState({ videoOpen: false, stream: null })
this.videoRef = null
}
this.setState({videoOpen: false, stream: null});
this.videoRef = null;
};
setVideoRef = (element) => {
this.videoRef = element;
setVideoRef = element => {
this.videoRef = element
}
renderQrReader() {
......@@ -80,31 +81,29 @@ class QrCode extends Component {
transitionEnterTimeout={200}
>
<div className="qr-code__modal">
<video
playsInline
muted
autoPlay
ref={this.setVideoRef}
className="qr-code__video"
>
</video>
<video playsInline muted autoPlay ref={this.setVideoRef} className="qr-code__video" />
</div>
</CSSTransitionGroup>
</Modal>
);
)
}
return null;
return null
}
render() {
return [
<img key="icon" src={QrCodeSVG} alt='code' onClick={() => {
this.state.videoOpen ? this.closeVideo() : this.openVideo();
}} />,
<img
key="icon"
src={QrCodeSVG}
alt="code"
onClick={() => {
this.state.videoOpen ? this.closeVideo() : this.openVideo()
}}
/>,
this.renderQrReader()
]
}
}
export default QrCode;
export default QrCode
.qr-code {
&__video {
height: 100%;
......
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import './tab.scss';
import './tab.scss'
export const Tabs = props => {
return (
<div className={classnames("tabs", props.className)}>
{ props.children }
</div>
);
};
return <div className={classnames('tabs', props.className)}>{props.children}</div>
}
export const Tab = props => {
return (
<div
className={classnames("tab", {
'tab--selected': props.isSelected,
className={classnames('tab', {
'tab--selected': props.isSelected
})}
onClick={props.onClick}
>
{ props.text ? <span>{props.text}</span> : null }
{props.text ? <span>{props.text}</span> : null}
</div>
);
};
)
}
Tab.propTypes = {
className: PropTypes.string,
text: PropTypes.string,
isSelected: PropTypes.bool,
onClick: PropTypes.func,
};
onClick: PropTypes.func
}
Tab.defaultProps = {
className: '',
};
className: ''
}
......@@ -6,7 +6,7 @@
height: 2.5rem;
background-color: $concrete-gray;
border-radius: 3rem;
box-shadow: 0 0 0 .5px darken($concrete-gray, 5);
box-shadow: 0 0 0 0.5px darken($concrete-gray, 5);
.tab:first-child {
//margin-left: -1px;
......@@ -35,7 +35,7 @@
&--selected {
background-color: $white;
border-radius: 3rem;
box-shadow: 0 0 .5px .5px $mercury-gray;
box-shadow: 0 0 0.5px 0.5px $mercury-gray;
font-weight: 500;
span {
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import EthereumLogo from '../../assets/images/ethereum-logo.svg';
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import EthereumLogo from '../../assets/images/ethereum-logo.svg'
const RINKEBY_TOKEN_MAP = {
'0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B': '0x0d8775f648430679a709e98d2b0cb6250d2887ef',
'0x2448eE2641d78CC42D7AD76498917359D961A783': '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359',
'0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85': '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
'0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0': '0xd26114cd6ee289accf82350c8d8487fedb8a0c07',
'0xF22e3F33768354c9805d046af3C0926f27741B43': '0xe41d2489571d322189246dafa5ebde1f4699f498',
};
'0xF22e3F33768354c9805d046af3C0926f27741B43': '0xe41d2489571d322189246dafa5ebde1f4699f498'
}
const TOKEN_ICON_API = 'https://raw.githubusercontent.com/TrustWallet/tokens/master/tokens';
const BAD_IMAGES = {};
const TOKEN_ICON_API = 'https://raw.githubusercontent.com/TrustWallet/tokens/master/tokens'
const BAD_IMAGES = {}
export default class TokenLogo extends Component {
static propTypes = {
address: PropTypes.string,
size: PropTypes.string,
className: PropTypes.string,
};
className: PropTypes.string
}
static defaultProps = {
address: '',
size: '1rem',
className: '',
};
className: ''
}
state = {
error: false,
};
error: false
}
render() {
const { address, size, className } = this.props;
const { address, size, className } = this.props
// let path = GenericTokenLogo;
let path = '';
const mainAddress = RINKEBY_TOKEN_MAP[address] ? RINKEBY_TOKEN_MAP[address] : address;
let path = ''
const mainAddress = RINKEBY_TOKEN_MAP[address] ? RINKEBY_TOKEN_MAP[address] : address
if (mainAddress === 'ETH') {
path = EthereumLogo;
path = EthereumLogo
}
if (!this.state.error && !BAD_IMAGES[mainAddress] && mainAddress !== 'ETH') {
path = `${TOKEN_ICON_API}/${mainAddress.toLowerCase()}.png`;
path = `${TOKEN_ICON_API}/${mainAddress.toLowerCase()}.png`
}
if (!path) {
return <div className={className} style={{ width: size, fontSize: size }}><span role='img' aria-label='thinking'>🤔</span></div>
return (
<div className={className} style={{ width: size, fontSize: size }}>
<span role="img" aria-label="thinking">
🤔
</span>
</div>
)
}
return (
<img
alt='images'
alt="images"
src={path}
className={className}
style={{
width: size,
height: size,
height: size
}}
onError={() => {
this.setState({ error: true });
BAD_IMAGES[mainAddress] = true;
this.setState({ error: true })
BAD_IMAGES[mainAddress] = true
}}
/>
);
)
}
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import classnames from 'classnames';
import Jazzicon from 'jazzicon';
import { CSSTransitionGroup } from "react-transition-group";
import { withNamespaces } from 'react-i18next';
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import classnames from 'classnames'
import Jazzicon from 'jazzicon'
import { CSSTransitionGroup } from 'react-transition-group'
import { withNamespaces } from 'react-i18next'
import { ethers } from 'ethers'
import './web3-status.scss';
import Modal from '../Modal';
import './web3-status.scss'
import Modal from '../Modal'
function getEtherscanLink(tx) {
return `https://etherscan.io/tx/${tx}`;
return `https://etherscan.io/tx/${tx}`
}
console.log(ethers)
class Web3Status extends Component {
state = {
isShowingModal: false,
};
isShowingModal: false
}
handleClick = () => {
if (this.props.pending.length && !this.state.isShowingModal) {
this.setState({isShowingModal: true});
this.setState({ isShowingModal: true })
}
}
};
renderPendingTransactions() {
return this.props.pending.map((transaction) => {
return this.props.pending.map(transaction => {
return (
<div
key={transaction}
className={classnames('pending-modal__transaction-row')}
onClick={() => window.open(getEtherscanLink(transaction), '_blank')}
>
<div className="pending-modal__transaction-label">
{transaction}
</div>
<div className="pending-modal__transaction-label">{transaction}</div>
<div className="pending-modal__pending-indicator">
<div className="loader" /> {this.props.t("pending")}
<div className="loader" /> {this.props.t('pending')}
</div>
</div>
);
});
)
})
}
renderModal() {
if (!this.state.isShowingModal) {
return null;
return null
}
return (
......@@ -68,84 +66,82 @@ class Web3Status extends Component {
</div>
</CSSTransitionGroup>
</Modal>
);
)
}
render() {
const { t, address, pending, confirmed } = this.props;
const hasPendingTransactions = !!pending.length;
const hasConfirmedTransactions = !!confirmed.length;
const { t, address, pending, confirmed } = this.props
const hasPendingTransactions = !!pending.length
const hasConfirmedTransactions = !!confirmed.length
return (
<div
className={classnames("web3-status", {
className={classnames('web3-status', {
'web3-status__connected': this.props.isConnected,
'web3-status--pending': hasPendingTransactions,
'web3-status--confirmed': hasConfirmedTransactions,
'web3-status--confirmed': hasConfirmedTransactions
})}
onClick={this.handleClick}
>
<div className="web3-status__text">
{hasPendingTransactions ? getPendingText(pending, t("pending")) : getText(address, t("disconnected")) }
{hasPendingTransactions ? getPendingText(pending, t('pending')) : getText(address, t('disconnected'))}
</div>
<div
className="web3-status__identicon"
ref={el => {
if (!el) {
return;
return
}
if (!address || address.length < 42 || !ethers.utils.isHexString(address)) {
return;
return
}
el.innerHTML = '';
el.appendChild(Jazzicon(16, parseInt(address.slice(2), 16)));
el.innerHTML = ''
el.appendChild(Jazzicon(16, parseInt(address.slice(2), 16)))
}}
/>
{this.renderModal()}
</div>
);
)
}
}
function getPendingText(pendingTransactions, pendingLabel) {
return (
<div className="web3-status__pending-container">
<div className="loader" />
<span key="text">{pendingTransactions.length} {pendingLabel}</span>
<span key="text">
{pendingTransactions.length} {pendingLabel}
</span>
</div>
);
)
}
function getText(text, disconnectedText) {
if (!text || text.length < 42 || !ethers.utils.isHexString(text)) {
return disconnectedText;
return disconnectedText
}
const address = ethers.utils.getAddress(text);
return `${address.substring(0, 6)}...${address.substring(38)}`;
const address = ethers.utils.getAddress(text)
return `${address.substring(0, 6)}...${address.substring(38)}`
}
Web3Status.propTypes = {
isConnected: PropTypes.bool,
address: PropTypes.string,
};
address: PropTypes.string
}
Web3Status.defaultProps = {
isConnected: false,
address: 'Disconnected',
};
address: 'Disconnected'
}
export default connect(
state => {
export default connect(state => {
return {
address: state.web3connect.account,
isConnected: !!(state.web3connect.web3 && state.web3connect.account),
pending: state.web3connect.transactions.pending,
confirmed: state.web3connect.transactions.confirmed,
};
confirmed: state.web3connect.transactions.confirmed
}
)(withNamespaces()(Web3Status));
})(withNamespaces()(Web3Status))
@import "../../variables.scss";
@import '../../variables.scss';
.web3-status {
@extend %row-nowrap;
height: 2rem;
font-size: .9rem;
font-size: 0.9rem;
align-items: center;
border: 1px solid $mercury-gray;
padding: .5rem;
padding: 0.5rem;
border-radius: 2rem;
color: $dove-gray;
font-weight: 400;
......@@ -22,9 +22,9 @@
&__text {
flex: 1 1 auto;
overflow: hidden;
margin-right: .75rem;
margin-left: .25rem;
font-size: .75rem;
margin-right: 0.75rem;
margin-left: 0.25rem;
font-size: 0.75rem;
}
&__pending-container {
......@@ -39,7 +39,6 @@
}
}
.pending-modal {
background-color: $white;
position: relative;
......@@ -80,12 +79,12 @@
color: $royal-blue;
border: 1px solid $royal-blue;
background-color: $zumthor-blue;
padding: .5rem .75rem;;
padding: 0.5rem 0.75rem;
border-radius: 100px;
font-size: .75rem;
font-size: 0.75rem;
& > .loading {
margin-right: .5rem;
margin-right: 0.5rem;
}
}
......@@ -96,7 +95,6 @@
}
}
.pending-modal-appear {
bottom: 0;
}
......
// string literals for actions
// set global web3 object
export const INITIALIZE_GLOBAL_WEB3 = 'INITIALIZE_GLOBAL_WEB3';
export const INITIALIZE_GLOBAL_WEB3 = 'INITIALIZE_GLOBAL_WEB3'
// web3 actions, all set from action creator to reducer to app
export const SET_WEB3_CONNECTION_STATUS = 'WEB3_CONNECTION_STATUS';
export const CHECK_WEB3_CONNECTION = 'CHECK_WEB3_CONNECTION';
export const SET_CURRENT_MASK_ADDRESS = 'SET_CURRENT_MASK_ADDRESS';
export const SET_WEB3_CONNECTION_STATUS = 'WEB3_CONNECTION_STATUS'
export const CHECK_WEB3_CONNECTION = 'CHECK_WEB3_CONNECTION'
export const SET_CURRENT_MASK_ADDRESS = 'SET_CURRENT_MASK_ADDRESS'
export const METAMASK_LOCKED = 'METAMASK_LOCKED';
export const METAMASK_UNLOCKED = 'METAMASK_UNLOCKED';
export const SET_INTERACTION_STATE = 'SET_INTERACTION_STATE';
export const SET_NETWORK_MESSAGE = 'SET_NETWORK_MESSAGE';
export const METAMASK_LOCKED = 'METAMASK_LOCKED'
export const METAMASK_UNLOCKED = 'METAMASK_UNLOCKED'
export const SET_INTERACTION_STATE = 'SET_INTERACTION_STATE'
export const SET_NETWORK_MESSAGE = 'SET_NETWORK_MESSAGE'
export const SET_BLOCK_TIMESTAMP = 'SET_BLOCK_TIMESTAMP';
export const SET_EXCHANGE_TYPE = 'SET_EXCHANGE_TYPE';
export const SET_BLOCK_TIMESTAMP = 'SET_BLOCK_TIMESTAMP'
export const SET_EXCHANGE_TYPE = 'SET_EXCHANGE_TYPE'
// actions to toggle divs
export const TOGGLE_ABOUT = 'TOGGLE_ABOUT';
export const TOGGLE_INVEST = 'TOGGLE_INVEST';
export const TOGGLE_ABOUT = 'TOGGLE_ABOUT'
export const TOGGLE_INVEST = 'TOGGLE_INVEST'
// CONTRACT actions in actions, action creator, reducer
export const FACTORY_CONTRACT_READY = 'FACTORY_CONTRACT_READY';
export const EXCHANGE_CONTRACT_READY = 'EXCHANGE_CONTRACT_READY';
export const TOKEN_CONTRACT_READY = 'TOKEN_CONTRACT_READY';
export const FACTORY_CONTRACT_READY = 'FACTORY_CONTRACT_READY'
export const EXCHANGE_CONTRACT_READY = 'EXCHANGE_CONTRACT_READY'
export const TOKEN_CONTRACT_READY = 'TOKEN_CONTRACT_READY'
// actions for the exchange
export const SET_INPUT_BALANCE = 'SET_INPUT_BALANCE';
export const SET_OUTPUT_BALANCE = 'SET_OUTPUT_BALANCE';
export const SET_INPUT_TOKEN = 'SET_INPUT_TOKEN';
export const SET_OUTPUT_TOKEN = 'SET_OUTPUT_TOKEN';
export const SET_ETH_POOL_1 = 'SET_ETH_POOL_1';
export const SET_ETH_POOL_2 = 'SET_ETH_POOL_2';
export const SET_TOKEN_POOL_1 = 'SET_TOKEN_POOL_1';
export const SET_TOKEN_POOL_2 = 'SET_TOKEN_POOL_2';
export const SET_ALLOWANCE_APPROVAL_STATE = 'SET_ALLOWANCE_APPROVAL_STATE';
export const SET_EXCHANGE_INPUT_VALUE = 'SET_EXCHANGE_INPUT_VALUE';
export const SET_EXCHANGE_OUTPUT_VALUE = 'SET_EXCHANGE_OUTPUT_VALUE';
export const SET_EXCHANGE_RATE = 'SET_EXCHANGE_RATE';
export const SET_EXCHANGE_FEE = 'SET_EXCHANGE_FEE';
export const SET_INVEST_TOKEN = 'SET_INVEST_TOKEN';
export const SET_INVEST_ETH_POOL = 'SET_INVEST_ETH';
export const SET_INVEST_TOKEN_POOL = 'SET_INVEST_TOKENS';
export const SET_INVEST_TOKEN_ALLOWANCE = 'SET_INVEST_TOKEN_ALLOWANCE';
export const SET_INVEST_SHARES = 'SET_INVEST_SHARES';
export const SET_USER_SHARES = 'SET_USER_SHARES';
export const SET_INVEST_TOKEN_BALANCE = 'SET_INVEST_TOKEN_BALANCE';
export const SET_INVEST_ETH_BALANCE = 'SET_INVEST_ETH_BALANCE';
export const SET_INVEST_SHARES_INPUT = 'SET_INVEST_SHARES_INPUT';
export const SET_INVEST_ETH_REQUIRED = 'SET_INVEST_ETH_REQUIRED';
export const SET_INVEST_TOKENS_REQUIRED = 'SET_INVEST_TOKENS_REQUIRED';
export const SET_INVEST_CHECKED = 'SET_INVEST_CHECKED';
export const SET_INPUT_BALANCE = 'SET_INPUT_BALANCE'
export const SET_OUTPUT_BALANCE = 'SET_OUTPUT_BALANCE'
export const SET_INPUT_TOKEN = 'SET_INPUT_TOKEN'
export const SET_OUTPUT_TOKEN = 'SET_OUTPUT_TOKEN'
export const SET_ETH_POOL_1 = 'SET_ETH_POOL_1'
export const SET_ETH_POOL_2 = 'SET_ETH_POOL_2'
export const SET_TOKEN_POOL_1 = 'SET_TOKEN_POOL_1'
export const SET_TOKEN_POOL_2 = 'SET_TOKEN_POOL_2'
export const SET_ALLOWANCE_APPROVAL_STATE = 'SET_ALLOWANCE_APPROVAL_STATE'
export const SET_EXCHANGE_INPUT_VALUE = 'SET_EXCHANGE_INPUT_VALUE'
export const SET_EXCHANGE_OUTPUT_VALUE = 'SET_EXCHANGE_OUTPUT_VALUE'
export const SET_EXCHANGE_RATE = 'SET_EXCHANGE_RATE'
export const SET_EXCHANGE_FEE = 'SET_EXCHANGE_FEE'
export const SET_INVEST_TOKEN = 'SET_INVEST_TOKEN'
export const SET_INVEST_ETH_POOL = 'SET_INVEST_ETH'
export const SET_INVEST_TOKEN_POOL = 'SET_INVEST_TOKENS'
export const SET_INVEST_TOKEN_ALLOWANCE = 'SET_INVEST_TOKEN_ALLOWANCE'
export const SET_INVEST_SHARES = 'SET_INVEST_SHARES'
export const SET_USER_SHARES = 'SET_USER_SHARES'
export const SET_INVEST_TOKEN_BALANCE = 'SET_INVEST_TOKEN_BALANCE'
export const SET_INVEST_ETH_BALANCE = 'SET_INVEST_ETH_BALANCE'
export const SET_INVEST_SHARES_INPUT = 'SET_INVEST_SHARES_INPUT'
export const SET_INVEST_ETH_REQUIRED = 'SET_INVEST_ETH_REQUIRED'
export const SET_INVEST_TOKENS_REQUIRED = 'SET_INVEST_TOKENS_REQUIRED'
export const SET_INVEST_CHECKED = 'SET_INVEST_CHECKED'
export const INSUFFICIENT_BALANCE = 'Insufficient balance';
export const INSUFFICIENT_BALANCE = 'Insufficient balance'
......@@ -2,30 +2,30 @@ const RINKEBY = {
factoryAddress: '0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36',
exchangeAddresses: {
addresses: [
['BAT','0x9B913956036a3462330B0642B20D3879ce68b450'],
['DAI','0x77dB9C915809e7BE439D2AB21032B1b8B58F6891'],
['MKR','0x93bB63aFe1E0180d0eF100D774B473034fd60C36'],
['OMG','0x26C226EBb6104676E593F8A070aD6f25cDa60F8D'],
['BAT', '0x9B913956036a3462330B0642B20D3879ce68b450'],
['DAI', '0x77dB9C915809e7BE439D2AB21032B1b8B58F6891'],
['MKR', '0x93bB63aFe1E0180d0eF100D774B473034fd60C36'],
['OMG', '0x26C226EBb6104676E593F8A070aD6f25cDa60F8D']
// ['ZRX','0xaBD44a1D1b9Fb0F39fE1D1ee6b1e2a14916D067D'],
],
fromToken: {
'0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B': '0x9B913956036a3462330B0642B20D3879ce68b450',
'0x2448eE2641d78CC42D7AD76498917359D961A783': '0x77dB9C915809e7BE439D2AB21032B1b8B58F6891',
'0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85': '0x93bB63aFe1E0180d0eF100D774B473034fd60C36',
'0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0': '0x26C226EBb6104676E593F8A070aD6f25cDa60F8D',
'0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0': '0x26C226EBb6104676E593F8A070aD6f25cDa60F8D'
// '0xF22e3F33768354c9805d046af3C0926f27741B43': '0xaBD44a1D1b9Fb0F39fE1D1ee6b1e2a14916D067D',
},
}
},
tokenAddresses: {
addresses: [
['BAT','0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B'],
['DAI','0x2448eE2641d78CC42D7AD76498917359D961A783'],
['MKR','0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85'],
['OMG','0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0'],
['BAT', '0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B'],
['DAI', '0x2448eE2641d78CC42D7AD76498917359D961A783'],
['MKR', '0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85'],
['OMG', '0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0']
// ['ZRX','0xF22e3F33768354c9805d046af3C0926f27741B43'],
],
},
};
]
}
}
const MAIN = {
factoryAddress: '0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95',
......@@ -73,7 +73,7 @@ const MAIN = {
['WETH', '0xA2881A90Bf33F03E7a3f803765Cd2ED5c8928dFb'],
['XCHF', '0x8dE0d002DC83478f479dC31F76cB0a8aa7CcEa17'],
['ZIL', '0x7dc095A5CF7D6208CC680fA9866F80a53911041a'],
['ZRX', '0xaE76c84C9262Cdb9abc0C2c8888e62Db8E22A0bF'],
['ZRX', '0xaE76c84C9262Cdb9abc0C2c8888e62Db8E22A0bF']
],
fromToken: {
'0x960b236A07cf122663c4303350609A66A7B288C0': '0x077d52B047735976dfdA76feF74d4d988AC25196',
......@@ -118,8 +118,8 @@ const MAIN = {
'0x05f4a42e251f2d52b8ed15E9FEdAacFcEF1FAD27': '0x7dc095A5CF7D6208CC680fA9866F80a53911041a',
'0xE41d2489571d322189246DaFA5ebDe1F4699F498': '0xaE76c84C9262Cdb9abc0C2c8888e62Db8E22A0bF',
'0x3772f9716Cf6D7a09edE3587738AA2af5577483a': '0x5d8888a212d033cff5f2e0ac24ad91a5495bad62',
'0x0cbe2df57ca9191b64a7af3baa3f946fa7df2f25': '0xa1ecdcca26150cf69090280ee2ee32347c238c7b',
},
'0x0cbe2df57ca9191b64a7af3baa3f946fa7df2f25': '0xa1ecdcca26150cf69090280ee2ee32347c238c7b'
}
},
tokenAddresses: {
addresses: [
......@@ -165,25 +165,27 @@ const MAIN = {
['WETH', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'],
['XCHF', '0xB4272071eCAdd69d933AdcD19cA99fe80664fc08'],
['ZIL', '0x05f4a42e251f2d52b8ed15E9FEdAacFcEF1FAD27'],
['ZRX', '0xE41d2489571d322189246DaFA5ebDe1F4699F498'],
],
},
};
['ZRX', '0xE41d2489571d322189246DaFA5ebDe1F4699F498']
]
}
}
const SET_ADDRESSES = 'app/addresses/setAddresses';
const ADD_EXCHANGE = 'app/addresses/addExchange';
const SET_ADDRESSES = 'app/addresses/setAddresses'
const ADD_EXCHANGE = 'app/addresses/addExchange'
const initialState = RINKEBY;
const initialState = RINKEBY
export const addExchange = ({label, exchangeAddress, tokenAddress}) => (dispatch, getState) => {
const { addresses: { tokenAddresses, exchangeAddresses } } = getState();
export const addExchange = ({ label, exchangeAddress, tokenAddress }) => (dispatch, getState) => {
const {
addresses: { tokenAddresses, exchangeAddresses }
} = getState()
if (tokenAddresses.addresses.filter(([ symbol ]) => symbol === label).length) {
return;
if (tokenAddresses.addresses.filter(([symbol]) => symbol === label).length) {
return
}
if (exchangeAddresses.fromToken[tokenAddresses]) {
return;
return
}
dispatch({
......@@ -191,68 +193,62 @@ export const addExchange = ({label, exchangeAddress, tokenAddress}) => (dispatch
payload: {
label,
exchangeAddress,
tokenAddress,
},
});
};
tokenAddress
}
})
}
export const setAddresses = networkId => {
switch(networkId) {
switch (networkId) {
// Main Net
case 1:
case '1':
return {
type: SET_ADDRESSES,
payload: MAIN,
};
payload: MAIN
}
// Rinkeby
case 4:
case '4':
default:
return {
type: SET_ADDRESSES,
payload: RINKEBY,
};
payload: RINKEBY
}
};
}
}
export default (state = initialState, { type, payload }) => {
switch (type) {
case SET_ADDRESSES:
return payload;
return payload
case ADD_EXCHANGE:
return handleAddExchange(state, { payload });
return handleAddExchange(state, { payload })
default:
return state;
return state
}
}
function handleAddExchange(state, { payload }) {
const { label, tokenAddress, exchangeAddress } = payload;
const { label, tokenAddress, exchangeAddress } = payload
if (!label || !tokenAddress || !exchangeAddress) {
return state;
return state
}
return {
...state,
exchangeAddresses: {
...state.exchangeAddresses,
addresses: [
...state.exchangeAddresses.addresses,
[label, exchangeAddress]
],
addresses: [...state.exchangeAddresses.addresses, [label, exchangeAddress]],
fromToken: {
...state.exchangeAddresses.fromToken,
[tokenAddress]: exchangeAddress,
},
[tokenAddress]: exchangeAddress
}
},
tokenAddresses: {
...state.tokenAddresses,
addresses: [
...state.tokenAddresses.addresses,
[label, tokenAddress]
],
},
};
addresses: [...state.tokenAddresses.addresses, [label, tokenAddress]]
}
}
}
const DISMISS_BETA_MESSAGE = 'app/app/dismissBetaMessage';
const DISMISS_BETA_MESSAGE = 'app/app/dismissBetaMessage'
const initialState = {
showBetaMessage: true,
};
showBetaMessage: true
}
export const dismissBetaMessage = () => ({ type: DISMISS_BETA_MESSAGE });
export const dismissBetaMessage = () => ({ type: DISMISS_BETA_MESSAGE })
export default function appReducer(state = initialState, { type, payload }) {
switch (type) {
case DISMISS_BETA_MESSAGE:
return { ...state, showBetaMessage: false };
return { ...state, showBetaMessage: false }
default:
return state;
return state
}
}
import { combineReducers } from 'redux';
import addresses from './addresses';
import app from './app';
import pending from './pending';
import web3connect from './web3connect';
import { combineReducers } from 'redux'
import addresses from './addresses'
import app from './app'
import pending from './pending'
import web3connect from './web3connect'
export default combineReducers({
app,
addresses,
pending,
web3connect,
});
web3connect
})
const ADD_APPROVAL_TX = 'app/send/addApprovalTx';
const ADD_APPROVAL_TX = 'app/send/addApprovalTx'
const getInitialState = () => {
return {
approvals: {},
};
};
approvals: {}
}
}
export const addApprovalTx = ({ tokenAddress, txId }) => ({
type: ADD_APPROVAL_TX,
payload: { tokenAddress, txId },
});
payload: { tokenAddress, txId }
})
export default function sendReducer(state = getInitialState(), { type, payload }) {
switch (type) {
......@@ -17,10 +17,10 @@ export default function sendReducer(state = getInitialState(), { type, payload }
return {
approvals: {
...state.approvals,
[payload.tokenAddress]: payload.txId,
[payload.tokenAddress]: payload.txId
}
}
};
default:
return state;
return state
}
}
This diff is collapsed.
export default function (matchmask = [], minMatchCharLength = 1) {
export default function(matchmask = [], minMatchCharLength = 1) {
let matchedIndices = []
let start = -1
let end = -1
......@@ -10,7 +10,7 @@ export default function (matchmask = [], minMatchCharLength = 1) {
start = i
} else if (!match && start !== -1) {
end = i - 1
if ((end - start) + 1 >= minMatchCharLength) {
if (end - start + 1 >= minMatchCharLength) {
matchedIndices.push([start, end])
}
start = -1
......@@ -18,7 +18,7 @@ export default function (matchmask = [], minMatchCharLength = 1) {
}
// (i-1 - start) + 1 => i - start
if (matchmask[i - 1] && (i - start) >= minMatchCharLength) {
if (matchmask[i - 1] && i - start >= minMatchCharLength) {
matchedIndices.push([start, i - 1])
}
......
export default function (pattern) {
export default function(pattern) {
let mask = {}
let len = pattern.length
......
// eslint-disable-next-line no-useless-escape
const SPECIAL_CHARS_REGEX = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g
export default function (text, pattern, tokenSeparator = / +/g) {
export default function(text, pattern, tokenSeparator = / +/g) {
let regex = new RegExp(pattern.replace(SPECIAL_CHARS_REGEX, '\\$&').replace(tokenSeparator, '|'))
let matches = text.match(regex)
let isMatch = !!matches
......
export default function (pattern, { errors = 0, currentLocation = 0, expectedLocation = 0, distance = 100 }) {
export default function(pattern, { errors = 0, currentLocation = 0, expectedLocation = 0, distance = 100 }) {
const accuracy = errors / pattern.length
const proximity = Math.abs(expectedLocation - currentLocation)
......@@ -7,5 +7,5 @@ export default function (pattern, { errors = 0, currentLocation = 0, expectedLoc
return proximity ? 1.0 : accuracy
}
return accuracy + (proximity / distance)
return accuracy + proximity / distance
}
import bitapScore from './bitap_score';
import matchedIndices from './bitap_matched_indices';
export default function (text, pattern, patternAlphabet, { location = 0, distance = 100, threshold = 0.6, findAllMatches = false, minMatchCharLength = 1 }) {
import bitapScore from './bitap_score'
import matchedIndices from './bitap_matched_indices'
export default function(
text,
pattern,
patternAlphabet,
{ location = 0, distance = 100, threshold = 0.6, findAllMatches = false, minMatchCharLength = 1 }
) {
const expectedLocation = location
// Set starting location at beginning text and initialize the alphabet.
const textLen = text.length
......@@ -63,7 +68,7 @@ export default function (text, pattern, patternAlphabet, { location = 0, distanc
currentLocation: expectedLocation + binMid,
expectedLocation,
distance
});
})
if (score <= currentThreshold) {
binMin = binMid
......@@ -98,7 +103,7 @@ export default function (text, pattern, patternAlphabet, { location = 0, distanc
// Subsequent passes: fuzzy match
if (i !== 0) {
bitArr[j] |= (((lastBitArr[j + 1] | lastBitArr[j]) << 1) | 1) | lastBitArr[j + 1]
bitArr[j] |= ((lastBitArr[j + 1] | lastBitArr[j]) << 1) | 1 | lastBitArr[j + 1]
}
if (bitArr[j] & mask) {
......
import bitapRegexSearch from './bitap_regex_search';
import bitapSearch from './bitap_search';
import patternAlphabet from './bitap_pattern_alphabet';
import bitapRegexSearch from './bitap_regex_search'
import bitapSearch from './bitap_search'
import patternAlphabet from './bitap_pattern_alphabet'
class Bitap {
constructor (pattern, {
constructor(
pattern,
{
// Approximately where in the text is the pattern expected to be found?
location = 0,
// Determines how close the match must be to the fuzzy location (specified above).
......@@ -26,7 +28,8 @@ class Bitap {
findAllMatches = false,
// Minimum number of characters that must be matched before a result is considered a match
minMatchCharLength = 1
}) {
}
) {
this.options = {
location,
distance,
......@@ -45,7 +48,7 @@ class Bitap {
}
}
search (text) {
search(text) {
if (!this.options.isCaseSensitive) {
text = text.toLowerCase()
}
......
module.exports = obj => !Array.isArray ? Object.prototype.toString.call(obj) === '[object Array]' : Array.isArray(obj)
module.exports = obj => (!Array.isArray ? Object.prototype.toString.call(obj) === '[object Array]' : Array.isArray(obj))
import Bitap from'./bitap';
import Bitap from './bitap'
const deepValue = require('./helpers/deep_value')
const isArray = require('./helpers/is_array')
class Fuse {
constructor (list, {
constructor(
list,
{
// Approximately where in the text is the pattern expected to be found?
location = 0,
// Determines how close the match must be to the fuzzy location (specified above).
......@@ -37,7 +39,7 @@ class Fuse {
// The default will search nested paths *ie foo.bar.baz*
getFn = deepValue,
// Default sort function
sortFn = (a, b) => (a.score - b.score),
sortFn = (a, b) => a.score - b.score,
// When true, the search algorithm will search individual words **and** the full string,
// computing the final score as a function of both. Note that when `tokenize` is `true`,
// the `threshold`, `distance`, and `location` are inconsequential for individual tokens.
......@@ -51,7 +53,8 @@ class Fuse {
// Will print to the console. Useful for debugging.
verbose = false
}) {
}
) {
this.options = {
location,
distance,
......@@ -76,18 +79,15 @@ class Fuse {
this.setCollection(list)
}
setCollection (list) {
setCollection(list) {
this.list = list
return list
}
search (pattern) {
search(pattern) {
this._log(`---------\nSearch pattern: "${pattern}"`)
const {
tokenSearchers,
fullSearcher
} = this._prepareSearchers(pattern)
const { tokenSearchers, fullSearcher } = this._prepareSearchers(pattern)
let { weights, results } = this._search(tokenSearchers, fullSearcher)
......@@ -100,7 +100,7 @@ class Fuse {
return this._format(results)
}
_prepareSearchers (pattern = '') {
_prepareSearchers(pattern = '') {
const tokenSearchers = []
if (this.options.tokenize) {
......@@ -116,7 +116,7 @@ class Fuse {
return { tokenSearchers, fullSearcher }
}
_search (tokenSearchers = [], fullSearcher) {
_search(tokenSearchers = [], fullSearcher) {
const list = this.list
const resultMap = {}
const results = []
......@@ -126,17 +126,20 @@ class Fuse {
if (typeof list[0] === 'string') {
// Iterate over every item
for (let i = 0, len = list.length; i < len; i += 1) {
this._analyze({
this._analyze(
{
key: '',
value: list[i],
record: i,
index: i
}, {
},
{
resultMap,
results,
tokenSearchers,
fullSearcher
})
}
)
}
return { weights: null, results }
......@@ -152,7 +155,7 @@ class Fuse {
let key = this.options.keys[j]
if (typeof key !== 'string') {
weights[key.name] = {
weight: (1 - key.weight) || 1
weight: 1 - key.weight || 1
}
if (key.weight <= 0 || key.weight > 1) {
throw new Error('Key weight has to be > 0 and <= 1')
......@@ -164,24 +167,30 @@ class Fuse {
}
}
this._analyze({
this._analyze(
{
key,
value: this.options.getFn(item, key),
record: item,
index: i
}, {
},
{
resultMap,
results,
tokenSearchers,
fullSearcher
})
}
)
}
}
return { weights, results }
}
_analyze ({ key, arrayIndex = -1, value, record, index }, { tokenSearchers = [], fullSearcher = [], resultMap = {}, results = [] }) {
_analyze(
{ key, arrayIndex = -1, value, record, index },
{ tokenSearchers = [], fullSearcher = [], resultMap = {}, results = [] }
) {
// Check if the texvaluet can be searched
if (value === undefined || value === null) {
return
......@@ -250,7 +259,8 @@ class Fuse {
this._log('Score average:', finalScore)
let checkTextMatches = (this.options.tokenize && this.options.matchAllTokens) ? numTextMatches >= tokenSearchers.length : true
let checkTextMatches =
this.options.tokenize && this.options.matchAllTokens ? numTextMatches >= tokenSearchers.length : true
this._log(`\nCheck Matches: ${checkTextMatches}`)
......@@ -272,13 +282,15 @@ class Fuse {
// Add it to the raw result list
resultMap[index] = {
item: record,
output: [{
output: [
{
key,
arrayIndex,
value,
score: finalScore,
matchedIndices: mainSearchResult.matchedIndices
}]
}
]
}
results.push(resultMap[index])
......@@ -286,23 +298,26 @@ class Fuse {
}
} else if (isArray(value)) {
for (let i = 0, len = value.length; i < len; i += 1) {
this._analyze({
this._analyze(
{
key,
arrayIndex: i,
value: value[i],
record,
index
}, {
},
{
resultMap,
results,
tokenSearchers,
fullSearcher
})
}
)
}
}
}
_computeScore (weights, results) {
_computeScore(weights, results) {
this._log('\n\nComputing score:\n')
for (let i = 0, len = results.length; i < len; i += 1) {
......@@ -314,7 +329,7 @@ class Fuse {
for (let j = 0; j < scoreLen; j += 1) {
let weight = weights ? weights[output[j].key].weight : 1
let score = weight === 1 ? output[j].score : (output[j].score || 0.001)
let score = weight === 1 ? output[j].score : output[j].score || 0.001
let nScore = score * weight
if (weight !== 1) {
......@@ -331,12 +346,12 @@ class Fuse {
}
}
_sort (results) {
_sort(results) {
this._log('\n\nSorting....')
results.sort(this.options.sortFn)
}
_format (results) {
_format(results) {
const finalOutput = []
if (this.options.verbose) {
......@@ -404,7 +419,7 @@ class Fuse {
return finalOutput
}
_log () {
_log() {
if (this.options.verbose) {
console.log(...arguments)
}
......
export function retry(func, retryCount=5) {
export function retry(func, retryCount = 5) {
return new Promise((resolve, reject) => {
func().then((...args) => {
resolve(...args);
}, () => {
func().then(
(...args) => {
resolve(...args)
},
() => {
if (retryCount === 0) {
return reject();
return reject()
}
setTimeout(() => retry(func, retryCount - 1).then(resolve, reject), 50);
});
});
setTimeout(() => retry(func, retryCount - 1).then(resolve, reject), 50)
}
)
})
}
export default function promisify(web3, methodName, ...args) {
return new Promise((resolve, reject) => {
if (!web3) {
reject(new Error('No Web3 object'));
return;
reject(new Error('No Web3 object'))
return
}
const method = web3.eth[methodName];
const method = web3.eth[methodName]
if (!method) {
reject(new Error(`Cannot find web3.eth.${methodName}`));
return;
reject(new Error(`Cannot find web3.eth.${methodName}`))
return
}
method(...args, (error, data) => {
if (error) {
reject(error);
return;
reject(error)
return
}
resolve(data);
resolve(data)
})
})
});
}
import promisify from "./web3-promisfy";
import promisify from './web3-promisfy'
export function getBlockDeadline(web3, deadline) {
return new Promise(async (resolve, reject) => {
const blockNumber = await promisify(web3, 'getBlockNumber');
const blockNumber = await promisify(web3, 'getBlockNumber')
if (!blockNumber && blockNumber !== 0) {
return reject();
return reject()
}
const block = await promisify(web3, 'getBlock', blockNumber);
const block = await promisify(web3, 'getBlock', blockNumber)
if (!block) {
return reject();
return reject()
}
resolve(block.timestamp + deadline);
});
resolve(block.timestamp + deadline)
})
}
import i18n from "i18next";
import Backend from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { reactI18nextModule } from "react-i18next";
import i18n from 'i18next'
import Backend from 'i18next-xhr-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
import { reactI18nextModule } from 'react-i18next'
const resources = {
loadPath: `./locales/{{lng}}.json`
......@@ -20,13 +20,13 @@ i18n
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
backend: resources,
fallbackLng: "en",
fallbackLng: 'en',
keySeparator: false,
interpolation: {
escapeValue: false
}
});
})
export default i18n;
export default i18n
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import ReactGA from 'react-ga';
import './i18n';
import App from './pages/App';
import store from './store';
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import ReactGA from 'react-ga'
import './i18n'
import App from './pages/App'
import store from './store'
import './index.scss';
import './index.scss'
if (process.env.NODE_ENV === 'development') {
// ReactGA.initialize('UA-128182339-02');
} else {
ReactGA.initialize('UA-128182339-1');
ReactGA.initialize('UA-128182339-1')
}
ReactGA.pageview(window.location.pathname + window.location.search);
ReactGA.pageview(window.location.pathname + window.location.search)
window.addEventListener('load', function() {
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root')
);
});
</Provider>,
document.getElementById('root')
)
})
@import url('https://rsms.me/inter/inter-ui.css');
@import "./variables.scss";
@import './variables.scss';
html, body {
html,
body {
margin: 0;
padding: 0;
font-family: "Inter UI", sans-serif;
font-family: 'Inter UI', sans-serif;
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
......@@ -22,7 +23,7 @@ html, body {
background-color: $white;
z-index: 100;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
@media only screen and (min-width : 768px) {
@media only screen and (min-width: 768px) {
justify-content: center;
align-items: center;
}
......@@ -40,13 +41,17 @@ html, body {
border: 1px solid transparent; /* Light grey */
border-top: 1px solid $royal-blue; /* Blue */
border-radius: 50%;
width: .75rem;
height: .75rem;
margin-right: .25rem;
width: 0.75rem;
height: 0.75rem;
margin-right: 0.25rem;
animation: spin 1s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
This diff is collapsed.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom';
import MediaQuery from 'react-responsive';
import { Web3Connect, startWatching, initialize } from '../ducks/web3connect';
import { setAddresses } from '../ducks/addresses';
import Header from '../components/Header';
import Swap from './Swap';
import Send from './Send';
import Pool from './Pool';
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'
import MediaQuery from 'react-responsive'
import { Web3Connect, startWatching, initialize } from '../ducks/web3connect'
import { setAddresses } from '../ducks/addresses'
import Header from '../components/Header'
import Swap from './Swap'
import Send from './Send'
import Pool from './Pool'
import './App.scss';
import './App.scss'
class App extends Component {
componentWillMount() {
const { initialize, startWatching} = this.props;
initialize().then(startWatching);
};
const { initialize, startWatching } = this.props
initialize().then(startWatching)
}
componentWillUpdate() {
const { web3, setAddresses } = this.props;
const { web3, setAddresses } = this.props
if (this.hasSetNetworkId || !web3 || !web3.eth || !web3.eth.net || !web3.eth.net.getId) {
return;
return
}
web3.eth.net.getId((err, networkId) => {
if (!err && !this.hasSetNetworkId) {
setAddresses(networkId);
this.hasSetNetworkId = true;
setAddresses(networkId)
this.hasSetNetworkId = true
}
});
})
}
render() {
if (!this.props.initialized) {
return <noscript />;
return <noscript />
}
return (
......@@ -56,7 +56,7 @@ class App extends Component {
</Switch>
</BrowserRouter>
</div>
);
)
}
}
......@@ -64,11 +64,11 @@ export default connect(
state => ({
account: state.web3connect.account,
initialized: state.web3connect.initialized,
web3: state.web3connect.web3,
web3: state.web3connect.web3
}),
dispatch => ({
setAddresses: networkId => dispatch(setAddresses(networkId)),
initialize: () => dispatch(initialize()),
startWatching: () => dispatch(startWatching()),
}),
)(App);
startWatching: () => dispatch(startWatching())
})
)(App)
@import "../variables.scss";
@import '../variables.scss';
.app {
&__wrapper {
......
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
const div = document.createElement('div')
ReactDOM.render(<App />, div)
ReactDOM.unmountComponentAtNode(div)
})
This diff is collapsed.
This diff is collapsed.
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { withNamespaces } from 'react-i18next';
import OversizedPanel from "../../components/OversizedPanel";
import Dropdown from "../../assets/images/dropdown-blue.svg";
import Modal from "../../components/Modal";
import {CSSTransitionGroup} from "react-transition-group";
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { withNamespaces } from 'react-i18next'
import OversizedPanel from '../../components/OversizedPanel'
import Dropdown from '../../assets/images/dropdown-blue.svg'
import Modal from '../../components/Modal'
import { CSSTransitionGroup } from 'react-transition-group'
const ADD = 'Add Liquidity';
const REMOVE = 'Remove Liquidity';
const CREATE = 'Create Exchange';
const ADD = 'Add Liquidity'
const REMOVE = 'Remove Liquidity'
const CREATE = 'Create Exchange'
class ModeSelector extends Component {
state = {
isShowingModal: false,
selected: ADD,
};
selected: ADD
}
changeView(view) {
const { history } = this.props;
const { history } = this.props
this.setState({
isShowingModal: false,
selected: view,
});
selected: view
})
switch (view) {
case ADD:
return history.push('/add-liquidity');
return history.push('/add-liquidity')
case REMOVE:
return history.push('/remove-liquidity');
return history.push('/remove-liquidity')
case CREATE:
return history.push('/create-exchange');
return history.push('/create-exchange')
default:
return;
return
}
}
renderModal() {
if (!this.state.isShowingModal) {
return;
return
}
return (
......@@ -52,41 +52,27 @@ class ModeSelector extends Component {
transitionEnterTimeout={200}
>
<div className="pool-modal">
<div
className="pool-modal__item"
onClick={() => this.changeView(ADD)}
>
{this.props.t("addLiquidity")}
<div className="pool-modal__item" onClick={() => this.changeView(ADD)}>
{this.props.t('addLiquidity')}
</div>
<div
className="pool-modal__item"
onClick={() => this.changeView(REMOVE)}
>
{this.props.t("removeLiquidity")}
<div className="pool-modal__item" onClick={() => this.changeView(REMOVE)}>
{this.props.t('removeLiquidity')}
</div>
<div
className="pool-modal__item"
onClick={() => this.changeView(CREATE)}
>
{this.props.t("createExchange")}
<div className="pool-modal__item" onClick={() => this.changeView(CREATE)}>
{this.props.t('createExchange')}
</div>
</div>
</CSSTransitionGroup>
</Modal>
);
)
}
render() {
return (
<OversizedPanel hideTop>
<div
className="pool__liquidity-container"
onClick={() => this.setState({ isShowingModal: true })}
>
<span className="pool__liquidity-label">
{this.props.title}
</span>
<img src={Dropdown} alt='dropdown' />
<div className="pool__liquidity-container" onClick={() => this.setState({ isShowingModal: true })}>
<span className="pool__liquidity-label">{this.props.title}</span>
<img src={Dropdown} alt="dropdown" />
</div>
{this.renderModal()}
</OversizedPanel>
......@@ -94,4 +80,4 @@ class ModeSelector extends Component {
}
}
export default withRouter(withNamespaces()(ModeSelector));
export default withRouter(withNamespaces()(ModeSelector))
This diff is collapsed.
import React, { Component } from 'react';
import Header from '../../components/Header';
import AddLiquidity from './AddLiquidity';
import CreateExchange from './CreateExchange';
import RemoveLiquidity from './RemoveLiquidity';
import { Switch, Route } from 'react-router-dom';
import "./pool.scss";
import MediaQuery from "react-responsive";
import ReactGA from "react-ga";
import React, { Component } from 'react'
import Header from '../../components/Header'
import AddLiquidity from './AddLiquidity'
import CreateExchange from './CreateExchange'
import RemoveLiquidity from './RemoveLiquidity'
import { Switch, Route } from 'react-router-dom'
import './pool.scss'
import MediaQuery from 'react-responsive'
import ReactGA from 'react-ga'
class Pool extends Component {
componentWillMount() {
ReactGA.pageview(window.location.pathname + window.location.search);
ReactGA.pageview(window.location.pathname + window.location.search)
}
render() {
return (
......@@ -25,8 +24,8 @@ class Pool extends Component {
<Route exact path="/create-exchange/:tokenAddress?" component={CreateExchange} />
</Switch>
</div>
);
)
}
}
export default Pool;
export default Pool
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
export default {};
export default {}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment