Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe35ca9db8 | ||
|
|
7801695180 | ||
|
|
5a9034fe95 |
@@ -9,27 +9,29 @@ import { useActiveWeb3React } from '../../hooks'
|
|||||||
const StyledPolling = styled.div`
|
const StyledPolling = styled.div`
|
||||||
position: fixed;
|
position: fixed;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
color: white;
|
|
||||||
transition: opacity 0.25s ease;
|
|
||||||
color: ${({ theme }) => theme.green1};
|
color: ${({ theme }) => theme.green1};
|
||||||
:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||||
display: none;
|
display: none;
|
||||||
`}
|
`}
|
||||||
`
|
`
|
||||||
|
const StyledPollingNumber = styled(TYPE.small)<{ breathe: boolean; hovering: boolean }>`
|
||||||
|
transition: opacity 0.25s ease;
|
||||||
|
opacity: ${({ breathe, hovering }) => (hovering ? 0.7 : breathe ? 1 : 0.2)};
|
||||||
|
:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`
|
||||||
const StyledPollingDot = styled.div`
|
const StyledPollingDot = styled.div`
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
min-height: 8px;
|
min-height: 8px;
|
||||||
min-width: 8px;
|
min-width: 8px;
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
margin-top: 3px;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: ${({ theme }) => theme.green1};
|
background-color: ${({ theme }) => theme.green1};
|
||||||
@@ -67,16 +69,21 @@ export default function Polling() {
|
|||||||
|
|
||||||
const blockNumber = useBlockNumber()
|
const blockNumber = useBlockNumber()
|
||||||
|
|
||||||
const [isMounted, setIsMounted] = useState(true)
|
const [isMounting, setIsMounting] = useState(false)
|
||||||
|
const [isHover, setIsHover] = useState(false)
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
const timer1 = setTimeout(() => setIsMounted(true), 1000)
|
if (!blockNumber) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsMounting(true)
|
||||||
|
const mountingTimer = setTimeout(() => setIsMounting(false), 1000)
|
||||||
|
|
||||||
// this will clear Timeout when component unmount like in willComponentUnmount
|
// this will clear Timeout when component unmount like in willComponentUnmount
|
||||||
return () => {
|
return () => {
|
||||||
setIsMounted(false)
|
clearTimeout(mountingTimer)
|
||||||
clearTimeout(timer1)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[blockNumber] //useEffect will run only one time
|
[blockNumber] //useEffect will run only one time
|
||||||
@@ -85,9 +92,11 @@ export default function Polling() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ExternalLink href={chainId && blockNumber ? getEtherscanLink(chainId, blockNumber.toString(), 'block') : ''}>
|
<ExternalLink href={chainId && blockNumber ? getEtherscanLink(chainId, blockNumber.toString(), 'block') : ''}>
|
||||||
<StyledPolling>
|
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
|
||||||
<TYPE.small style={{ opacity: isMounted ? '0.2' : '0.6' }}>{blockNumber}</TYPE.small>
|
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
|
||||||
<StyledPollingDot>{!isMounted && <Spinner />}</StyledPollingDot>
|
{blockNumber}
|
||||||
|
</StyledPollingNumber>
|
||||||
|
<StyledPollingDot>{isMounting && <Spinner />}</StyledPollingDot>
|
||||||
</StyledPolling>
|
</StyledPolling>
|
||||||
</ExternalLink>
|
</ExternalLink>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,27 +3,33 @@ import { AutoColumn } from '../../components/Column'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { RouteComponentProps } from 'react-router-dom'
|
import { RouteComponentProps } from 'react-router-dom'
|
||||||
import { TYPE, StyledInternalLink, ExternalLink } from '../../theme'
|
import { ExternalLink, StyledInternalLink, TYPE } from '../../theme'
|
||||||
import { RowFixed, RowBetween } from '../../components/Row'
|
import { RowBetween, RowFixed } from '../../components/Row'
|
||||||
import { CardSection, DataCard } from '../../components/earn/styled'
|
import { CardSection, DataCard } from '../../components/earn/styled'
|
||||||
import { ArrowLeft } from 'react-feather'
|
import { ArrowLeft } from 'react-feather'
|
||||||
import { ButtonPrimary } from '../../components/Button'
|
import { ButtonPrimary } from '../../components/Button'
|
||||||
import { ProposalStatus } from './styled'
|
import { ProposalStatus } from './styled'
|
||||||
import { useProposalData, useUserVotesAsOfBlock, ProposalData, useUserDelegatee } from '../../state/governance/hooks'
|
import {
|
||||||
|
ProposalData,
|
||||||
|
ProposalState,
|
||||||
|
useProposalData,
|
||||||
|
useUserDelegatee,
|
||||||
|
useUserVotesAsOfBlock
|
||||||
|
} from '../../state/governance/hooks'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
import ReactMarkdown from 'react-markdown'
|
import ReactMarkdown from 'react-markdown'
|
||||||
import VoteModal from '../../components/vote/VoteModal'
|
import VoteModal from '../../components/vote/VoteModal'
|
||||||
import { TokenAmount, JSBI } from '@uniswap/sdk'
|
import { JSBI, TokenAmount } from '@uniswap/sdk'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { AVERAGE_BLOCK_TIME_IN_SECS, COMMON_CONTRACT_NAMES, UNI, ZERO_ADDRESS } from '../../constants'
|
import { AVERAGE_BLOCK_TIME_IN_SECS, COMMON_CONTRACT_NAMES, UNI, ZERO_ADDRESS } from '../../constants'
|
||||||
import { isAddress, getEtherscanLink } from '../../utils'
|
import { getEtherscanLink, isAddress } from '../../utils'
|
||||||
import { ApplicationModal } from '../../state/application/actions'
|
import { ApplicationModal } from '../../state/application/actions'
|
||||||
import { useModalOpen, useToggleDelegateModal, useToggleVoteModal, useBlockNumber } from '../../state/application/hooks'
|
import { useBlockNumber, useModalOpen, useToggleDelegateModal, useToggleVoteModal } from '../../state/application/hooks'
|
||||||
import DelegateModal from '../../components/vote/DelegateModal'
|
import DelegateModal from '../../components/vote/DelegateModal'
|
||||||
import { GreyCard } from '../../components/Card'
|
|
||||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||||
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||||
import { BigNumber } from 'ethers'
|
import { BigNumber } from 'ethers'
|
||||||
|
import { GreyCard } from '../../components/Card'
|
||||||
|
|
||||||
const PageWrapper = styled(AutoColumn)`
|
const PageWrapper = styled(AutoColumn)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -152,7 +158,7 @@ export default function VotePage({
|
|||||||
availableVotes &&
|
availableVotes &&
|
||||||
JSBI.greaterThan(availableVotes.raw, JSBI.BigInt(0)) &&
|
JSBI.greaterThan(availableVotes.raw, JSBI.BigInt(0)) &&
|
||||||
proposalData &&
|
proposalData &&
|
||||||
proposalData.status === 'active'
|
proposalData.status === ProposalState.Active
|
||||||
|
|
||||||
const uniBalance: TokenAmount | undefined = useTokenBalance(account ?? undefined, chainId ? UNI[chainId] : undefined)
|
const uniBalance: TokenAmount | undefined = useTokenBalance(account ?? undefined, chainId ? UNI[chainId] : undefined)
|
||||||
const userDelegatee: string | undefined = useUserDelegatee()
|
const userDelegatee: string | undefined = useUserDelegatee()
|
||||||
@@ -181,7 +187,9 @@ export default function VotePage({
|
|||||||
<ArrowWrapper to="/vote">
|
<ArrowWrapper to="/vote">
|
||||||
<ArrowLeft size={20} /> All Proposals
|
<ArrowLeft size={20} /> All Proposals
|
||||||
</ArrowWrapper>
|
</ArrowWrapper>
|
||||||
{proposalData && <ProposalStatus status={proposalData?.status ?? ''}>{proposalData?.status}</ProposalStatus>}
|
{proposalData && (
|
||||||
|
<ProposalStatus status={proposalData?.status}>{ProposalState[proposalData?.status]}</ProposalStatus>
|
||||||
|
)}
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<AutoColumn gap="10px" style={{ width: '100%' }}>
|
<AutoColumn gap="10px" style={{ width: '100%' }}>
|
||||||
<TYPE.largeHeader style={{ marginBottom: '.5rem' }}>{proposalData?.title}</TYPE.largeHeader>
|
<TYPE.largeHeader style={{ marginBottom: '.5rem' }}>{proposalData?.title}</TYPE.largeHeader>
|
||||||
@@ -194,7 +202,7 @@ export default function VotePage({
|
|||||||
: ''}
|
: ''}
|
||||||
</TYPE.main>
|
</TYPE.main>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
{proposalData && proposalData.status === 'active' && !showVotingButtons && (
|
{proposalData && proposalData.status === ProposalState.Active && !showVotingButtons && (
|
||||||
<GreyCard>
|
<GreyCard>
|
||||||
<TYPE.black>
|
<TYPE.black>
|
||||||
Only UNI votes that were self delegated or delegated to another address before block{' '}
|
Only UNI votes that were self delegated or delegated to another address before block{' '}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { AutoColumn } from '../../components/Column'
|
import { AutoColumn } from '../../components/Column'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { TYPE, ExternalLink } from '../../theme'
|
import { ExternalLink, TYPE } from '../../theme'
|
||||||
import { RowBetween, RowFixed } from '../../components/Row'
|
import { RowBetween, RowFixed } from '../../components/Row'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { ProposalStatus } from './styled'
|
import { ProposalStatus } from './styled'
|
||||||
@@ -9,14 +9,20 @@ import { ButtonPrimary } from '../../components/Button'
|
|||||||
|
|
||||||
import { Button } from 'rebass/styled-components'
|
import { Button } from 'rebass/styled-components'
|
||||||
import { darken } from 'polished'
|
import { darken } from 'polished'
|
||||||
import { CardSection, DataCard, CardNoise, CardBGImage } from '../../components/earn/styled'
|
import { CardBGImage, CardNoise, CardSection, DataCard } from '../../components/earn/styled'
|
||||||
import { useAllProposalData, ProposalData, useUserVotes, useUserDelegatee } from '../../state/governance/hooks'
|
import {
|
||||||
|
ProposalData,
|
||||||
|
ProposalState,
|
||||||
|
useAllProposalData,
|
||||||
|
useUserDelegatee,
|
||||||
|
useUserVotes
|
||||||
|
} from '../../state/governance/hooks'
|
||||||
import DelegateModal from '../../components/vote/DelegateModal'
|
import DelegateModal from '../../components/vote/DelegateModal'
|
||||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { UNI, ZERO_ADDRESS } from '../../constants'
|
import { UNI, ZERO_ADDRESS } from '../../constants'
|
||||||
import { JSBI, TokenAmount, ChainId } from '@uniswap/sdk'
|
import { ChainId, JSBI, TokenAmount } from '@uniswap/sdk'
|
||||||
import { shortenAddress, getEtherscanLink } from '../../utils'
|
import { getEtherscanLink, shortenAddress } from '../../utils'
|
||||||
import Loader from '../../components/Loader'
|
import Loader from '../../components/Loader'
|
||||||
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
||||||
import { useModalOpen, useToggleDelegateModal } from '../../state/application/hooks'
|
import { useModalOpen, useToggleDelegateModal } from '../../state/application/hooks'
|
||||||
@@ -223,7 +229,7 @@ export default function Vote() {
|
|||||||
<Proposal as={Link} to={'/vote/' + p.id} key={i}>
|
<Proposal as={Link} to={'/vote/' + p.id} key={i}>
|
||||||
<ProposalNumber>{p.id}</ProposalNumber>
|
<ProposalNumber>{p.id}</ProposalNumber>
|
||||||
<ProposalTitle>{p.title}</ProposalTitle>
|
<ProposalTitle>{p.title}</ProposalTitle>
|
||||||
<ProposalStatus status={p.status}>{p.status}</ProposalStatus>
|
<ProposalStatus status={p.status}>{ProposalState[p.status]}</ProposalStatus>
|
||||||
</Proposal>
|
</Proposal>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
import { ProposalState } from '../../state/governance/hooks'
|
||||||
|
|
||||||
const handleColorType = (status?: any, theme?: any) => {
|
const handleColorType = (status?: ProposalState, theme?: any) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'pending':
|
case ProposalState.Pending:
|
||||||
|
case ProposalState.Active:
|
||||||
return theme.blue1
|
return theme.blue1
|
||||||
case 'active':
|
case ProposalState.Succeeded:
|
||||||
return theme.blue1
|
case ProposalState.Executed:
|
||||||
case 'succeeded':
|
|
||||||
return theme.green1
|
return theme.green1
|
||||||
case 'defeated':
|
case ProposalState.Defeated:
|
||||||
return theme.red1
|
return theme.red1
|
||||||
case 'queued':
|
case ProposalState.Queued:
|
||||||
return theme.text3
|
case ProposalState.Canceled:
|
||||||
case 'executed':
|
case ProposalState.Expired:
|
||||||
return theme.green1
|
|
||||||
case 'canceled':
|
|
||||||
return theme.text3
|
|
||||||
case 'expired':
|
|
||||||
return theme.text3
|
|
||||||
default:
|
default:
|
||||||
return theme.text3
|
return theme.text3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalStatus = styled.span<{ status: string }>`
|
export const ProposalStatus = styled.span<{ status: ProposalState }>`
|
||||||
font-size: 0.825rem;
|
font-size: 0.825rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export interface ProposalData {
|
|||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
proposer: string
|
proposer: string
|
||||||
status: string
|
status: ProposalState
|
||||||
forCount: number
|
forCount: number
|
||||||
againstCount: number
|
againstCount: number
|
||||||
startBlock: number
|
startBlock: number
|
||||||
@@ -30,9 +30,16 @@ export interface ProposalData {
|
|||||||
details: ProposalDetail[]
|
details: ProposalDetail[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const enumerateProposalState = (state: number) => {
|
export enum ProposalState {
|
||||||
const proposalStates = ['pending', 'active', 'canceled', 'defeated', 'succeeded', 'queued', 'expired', 'executed']
|
Undetermined = -1,
|
||||||
return proposalStates[state]
|
Pending,
|
||||||
|
Active,
|
||||||
|
Canceled,
|
||||||
|
Defeated,
|
||||||
|
Succeeded,
|
||||||
|
Queued,
|
||||||
|
Expired,
|
||||||
|
Executed
|
||||||
}
|
}
|
||||||
|
|
||||||
// get count of all proposals made
|
// get count of all proposals made
|
||||||
@@ -127,7 +134,7 @@ export function useAllProposalData() {
|
|||||||
title: description?.split(/# |\n/g)[1] || 'Untitled',
|
title: description?.split(/# |\n/g)[1] || 'Untitled',
|
||||||
description: description || 'No description.',
|
description: description || 'No description.',
|
||||||
proposer: allProposals[i]?.result?.proposer,
|
proposer: allProposals[i]?.result?.proposer,
|
||||||
status: enumerateProposalState(allProposalStates[i]?.result?.[0]) ?? 'Undetermined',
|
status: allProposalStates[i]?.result?.[0] ?? ProposalState.Undetermined,
|
||||||
forCount: parseFloat(ethers.utils.formatUnits(allProposals[i]?.result?.forVotes.toString(), 18)),
|
forCount: parseFloat(ethers.utils.formatUnits(allProposals[i]?.result?.forVotes.toString(), 18)),
|
||||||
againstCount: parseFloat(ethers.utils.formatUnits(allProposals[i]?.result?.againstVotes.toString(), 18)),
|
againstCount: parseFloat(ethers.utils.formatUnits(allProposals[i]?.result?.againstVotes.toString(), 18)),
|
||||||
startBlock: parseInt(allProposals[i]?.result?.startBlock?.toString()),
|
startBlock: parseInt(allProposals[i]?.result?.startBlock?.toString()),
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ export function listToTokenMap(list: TokenList): TokenAddressMap {
|
|||||||
})
|
})
|
||||||
?.filter((x): x is TagInfo => Boolean(x)) ?? []
|
?.filter((x): x is TagInfo => Boolean(x)) ?? []
|
||||||
const token = new WrappedTokenInfo(tokenInfo, tags)
|
const token = new WrappedTokenInfo(tokenInfo, tags)
|
||||||
if (tokenMap[token.chainId][token.address] !== undefined) throw Error('Duplicate tokens.')
|
if (tokenMap[token.chainId][token.address] !== undefined) {
|
||||||
|
console.error(new Error(`Duplicate token! ${token.address}`))
|
||||||
|
return tokenMap
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...tokenMap,
|
...tokenMap,
|
||||||
[token.chainId]: {
|
[token.chainId]: {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useFetchListCallback } from '../../hooks/useFetchListCallback'
|
|||||||
import useInterval from '../../hooks/useInterval'
|
import useInterval from '../../hooks/useInterval'
|
||||||
import useIsWindowVisible from '../../hooks/useIsWindowVisible'
|
import useIsWindowVisible from '../../hooks/useIsWindowVisible'
|
||||||
import { AppDispatch } from '../index'
|
import { AppDispatch } from '../index'
|
||||||
import { acceptListUpdate, removeList } from './actions'
|
import { acceptListUpdate } from './actions'
|
||||||
import { useActiveListUrls } from './hooks'
|
import { useActiveListUrls } from './hooks'
|
||||||
import { useAllInactiveTokens } from 'hooks/Tokens'
|
import { useAllInactiveTokens } from 'hooks/Tokens'
|
||||||
import { UNSUPPORTED_LIST_URLS } from 'constants/lists'
|
import { UNSUPPORTED_LIST_URLS } from 'constants/lists'
|
||||||
@@ -35,13 +35,6 @@ export default function Updater(): null {
|
|||||||
// fetch all lists every 10 minutes, but only after we initialize library
|
// fetch all lists every 10 minutes, but only after we initialize library
|
||||||
useInterval(fetchAllListsCallback, library ? 1000 * 60 * 10 : null)
|
useInterval(fetchAllListsCallback, library ? 1000 * 60 * 10 : null)
|
||||||
|
|
||||||
// hot fix for fetching error
|
|
||||||
useEffect(() => {
|
|
||||||
if (lists['https://tokens.coingecko.com/uniswap/all.json']) {
|
|
||||||
dispatch(removeList('https://tokens.coingecko.com/uniswap/all.json'))
|
|
||||||
}
|
|
||||||
}, [dispatch, lists])
|
|
||||||
|
|
||||||
// whenever a list is not loaded and not loading, try again to load it
|
// whenever a list is not loaded and not loading, try again to load it
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Object.keys(lists).forEach(listUrl => {
|
Object.keys(lists).forEach(listUrl => {
|
||||||
|
|||||||
Reference in New Issue
Block a user