Refactor votingCards (#71)

This commit is contained in:
Szymon Szlachtowicz 2021-09-14 23:16:05 +02:00 committed by GitHub
parent 98fb2ea515
commit 983f557fbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 112 additions and 158 deletions

View File

@ -73,6 +73,7 @@ export class WakuVoting extends WakuMessaging {
this.lastGetPollsBlockNumber = blockNumber
const polls = await this.votingContract.getVotingRooms()
this.lastPolls = polls.map((poll: any, idx: number): VotingRoom => {
const timeLeft = poll[1].toNumber() - Date.now() / 1000
return {
startBlock: poll[0],
endAt: poll[1],
@ -82,12 +83,18 @@ export class WakuVoting extends WakuMessaging {
totalVotesAgainst: poll[5],
voters: poll[6],
id: idx,
timeLeft,
voteWinner: timeLeft <= 0 ? (poll[5].gt(poll[4]) ? 1 : 2) : undefined,
}
})
}
return this.lastPolls
}
public async getVotingRoom(id: number) {
return (await this.getVotingRooms())[id]
}
public async sendVote(
signer: JsonRpcSigner | Wallet,
roomId: number,

View File

@ -14,4 +14,6 @@ export type VotingRoom = {
totalVotesAgainst: BigNumber
voters: string[]
id: number
timeLeft: number
voteWinner: number | undefined
}

View File

@ -4,35 +4,22 @@ import styled from 'styled-components'
import { Theme } from '@status-waku-voting/react-components'
import { ProposalInfo } from './ProposalInfo'
import { ProposalVote } from './ProposalVoteCard/ProposalVote'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
interface ProposalCardProps {
id: number
theme: Theme
heading: string
text: string
address: string
votingRoom: VotingRoom
mobileVersion?: boolean
vote?: number
voteWinner?: number
theme: Theme
hideModalFunction?: (val: boolean) => void
}
export function ProposalCard({
id,
heading,
text,
address,
vote,
voteWinner,
theme,
mobileVersion,
}: ProposalCardProps) {
export function ProposalCard({ theme, votingRoom, mobileVersion }: ProposalCardProps) {
const history = useHistory()
return (
<Card onClick={() => mobileVersion && history.push(`/votingRoom/${id.toString}`)}>
<ProposalInfo heading={heading} text={text} address={address} />
<ProposalVote vote={vote} voteWinner={voteWinner} address={address} heading={heading} theme={theme} />
<Card onClick={() => mobileVersion && history.push(`/votingRoom/${votingRoom.id.toString()}`)}>
<ProposalInfo votingRoom={votingRoom} />
<ProposalVote votingRoom={votingRoom} theme={theme} />
</Card>
)
}

View File

@ -1,21 +1,20 @@
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
import React from 'react'
import styled from 'styled-components'
import { ViewLink } from './ViewLink'
type ProposalInfoProps = {
heading: string
text: string
address: string
votingRoom: VotingRoom
mobileMode?: boolean
}
export function ProposalInfo({ heading, text, address, mobileMode }: ProposalInfoProps) {
export function ProposalInfo({ votingRoom, mobileMode }: ProposalInfoProps) {
return (
<Card>
<CardHeading>{heading}</CardHeading>
<CardText className={mobileMode ? 'mobile' : ''}>{text}</CardText>
<CardHeading>{votingRoom.question}</CardHeading>
<CardText className={mobileMode ? 'mobile' : ''}>{votingRoom.description}</CardText>
<CardViewLink className={mobileMode ? 'mobile' : ''}>
<ViewLink address={address} />
<ViewLink address={'#'} />
</CardViewLink>
</Card>
)

View File

@ -16,18 +16,8 @@ export function ProposalList({ theme, wakuVoting, votes }: ProposalListProps) {
const mobileVersion = useMobileVersion(ref, 600)
return (
<List ref={ref}>
{votes.map((vote) => {
return (
<ProposalCard
heading={vote.question}
text={vote.description}
address={'#'}
theme={theme}
key={vote.id}
id={vote.id}
mobileVersion={mobileVersion}
/>
)
{votes.map((votingRoom) => {
return <ProposalCard votingRoom={votingRoom} theme={theme} key={votingRoom.id} mobileVersion={mobileVersion} />
})}
</List>
)

View File

@ -8,17 +8,15 @@ import { ViewLink } from '../ViewLink'
import { Modal, Theme } from '@status-waku-voting/react-components'
import { VoteModal } from '../VoteModal'
import { VoteAnimatedModal } from '../VoteAnimatedModal'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
interface ProposalVoteProps {
theme: Theme
vote?: number
voteWinner?: number
heading: string
address: string
votingRoom: VotingRoom
hideModalFunction?: (val: boolean) => void
}
export function ProposalVote({ vote, voteWinner, address, heading, theme, hideModalFunction }: ProposalVoteProps) {
export function ProposalVote({ votingRoom, theme, hideModalFunction }: ProposalVoteProps) {
const { account } = useEthers()
const [showVoteModal, setShowVoteModal] = useState(false)
const [showConfirmModal, setShowConfirmModal] = useState(false)
@ -40,11 +38,9 @@ export function ProposalVote({ vote, voteWinner, address, heading, theme, hideMo
return (
<Card>
{showVoteModal && (
<Modal heading={heading} setShowModal={setShowVoteModal} theme={theme}>
<Modal heading={votingRoom.question} setShowModal={setShowVoteModal} theme={theme}>
<VoteModal
votesFor={1865567}
votesAgainst={1740235}
timeLeft={4855555577}
votingRoom={votingRoom}
availableAmount={65245346}
selectedVote={selectedVoted}
proposingAmount={proposingAmount}
@ -54,29 +50,25 @@ export function ProposalVote({ vote, voteWinner, address, heading, theme, hideMo
</Modal>
)}
{showConfirmModal && (
<Modal heading={heading} setShowModal={hideConfirm} theme={theme}>
<Modal heading={votingRoom.question} setShowModal={hideConfirm} theme={theme}>
<VoteAnimatedModal
votesFor={1865567}
votesAgainst={1740235}
timeLeft={4855555577}
votingRoom={votingRoom}
selectedVote={selectedVoted}
setShowModal={hideConfirm}
proposingAmount={proposingAmount}
/>
</Modal>
)}
{voteWinner ? <CardHeading>Proposal {voteWinner == 1 ? 'rejected' : 'passed'}</CardHeading> : <CardHeading />}
{votingRoom.voteWinner ? (
<CardHeading>Proposal {votingRoom.voteWinner == 1 ? 'rejected' : 'passed'}</CardHeading>
) : (
<CardHeading />
)}
<VoteChart
votesFor={1865567}
votesAgainst={1740235}
timeLeft={4855555577}
voteWinner={voteWinner}
selectedVote={selectedVoted}
/>
<VoteChart votingRoom={votingRoom} selectedVote={selectedVoted} />
<CardButtons>
{voteWinner ? (
{votingRoom.voteWinner ? (
<FinalBtn disabled={!account}>Finalize the vote</FinalBtn>
) : (
<VotesBtns>
@ -105,9 +97,9 @@ export function ProposalVote({ vote, voteWinner, address, heading, theme, hideMo
<CardVoteBottom>
<CardViewLink>
{' '}
<ViewLink address={address} />
<ViewLink address={'#'} />
</CardViewLink>
{vote && <VoteSubmitButton votes={vote} disabled={!account} />}
<VoteSubmitButton votes={15} disabled={!account} />
</CardVoteBottom>
</Card>
)

View File

@ -1,4 +1,4 @@
import React, { useRef } from 'react'
import React, { useMemo, useRef } from 'react'
import CountUp from 'react-countup'
import styled from 'styled-components'
import { addCommas } from '../../helpers/addCommas'
@ -9,43 +9,39 @@ import crossWinnerIcon from '../../assets/svg/crossWinner.svg'
import checkIcon from '../../assets/svg/check.svg'
import checkWinnerIcon from '../../assets/svg/checkWinner.svg'
import { useMobileVersion } from '@status-waku-voting/react-components'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
export interface VoteChartProps {
votesFor: number
votesAgainst: number
timeLeft: number
voteWinner?: number
votingRoom: VotingRoom
proposingAmount?: number
selectedVote?: number
isAnimation?: boolean
tabletMode?: (val: boolean) => void
}
export function VoteChart({
votesFor,
votesAgainst,
timeLeft,
voteWinner,
proposingAmount,
selectedVote,
isAnimation,
tabletMode,
}: VoteChartProps) {
export function VoteChart({ votingRoom, proposingAmount, selectedVote, isAnimation, tabletMode }: VoteChartProps) {
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600)
const voteSum = votesFor + votesAgainst
const graphWidth = (100 * votesAgainst) / voteSum
const voteSum = useMemo(
() => votingRoom.totalVotesFor.add(votingRoom.totalVotesAgainst),
[votingRoom.totalVotesFor.toString(), votingRoom.totalVotesAgainst.toString()]
)
const graphWidth = useMemo(() => votingRoom.totalVotesAgainst.mul(100).div(voteSum).toNumber(), [voteSum])
let balanceWidth = graphWidth
if (proposingAmount) {
balanceWidth =
selectedVote === 0
? (100 * (votesAgainst + proposingAmount)) / (voteSum + proposingAmount)
: (100 * votesAgainst) / (voteSum + proposingAmount)
const balanceWidth = useMemo(() => {
if (!proposingAmount) {
return graphWidth
} else {
const divider = voteSum.add(proposingAmount)
return selectedVote === 0
? votingRoom.totalVotesAgainst.add(proposingAmount).mul(100).div(divider).toNumber()
: votingRoom.totalVotesAgainst.mul(100).div(divider).toNumber()
}
}, [graphWidth, voteSum, proposingAmount])
const timeLeft = useMemo(() => votingRoom.timeLeft, [votingRoom.timeLeft])
const voteWinner = useMemo(() => votingRoom.voteWinner, [votingRoom.voteWinner])
return (
<Votes ref={ref}>
<VotesChart className={selectedVote || tabletMode ? '' : 'notModal'}>
@ -65,9 +61,9 @@ export function VoteChart({
<span>
{' '}
{isAnimation && proposingAmount && selectedVote && selectedVote === 0 ? (
<CountUp end={votesAgainst + proposingAmount} separator="," />
<CountUp end={votingRoom.totalVotesAgainst.toNumber() + proposingAmount} separator="," />
) : (
addCommas(votesAgainst)
addCommas(votingRoom.totalVotesAgainst.toNumber())
)}{' '}
<span style={{ fontWeight: 'normal' }}>ABC</span>
</span>
@ -89,9 +85,9 @@ export function VoteChart({
<span>
{' '}
{isAnimation && proposingAmount && selectedVote && selectedVote === 1 ? (
<CountUp end={votesFor + proposingAmount} separator="," />
<CountUp end={votingRoom.totalVotesFor.toNumber() + proposingAmount} separator="," />
) : (
addCommas(votesFor)
addCommas(votingRoom.totalVotesFor.toNumber())
)}{' '}
<span style={{ fontWeight: 'normal' }}>ABC</span>
</span>

View File

@ -1,32 +1,22 @@
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
import React from 'react'
import styled from 'styled-components'
import { FinalBtn } from './Buttons'
import { VoteChart } from './ProposalVoteCard/VoteChart'
interface VoteAnimatedModalProps {
votesFor: number
votesAgainst: number
timeLeft: number
votingRoom: VotingRoom
proposingAmount: number
selectedVote: number
setShowModal: (val: boolean) => void
}
export function VoteAnimatedModal({
votesFor,
votesAgainst,
timeLeft,
selectedVote,
proposingAmount,
setShowModal,
}: VoteAnimatedModalProps) {
export function VoteAnimatedModal({ votingRoom, selectedVote, proposingAmount, setShowModal }: VoteAnimatedModalProps) {
return (
<VoteConfirm>
<ConfirmText>Your vote {selectedVote === 0 ? 'against' : 'for'} this proposal has been cast!</ConfirmText>
<VoteChart
votesFor={votesFor}
votesAgainst={votesAgainst}
timeLeft={timeLeft}
votingRoom={votingRoom}
proposingAmount={proposingAmount}
selectedVote={selectedVote}
isAnimation={true}

View File

@ -3,24 +3,19 @@ import styled from 'styled-components'
import { VoteChart } from './ProposalVoteCard/VoteChart'
import { DisabledButton, VoteBtnAgainst, VoteBtnFor } from './Buttons'
import { VotePropose } from './VotePropose'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
export interface VoteModalProps {
votesFor: number
votesAgainst: number
timeLeft: number
voteWinner?: number
selectedVote: number
votingRoom: VotingRoom
availableAmount: number
selectedVote: number
proposingAmount: number
setShowConfirmModal: (show: boolean) => void
setProposingAmount: (val: number) => void
}
export function VoteModal({
votesFor,
votesAgainst,
timeLeft,
voteWinner,
votingRoom,
selectedVote,
availableAmount,
proposingAmount,
@ -32,14 +27,7 @@ export function VoteModal({
return (
<Column>
<VoteChart
votesFor={votesFor}
votesAgainst={votesAgainst}
timeLeft={timeLeft}
voteWinner={voteWinner}
proposingAmount={proposingAmount}
selectedVote={selectedVote}
/>
<VoteChart votingRoom={votingRoom} proposingAmount={proposingAmount} selectedVote={selectedVote} />
<VotePropose
availableAmount={availableAmount}
setProposingAmount={setProposingAmount}

View File

@ -17,7 +17,9 @@ export function ProposalMobile({ wakuVoting }: ProposalMobileProps) {
<ProposalWrapper>
<Switch>
<Route exact path="/" render={() => <Redirect to="/proposal" />} />
<Route exact path="/votingRoom/:id" component={ProposalVoteMobile} />
<Route exact path="/votingRoom/:id">
<ProposalVoteMobile wakuVoting={wakuVoting} availableAmount={123} />
</Route>
<Route exact path="/creation" component={ProposeMobile} />
<Route exact path="/proposal">
<ProposalMainMobile wakuVoting={wakuVoting} />

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useMemo, useState } from 'react'
import { useParams } from 'react-router'
import styled from 'styled-components'
import { useEthers } from '@usedapp/core'
@ -8,48 +8,31 @@ import { VoteChart } from '../ProposalVoteCard/VoteChart'
import { ProposalInfo } from '../ProposalInfo'
import { VotePropose } from '../VotePropose'
import { VotesBtns } from '../ProposalVoteCard/ProposalVote'
import { useVotingRoom } from '@status-waku-voting/proposal-hooks'
import { WakuVoting } from '@status-waku-voting/core'
interface ProposalVoteMobileProps {
vote?: number
voteWinner?: number
votesFor: number
votesAgainst: number
timeLeft: number
wakuVoting: WakuVoting
availableAmount: number
heading: string
text: string
address: string
}
export function ProposalVoteMobile({
votesFor,
votesAgainst,
timeLeft,
vote,
voteWinner,
address,
heading,
text,
availableAmount,
}: ProposalVoteMobileProps) {
export function ProposalVoteMobile({ wakuVoting, availableAmount }: ProposalVoteMobileProps) {
const { id } = useParams<{ id: string }>()
const { account } = useEthers()
const [proposingAmount, setProposingAmount] = useState(0)
const [selectedVoted, setSelectedVoted] = useState(0)
const [mobileVersion, setMobileVersion] = useState(true)
const votingRoom = useVotingRoom(Number(id), wakuVoting)
const voteWinner = useMemo(() => votingRoom?.voteWinner, [votingRoom?.voteWinner])
if (!votingRoom) {
return <>Loading</>
}
return (
<Card>
<ProposalInfo
heading={'This is a very long, explainative and sophisticated title for a proposal.'}
text={
'This is a longer description of the proposal. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque interdum rutrum sodales. Nullam mattis fermentum libero, non volutpat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque interdum rutrum sodales. Nullam mattis fermentum libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque interdum rutrum sodales. Nullam mattis fermentum libero.'
}
address={'#'}
mobileMode={mobileVersion}
/>
<ProposalInfo votingRoom={votingRoom} mobileMode={true} />
<VoteChartWrap>
<VoteChart votesFor={1865567} votesAgainst={1740235} timeLeft={4855555577} selectedVote={selectedVoted} />
<VoteChart votingRoom={votingRoom} selectedVote={selectedVoted} />
</VoteChartWrap>
{!voteWinner && (
<VotePropose
@ -86,7 +69,7 @@ export function ProposalVoteMobile({
<CardVoteBottom>
{' '}
<VoteSubmitButton votes={2345678} disabled={!account} />
<VoteSubmitButton votes={15} disabled={!account} />
</CardVoteBottom>
</Card>
)

View File

@ -0,0 +1,18 @@
import React, { useEffect, useState } from 'react'
import { WakuVoting } from '@status-waku-voting/core'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
export function useVotingRoom(id: number, wakuVoting: WakuVoting) {
const [votingRoom, setVotingRoom] = useState<VotingRoom | undefined>(undefined)
useEffect(() => {
const updateFunction = async () => {
setVotingRoom(await wakuVoting.getVotingRoom(id))
}
updateFunction()
const interval = setInterval(updateFunction, 10000)
return () => clearInterval(interval)
}, [id])
return votingRoom
}

View File

@ -1,3 +1,3 @@
import { useWakuProposal } from './hooks/useWakuProposal'
export { useWakuProposal }
import { useVotingRoom } from './hooks/useVotingRoom'
export { useWakuProposal, useVotingRoom }