diff --git a/apps/governance/src/routes/proposals/components/proposal-detail-header/proposal-header.tsx b/apps/governance/src/routes/proposals/components/proposal-detail-header/proposal-header.tsx index cc83dbc68..a8baff2f1 100644 --- a/apps/governance/src/routes/proposals/components/proposal-detail-header/proposal-header.tsx +++ b/apps/governance/src/routes/proposals/components/proposal-detail-header/proposal-header.tsx @@ -38,6 +38,7 @@ import { differenceInHours, format, formatDistanceToNowStrict } from 'date-fns'; import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats'; import { MarketName } from '../proposal/market-name'; import { Indicator } from '../proposal/indicator'; +import { type ProposalNode } from '../proposal/proposal-utils'; const ProposalTypeTags = ({ proposal, @@ -540,10 +541,12 @@ const BatchProposalStateText = ({ export const ProposalHeader = ({ proposal, + restData, isListItem = true, voteState, }: { proposal: Proposal | BatchProposal; + restData?: ProposalNode | null; isListItem?: boolean; voteState?: VoteState | null; }) => { @@ -595,7 +598,7 @@ export const ProposalHeader = ({ )} - + ); }; diff --git a/apps/governance/src/routes/proposals/components/proposal/proposal-utils.ts b/apps/governance/src/routes/proposals/components/proposal/proposal-utils.ts index 782e384e0..2bd804ed3 100644 --- a/apps/governance/src/routes/proposals/components/proposal/proposal-utils.ts +++ b/apps/governance/src/routes/proposals/components/proposal/proposal-utils.ts @@ -91,6 +91,28 @@ export type ProposalNode = { proposal: ProposalData; proposalType: ProposalNodeType; proposals: SubProposalData[]; + yes?: [ + { + partyId: string; + elsPerMarket?: [ + { + marketId: string; + els: string; + } + ]; + } + ]; + no?: [ + { + partyId: string; + elsPerMarket?: [ + { + marketId: string; + els: string; + } + ]; + } + ]; }; type SingleProposalNode = ProposalNode & { diff --git a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx index c42e6430e..36550fa38 100644 --- a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx +++ b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx @@ -48,6 +48,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => { diff --git a/apps/governance/src/routes/proposals/components/vote-breakdown/vote-breakdown.tsx b/apps/governance/src/routes/proposals/components/vote-breakdown/vote-breakdown.tsx index 634a5495b..06ad64b09 100644 --- a/apps/governance/src/routes/proposals/components/vote-breakdown/vote-breakdown.tsx +++ b/apps/governance/src/routes/proposals/components/vote-breakdown/vote-breakdown.tsx @@ -17,6 +17,7 @@ import { import { useBatchVoteInformation } from '../../hooks/use-vote-information'; import { MarketName } from '../proposal/market-name'; import { Indicator } from '../proposal/indicator'; +import { type ProposalNode } from '../proposal/proposal-utils'; export const CompactVotes = ({ number }: { number: BigNumber }) => ( { export const VoteBreakdown = ({ proposal, + restData, }: { proposal: Proposal | BatchProposal; + restData?: ProposalNode | null; }) => { if (proposal.__typename === 'Proposal') { return ; } if (proposal.__typename === 'BatchProposal') { - return ; + return ; } return null; }; -const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => { +const VoteBreakdownBatch = ({ + proposal, + restData, +}: { + proposal: BatchProposal; + restData?: ProposalNode | null; +}) => { const [fullBreakdown, setFullBreakdown] = useState(false); const { t } = useTranslation(); + const yesELS = + restData?.yes?.reduce((all, y) => { + if (y.elsPerMarket) { + y.elsPerMarket.forEach((item) => { + const share = Number(item.els); + if (all[item.marketId]) { + all[item.marketId].push(share); + } else { + all[item.marketId] = [share]; + } + return all; + }); + } + return all; + }, {} as Record) || {}; + + const noELS = + restData?.no?.reduce((all, y) => { + if (y.elsPerMarket) { + y.elsPerMarket.forEach((item) => { + const share = Number(item.els); + if (all[item.marketId]) { + all[item.marketId].push(share); + } else { + all[item.marketId] = [share]; + } + return all; + }); + } + return all; + }, {} as Record) || {}; + const voteInfo = useBatchVoteInformation({ terms: compact( proposal.subProposals ? proposal.subProposals.map((p) => p?.terms) : [] @@ -194,6 +235,8 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => { proposal={proposal} votes={proposal.votes} terms={p.terms} + yesELS={yesELS} + noELS={noELS} /> ); })} @@ -254,6 +297,8 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => { proposal={proposal} votes={proposal.votes} terms={p.terms} + yesELS={yesELS} + noELS={noELS} /> ); })} @@ -271,17 +316,17 @@ const VoteBreakdownBatchSubProposal = ({ votes, terms, indicator, + yesELS, + noELS, }: { proposal: BatchProposal; votes: VoteFieldsFragment; terms: ProposalTermsFieldsFragment; indicator?: number; + yesELS: Record; + noELS: Record; }) => { const { t } = useTranslation(); - const voteInfo = useVoteInformation({ - votes, - terms, - }); const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN; const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket'; @@ -294,6 +339,15 @@ const VoteBreakdownBatchSubProposal = ({ marketId = terms.change.market.id; } + const voteInfo = useVoteInformation({ + votes, + terms, + // yes votes ELS for this specific proposal (market) + yesELS: marketId ? yesELS[marketId] : undefined, + // no votes ELS for this specific proposal (market) + noELS: marketId ? noELS[marketId] : undefined, + }); + const marketName = marketId ? ( <> : diff --git a/apps/governance/src/routes/proposals/hooks/use-vote-information.ts b/apps/governance/src/routes/proposals/hooks/use-vote-information.ts index e3abf86e9..99363d1ae 100644 --- a/apps/governance/src/routes/proposals/hooks/use-vote-information.ts +++ b/apps/governance/src/routes/proposals/hooks/use-vote-information.ts @@ -8,13 +8,18 @@ import { type VoteFieldsFragment, } from '../__generated__/Proposals'; import { type ProposalChangeType } from '../types'; +import sum from 'lodash/sum'; export const useVoteInformation = ({ votes, terms, + yesELS, + noELS, }: { votes: VoteFieldsFragment; terms: ProposalTermsFieldsFragment; + yesELS?: number[]; + noELS?: number[]; }) => { const { appState: { totalSupply, decimals }, @@ -31,7 +36,9 @@ export const useVoteInformation = ({ paramsForChange, votes, totalSupply, - decimals + decimals, + yesELS, + noELS ); }; @@ -72,7 +79,11 @@ const getVoteData = ( }, votes: ProposalFieldsFragment['votes'], totalSupply: BigNumber, - decimals: number + decimals: number, + /** A list of ELS yes votes */ + yesELS?: number[], + /** A list if ELS no votes */ + noELS?: number[] ) => { const requiredMajorityPercentage = params.requiredMajority ? new BigNumber(params.requiredMajority).times(100) @@ -86,17 +97,31 @@ const getVoteData = ( addDecimal(votes.no.totalTokens ?? 0, decimals) ); - const noEquityLikeShareWeight = !votes.no.totalEquityLikeShareWeight + let noEquityLikeShareWeight = !votes.no.totalEquityLikeShareWeight ? new BigNumber(0) : new BigNumber(votes.no.totalEquityLikeShareWeight).times(100); + // there's no meaningful `totalEquityLikeShareWeight` in batch proposals, + // it has to be deduced from `elsPerMarket` of `no` votes of given proposal + // data. (by REST DATA) + if (noELS != null) { + const noTotalELS = sum(noELS); + noEquityLikeShareWeight = new BigNumber(noTotalELS).times(100); + } const yesTokens = new BigNumber( addDecimal(votes.yes.totalTokens ?? 0, decimals) ); - const yesEquityLikeShareWeight = !votes.yes.totalEquityLikeShareWeight + let yesEquityLikeShareWeight = !votes.yes.totalEquityLikeShareWeight ? new BigNumber(0) : new BigNumber(votes.yes.totalEquityLikeShareWeight).times(100); + // there's no meaningful `totalEquityLikeShareWeight` in batch proposals, + // it has to be deduced from `elsPerMarket` of `yes` votes of given proposal + // data. (by REST DATA) + if (noELS != null) { + const yesTotalELS = sum(yesELS); + yesEquityLikeShareWeight = new BigNumber(yesTotalELS).times(100); + } const totalTokensVoted = yesTokens.plus(noTokens);