Refactor VoteProgress (#70)

This commit is contained in:
Szymon Szlachtowicz 2021-09-14 21:40:13 +02:00 committed by GitHub
parent d1790007c0
commit 98fb2ea515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 57 deletions

View File

@ -5,6 +5,7 @@ import { Provider } from '@ethersproject/providers'
import { Contract } from '@ethersproject/contracts' import { Contract } from '@ethersproject/contracts'
import { Interface } from '@ethersproject/abi' import { Interface } from '@ethersproject/abi'
import { ERC20 } from '../abi' import { ERC20 } from '../abi'
import { createWaku } from '../utils/createWaku'
const ABI = [ const ABI = [
'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)', 'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)',
] ]
@ -23,7 +24,7 @@ type WakuMessageStores = {
export class WakuMessaging { export class WakuMessaging {
protected appName: string protected appName: string
protected waku: Waku protected waku: Waku | undefined
public tokenAddress: string public tokenAddress: string
protected provider: Provider protected provider: Provider
protected chainId = 0 protected chainId = 0
@ -34,10 +35,10 @@ export class WakuMessaging {
protected constructor( protected constructor(
appName: string, appName: string,
tokenAddress: string, tokenAddress: string,
waku: Waku,
provider: Provider, provider: Provider,
chainId: number, chainId: number,
multicall: string multicall: string,
waku?: Waku
) { ) {
this.appName = appName this.appName = appName
this.tokenAddress = tokenAddress this.tokenAddress = tokenAddress
@ -48,18 +49,19 @@ export class WakuMessaging {
} }
public cleanUp() { public cleanUp() {
this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics)) this.observers.forEach((observer) => this?.waku?.relay.deleteObserver(observer.callback, observer.topics))
this.wakuMessages = {} this.wakuMessages = {}
} }
protected async setObserver() { protected async setObserver() {
this.waku = await createWaku(this.waku)
await Promise.all( await Promise.all(
Object.values(this.wakuMessages).map(async (msgObj) => { Object.values(this.wakuMessages).map(async (msgObj) => {
const storeMessages = await this.waku?.store.queryHistory([msgObj.topic]) const storeMessages = await this.waku?.store.queryHistory([msgObj.topic])
if (storeMessages) { if (storeMessages) {
msgObj.updateFunction(storeMessages) msgObj.updateFunction(storeMessages)
} }
this.waku.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic]) this?.waku?.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic])
this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [msgObj.topic] }) this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [msgObj.topic] })
}) })
) )

View File

@ -21,12 +21,12 @@ export class WakuPolling extends WakuMessaging {
protected constructor( protected constructor(
appName: string, appName: string,
tokenAddress: string, tokenAddress: string,
waku: Waku,
provider: Provider, provider: Provider,
chainId: number, chainId: number,
multicall: string multicall: string,
waku?: Waku
) { ) {
super(appName, tokenAddress, waku, provider, chainId, multicall) super(appName, tokenAddress, provider, chainId, multicall, waku)
this.wakuMessages['pollInit'] = { this.wakuMessages['pollInit'] = {
topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`, topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`,
hashMap: {}, hashMap: {},
@ -59,14 +59,7 @@ export class WakuPolling extends WakuMessaging {
waku?: Waku waku?: Waku
) { ) {
const network = await provider.getNetwork() const network = await provider.getNetwork()
const wakuPolling = new WakuPolling( const wakuPolling = new WakuPolling(appName, tokenAddress, provider, network.chainId, multicall, waku)
appName,
tokenAddress,
await createWaku(waku),
provider,
network.chainId,
multicall
)
return wakuPolling return wakuPolling
} }

View File

@ -19,12 +19,12 @@ export class WakuVoting extends WakuMessaging {
appName: string, appName: string,
votingContract: Contract, votingContract: Contract,
token: string, token: string,
waku: Waku,
provider: Provider, provider: Provider,
chainId: number, chainId: number,
multicallAddress: string multicallAddress: string,
waku?: Waku
) { ) {
super(appName, token, waku, provider, chainId, multicallAddress) super(appName, token, provider, chainId, multicallAddress, waku)
this.votingContract = votingContract this.votingContract = votingContract
this.wakuMessages['vote'] = { this.wakuMessages['vote'] = {
topic: `/${this.appName}/waku-voting/votes/proto/`, topic: `/${this.appName}/waku-voting/votes/proto/`,
@ -38,6 +38,7 @@ export class WakuVoting extends WakuMessaging {
this.wakuMessages['vote'] this.wakuMessages['vote']
), ),
} }
this.setObserver()
} }
public static async create( public static async create(
@ -50,15 +51,7 @@ export class WakuVoting extends WakuMessaging {
const network = await provider.getNetwork() const network = await provider.getNetwork()
const votingContract = new Contract(contractAddress, VotingContract.abi, provider) const votingContract = new Contract(contractAddress, VotingContract.abi, provider)
const tokenAddress = await votingContract.token() const tokenAddress = await votingContract.token()
return new WakuVoting( return new WakuVoting(appName, votingContract, tokenAddress, provider, network.chainId, multicall, waku)
appName,
votingContract,
tokenAddress,
await createWaku(waku),
provider,
network.chainId,
multicall
)
} }
public async createVote( public async createVote(

View File

@ -19,6 +19,7 @@ export function Proposal({ wakuVoting }: ProposalProps) {
const interval = setInterval(async () => { const interval = setInterval(async () => {
setVotes(await wakuVoting.getVotingRooms()) setVotes(await wakuVoting.getVotingRooms())
}, 10000) }, 10000)
wakuVoting.getVotingRooms().then((e) => setVotes(e))
return () => clearInterval(interval) return () => clearInterval(interval)
}, []) }, [])

View File

@ -11,16 +11,26 @@ interface ProposalCardProps {
heading: string heading: string
text: string text: string
address: string address: string
mobileVersion?: boolean
vote?: number vote?: number
voteWinner?: number voteWinner?: number
hideModalFunction?: (val: boolean) => void hideModalFunction?: (val: boolean) => void
} }
export function ProposalCard({ id, heading, text, address, vote, voteWinner, theme }: ProposalCardProps) { export function ProposalCard({
id,
heading,
text,
address,
vote,
voteWinner,
theme,
mobileVersion,
}: ProposalCardProps) {
const history = useHistory() const history = useHistory()
return ( return (
<Card onClick={() => history.push(`/votingRoom/${id.toString}`)}> <Card onClick={() => mobileVersion && history.push(`/votingRoom/${id.toString}`)}>
<ProposalInfo heading={heading} text={text} address={address} /> <ProposalInfo heading={heading} text={text} address={address} />
<ProposalVote vote={vote} voteWinner={voteWinner} address={address} heading={heading} theme={theme} /> <ProposalVote vote={vote} voteWinner={voteWinner} address={address} heading={heading} theme={theme} />
</Card> </Card>

View File

@ -1,6 +1,6 @@
import React from 'react' import React, { useRef } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { Theme } from '@status-waku-voting/react-components' import { Theme, useMobileVersion } from '@status-waku-voting/react-components'
import { ProposalCard } from './ProposalCard' import { ProposalCard } from './ProposalCard'
import { WakuVoting } from '@status-waku-voting/core' import { WakuVoting } from '@status-waku-voting/core'
import { VotingEmpty } from './VotingEmpty' import { VotingEmpty } from './VotingEmpty'
@ -12,8 +12,10 @@ type ProposalListProps = {
votes: VotingRoom[] votes: VotingRoom[]
} }
export function ProposalList({ theme, wakuVoting, votes }: ProposalListProps) { export function ProposalList({ theme, wakuVoting, votes }: ProposalListProps) {
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600)
return ( return (
<List> <List ref={ref}>
{votes.map((vote) => { {votes.map((vote) => {
return ( return (
<ProposalCard <ProposalCard
@ -23,6 +25,7 @@ export function ProposalList({ theme, wakuVoting, votes }: ProposalListProps) {
theme={theme} theme={theme}
key={vote.id} key={vote.id}
id={vote.id} id={vote.id}
mobileVersion={mobileVersion}
/> />
) )
})} })}

View File

@ -1,4 +1,4 @@
import React from 'react' import React, { useCallback, useMemo } from 'react'
import { useState } from 'react' import { useState } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { addCommas } from '../helpers/addCommas' import { addCommas } from '../helpers/addCommas'
@ -11,36 +11,26 @@ export interface VoteProposingProps {
} }
export function VotePropose({ availableAmount, proposingAmount, setProposingAmount }: VoteProposingProps) { export function VotePropose({ availableAmount, proposingAmount, setProposingAmount }: VoteProposingProps) {
const [displayAmount, setDisplayAmount] = useState(addCommas(proposingAmount) + ' ABC') const [inputFocused, setInputFocused] = useState(false)
const disabled = availableAmount === 0 const disabled = useMemo(() => availableAmount === 0, [availableAmount])
const step = useMemo(
let step = 10 ** (Math.floor(Math.log10(availableAmount)) - 2) () => (availableAmount < 100 ? 1 : 10 ** (Math.floor(Math.log10(availableAmount)) - 2)),
[availableAmount]
if (availableAmount < 100) { )
step = 1 const progress = useMemo(() => (proposingAmount / availableAmount) * 100 + '%', [proposingAmount, availableAmount])
}
const setAvailableAmount = () => {
setProposingAmount(availableAmount)
setDisplayAmount(addCommas(availableAmount) + ' ABC')
}
const sliderChange = (e: React.ChangeEvent<HTMLInputElement>) => { const sliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (Number(e.target.value) == step * Math.floor(availableAmount / step)) { if (Number(e.target.value) == step * Math.floor(availableAmount / step)) {
setAvailableAmount() setProposingAmount(availableAmount)
} else { } else {
setProposingAmount(Number(e.target.value)) setProposingAmount(Number(e.target.value))
setDisplayAmount(addCommas(Number(e.target.value)) + ' ABC')
} }
} }
const progress = (proposingAmount / availableAmount) * 100 + '%'
const onInputAmountBlur = () => { const onInputAmountBlur = () => {
setInputFocused(false)
if (proposingAmount > availableAmount) { if (proposingAmount > availableAmount) {
setAvailableAmount() setProposingAmount(availableAmount)
} else {
setDisplayAmount(addCommas(proposingAmount) + ' ABC')
} }
} }
@ -51,13 +41,12 @@ export function VotePropose({ availableAmount, proposingAmount, setProposingAmou
<span>Available {addCommas(availableAmount)} ABC</span> <span>Available {addCommas(availableAmount)} ABC</span>
</VoteProposingInfo> </VoteProposingInfo>
<VoteProposingAmount <VoteProposingAmount
value={displayAmount} value={inputFocused ? proposingAmount.toString() : addCommas(proposingAmount) + ' ABC'}
onInput={(e) => { onInput={(e) => {
setProposingAmount(Number(e.currentTarget.value)) setProposingAmount(Number(e.currentTarget.value))
setDisplayAmount(e.currentTarget.value)
}} }}
onBlur={onInputAmountBlur} onBlur={onInputAmountBlur}
onFocus={() => setDisplayAmount(proposingAmount.toString())} onFocus={() => setInputFocused(true)}
/> />
<VoteProposingRangeWrap> <VoteProposingRangeWrap>
<VoteProposingRange <VoteProposingRange