From f666f11c8f840e5e31a940579610d9c1fd55edd7 Mon Sep 17 00:00:00 2001 From: Yash Goyal Date: Tue, 26 Mar 2024 08:51:38 +0530 Subject: [PATCH] added poll detail page --- packages/hardhat/contracts/PollManager.sol | 39 +- packages/nextjs/abi/Poll.json | 966 ++++++++++++++++++ packages/nextjs/app/admin/page.tsx | 4 +- packages/nextjs/app/page.tsx | 3 + packages/nextjs/app/polls/[id]/page.tsx | 140 +++ packages/nextjs/app/polls/page.tsx | 54 + .../components/card/HoverBorderCard.tsx | 41 + packages/nextjs/components/card/VoteCard.tsx | 37 + .../nextjs/contracts/deployedContracts.ts | 107 +- packages/nextjs/hooks/useAuthUserOnly.tsx | 6 +- packages/nextjs/hooks/useFetchPoll.tsx | 8 + 11 files changed, 1345 insertions(+), 60 deletions(-) create mode 100644 packages/nextjs/abi/Poll.json create mode 100644 packages/nextjs/app/polls/[id]/page.tsx create mode 100644 packages/nextjs/app/polls/page.tsx create mode 100644 packages/nextjs/components/card/HoverBorderCard.tsx create mode 100644 packages/nextjs/components/card/VoteCard.tsx create mode 100644 packages/nextjs/hooks/useFetchPoll.tsx diff --git a/packages/hardhat/contracts/PollManager.sol b/packages/hardhat/contracts/PollManager.sol index 6dbf923..b121c15 100644 --- a/packages/hardhat/contracts/PollManager.sol +++ b/packages/hardhat/contracts/PollManager.sol @@ -14,6 +14,7 @@ contract PollManager is Params, DomainObjs { } struct PollData { + uint256 id; string name; bytes encodedOptions; string ipfsHash; @@ -25,6 +26,7 @@ contract PollManager is Params, DomainObjs { } mapping(uint256 => PollData) internal polls; + mapping(address => uint256) public pollIdByAddress; // poll address => poll id uint256 public totalPolls; MACI public maci; @@ -38,13 +40,10 @@ contract PollManager is Params, DomainObjs { event PollCreated( uint256 indexed pollId, address indexed creator, - address indexed poll, + PollContracts pollContracts, string name, string[] options, string ipfsHash, - address messageProcessor, - address tally, - address subsidy, uint256 startTime, uint256 endTime ); @@ -97,37 +96,39 @@ contract PollManager is Params, DomainObjs { // encode options to bytes for retrieval bytes memory encodedOptions = abi.encode(_options); - uint256 startTime = block.timestamp; uint256 endTime = block.timestamp + _duration; + uint256 pollId = ++totalPolls; + + PollContracts memory pollContracts = PollContracts({ + poll: c.poll, + messageProcessor: c.messageProcessor, + tally: c.tally, + subsidy: c.subsidy + }); + + pollIdByAddress[c.poll] = pollId; // create poll - polls[++totalPolls] = PollData({ + polls[pollId] = PollData({ + id: pollId, name: _name, encodedOptions: encodedOptions, numOfOptions: _options.length, ipfsHash: _ipfsHash, - startTime: startTime, + startTime: block.timestamp, endTime: endTime, - pollContracts: PollContracts({ - poll: c.poll, - messageProcessor: c.messageProcessor, - tally: c.tally, - subsidy: c.subsidy - }), + pollContracts: pollContracts, options: _options }); emit PollCreated( - totalPolls, + pollId, msg.sender, - c.poll, + pollContracts, _name, _options, _ipfsHash, - c.messageProcessor, - c.tally, - c.subsidy, - startTime, + block.timestamp, endTime ); } diff --git a/packages/nextjs/abi/Poll.json b/packages/nextjs/abi/Poll.json new file mode 100644 index 0000000..671177b --- /dev/null +++ b/packages/nextjs/abi/Poll.json @@ -0,0 +1,966 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "maxMessages", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxVoteOptions", + "type": "uint256" + } + ], + "internalType": "struct Params.MaxValues", + "name": "_maxValues", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "intStateTreeDepth", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "messageTreeSubDepth", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "messageTreeDepth", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "voteOptionTreeDepth", + "type": "uint8" + } + ], + "internalType": "struct Params.TreeDepths", + "name": "_treeDepths", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.PubKey", + "name": "_coordinatorPubKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "contract IMACI", + "name": "maci", + "type": "address" + }, + { + "internalType": "contract AccQueue", + "name": "messageAq", + "type": "address" + }, + { + "internalType": "contract TopupCredit", + "name": "topupCredit", + "type": "address" + } + ], + "internalType": "struct Params.ExtContracts", + "name": "_extContracts", + "type": "tuple" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidBatchLength", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMessage", + "type": "error" + }, + { + "inputs": [], + "name": "MaciPubKeyLargerThanSnarkFieldSize", + "type": "error" + }, + { + "inputs": [], + "name": "PollAlreadyInit", + "type": "error" + }, + { + "inputs": [], + "name": "StateAqAlreadyMerged", + "type": "error" + }, + { + "inputs": [], + "name": "StateAqSubtreesNeedMerge", + "type": "error" + }, + { + "inputs": [], + "name": "TooManyMessages", + "type": "error" + }, + { + "inputs": [], + "name": "VotingPeriodNotOver", + "type": "error" + }, + { + "inputs": [], + "name": "VotingPeriodOver", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_stateRoot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_numSignups", + "type": "uint256" + } + ], + "name": "MergeMaciStateAq", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_numSrQueueOps", + "type": "uint256" + } + ], + "name": "MergeMaciStateAqSubRoots", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_messageRoot", + "type": "uint256" + } + ], + "name": "MergeMessageAq", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_numSrQueueOps", + "type": "uint256" + } + ], + "name": "MergeMessageAqSubRoots", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + }, + { + "internalType": "uint256[10]", + "name": "data", + "type": "uint256[10]" + } + ], + "indexed": false, + "internalType": "struct DomainObjs.Message", + "name": "_message", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct DomainObjs.PubKey", + "name": "_encPubKey", + "type": "tuple" + } + ], + "name": "PublishMessage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + }, + { + "internalType": "uint256[10]", + "name": "data", + "type": "uint256[10]" + } + ], + "indexed": false, + "internalType": "struct DomainObjs.Message", + "name": "_message", + "type": "tuple" + } + ], + "name": "TopupMessage", + "type": "event" + }, + { + "inputs": [], + "name": "MESSAGE_DATA_LENGTH", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "coordinatorPubKey", + "outputs": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "coordinatorPubKeyHash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentSbCommitment", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "extContracts", + "outputs": [ + { + "internalType": "contract IMACI", + "name": "maci", + "type": "address" + }, + { + "internalType": "contract AccQueue", + "name": "messageAq", + "type": "address" + }, + { + "internalType": "contract TopupCredit", + "name": "topupCredit", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDeployTimeAndDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "pollDeployTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pollDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[2]", + "name": "array", + "type": "uint256[2]" + } + ], + "name": "hash2", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[3]", + "name": "array", + "type": "uint256[3]" + } + ], + "name": "hash3", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[4]", + "name": "array", + "type": "uint256[4]" + } + ], + "name": "hash4", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[5]", + "name": "array", + "type": "uint256[5]" + } + ], + "name": "hash5", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "left", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "right", + "type": "uint256" + } + ], + "name": "hashLeftRight", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + }, + { + "internalType": "uint256[10]", + "name": "data", + "type": "uint256[10]" + } + ], + "internalType": "struct DomainObjs.Message", + "name": "_message", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.PubKey", + "name": "_encPubKey", + "type": "tuple" + } + ], + "name": "hashMessageAndEncPubKey", + "outputs": [ + { + "internalType": "uint256", + "name": "msgHash", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.PubKey", + "name": "pubKey", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "voiceCreditBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.StateLeaf", + "name": "_stateLeaf", + "type": "tuple" + } + ], + "name": "hashStateLeaf", + "outputs": [ + { + "internalType": "uint256", + "name": "ciphertext", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "maxValues", + "outputs": [ + { + "internalType": "uint256", + "name": "maxMessages", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxVoteOptions", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_pollId", + "type": "uint256" + } + ], + "name": "mergeMaciStateAq", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_numSrQueueOps", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_pollId", + "type": "uint256" + } + ], + "name": "mergeMaciStateAqSubRoots", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "mergeMessageAq", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_numSrQueueOps", + "type": "uint256" + } + ], + "name": "mergeMessageAqSubRoots", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "mergedStateRoot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numMessages", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numSignUpsAndMessages", + "outputs": [ + { + "internalType": "uint256", + "name": "numSUps", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numMsgs", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numSignups", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[2]", + "name": "dataToPad", + "type": "uint256[2]" + }, + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + } + ], + "name": "padAndHashMessage", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + }, + { + "internalType": "uint256[10]", + "name": "data", + "type": "uint256[10]" + } + ], + "internalType": "struct DomainObjs.Message", + "name": "message", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.PubKey", + "name": "padKey", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "msgHash", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + }, + { + "internalType": "uint256[10]", + "name": "data", + "type": "uint256[10]" + } + ], + "internalType": "struct DomainObjs.Message", + "name": "_message", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.PubKey", + "name": "_encPubKey", + "type": "tuple" + } + ], + "name": "publishMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "msgType", + "type": "uint256" + }, + { + "internalType": "uint256[10]", + "name": "data", + "type": "uint256[10]" + } + ], + "internalType": "struct DomainObjs.Message[]", + "name": "_messages", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct DomainObjs.PubKey[]", + "name": "_encPubKeys", + "type": "tuple[]" + } + ], + "name": "publishMessageBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "array", + "type": "uint256[]" + } + ], + "name": "sha256Hash", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "stateAqMerged", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "stateIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "topup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "treeDepths", + "outputs": [ + { + "internalType": "uint8", + "name": "intStateTreeDepth", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "messageTreeSubDepth", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "messageTreeDepth", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "voteOptionTreeDepth", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/nextjs/app/admin/page.tsx b/packages/nextjs/app/admin/page.tsx index 4732447..dc7ebb5 100644 --- a/packages/nextjs/app/admin/page.tsx +++ b/packages/nextjs/app/admin/page.tsx @@ -59,7 +59,9 @@ export default function AdminPage() { ))} - + {totalPages > 1 && ( + + )} ) : (
No polls found
diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 481af2a..f197855 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -6,10 +6,13 @@ import type { NextPage } from "next"; import { useAccount } from "wagmi"; import { BugAntIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { Address } from "~~/components/scaffold-eth"; +import { useAuthUserOnly } from "~~/hooks/useAuthUserOnly"; const Home: NextPage = () => { const { address: connectedAddress } = useAccount(); + useAuthUserOnly({ inverted: true }); + return ( <>
diff --git a/packages/nextjs/app/polls/[id]/page.tsx b/packages/nextjs/app/polls/[id]/page.tsx new file mode 100644 index 0000000..1a174bc --- /dev/null +++ b/packages/nextjs/app/polls/[id]/page.tsx @@ -0,0 +1,140 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useParams } from "next/navigation"; +import { genRandomSalt } from "@se-2/hardhat/maci-ts/crypto"; +import { Keypair, Message, PCommand, PubKey } from "@se-2/hardhat/maci-ts/domainobjs"; +import { useContractRead, useContractWrite } from "wagmi"; +import PollAbi from "~~/abi/Poll.json"; +import VoteCard from "~~/components/card/VoteCard"; +import { useAuthContext } from "~~/contexts/AuthContext"; +import { useAuthUserOnly } from "~~/hooks/useAuthUserOnly"; +import { useFetchPoll } from "~~/hooks/useFetchPoll"; + +export default function PollDetail() { + const { id } = useParams<{ id: string }>(); + + const { data: poll, error, isLoading } = useFetchPoll(id); + + useAuthUserOnly({}); + + const { keypair } = useAuthContext(); + + const [clickedIndex, setClickedIndex] = useState(null); + const handleCardClick = (index: number) => { + setClickedIndex(clickedIndex === index ? null : index); + }; + + const castVote = async () => { + console.log("Voting for candidate", clickedIndex); + // navigate to the home page + try { + // setLoaderMessage("Casting the vote, please wait..."); + + await writeAsync(); + // router.push(`/voted-success?id=${clickedIndex}`); + } catch (err) { + console.log("err", err); + // toast.error("Casting vote failed, please try again "); + } + }; + + const { data: maxValues } = useContractRead({ + abi: PollAbi, + address: poll?.pollContracts.poll, + functionName: "maxValues", + args: [], + }); + + const { data: coordinatorPubKeyResult } = useContractRead({ + abi: PollAbi, + address: poll?.pollContracts.poll, + functionName: "coordinatorPubKey", + args: [], + }); + + const [message, setMessage] = useState<{ message: Message; encKeyPair: Keypair }>(); + + console.log("message", message); + + const { writeAsync } = useContractWrite({ + abi: PollAbi, + address: poll?.pollContracts.poll, + functionName: "publishMessage", + args: [message?.message.asContractParam(), message?.encKeyPair.pubKey.asContractParam()], + }); + + const [coordinatorPubKey, setCoordinatorPubKey] = useState(); + + useEffect(() => { + if (!coordinatorPubKeyResult) { + return; + } + + const coordinatorPubKey_ = new PubKey([ + BigInt((coordinatorPubKeyResult as any)[0].toString()), + BigInt((coordinatorPubKeyResult as any)[1].toString()), + ]); + + setCoordinatorPubKey(coordinatorPubKey_); + }, [`coordinatorPubKeyResult`]); + + useEffect(() => { + if (!clickedIndex || !coordinatorPubKey || !keypair) { + return; + } + const command: PCommand = new PCommand( + 1n, // stateindex + keypair.pubKey, // userMaciPubKey + BigInt(clickedIndex), + 1n, + 1n, + BigInt(id), + genRandomSalt(), + ); + + const signature = command.sign(keypair.privKey); + + const encKeyPair = new Keypair(); + + const message = command.encrypt(signature, Keypair.genEcdhSharedKey(encKeyPair.privKey, coordinatorPubKey)); + + setMessage({ message, encKeyPair }); + }, [id, clickedIndex, coordinatorPubKey, keypair]); + + console.log(maxValues && (maxValues as any)[1]); + console.log(coordinatorPubKeyResult); + + if (isLoading) return
Loading...
; + + if (error) return
Poll not found
; + console.log(poll); + + return ( +
+
+
+
Vote for {poll?.name}
+
+ {poll?.options.map((candidate, index) => ( +
+ handleCardClick(index)}> +
{candidate}
+
+
+ ))} +
+ +
+
+
+ ); +} diff --git a/packages/nextjs/app/polls/page.tsx b/packages/nextjs/app/polls/page.tsx new file mode 100644 index 0000000..87f3418 --- /dev/null +++ b/packages/nextjs/app/polls/page.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import Paginator from "~~/components/Paginator"; +import HoverBorderCard from "~~/components/card/HoverBorderCard"; +import { useFetchPolls } from "~~/hooks/useFetchPolls"; +import { useTotalPages } from "~~/hooks/useTotalPages"; + +export default function Polls() { + const [currentPage, setCurrentPage] = useState(1); + const [limit] = useState(10); + const { totalPolls, polls } = useFetchPolls(currentPage, limit); + const totalPages = useTotalPages(totalPolls, limit); + + console.log(polls); + + const router = useRouter(); + + return ( +
+
+
Polls
+
+ {polls !== undefined ? ( + polls.length !== 0 ? ( + <> +
+ {polls.map((poll: any) => ( + router.push(`/polls/${poll.id}`)}> +
+
+

+ {poll.name} ({"Closed"}) +

+

{poll.options.length} Candidates

+
+
+
+ ))} +
+ {totalPages > 1 && ( + + )} + + ) : ( +
No polls found
+ ) + ) : ( +
Loading...
+ )} +
+ ); +} diff --git a/packages/nextjs/components/card/HoverBorderCard.tsx b/packages/nextjs/components/card/HoverBorderCard.tsx new file mode 100644 index 0000000..c3e1d65 --- /dev/null +++ b/packages/nextjs/components/card/HoverBorderCard.tsx @@ -0,0 +1,41 @@ +import React from "react"; + +interface HoverBorderProps { + children: React.ReactNode; + showArrow?: boolean; + click?: () => void; + disabled?: boolean; +} + +const HoverBorderCard: React.FC = ({ children, showArrow = false, click, disabled = false }) => { + return ( +
{ + if (!disabled && click) { + click(); + } + }} + > + {children} + {showArrow && ( + + + + )} +
+ ); +}; + +export default HoverBorderCard; diff --git a/packages/nextjs/components/card/VoteCard.tsx b/packages/nextjs/components/card/VoteCard.tsx new file mode 100644 index 0000000..c954e9d --- /dev/null +++ b/packages/nextjs/components/card/VoteCard.tsx @@ -0,0 +1,37 @@ +import { BiLike } from "react-icons/bi"; + +type VoteCardProps = { + children: React.ReactNode; + clicked: boolean; + onClick: () => void; +}; + +const VoteCard = ({ children, clicked, onClick }: VoteCardProps) => { + const handleClick = () => { + onClick(); + }; + + // Rest of the component code... + + return ( +
+
{children}
+
+ +
+
+ ); +}; + +export default VoteCard; diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 963b11f..79ef397 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -7,7 +7,7 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; const deployedContracts = { 31337: { ConstantInitialVoiceCreditProxy: { - address: "0x5FbDB2315678afecb367f032d93F642f64180aa3", + address: "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", abi: [ { inputs: [ @@ -50,7 +50,7 @@ const deployedContracts = { }, }, FreeForAllGatekeeper: { - address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + address: "0x59b670e9fA9D0A427751Af201D676719a970857b", abi: [ { inputs: [], @@ -92,7 +92,7 @@ const deployedContracts = { inheritedFunctions: {}, }, MACI: { - address: "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", + address: "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", abi: [ { inputs: [ @@ -1084,7 +1084,7 @@ const deployedContracts = { }, }, MessageProcessorFactory: { - address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + address: "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", abi: [ { inputs: [], @@ -1139,7 +1139,7 @@ const deployedContracts = { }, }, PollFactory: { - address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + address: "0xc5a5C42992dECbae36851359345FE25997F5C42d", abi: [ { inputs: [], @@ -1266,7 +1266,7 @@ const deployedContracts = { }, }, PollManager: { - address: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1", + address: "0x851356ae760d987E095750cCeb3bC6014560891C", abi: [ { inputs: [ @@ -1295,10 +1295,32 @@ const deployedContracts = { type: "address", }, { - indexed: true, - internalType: "address", - name: "poll", - type: "address", + components: [ + { + internalType: "address", + name: "poll", + type: "address", + }, + { + internalType: "address", + name: "messageProcessor", + type: "address", + }, + { + internalType: "address", + name: "tally", + type: "address", + }, + { + internalType: "address", + name: "subsidy", + type: "address", + }, + ], + indexed: false, + internalType: "struct PollManager.PollContracts", + name: "pollContracts", + type: "tuple", }, { indexed: false, @@ -1318,24 +1340,6 @@ const deployedContracts = { name: "ipfsHash", type: "string", }, - { - indexed: false, - internalType: "address", - name: "messageProcessor", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "tally", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "subsidy", - type: "address", - }, { indexed: false, internalType: "uint256", @@ -1423,6 +1427,11 @@ const deployedContracts = { outputs: [ { components: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, { internalType: "string", name: "name", @@ -1516,6 +1525,11 @@ const deployedContracts = { outputs: [ { components: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, { internalType: "string", name: "name", @@ -1613,6 +1627,25 @@ const deployedContracts = { stateMutability: "view", type: "function", }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + name: "pollIdByAddress", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, { inputs: [ { @@ -1766,7 +1799,7 @@ const deployedContracts = { }, }, PoseidonT3: { - address: "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + address: "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f", abi: [ { inputs: [ @@ -1791,7 +1824,7 @@ const deployedContracts = { inheritedFunctions: {}, }, PoseidonT4: { - address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", + address: "0x4A679253410272dd5232B3Ff7cF5dbB88f295319", abi: [ { inputs: [ @@ -1816,7 +1849,7 @@ const deployedContracts = { inheritedFunctions: {}, }, PoseidonT5: { - address: "0x0165878A594ca255338adfa4d48449f69242Eb8F", + address: "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F", abi: [ { inputs: [ @@ -1841,7 +1874,7 @@ const deployedContracts = { inheritedFunctions: {}, }, PoseidonT6: { - address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + address: "0x09635F643e140090A9A8Dcd712eD6285858ceBef", abi: [ { inputs: [ @@ -1866,7 +1899,7 @@ const deployedContracts = { inheritedFunctions: {}, }, SubsidyFactory: { - address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", + address: "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690", abi: [ { inputs: [ @@ -1913,7 +1946,7 @@ const deployedContracts = { }, }, TallyFactory: { - address: "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", + address: "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E", abi: [ { inputs: [ @@ -1960,7 +1993,7 @@ const deployedContracts = { }, }, TopupCredit: { - address: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", + address: "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44", abi: [ { inputs: [], @@ -2370,7 +2403,7 @@ const deployedContracts = { }, }, Verifier: { - address: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + address: "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1", abi: [ { inputs: [], @@ -2532,7 +2565,7 @@ const deployedContracts = { }, }, VkRegistry: { - address: "0x9A676e781A523b5d0C0e43731313A708CB607508", + address: "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", abi: [ { inputs: [], diff --git a/packages/nextjs/hooks/useAuthUserOnly.tsx b/packages/nextjs/hooks/useAuthUserOnly.tsx index f84a6ee..13bdcb0 100644 --- a/packages/nextjs/hooks/useAuthUserOnly.tsx +++ b/packages/nextjs/hooks/useAuthUserOnly.tsx @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { permanentRedirect } from "next/navigation"; +import { redirect } from "next/navigation"; import { useAuthContext } from "~~/contexts/AuthContext"; export function useAuthUserOnly({ inverted }: { inverted?: boolean }) { @@ -7,11 +7,11 @@ export function useAuthUserOnly({ inverted }: { inverted?: boolean }) { useEffect(() => { if (inverted && isRegistered) { - permanentRedirect("/"); + redirect("/polls"); } if (!inverted && !isRegistered) { - permanentRedirect("/register"); + redirect("/"); } }, [isRegistered, inverted]); diff --git a/packages/nextjs/hooks/useFetchPoll.tsx b/packages/nextjs/hooks/useFetchPoll.tsx new file mode 100644 index 0000000..e681476 --- /dev/null +++ b/packages/nextjs/hooks/useFetchPoll.tsx @@ -0,0 +1,8 @@ +import { useScaffoldContractRead } from "./scaffold-eth"; + +export const useFetchPoll = (id: string) => + useScaffoldContractRead({ + contractName: "PollManager", + functionName: "fetchPoll", + args: [BigInt(id)], + });