Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: quorum information on vote section #785

Merged
merged 5 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#785](https://github.com/alleslabs/celatone-frontend/pull/785) Quorum status on vote details section
- [#782](https://github.com/alleslabs/celatone-frontend/pull/782) Show proposal details on vote details section tabs
- [#779](https://github.com/alleslabs/celatone-frontend/pull/779) Proposal period overview voting - no with veto alert
- [#778](https://github.com/alleslabs/celatone-frontend/pull/778) Proposal period overview voting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@ interface VoteQuorumCircleProps {
nonAbstainVotes: Big;
totalVotes: Big;
isCompact: boolean;
isBgGray?: boolean;
}

export const VoteQuorumCircle = ({
quorum,
nonAbstainVotes,
totalVotes,
isCompact,
isBgGray,
}: VoteQuorumCircleProps) => {
const nonAbstainVotesAngle = nonAbstainVotes.toNumber() * 360;

const totalVotesAngle = totalVotes.toNumber() * 360;
const totalVotesPercent = formatPrettyPercent(
totalVotes.toNumber(),
isCompact ? 1 : 2
);
const totalVotesPercent = formatPrettyPercent(totalVotes.toNumber(), 1);

const quorumAngle = quorum * 360;
const quorumPercent = formatPrettyPercent(quorum);
Expand Down Expand Up @@ -51,7 +50,7 @@ export const VoteQuorumCircle = ({
<Circle
size={isCompact ? "52px" : "134px"}
position="absolute"
bgColor="background.main"
bgColor={isBgGray ? "gray.900" : "background.main"}
>
{!isCompact && (
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { Text } from "@chakra-ui/react";
import { ProposalStatus } from "lib/types";
import { formatPrettyPercent } from "lib/utils";

interface VotingOverviewQuorumTextProps {
interface VoteQuorumTextProps {
status: ProposalStatus;
quorum: number;
totalVotes: Big;
isCompact: boolean;
}

const Established = () => (
Expand All @@ -20,37 +21,39 @@ const Established = () => (
</span>
);

export const VotingOverviewQuorumText = ({
export const VoteQuorumText = ({
status,
quorum,
totalVotes,
}: VotingOverviewQuorumTextProps) => {
isCompact,
}: VoteQuorumTextProps) => {
const fontVariant = isCompact ? "body2" : "body1";
const quorumPercent = formatPrettyPercent(quorum);
const isPassingQuorum = totalVotes.gte(quorum);

if (status === ProposalStatus.VOTING_PERIOD)
return isPassingQuorum ? (
<Text variant="body2" color="text.main">
<Text variant={fontVariant} color="text.main">
The proposal has successfully met the voting{" "}
<span style={{ fontWeight: 700 }}>{quorumPercent}</span> quorum and will
be <Established /> after the voting period ends.
</Text>
) : (
<Text variant="body2" color="text.main">
<Text variant={fontVariant} color="text.main">
The proposal required{" "}
<span style={{ fontWeight: 700 }}>{quorumPercent}</span> vote quorum to
establish.
</Text>
);

return isPassingQuorum ? (
<Text variant="body2" color="text.main">
<Text variant={fontVariant} color="text.main">
The proposal has successfully met the voting{" "}
<span style={{ fontWeight: 700 }}>{quorumPercent}</span> quorum and{" "}
<Established />.
</Text>
) : (
<Text variant="body2" color="text.main">
<Text variant={fontVariant} color="text.main">
This proposal{" "}
<span
style={{
Expand Down
45 changes: 45 additions & 0 deletions src/lib/pages/proposal-details/components/VpPercentCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Flex, Text, type FlexProps, Heading } from "@chakra-ui/react";

import { d0Formatter, formatPrettyPercent } from "lib/utils";

interface VpPercentCardProps {
name: string;
ratio: Big;
power: Big;
color: FlexProps["bgColor"];
isCompact: boolean;
}

export const VpPercentCard = ({
name,
ratio,
power,
color,
isCompact,
}: VpPercentCardProps) => (
<Flex
direction={isCompact ? "row-reverse" : "column"}
justifyContent="flex-end"
gap={2}
w="full"
>
<Flex direction="column" gap={isCompact ? 1 : 2} align="start">
<Text variant="body2" color="text.main">
{name}
</Text>
<Flex direction={isCompact ? "row" : "column"} gap={isCompact ? 2 : 0}>
<Heading as="h6" variant="h6" fontWeight={600}>
{formatPrettyPercent(ratio.toNumber())}
</Heading>
<Text variant="body2" color="text.dark">
({d0Formatter(power, "0")})
</Text>
</Flex>
</Flex>
<Flex
bgColor={color}
borderRadius={10}
{...(isCompact ? { w: 1, h: "full" } : { w: "full", h: 1 })}
/>
</Flex>
);
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const VotingOverviewBody = ({
);

if (isLoading) return <Loading my={0} />;
if (!params || !votesInfo) return <ErrorFetchingProposalInfos isParamsOnly />;
if (!params || !votesInfo) return <ErrorFetchingProposalInfos />;

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, Divider, Flex, Text } from "@chakra-ui/react";

import { VoteQuorumBadge } from "../../VoteQuorumBadge";
import { VoteQuorumCircle } from "../../VoteQuorumCircle";
import { VoteQuorumText } from "../../VoteQuorumText";
import { CustomIcon } from "lib/components/icon";
import { Tooltip } from "lib/components/Tooltip";
import {
Expand All @@ -15,8 +16,6 @@ import type {
} from "lib/types";
import { dateFromNow, formatPrettyPercent, formatUTC } from "lib/utils";

import { VotingOverviewQuorumText } from "./VotingOverviewQuorumText";

interface VotingOverviewQuorumProps {
proposalData: ProposalData;
params: ProposalParams;
Expand Down Expand Up @@ -82,10 +81,11 @@ export const VotingOverviewQuorum = ({
</Box>
</Tooltip>
<Flex direction="column" gap={2}>
<VotingOverviewQuorumText
<VoteQuorumText
status={proposalData.status}
quorum={quorum}
totalVotes={totalVotes}
isCompact
/>
<div>
<Text variant="body3" color="text.dark">
Expand Down
18 changes: 13 additions & 5 deletions src/lib/pages/proposal-details/components/vote-details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@ import {
} from "@chakra-ui/react";

import { useMobile } from "lib/app-provider";
import type { ProposalData } from "lib/types";
import type {
Option,
ProposalData,
ProposalParams,
ProposalVotesInfo,
} from "lib/types";

import { DepositPeriodSection } from "./deposit-period/DepositPeriodSection";
import { VoteDetailsAccordionItem } from "./VoteDetailsAccordionItem";
import { VoteDetailsTab } from "./VoteDetailsTab";
import { VotingPeriod } from "./voting-period";

interface VoteDetailsProps {
export interface VoteDetailsProps {
proposalData: ProposalData;
votesInfo: Option<ProposalVotesInfo>;
params: Option<ProposalParams>;
isLoading: boolean;
}

export const VoteDetails = ({ proposalData }: VoteDetailsProps) => {
export const VoteDetails = ({ proposalData, ...props }: VoteDetailsProps) => {
const isMobile = useMobile();

return isMobile ? (
Expand All @@ -29,7 +37,7 @@ export const VoteDetails = ({ proposalData }: VoteDetailsProps) => {
<DepositPeriodSection />
</VoteDetailsAccordionItem>
<VoteDetailsAccordionItem step={2} proposalData={proposalData}>
<VotingPeriod id={proposalData.id} />
<VotingPeriod proposalData={proposalData} {...props} />
</VoteDetailsAccordionItem>
</Accordion>
</Flex>
Expand All @@ -52,7 +60,7 @@ export const VoteDetails = ({ proposalData }: VoteDetailsProps) => {
<DepositPeriodSection />
</TabPanel>
<TabPanel>
<VotingPeriod id={proposalData.id} />
<VotingPeriod proposalData={proposalData} {...props} />
</TabPanel>
</TabPanels>
</Tabs>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Divider, Flex, Heading, Spacer, Text } from "@chakra-ui/react";
import big from "big.js";

import type { VoteDetailsProps } from "..";
import { ErrorFetchingProposalInfos } from "../../ErrorFetchingProposalInfos";
import { VoteQuorumBadge } from "../../VoteQuorumBadge";
import { VoteQuorumCircle } from "../../VoteQuorumCircle";
import { VoteQuorumText } from "../../VoteQuorumText";
import { VpPercentCard } from "../../VpPercentCard";
import { useMobile } from "lib/app-provider";
import { Loading } from "lib/components/Loading";
import {
extractParams,
normalizeVotesInfo,
} from "lib/pages/proposal-details/utils";

export const VotingQuorum = ({
proposalData,
params,
votesInfo,
isLoading,
}: VoteDetailsProps) => {
const isMobile = useMobile();
if (isLoading) return <Loading my={0} />;
if (!params || !votesInfo) return <ErrorFetchingProposalInfos />;

const { quorum } = extractParams(params, proposalData.isExpedited);
const { abstain, nonAbstainVotes, totalVotes } =
normalizeVotesInfo(votesInfo);

const votes = votesInfo.yes.add(votesInfo.no).add(votesInfo.noWithVeto);
const allVotes = votes.add(votesInfo.abstain);

return (
<Flex direction="column" gap={4}>
<Flex gap={2} align="center">
{isMobile ? (
<>
<VoteQuorumBadge
status={proposalData.status}
quorum={quorum}
totalVotes={totalVotes}
isCompact
/>
<Text variant="body1" color="text.main">
Quorum
</Text>
</>
) : (
<>
<Heading as="h6" variant="h6" textColor="text.main">
Vote Participations
</Heading>
<VoteQuorumBadge
status={proposalData.status}
quorum={quorum}
totalVotes={totalVotes}
isCompact={false}
/>
<Spacer />
<Text variant="body3" textColor="text.dark">
* Voting power displayed in bracket
</Text>
</>
)}
</Flex>
{isMobile && <Divider borderColor="gray.700" />}
<Flex
direction={{ base: "column", md: "row" }}
gap={{ base: 3, md: 12 }}
align="center"
textAlign={{ base: "center", md: "start" }}
w="full"
>
<VoteQuorumCircle
quorum={quorum}
nonAbstainVotes={nonAbstainVotes}
totalVotes={totalVotes}
isCompact={false}
isBgGray={!isMobile}
/>
<Flex direction="column" gap={4} w="full">
<VoteQuorumText
status={proposalData.status}
quorum={quorum}
totalVotes={totalVotes}
isCompact={false}
/>
<Flex direction={isMobile ? "column" : "row"} gap={isMobile ? 3 : 8}>
<VpPercentCard
name="Voted"
ratio={nonAbstainVotes}
power={votes}
color="primary.main"
isCompact={isMobile}
/>
<VpPercentCard
name="Voted Abstain"
ratio={abstain}
power={votesInfo.abstain}
color="secondary.main"
isCompact={isMobile}
/>
<Divider
orientation="vertical"
h="auto"
color="gray.700"
display={{ base: "none", lg: "flex" }}
/>
<VpPercentCard
name="Did not vote"
ratio={big(1).minus(totalVotes)}
power={votesInfo.totalVotingPower.minus(allVotes)}
color="gray.800"
isCompact={isMobile}
/>
</Flex>
</Flex>
</Flex>
</Flex>
);
};
Loading
Loading