Skip to content

Commit

Permalink
mpDAO milestone progress update
Browse files Browse the repository at this point in the history
  • Loading branch information
carina-akaia committed Dec 31, 2024
1 parent ce1cf8b commit 606c871
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 81 deletions.
2 changes: 1 addition & 1 deletion src/common/ui/components/atoms/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const AlertDescription = forwardRef<HTMLParagraphElement, AlertDescriptionProps>
<div
ref={ref}
className={cn(
"prose font-500 text-sm text-neutral-700 [&_p]:leading-relaxed",
"font-500 text-sm text-neutral-700 [&_p]:leading-relaxed",
{ "important:pl-0": inline, "important:pl-8": !inline },
className,
)}
Expand Down
122 changes: 63 additions & 59 deletions src/entities/voting-round/components/Leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useVotingRoundResults } from "../hooks/results";
export type VotingRoundLeaderboardProps = ByPotId & {};

export const VotingRoundLeaderboard: React.FC<VotingRoundLeaderboardProps> = ({ potId }) => {
const votingRoundResults = useVotingRoundResults({ potId });
const { votingRoundResults } = useVotingRoundResults({ potId });

const leadingPositions = useMemo(
() =>
Expand All @@ -27,67 +27,71 @@ export const VotingRoundLeaderboard: React.FC<VotingRoundLeaderboardProps> = ({
[votingRoundResults?.winners],
);

return votingRoundResults === undefined ? null : (
<div className="md:max-w-126.5 flex w-full flex-col gap-3 rounded-3xl bg-neutral-50 p-3">
{leadingPositions.map(
({ accountId, voteCount, accumulatedWeight: _, estimatedPayoutAmount }, index) => {
return (
<div
key={accountId}
className={cn(
"elevation-low inline-flex h-16 items-center justify-start gap-2 md:gap-6",
"bg-background overflow-hidden rounded-2xl p-3",
)}
>
<div
className={cn(
"flex h-8 w-8 shrink-0 items-center justify-center",
"rounded-full border border-neutral-200",
)}
>
<span className="text-right text-xs font-medium leading-none">{index + 1}</span>
</div>

<div className="flex h-10 shrink grow basis-0 items-center justify-start gap-4">
<AccountProfilePicture className="h-10 w-10" {...{ accountId }} />

return votingRoundResults === undefined
? null
: // TODO: remove the placeholder once accumulated weight is calculated correctly
// @ts-expect-error WIP
("🚧 Leaderboard coming soon 🚧" ?? (
<div className="md:max-w-126.5 flex w-full flex-col gap-3 rounded-3xl bg-neutral-50 p-3">
{leadingPositions.map(
({ accountId, voteCount, accumulatedWeight, estimatedPayoutAmount }, index) => {
return (
<div
className={
"inline-flex shrink grow basis-0 flex-col items-start justify-start gap-1"
}
key={accountId}
className={cn(
"elevation-low inline-flex h-16 items-center justify-start gap-2 md:gap-6",
"bg-background overflow-hidden rounded-2xl p-3",
)}
>
<AccountHandle
maxLength={22}
className="font-600 text-neutral-950"
{...{ accountId }}
/>
<div
className={cn(
"flex h-8 w-8 shrink-0 items-center justify-center",
"rounded-full border border-neutral-200",
)}
>
<span className="text-right text-xs font-medium leading-none">{index + 1}</span>
</div>

<div className="flex h-10 shrink grow basis-0 items-center justify-start gap-4">
<AccountProfilePicture className="h-10 w-10" {...{ accountId }} />

<div
className={
"inline-flex shrink grow basis-0 flex-col items-start justify-start gap-1"
}
>
<AccountHandle
maxLength={22}
className="font-600 text-neutral-950"
{...{ accountId }}
/>

<div className="self-stretch text-sm font-medium leading-tight text-neutral-500">
{`${voteCount} votes`}
<div className="self-stretch text-sm font-medium leading-tight text-neutral-500">
{`${voteCount} votes weighing ${accumulatedWeight}`}
</div>
</div>
</div>
</div>
</div>

<div
className={cn(
"bg-peach-100 flex h-fit items-center justify-center",
"rounded-lg py-1.5 pl-2 pr-3",
)}
>
<LabeledIcon
positioning="icon-text"
caption={estimatedPayoutAmount.toFixed(2)}
classNames={{
caption: "font-600 text-sm gap-1.5 text-nowrap",
}}
>
<TokenIcon tokenId={NATIVE_TOKEN_ID} className="color-peach-600" />
</LabeledIcon>
</div>
</div>
);
},
)}
</div>
);
<div
className={cn(
"bg-peach-100 flex h-fit items-center justify-center",
"rounded-lg py-1.5 pl-2 pr-3",
)}
>
<LabeledIcon
positioning="icon-text"
caption={estimatedPayoutAmount.toFixed(2)}
classNames={{
caption: "font-600 text-sm gap-1.5 text-nowrap",
}}
>
<TokenIcon tokenId={NATIVE_TOKEN_ID} className="color-peach-600" />
</LabeledIcon>
</div>
</div>
);
},
)}
</div>
));
};
52 changes: 49 additions & 3 deletions src/entities/voting-round/hooks/results.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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 });
Expand Down Expand Up @@ -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,
};
}
};
1 change: 1 addition & 0 deletions src/entities/voting-round/model/round-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const useRoundResultsStore = create<VotingRoundResultsState>()(
})
: null;

// TODO: Take from the voter info response instead ( when it's ready )
const stakingTokenBalance =
stakingContractAccountId && stakingTokenMetadata
? await ftClient
Expand Down
32 changes: 17 additions & 15 deletions src/pages/pot/[potId]/payouts.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -129,12 +127,16 @@ export default function PayoutsTab() {
<div className="flex w-full flex-wrap items-center justify-between">
<h2 className="text-xl font-semibold">{"Estimated Payout"}</h2>

{votingRoundResults === undefined ? (
{handleVotingRoundResultsCsvDownload === undefined ? (
<Skeleton className="w-45 h-10" />
) : (
<Button variant="brand-outline" onClick={handleCsvExport} disabled>
<Button
variant="brand-outline"
onClick={handleVotingRoundResultsCsvDownload}
disabled // TODO: remove once accumulated weight is calculated correctly
>
<MdFileDownload className="h-5 w-5" />
<span>{"Export results in CSV"}</span>
<span className="prose">{"Download CSV"}</span>
</Button>
)}
</div>
Expand Down Expand Up @@ -175,18 +177,18 @@ export default function PayoutsTab() {
{ hidden: !showChallenges },
)}
>
<PotPayoutChallenges potDetail={potDetail} setTotalChallenges={setTotalChallenges} />
<PotPayoutChallenges potDetail={pot} setTotalChallenges={setTotalChallenges} />
</div>

<div className="mb-16 flex w-full flex-col items-start gap-6 md:flex-row">
<div className="w-full">
{!potDetail?.all_paid_out ? (
{!pot?.all_paid_out ? (
<Alert variant="neutral">
<MdOutlineInfo className="color-neutral-400 h-6 w-6" />
<AlertTitle>{"Justification For Payout Changes"}</AlertTitle>

<AlertDescription>
{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."}
</AlertDescription>
Expand Down Expand Up @@ -318,7 +320,7 @@ export default function PayoutsTab() {
"hidden w-full transition-all duration-500 ease-in-out md:w-[33%]",
)}
>
<PotPayoutChallenges potDetail={potDetail} setTotalChallenges={setTotalChallenges} />
<PotPayoutChallenges potDetail={pot} setTotalChallenges={setTotalChallenges} />
</div>
</div>
);
Expand Down
4 changes: 1 addition & 3 deletions src/pages/pot/[potId]/votes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,7 @@ export default function PotVotesTab() {
<Alert variant={isVotingPeriodOngoing ? "neutral" : "warning"}>
<MdOutlineInfo className="color-neutral-400 h-6 w-6" />

<AlertTitle>
{`Voting is ${isVotingPeriodOngoing ? "open" : "closed"} for this round`}
</AlertTitle>
<AlertTitle>{`Voting round is ${isVotingPeriodOngoing ? "open" : "closed"}`}</AlertTitle>

{isVotingPeriodOngoing && (
<AlertDescription>{"You can cast your votes now."}</AlertDescription>
Expand Down

1 comment on commit 606c871

@vercel
Copy link

@vercel vercel bot commented on 606c871 Dec 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.