Commit 2b15979e authored by Ian Lapham's avatar Ian Lapham Committed by GitHub

Hide dark and advanced, fix bug on empty balances (#660)

* Hide dark and advanced, fix bug on empty balances

* remove unused imports

* change default dark mode

* add warning on main net

* remove unused imports
parent 6211dff0
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import { useTranslation } from 'react-i18next'
import { transparentize } from 'polished'
import QR from '../../assets/svg/QR.svg'
......@@ -32,23 +31,6 @@ const InputContainer = styled.div`
flex: 1;
`
const LabelRow = styled.div`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
color: ${({ theme }) => theme.doveGray};
font-size: 0.75rem;
line-height: 1rem;
padding: 0.75rem 1rem;
`
const LabelContainer = styled.div`
flex: 1 1 auto;
width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
`
const InputRow = styled.div`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
......@@ -82,9 +64,7 @@ const QRWrapper = styled.div`
border-radius: 8px;
`
export default function AddressInputPanel({ title, initialInput = '', onChange, onError}) {
const { t } = useTranslation()
export default function AddressInputPanel({ initialInput = '', onChange, onError }) {
const { library } = useWeb3React()
const [input, setInput] = useState(initialInput.address ? initialInput.address : '')
......@@ -191,9 +171,9 @@ export default function AddressInputPanel({ title, initialInput = '', onChange,
onChange={onInput}
value={input}
/>
<QRWrapper>
<img src={QR} alt="" />
</QRWrapper>
<QRWrapper>
<img src={QR} alt="" />
</QRWrapper>
</InputRow>
</InputContainer>
</ContainerRow>
......
......@@ -5,10 +5,10 @@ import { parseUnits, parseEther } from '@ethersproject/units'
import { WETH, TradeType, Route, Exchange, Trade, TokenAmount, JSBI, Percent } from '@uniswap/sdk'
import TokenLogo from '../TokenLogo'
import AddressInputPanel from '../AddressInputPanel'
import QuestionHelper from '../Question'
import NumericalInput from '../NumericalInput'
import AdvancedSettings from '../AdvancedSettings'
import AddressInputPanel from '../AddressInputPanel'
import ConfirmationModal from '../ConfirmationModal'
import CurrencyInputPanel from '../CurrencyInputPanel'
import { Link } from '../../theme/components'
......@@ -340,16 +340,24 @@ export default function ExchangePage({ sendingInput = false }) {
}, [])
const MIN_ETHER: TokenAmount = chainId && new TokenAmount(WETH[chainId], JSBI.BigInt(parseEther('.01')))
const maxAmountInput: TokenAmount =
!!userBalances[Field.INPUT] &&
JSBI.greaterThan(
userBalances[Field.INPUT].raw,
tokens[Field.INPUT].equals(WETH[chainId]) ? MIN_ETHER.raw : JSBI.BigInt(0)
)
? tokens[Field.INPUT].equals(WETH[chainId])
? userBalances[Field.INPUT].subtract(MIN_ETHER)
: userBalances[Field.INPUT]
: undefined
let maxAmountInput: TokenAmount
try {
maxAmountInput =
!!userBalances[Field.INPUT] &&
!!tokens[Field.INPUT] &&
WETH[chainId] &&
JSBI.greaterThan(
userBalances[Field.INPUT].raw,
tokens[Field.INPUT].equals(WETH[chainId]) ? MIN_ETHER.raw : JSBI.BigInt(0)
)
? tokens[Field.INPUT].equals(WETH[chainId])
? userBalances[Field.INPUT].subtract(MIN_ETHER)
: userBalances[Field.INPUT]
: undefined
} catch {}
const atMaxAmountInput: boolean =
!!maxAmountInput && !!parsedAmounts[Field.INPUT]
? JSBI.equal(maxAmountInput.raw, parsedAmounts[Field.INPUT].raw)
......@@ -828,8 +836,9 @@ export default function ExchangePage({ sendingInput = false }) {
function _onTokenSelect(address: string) {
const balance = allBalances?.[account]?.[address]
// if no user balance - switch view to a send with swap
const hasBalance = balance && JSBI.greaterThan(JSBI.BigInt(0), balance.raw)
const hasBalance = balance && JSBI.greaterThan(balance.raw, JSBI.BigInt(0))
if (!hasBalance && sending) {
onTokenSelection(Field.INPUT, null)
onTokenSelection(Field.OUTPUT, address)
setSendingWithSwap(true)
} else {
......@@ -965,7 +974,6 @@ export default function ExchangePage({ sendingInput = false }) {
{sending && (
<AutoColumn gap="10px">
<AddressInputPanel
title={''}
onChange={_onRecipient}
onError={error => {
if (error) {
......
import React, { useRef, useEffect, useState } from 'react'
import React, { useRef, useEffect } from 'react'
import styled from 'styled-components'
import { useDarkModeManager } from '../../contexts/LocalStorage'
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import { Link } from '../../theme'
import { darken, transparentize } from 'polished'
import Toggle from 'react-switch'
import { darken } from 'polished'
import { useToggle } from '../../hooks'
......@@ -80,67 +77,8 @@ const MenuItem = styled(Link)`
cursor: pointer;
}
`
const ToggleItem = styled.span`
color: ${({ theme }) => theme.doveGray};
padding: 0.5rem 0.5rem 0.5rem 0.5rem;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
width: 100%;
`
const Divider = styled.span`
width: 100%;
margin-bottom: 0.5rem;
padding-top: 0.5rem;
border-bottom: 1px solid ${({ theme }) => theme.mercuryGray};
`
const StyledToggle = styled(Toggle)`
margin-right: 0.75rem;
.react-switch-bg[style] {
background-color: ${({ theme, checked, showColor }) =>
checked ? theme.connectedGreen : darken(0.05, theme.inputBackground)} !important;
border: 1px solid ${({ theme }) => theme.concreteGray} !important;
}
.react-switch-handle[style] {
background-color: ${({ theme }) => theme.connectedGreen};
box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.93, theme.shadowColor)};
border: 1px solid ${({ theme }) => theme.mercuryGray};
border-color: ${({ theme }) => theme.mercuryGray} !important;
top: 2px !important;
margin-left: 1px;
}
`
const StyledToggleNoColor = styled(Toggle)`
margin-right: 0.75rem;
.react-switch-bg[style] {
background-color: ${({ theme }) => darken(0.05, theme.inputBackground)} !important;
border: 1px solid ${({ theme }) => theme.concreteGray} !important;
}
.react-switch-handle[style] {
background-color: ${({ theme }) => theme.connectedGreen};
box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.93, theme.shadowColor)};
border: 1px solid ${({ theme }) => theme.mercuryGray};
border-color: ${({ theme }) => theme.mercuryGray} !important;
top: 2px !important;
margin-left: 1px;
}
`
const EmojiToggle = styled.span`
font-family: Arial sans-serif;
vertical-align: middle;
text-align: center;
width: 100%;
`
export default function Menu() {
const [isDark, toggleDarkMode] = useDarkModeManager()
const [isAdvanced, toggleAdvanced] = useState(false)
const node = useRef()
const [open, toggle] = useToggle(false)
......@@ -170,10 +108,10 @@ export default function Menu() {
</StyledMenuButton>
{open ? (
<MenuFlyout>
<MenuItem id="link" href="https://uniswap.io/">
<MenuItem id="link" href="https://uniswap.org/">
About
</MenuItem>
<MenuItem id="link" href="https://docs.uniswap.io/">
<MenuItem id="link" href="https://uniswap.org/docs/v2">
Docs
</MenuItem>
<MenuItem id="link" href="https://github.com/Uniswap">
......@@ -182,35 +120,6 @@ export default function Menu() {
<MenuItem id="link" href="https://uniswap.info/">
Stats
</MenuItem>
<Divider></Divider>
<ToggleItem>
<span>Theme</span>
<StyledToggleNoColor
checked={!isDark}
uncheckedIcon={
<EmojiToggle role="img" aria-label="moon">
{/* eslint-disable-line jsx-a11y/accessible-emoji */}
🌙️
</EmojiToggle>
}
checkedIcon={
<EmojiToggle role="img" aria-label="sun">
{/* eslint-disable-line jsx-a11y/accessible-emoji */}
{'☀️'}
</EmojiToggle>
}
onChange={() => toggleDarkMode()}
/>
</ToggleItem>
<ToggleItem>
<span>Advanced</span>
<StyledToggle
checked={isAdvanced}
uncheckedIcon={false}
checkedIcon={false}
onChange={() => toggleAdvanced()}
/>
</ToggleItem>
</MenuFlyout>
) : (
''
......
import React, { useCallback } from 'react'
import { withRouter, NavLink, Link as HistoryLink } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { transparentize, darken } from 'polished'
import { darken } from 'polished'
import { useTranslation } from 'react-i18next'
import { withRouter, NavLink, Link as HistoryLink } from 'react-router-dom'
import { RowBetween } from '../Row'
import QuestionHelper from '../Question'
import { ArrowLeft } from 'react-feather'
import { RowBetween } from '../Row'
import { useBodyKeyDown } from '../../hooks'
import { useBetaMessageManager } from '../../contexts/LocalStorage'
const tabOrder = [
{
path: '/swap',
......@@ -30,35 +28,6 @@ const tabOrder = [
}
]
const BetaMessage = styled.div`
${({ theme }) => theme.flexRowNoWrap}
cursor: pointer;
flex: 1 0 auto;
align-items: center;
position: relative;
padding: 0.5rem 1rem;
padding-right: 2rem;
margin-bottom: 1rem;
border: 1px solid ${({ theme }) => transparentize(0.6, theme.wisteriaPurple)};
background-color: ${({ theme }) => transparentize(0.9, theme.wisteriaPurple)};
border-radius: 1rem;
font-size: 0.75rem;
line-height: 1rem;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: ${({ theme }) => theme.wisteriaPurple};
&:after {
content: '✕';
top: 0.5rem;
right: 1rem;
position: absolute;
color: ${({ theme }) => theme.wisteriaPurple};
}
`
const Tabs = styled.div`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
......@@ -110,8 +79,6 @@ const ArrowLink = styled(ArrowLeft)`
function NavigationTabs({ location: { pathname }, history }) {
const { t } = useTranslation()
const [showBetaMessage, dismissBetaMessage] = useBetaMessageManager()
const navigate = useCallback(
direction => {
const tabIndex = tabOrder.findIndex(({ regex }) => pathname.match(regex))
......@@ -164,14 +131,6 @@ function NavigationTabs({ location: { pathname }, history }) {
))}
</Tabs>
)}
{showBetaMessage && (
<BetaMessage onClick={dismissBetaMessage}>
<span role="img" aria-label="warning">
💀
</span>{' '}
{t('betaWarning')}
</BetaMessage>
)}
</>
)
}
......
......@@ -250,7 +250,7 @@ function SearchModal({
})
}, [account, allBalances, allExchanges, sortDirection])
const filteredPairList = useMemo(() => {
const filteredPairList = useMemo(() => {
const isAddress = searchQuery.slice(0, 2) === '0x'
return sortedPairList.filter(exchangeAddress => {
const exchange = allExchanges[exchangeAddress]
......@@ -275,7 +275,7 @@ function SearchModal({
return regexMatches.some(m => m)
})
}, [account, allBalances, allExchanges, allTokens, searchQuery, sortDirection])
}, [allExchanges, allTokens, searchQuery, sortedPairList])
// update the amount shown as filtered list changes
useEffect(() => {
......@@ -347,7 +347,7 @@ function SearchModal({
!INITIAL_TOKENS_CONTEXT[chainId].hasOwnProperty(address) &&
!urlAdded
const zeroBalance = JSBI.equal(JSBI.BigInt(0), balance.raw)
const zeroBalance = balance && JSBI.equal(JSBI.BigInt(0), balance.raw)
return (
<MenuItem key={address} onClick={() => (zeroBalance ? _onTokenSelect(address, true) : _onTokenSelect(address))}>
......
......@@ -281,7 +281,7 @@ export function Updater() {
.filter(tokenAddress => {
const hasValue = !!stateRef.current?.[chainId]?.[account]?.[tokenAddress]?.value
const cachedFetchedAsOf = fetchedAsOfCache.current?.[chainId]?.[account]?.[tokenAddress]
const fetchedAsOf = stateRef.current?.[chainId]?.[account][tokenAddress]?.blockNumber ?? cachedFetchedAsOf
const fetchedAsOf = stateRef.current?.[chainId]?.[account]?.[tokenAddress]?.blockNumber ?? cachedFetchedAsOf
// if there's no value, and it's not being fetched, we need to fetch!
if (!hasValue && typeof cachedFetchedAsOf !== 'number') {
......@@ -459,6 +459,7 @@ export function useAddressBalance(address: string, token: Token): TokenAmount |
stopListening(chainId, address, token.address)
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [chainId, address, startListening, stopListening])
return useMemo(() => formattedValue, [formattedValue])
......
......@@ -178,6 +178,7 @@ export function useTotalSupply(exchange: Exchange) {
* @todo
* fix this
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [exchangeContract])
// on the block make sure we're updated
......
......@@ -7,16 +7,9 @@ const CURRENT_VERSION = 0
const LAST_SAVED = 'LAST_SAVED'
const BETA_MESSAGE_DISMISSED = 'BETA_MESSAGE_DISMISSED'
const GENERAL_DAI__MESSAGE_DISMISSED = 'GENERAL_DAI__MESSAGE_DISMISSED'
const SAI_HOLDER__MESSAGE_DISMISSED = 'SAI_HOLDER__MESSAGE_DISMISSED'
const DARK_MODE = 'DARK_MODE'
const UPDATABLE_KEYS = [
GENERAL_DAI__MESSAGE_DISMISSED,
SAI_HOLDER__MESSAGE_DISMISSED,
BETA_MESSAGE_DISMISSED,
DARK_MODE
]
const UPDATABLE_KEYS = [BETA_MESSAGE_DISMISSED, DARK_MODE]
const UPDATE_KEY = 'UPDATE_KEY'
......@@ -49,9 +42,7 @@ function init() {
const defaultLocalStorage = {
[VERSION]: CURRENT_VERSION,
[BETA_MESSAGE_DISMISSED]: false,
[GENERAL_DAI__MESSAGE_DISMISSED]: false,
[SAI_HOLDER__MESSAGE_DISMISSED]: false,
[DARK_MODE]: true
[DARK_MODE]: false
}
try {
......@@ -91,26 +82,6 @@ export function Updater() {
return null
}
export function useSaiHolderMessageManager() {
const [state, { updateKey }] = useLocalStorageContext()
const dismissSaiHolderMessage = useCallback(() => {
updateKey(SAI_HOLDER__MESSAGE_DISMISSED, true)
}, [updateKey])
return [!state[SAI_HOLDER__MESSAGE_DISMISSED], dismissSaiHolderMessage]
}
export function useGeneralDaiMessageManager() {
const [state, { updateKey }] = useLocalStorageContext()
const dismissGeneralDaiMessage = useCallback(() => {
updateKey(GENERAL_DAI__MESSAGE_DISMISSED, true)
}, [updateKey])
return [!state[GENERAL_DAI__MESSAGE_DISMISSED], dismissGeneralDaiMessage]
}
export function useBetaMessageManager() {
const [state, { updateKey }] = useLocalStorageContext()
......
......@@ -113,7 +113,7 @@ export function useAllTokens(): string[] {
return useMemo(() => {
// hardcode overide weth as ETH
if (state && state[chainId]) {
if (state && state[chainId] && state[chainId][WETH[chainId].address]) {
state[chainId][WETH[chainId].address].symbol = 'ETH'
state[chainId][WETH[chainId].address].name = 'ETH'
}
......
import React, { Suspense, lazy } from 'react'
import styled from 'styled-components'
import { transparentize } from 'polished'
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'
import Header from '../components/Header'
import NavigationTabs from '../components/NavigationTabs'
import Web3ReactManager from '../components/Web3ReactManager'
import { useWeb3React } from '../hooks'
import { isAddress, getAllQueryParams } from '../utils'
const Swap = lazy(() => import('./Swap'))
......@@ -27,6 +29,27 @@ const HeaderWrapper = styled.div`
justify-content: space-between;
`
const BetaMessage = styled.div`
${({ theme }) => theme.flexRowNoWrap}
cursor: pointer;
max-height: 40px;
flex: 1 0 auto;
align-items: center;
position: relative;
padding: 0.5rem 1rem;
margin-bottom: 1rem;
border: 1px solid ${({ theme }) => transparentize(0.6, theme.wisteriaPurple)};
background-color: ${({ theme }) => transparentize(0.9, theme.wisteriaPurple)};
border-radius: 1rem;
font-size: 0.75rem;
line-height: 1rem;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: ${({ theme }) => theme.wisteriaPurple};
`
const BodyWrapper = styled.div`
display: flex;
flex-direction: column;
......@@ -49,6 +72,9 @@ const Body = styled.div`
export default function App() {
const params = getAllQueryParams()
const { chainId } = useWeb3React()
return (
<>
<Suspense fallback={null}>
......@@ -57,6 +83,10 @@ export default function App() {
<Header />
</HeaderWrapper>
<BodyWrapper>
{chainId === 1 && (
<BetaMessage>Incorrect network. This site is intended to be used on Ethereum testnets only.</BetaMessage>
)}
<Body>
<Web3ReactManager>
<BrowserRouter>
......
......@@ -587,8 +587,8 @@ export default function AddLiquidity({ token0, token1 }) {
<RowBetween>
Rate:
<div>
1 {tokens[independentField].symbol} = {route?.midPrice?.toSignificant(6)}
{tokens[dependentField].symbol}
1 {tokens[independentField]?.symbol} = {route?.midPrice?.toSignificant(6)}
{tokens[dependentField]?.symbol}
</div>
</RowBetween>
)}
......
......@@ -29,6 +29,7 @@ import { BigNumber } from 'ethers/utils'
import { splitSignature } from '@ethersproject/bytes'
import { ROUTER_ADDRESSES } from '../../constants'
import { getRouterContract, calculateGasMargin } from '../../utils'
import { TYPE } from '../../theme'
// denominated in seconds
const DEADLINE_FROM_NOW = 60 * 15
......@@ -549,13 +550,13 @@ export default function RemoveLiquidity({ token0, token1 }) {
</Text>
</ButtonPrimary>
</RowBetween>
<Text fontSize={12} color="#565A69" textAlign="center">
<TYPE.italic fontSize={12} color="#565A69" textAlign="center">
{`Output is estimated. You will receive at least ${parsedAmounts[Field.TOKEN0]?.toFixed(6)} ${
tokens[Field.TOKEN0]?.symbol
} and at least ${parsedAmounts[Field.TOKEN1]?.toFixed(6)} ${
tokens[Field.TOKEN1]?.symbol
} or the transaction will revert.`}
</Text>
</TYPE.italic>
</>
)
}
......
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