From 606c871c85c99c6f38f63d72be662c2e0099e4b9 Mon Sep 17 00:00:00 2001 From: "Carina.Akaia.io" Date: Tue, 31 Dec 2024 02:24:36 +0000 Subject: [PATCH] mpDAO milestone progress update --- src/common/ui/components/atoms/alert.tsx | 2 +- .../voting-round/components/Leaderboard.tsx | 122 +++++++++--------- src/entities/voting-round/hooks/results.ts | 52 +++++++- .../voting-round/model/round-results.ts | 1 + src/pages/pot/[potId]/payouts.tsx | 32 ++--- src/pages/pot/[potId]/votes.tsx | 4 +- 6 files changed, 132 insertions(+), 81 deletions(-) diff --git a/src/common/ui/components/atoms/alert.tsx b/src/common/ui/components/atoms/alert.tsx index f47f7f1a..2f8e1f7f 100644 --- a/src/common/ui/components/atoms/alert.tsx +++ b/src/common/ui/components/atoms/alert.tsx @@ -68,7 +68,7 @@ const AlertDescription = forwardRef
= ({ potId }) => { - const votingRoundResults = useVotingRoundResults({ potId }); + const { votingRoundResults } = useVotingRoundResults({ potId }); const leadingPositions = useMemo( () => @@ -27,67 +27,71 @@ export const VotingRoundLeaderboard: React.FC = ({ [votingRoundResults?.winners], ); - return votingRoundResults === undefined ? null : ( -
- {leadingPositions.map( - ({ accountId, voteCount, accumulatedWeight: _, estimatedPayoutAmount }, index) => { - return ( -
-
- {index + 1} -
- -
- - + return votingRoundResults === undefined + ? null + : // TODO: remove the placeholder once accumulated weight is calculated correctly + // @ts-expect-error WIP + ("🚧 Leaderboard coming soon 🚧" ?? ( +
+ {leadingPositions.map( + ({ accountId, voteCount, accumulatedWeight, estimatedPayoutAmount }, index) => { + return (
- +
+ {index + 1} +
+ +
+ + +
+ -
- {`${voteCount} votes`} +
+ {`${voteCount} votes weighing ${accumulatedWeight}`} +
+
-
-
-
- - - -
-
- ); - }, - )} -
- ); +
+ + + +
+
+ ); + }, + )} +
+ )); }; diff --git a/src/entities/voting-round/hooks/results.ts b/src/entities/voting-round/hooks/results.ts index 17287a07..b36ca39a 100644 --- a/src/entities/voting-round/hooks/results.ts +++ b/src/entities/voting-round/hooks/results.ts @@ -1,3 +1,5 @@ +import { useCallback, useMemo } from "react"; + import { indexer } from "@/common/api/indexer"; import { NATIVE_TOKEN_DECIMALS } from "@/common/constants"; import { votingContractHooks } from "@/common/contracts/core/voting"; @@ -8,6 +10,7 @@ import { useRoundResultsStore } from "../model/round-results"; import type { VotingRoundKey } from "../types"; import { useVotingRound } from "./rounds"; +// TODO: Apply performance optimizations export const useVotingRoundResults = ({ potId }: VotingRoundKey) => { const { data: pot } = indexer.usePot({ potId }); const { hasProportionalFundingMechanism } = usePotFeatureFlags({ potId }); @@ -37,7 +40,50 @@ export const useVotingRoundResults = ({ potId }: VotingRoundKey) => { } } - if (votingRound) { - return store.resultsCache[votingRound.electionId]; - } else return undefined; + const results = useMemo( + () => (votingRound ? store.resultsCache[votingRound.electionId] : undefined), + [store.resultsCache, votingRound], + ); + + const handleCsvDownload = useCallback(() => { + if (results?.winners) { + const headers = [ + "Project ID", + "Vote Count", + "Accumulated Weight", + "Estimated NEAR Payout Amount", + ]; + + const rows = Object.values(results.winners).map((winner) => [ + winner.accountId, + winner.voteCount, + winner.accumulatedWeight, + winner.estimatedPayoutAmount, + ]); + + const csvContent = [headers.join(","), ...rows.map((row) => row.join(","))].join("\n"); + const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); + const blobUrl = URL.createObjectURL(blob); + + const link = document.createElement("a"); + link.href = blobUrl; + // Setting filename received in response + link.setAttribute("download", `${potId}-results.csv`); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + }, [potId, results]); + + if (results) { + return { + votingRoundResults: results, + handleVotingRoundResultsCsvDownload: handleCsvDownload, + }; + } else { + return { + votingRoundResults: undefined, + handleVotingRoundResultsCsvDownload: undefined, + }; + } }; diff --git a/src/entities/voting-round/model/round-results.ts b/src/entities/voting-round/model/round-results.ts index 5bd34520..e1fd1784 100644 --- a/src/entities/voting-round/model/round-results.ts +++ b/src/entities/voting-round/model/round-results.ts @@ -72,6 +72,7 @@ export const useRoundResultsStore = create()( }) : null; + // TODO: Take from the voter info response instead ( when it's ready ) const stakingTokenBalance = stakingContractAccountId && stakingTokenMetadata ? await ftClient diff --git a/src/pages/pot/[potId]/payouts.tsx b/src/pages/pot/[potId]/payouts.tsx index 7c28209c..daf6245f 100644 --- a/src/pages/pot/[potId]/payouts.tsx +++ b/src/pages/pot/[potId]/payouts.tsx @@ -1,6 +1,7 @@ -import { ReactElement, useCallback, useMemo, useState } from "react"; +import { ReactElement, useCallback, useEffect, useMemo, useState } from "react"; import { formatNearAmount } from "near-api-js/lib/utils/format"; +import Link from "next/link"; import { useRouter } from "next/router"; import { MdFileDownload, MdOutlineInfo } from "react-icons/md"; @@ -33,14 +34,11 @@ const MAX_ACCOUNT_ID_DISPLAY_LENGTH = 10; export default function PayoutsTab() { const router = useRouter(); const { potId } = router.query as { potId: string }; - const { data: potDetail } = indexer.usePot({ potId }); - const votingRoundResults = useVotingRoundResults({ potId }); + const { data: pot } = indexer.usePot({ potId }); - const handleCsvExport = useCallback(() => { - // Form CSV file from votingRoundResults and initiate download - }, []); - - console.log(votingRoundResults?.winners); + const { votingRoundResults, handleVotingRoundResultsCsvDownload } = useVotingRoundResults({ + potId, + }); const { payouts, @@ -129,12 +127,16 @@ export default function PayoutsTab() {

{"Estimated Payout"}

- {votingRoundResults === undefined ? ( + {handleVotingRoundResultsCsvDownload === undefined ? ( ) : ( - )}
@@ -175,18 +177,18 @@ export default function PayoutsTab() { { hidden: !showChallenges }, )} > - +
- {!potDetail?.all_paid_out ? ( + {!pot?.all_paid_out ? ( {"Justification For Payout Changes"} - {potDetail?.cooldown_end + {pot?.cooldown_end ? "These payouts have been set on the contract but have not been paid out yet." : "These payouts are estimated amounts only and have not been set on the contract yet."} @@ -318,7 +320,7 @@ export default function PayoutsTab() { "hidden w-full transition-all duration-500 ease-in-out md:w-[33%]", )} > - +
); diff --git a/src/pages/pot/[potId]/votes.tsx b/src/pages/pot/[potId]/votes.tsx index 4125ab8b..3dca832f 100644 --- a/src/pages/pot/[potId]/votes.tsx +++ b/src/pages/pot/[potId]/votes.tsx @@ -143,9 +143,7 @@ export default function PotVotesTab() { - - {`Voting is ${isVotingPeriodOngoing ? "open" : "closed"} for this round`} - + {`Voting round is ${isVotingPeriodOngoing ? "open" : "closed"}`} {isVotingPeriodOngoing && ( {"You can cast your votes now."}