diff --git a/packages/core/src/classes/WakuVoting.ts b/packages/core/src/classes/WakuVoting.ts index d37cffa..990e64f 100644 --- a/packages/core/src/classes/WakuVoting.ts +++ b/packages/core/src/classes/WakuVoting.ts @@ -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, diff --git a/packages/core/src/types/PollType.ts b/packages/core/src/types/PollType.ts index 45f9660..b18389f 100644 --- a/packages/core/src/types/PollType.ts +++ b/packages/core/src/types/PollType.ts @@ -14,4 +14,6 @@ export type VotingRoom = { totalVotesAgainst: BigNumber voters: string[] id: number + timeLeft: number + voteWinner: number | undefined } diff --git a/packages/proposal-components/src/components/ProposalCard.tsx b/packages/proposal-components/src/components/ProposalCard.tsx index d5faebd..343ba15 100644 --- a/packages/proposal-components/src/components/ProposalCard.tsx +++ b/packages/proposal-components/src/components/ProposalCard.tsx @@ -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 ( - mobileVersion && history.push(`/votingRoom/${id.toString}`)}> - - + mobileVersion && history.push(`/votingRoom/${votingRoom.id.toString()}`)}> + + ) } diff --git a/packages/proposal-components/src/components/ProposalInfo.tsx b/packages/proposal-components/src/components/ProposalInfo.tsx index 14b8662..036d89f 100644 --- a/packages/proposal-components/src/components/ProposalInfo.tsx +++ b/packages/proposal-components/src/components/ProposalInfo.tsx @@ -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 ( - {heading} - {text} + {votingRoom.question} + {votingRoom.description} - + ) diff --git a/packages/proposal-components/src/components/ProposalList.tsx b/packages/proposal-components/src/components/ProposalList.tsx index 254b140..9e86f2e 100644 --- a/packages/proposal-components/src/components/ProposalList.tsx +++ b/packages/proposal-components/src/components/ProposalList.tsx @@ -16,18 +16,8 @@ export function ProposalList({ theme, wakuVoting, votes }: ProposalListProps) { const mobileVersion = useMobileVersion(ref, 600) return ( - {votes.map((vote) => { - return ( - - ) + {votes.map((votingRoom) => { + return })} ) diff --git a/packages/proposal-components/src/components/ProposalVoteCard/ProposalVote.tsx b/packages/proposal-components/src/components/ProposalVoteCard/ProposalVote.tsx index 22755d6..b1899d0 100644 --- a/packages/proposal-components/src/components/ProposalVoteCard/ProposalVote.tsx +++ b/packages/proposal-components/src/components/ProposalVoteCard/ProposalVote.tsx @@ -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 ( {showVoteModal && ( - + )} {showConfirmModal && ( - + )} - {voteWinner ? Proposal {voteWinner == 1 ? 'rejected' : 'passed'} : } + {votingRoom.voteWinner ? ( + Proposal {votingRoom.voteWinner == 1 ? 'rejected' : 'passed'} + ) : ( + + )} - + - {voteWinner ? ( + {votingRoom.voteWinner ? ( Finalize the vote ) : ( @@ -105,9 +97,9 @@ export function ProposalVote({ vote, voteWinner, address, heading, theme, hideMo {' '} - + - {vote && } + ) diff --git a/packages/proposal-components/src/components/ProposalVoteCard/VoteChart.tsx b/packages/proposal-components/src/components/ProposalVoteCard/VoteChart.tsx index 8544dfa..ddcbe65 100644 --- a/packages/proposal-components/src/components/ProposalVoteCard/VoteChart.tsx +++ b/packages/proposal-components/src/components/ProposalVoteCard/VoteChart.tsx @@ -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(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 ( @@ -65,9 +61,9 @@ export function VoteChart({ {' '} {isAnimation && proposingAmount && selectedVote && selectedVote === 0 ? ( - + ) : ( - addCommas(votesAgainst) + addCommas(votingRoom.totalVotesAgainst.toNumber()) )}{' '} ABC @@ -89,9 +85,9 @@ export function VoteChart({ {' '} {isAnimation && proposingAmount && selectedVote && selectedVote === 1 ? ( - + ) : ( - addCommas(votesFor) + addCommas(votingRoom.totalVotesFor.toNumber()) )}{' '} ABC diff --git a/packages/proposal-components/src/components/VoteAnimatedModal.tsx b/packages/proposal-components/src/components/VoteAnimatedModal.tsx index b39708a..ca1c065 100644 --- a/packages/proposal-components/src/components/VoteAnimatedModal.tsx +++ b/packages/proposal-components/src/components/VoteAnimatedModal.tsx @@ -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 ( Your vote {selectedVote === 0 ? 'against' : 'for'} this proposal has been cast! void setProposingAmount: (val: number) => void } export function VoteModal({ - votesFor, - votesAgainst, - timeLeft, - voteWinner, + votingRoom, selectedVote, availableAmount, proposingAmount, @@ -32,14 +27,7 @@ export function VoteModal({ return ( - + } /> - + + + diff --git a/packages/proposal-components/src/components/mobile/ProposalVoteMobile.tsx b/packages/proposal-components/src/components/mobile/ProposalVoteMobile.tsx index 2f6dd60..8a161d3 100644 --- a/packages/proposal-components/src/components/mobile/ProposalVoteMobile.tsx +++ b/packages/proposal-components/src/components/mobile/ProposalVoteMobile.tsx @@ -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 ( - + - + {!voteWinner && ( {' '} - + ) diff --git a/packages/proposal-hooks/src/hooks/useVotingRoom.ts b/packages/proposal-hooks/src/hooks/useVotingRoom.ts new file mode 100644 index 0000000..a4f89dd --- /dev/null +++ b/packages/proposal-hooks/src/hooks/useVotingRoom.ts @@ -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(undefined) + + useEffect(() => { + const updateFunction = async () => { + setVotingRoom(await wakuVoting.getVotingRoom(id)) + } + updateFunction() + const interval = setInterval(updateFunction, 10000) + return () => clearInterval(interval) + }, [id]) + + return votingRoom +} diff --git a/packages/proposal-hooks/src/index.ts b/packages/proposal-hooks/src/index.ts index 0189719..ebde47d 100644 --- a/packages/proposal-hooks/src/index.ts +++ b/packages/proposal-hooks/src/index.ts @@ -1,3 +1,3 @@ import { useWakuProposal } from './hooks/useWakuProposal' - -export { useWakuProposal } +import { useVotingRoom } from './hooks/useVotingRoom' +export { useWakuProposal, useVotingRoom }