Skip to content

Commit

Permalink
Applying common statuses to the proposal list
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed Mar 4, 2024
1 parent 469217c commit 71f8a74
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 81 deletions.
45 changes: 2 additions & 43 deletions plugins/tokenVoting/components/proposal/header.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { AlertInline, Button, Tag } from "@aragon/ods";
import { Proposal, VotingMode } from "@/plugins/tokenVoting/utils/types";
import { Proposal } from "@/plugins/tokenVoting/utils/types";
import { AlertVariant } from "@aragon/ods";
import { getProposalStatusVariant } from "@/plugins/tokenVoting/utils/proposal-status";
import { Else, ElseIf, If, Then } from "@/components/if";
import { AddressText } from "@/components/text/address";
import { PleaseWaitSpinner } from "@/components/please-wait";
import dayjs from "dayjs";

const RATIO_BASE = 1_000_000;
const DEFAULT_PROPOSAL_TITLE = "(No proposal title)";

interface ProposalHeaderProps {
Expand Down Expand Up @@ -128,47 +128,6 @@ const ProposalHeader: React.FC<ProposalHeaderProps> = ({
);
};

const getProposalStatusVariant = (proposal: Proposal, tokenSupply: bigint) => {
// Terminal cases
if (!proposal?.tally) return { variant: "info", label: "" };
else if (proposal.executed) return { variant: "primary", label: "Executed" };

const yesNoVotes = proposal.tally.no + proposal.tally.yes;
if (!yesNoVotes) return { variant: "info", label: "" };

const totalVotes = proposal.tally.abstain + yesNoVotes;
const supportThreshold = proposal.parameters.supportThreshold;

if (!proposal.active) {
// Defeated or executable?
if (totalVotes < proposal.parameters.minVotingPower) {
return { variant: "critical", label: "Low turnout" };
}

const totalYesNo = proposal.tally.yes + proposal.tally.no;
const finalRatio = (BigInt(RATIO_BASE) * proposal.tally.yes) / totalYesNo;

if (finalRatio > BigInt(supportThreshold)) {
return { variant: "success", label: "Executable" };
}
return { variant: "critical", label: "Defeated" };
}

// Active or early execution?
const noVotesWorstCase =
tokenSupply - proposal.tally.yes - proposal.tally.abstain;
const totalYesNoWc = proposal.tally.yes + noVotesWorstCase;

if (proposal.parameters.votingMode == VotingMode.EarlyExecution) {
const currentRatio =
(BigInt(RATIO_BASE) * proposal.tally.yes) / totalYesNoWc;
if (currentRatio > BigInt(supportThreshold)) {
return { variant: "success", label: "Executable" };
}
}
return { variant: "info", label: "Active" };
};

const getUserVoteVariant = (userVote?: number) => {
switch (userVote) {
case 3:
Expand Down
53 changes: 15 additions & 38 deletions plugins/tokenVoting/components/proposal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Link from "next/link";
import { Proposal } from "@/plugins/tokenVoting/utils/types";
import { useProposal } from "@/plugins/tokenVoting/hooks/useProposal";
import { TagVariant } from "@aragon/ods";
import { getProposalStatusVariant } from "@/plugins/tokenVoting/utils/proposal-status";
import { Card, Tag } from "@aragon/ods";
import * as DOMPurify from 'dompurify';
import * as DOMPurify from "dompurify";
import { PleaseWaitSpinner } from "@/components/please-wait";
import { If } from "@/components/if";

Expand All @@ -13,31 +12,11 @@ const DEFAULT_PROPOSAL_METADATA_SUMMARY =

type ProposalInputs = {
proposalId: bigint;
};

const getProposalVariantStatus = (proposal: Proposal) => {
return {
variant: (proposal?.active
? "info"
: proposal?.executed
? "primary"
: proposal?.tally?.no >= proposal?.tally?.yes
? "critical"
: "success") as TagVariant,
label: proposal?.active
? "Active"
: proposal?.executed
? "Executed"
: proposal?.tally?.no >= proposal?.tally?.yes
? "Defeated"
: "Executable",
};
tokenSupply: bigint;
};

export default function ProposalCard(props: ProposalInputs) {
const { proposal, status } = useProposal(
props.proposalId.toString()
);
const { proposal, status } = useProposal(props.proposalId.toString());

const showLoading = getShowProposalLoading(proposal, status);

Expand All @@ -53,15 +32,11 @@ export default function ProposalCard(props: ProposalInputs) {
);
} else if (status.metadataReady && !proposal?.title) {
return (
<Link
href={`#/proposals/${props.proposalId}`}
className="w-full mb-4"
>
<Link href={`#/proposals/${props.proposalId}`} className="w-full mb-4">
<Card className="p-4">
<div className="md:w-7/12 lg:w-3/4 xl:4/5 pr-4 text-nowrap text-ellipsis overflow-hidden">
<h4 className="mb-1 text-lg text-neutral-300 line-clamp-1">
{Number(props.proposalId) + 1} -{" "}
{DEFAULT_PROPOSAL_METADATA_TITLE}
{Number(props.proposalId) + 1} - {DEFAULT_PROPOSAL_METADATA_TITLE}
</h4>
<p className="text-base text-neutral-300 line-clamp-3">
{DEFAULT_PROPOSAL_METADATA_SUMMARY}
Expand All @@ -72,29 +47,31 @@ export default function ProposalCard(props: ProposalInputs) {
);
}

const { variant: statusVariant, label: statusLabel } =
getProposalStatusVariant(proposal, props.tokenSupply);

return (
<Link href={`#/proposals/${props.proposalId}`} className="w-full">
<Card className="w-full mb-4 p-5">
<div className="w-full">
<If condition={proposal.tally}>
<div className="flex mb-2">
<Tag
variant={getProposalVariantStatus(proposal as Proposal).variant}
label={getProposalVariantStatus(proposal as Proposal).label}
/>
<Tag variant={statusVariant as any} label={statusLabel} />
</div>
</If>

<div className="text-ellipsis overflow-hidden">
<h4 className=" mb-1 text-lg font-semibold text-dark line-clamp-1">
{Number(props.proposalId) + 1} - {proposal.title}
</h4>
<div className="text-ellipsis overflow-hidden box line-clamp-2"
<div
className="text-ellipsis overflow-hidden box line-clamp-2"
dangerouslySetInnerHTML={{
__html: proposal.summary
? DOMPurify.sanitize(proposal.summary)
: DEFAULT_PROPOSAL_METADATA_SUMMARY
}} />
: DEFAULT_PROPOSAL_METADATA_SUMMARY,
}}
/>
</div>
</div>
</Card>
Expand Down
3 changes: 3 additions & 0 deletions plugins/tokenVoting/pages/proposal-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { If } from "@/components/if";
import { PleaseWaitSpinner } from "@/components/please-wait";
import { useSkipFirstRender } from "@/hooks/useSkipFirstRender";
import { PUB_TOKEN_VOTING_PLUGIN_ADDRESS } from "@/constants";
import { useVotingToken } from "@/plugins/tokenVoting/hooks/useVotingToken";

const PROPOSALS_PER_PAGE = 10;

export default function Proposals() {
const [proposalCount, setProposalCount] = useState(0);
const { data: blockNumber } = useBlockNumber({ watch: true });
const canCreate = useCanCreateProposal();
const { tokenSupply } = useVotingToken();

const [currentPage, setCurrentPage] = useState(0);
const [paginatedProposals, setPaginatedProposals] = useState<number[]>([]);
Expand Down Expand Up @@ -72,6 +74,7 @@ export default function Proposals() {
proposalId={BigInt(
proposalCount! - 1 - currentPage * PROPOSALS_PER_PAGE - i
)}
tokenSupply={tokenSupply || BigInt("0")}
/>
))}
<div className="w-full flex flex-row justify-end gap-2 mt-4 mb-10">
Expand Down
45 changes: 45 additions & 0 deletions plugins/tokenVoting/utils/proposal-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Proposal, VotingMode } from "@/plugins/tokenVoting/utils/types";
export const RATIO_BASE = 1_000_000;

export function getProposalStatusVariant(
proposal: Proposal,
tokenSupply: bigint
) {
// Terminal cases
if (!proposal?.tally) return { variant: "info", label: "(Loading)" };
else if (proposal.executed) return { variant: "primary", label: "Executed" };

const supportThreshold = proposal.parameters.supportThreshold;

if (!proposal.active) {
// Defeated or executable?
const yesNoVotes = proposal.tally.no + proposal.tally.yes;
if (!yesNoVotes) return { variant: "critical", label: "Defeated" };

const totalVotes = proposal.tally.abstain + yesNoVotes;
if (totalVotes < proposal.parameters.minVotingPower) {
return { variant: "critical", label: "Low turnout" };
}

const finalRatio = (BigInt(RATIO_BASE) * proposal.tally.yes) / yesNoVotes;

if (finalRatio > BigInt(supportThreshold)) {
return { variant: "success", label: "Executable" };
}
return { variant: "critical", label: "Defeated" };
}

// Active or early execution?
const noVotesWorstCase =
tokenSupply - proposal.tally.yes - proposal.tally.abstain;
const totalYesNoWc = proposal.tally.yes + noVotesWorstCase;

if (proposal.parameters.votingMode == VotingMode.EarlyExecution) {
const currentRatio =
(BigInt(RATIO_BASE) * proposal.tally.yes) / totalYesNoWc;
if (currentRatio > BigInt(supportThreshold)) {
return { variant: "success", label: "Executable" };
}
}
return { variant: "info", label: "Active" };
}

0 comments on commit 71f8a74

Please sign in to comment.