Skip to content

Commit

Permalink
Merge branch 'proposal-supporters' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati0x committed Dec 12, 2024
2 parents effe34f + 582021b commit 7124d8d
Show file tree
Hide file tree
Showing 5 changed files with 1,186 additions and 855 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useAccount, useToken } from "wagmi";
import {
getProposalDataDocument,
getProposalDataQuery,
getProposalSupportersQuery,
getProposalSupportersDocument,
isMemberDocument,
isMemberQuery,
} from "#/subgraph/.graphclient";
Expand All @@ -37,12 +39,18 @@ import { useConvictionRead } from "@/hooks/useConvictionRead";
import { ConditionObject, useDisableButtons } from "@/hooks/useDisableButtons";
import { useMetadataIpfsFetch } from "@/hooks/useIpfsFetch";
import { useSubgraphQuery } from "@/hooks/useSubgraphQuery";
import { alloABI } from "@/src/generated";
import { alloABI, safeABI } from "@/src/generated";
import { PoolTypes, ProposalStatus } from "@/types";

import { useErrorDetails } from "@/utils/getErrorName";
import { calculatePercentageBigInt } from "@/utils/numbers";
import { prettyTimestamp } from "@/utils/text";

type ProposalSupporter = {
id: string;
stakes: { amount: number }[];
};

export default function Page({
params: { proposalId, garden, community: communityAddr, poolId },
}: {
Expand All @@ -65,6 +73,7 @@ export default function Page({
variables: {
garden: garden.toLowerCase(),
proposalId: proposalId.toLowerCase(),
communityId: communityAddr.toLowerCase(),
},
changeScope: {
topic: "proposal",
Expand All @@ -74,6 +83,16 @@ export default function Page({
},
});

//query to get proposal supporters
const { data: supportersData } = useSubgraphQuery<getProposalSupportersQuery>(
{
query: getProposalSupportersDocument,
variables: {
proposalId: proposalId.toLowerCase(),
},
},
);

//query to get member registry in community
const { data: memberData } = useSubgraphQuery<isMemberQuery>({
query: isMemberDocument,
Expand All @@ -89,6 +108,27 @@ export default function Page({
//

const proposalData = data?.cvproposal;
const proposalSupporters = supportersData?.members;

const filteredAndSortedProposalSupporters =
proposalSupporters ?
proposalSupporters
.filter((item) => item.stakes && item.stakes.length > 0)
.sort((a, b) => {
const maxStakeA = Math.max(
...(a.stakes ?? []).map((stake) => stake.amount),
);
const maxStakeB = Math.max(
...(b.stakes ?? []).map((stake) => stake.amount),
);
return maxStakeB - maxStakeA;
})
: [];
const totalEffectiveActivePoints =
proposalData?.strategy?.totalEffectiveActivePoints;

//

const proposalIdNumber =
proposalData?.proposalNumber ?
BigInt(proposalData.proposalNumber)
Expand Down Expand Up @@ -196,6 +236,7 @@ export default function Page({
router.push(newPath + `?${QUERY_PARAMS.poolPage.allocationView}=true`);
};
const distributeErrorName = useErrorDetails(errorDistribute);

useEffect(() => {
if (isErrorDistribute && distributeErrorName.errorName !== undefined) {
toast.error("NOT EXECUTABLE:" + " " + distributeErrorName.errorName);
Expand All @@ -204,6 +245,7 @@ export default function Page({

if (
!proposalData ||
!supportersData ||
!metadata ||
proposalIdNumber == null ||
updatedConviction == null
Expand All @@ -224,7 +266,6 @@ export default function Page({
};

const status = ProposalStatus[proposalData.proposalStatus];

return (
<div className="page-layout">
<header
Expand Down Expand Up @@ -321,42 +362,165 @@ export default function Page({
Manage support
</Button>
</div>
<ConvictionBarChart
currentConvictionPct={currentConvictionPct}
thresholdPct={thresholdPct}
proposalSupportPct={totalSupportPct}
isSignalingType={isSignalingType}
proposalNumber={Number(proposalIdNumber)}
timeToPass={Number(timeToPass)}
onReadyToExecute={triggerConvictionRefetch}
defaultChartMaxValue
/>
<div className="flex justify-center w-full">
{status === "active" && !isSignalingType && (
<Button
onClick={() =>
writeDistribute?.({
args: [
BigInt(poolId),
[proposalData?.strategy.id as Address],
encodedDataProposalId(proposalIdNumber),
],
})
}
disabled={currentConvictionPct < thresholdPct || !isConnected}
tooltip={
tooltipMessage ?? currentConvictionPct < thresholdPct ?
"Proposal not executable"
: undefined
}
>
Execute
</Button>
)}
<div className="flex flex-col gap-7">
<ConvictionBarChart
currentConvictionPct={currentConvictionPct}
thresholdPct={thresholdPct}
proposalSupportPct={totalSupportPct}
isSignalingType={isSignalingType}
proposalNumber={Number(proposalIdNumber)}
timeToPass={Number(timeToPass)}
onReadyToExecute={triggerConvictionRefetch}
defaultChartMaxValue
/>
<div className="flex justify-center lg:justify-end w-full">
{status === "active" && !isSignalingType && (
<Button
onClick={() =>
writeDistribute?.({
args: [
BigInt(poolId),
[proposalData?.strategy.id as Address],
encodedDataProposalId(proposalIdNumber),
],
})
}
disabled={
currentConvictionPct < thresholdPct || !isConnected
}
tooltip={
(tooltipMessage ?? currentConvictionPct < thresholdPct) ?
"Proposal not executable"
: undefined
}
>
Execute
</Button>
)}
</div>
</div>
</>
}
</section>
{filteredAndSortedProposalSupporters.length > 0 && (
<ProposalSupportersTable
_proposalSupporters={
filteredAndSortedProposalSupporters as ProposalSupporter[]
}
_totalActivePoints={totalEffectiveActivePoints}
_totalStakedAmount={totalSupportPct}
_beneficiary={beneficiary}
_submitter={submitter}
/>
)}
</div>
);
}

function ProposalSupportersTable({
_proposalSupporters,
_totalActivePoints,
_totalStakedAmount,
_beneficiary,
_submitter,
}: {
_proposalSupporters: ProposalSupporter[];
_totalActivePoints: number;
_totalStakedAmount: number;
_beneficiary: string | undefined;
_submitter: string | undefined;
}) {
return (
<div className="px-2 section-layout">
<div className="sm:flex sm:items-center">
<div className="sm:flex-auto">
<h3>Supported By</h3>
<p className="mt-2 text-sm text-neutral-soft-content">
A list of all the community members that are supporting this
proposal.
</p>
</div>
</div>
<div className="mt-8 flow-root">
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<table className="min-w-full divide-y divide-neutral-soft">
<thead>
<tr>
<th scope="col" className="py-3.5 pl-4 pr-3 sm:pl-0">
<h5>
{_proposalSupporters.length > 1 ?
"Supporters"
: "Supporter"}
</h5>
</th>
<th scope="col" className="px-3 py-3.5">
<h5>Role</h5>
</th>
<th scope="col" className="px-3 py-3.5 text-center">
<h5>Support</h5>
</th>
</tr>
</thead>
<tbody className="divide-y divide-neutral-soft">
{_proposalSupporters.map((supporter: ProposalSupporter) => (
<tr key={supporter.id}>
<td className="whitespace-nowrap py-5 pl-4 pr-3 sm:pl-0 text-sm text-neutral-soft-content">
<div className="flex items-center">
<div className="ml-4">
<EthAddress
address={supporter.id as Address}
actions="copy"
shortenAddress={false}
icon={"ens"}
/>
</div>
</div>
</td>
{/* members role */}
<td className="whitespace-nowrap px-3 py-5 text-sm text-neutral-soft-content">
<p>
{supporter.id === _beneficiary ?
"Beneficiary"
: supporter.id === _submitter ?
"Submitter"
: "Member"}
</p>
</td>
{/* members support */}
<td className="whitespace-nowrap px-3 py-5 text-sm text-neutral-soft-content">
<p className="subtitle">
{(_totalActivePoints ?? 0) > 0 ?
calculatePercentageBigInt(
BigInt(supporter?.stakes[0]?.amount),
BigInt(_totalActivePoints ?? 0),
)
: undefined}{" "}
%
</p>{" "}
</td>
</tr>
))}
</tbody>
<tfoot>
<tr>
<th
scope="col"
colSpan={2}
className="pl-8 pr-3 pt-4 sm:table-cell sm:pl-0"
>
<p className="subtitle">Total Support:</p>
</th>

<td className="pl-3 pr-4 pt-4 text-left sm:pr-0">
<p className="subtitle">{_totalStakedAmount} %</p>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
);
}
18 changes: 18 additions & 0 deletions pkg/subgraph/.graphclient/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3529,6 +3529,9 @@ export declare function getBuiltGraphSDK<TGlobalContext = any, TOperationContext
communityAddr: Scalars["ID"]["input"];
tokenAddr: Scalars["ID"]["input"];
}>, options?: TOperationContext): Promise<getPoolCreationDataQuery>;
getProposalSupporters(variables: Exact<{
proposalId: Scalars["String"]["input"];
}>, options?: TOperationContext): Promise<getProposalSupportersQuery>;
getGardenCommunities(variables: Exact<{
chainId: Scalars["BigInt"]["input"];
tokenGarden: Scalars["ID"]["input"];
Expand All @@ -3547,6 +3550,7 @@ export declare function getBuiltGraphSDK<TGlobalContext = any, TOperationContext
getProposalData(variables: Exact<{
garden: Scalars["ID"]["input"];
proposalId: Scalars["ID"]["input"];
communityId: Scalars["ID"]["input"];
}>, options?: TOperationContext): Promise<getProposalDataQuery>;
getAllo(variables?: Exact<{
[key: string]: never;
Expand Down Expand Up @@ -3660,6 +3664,16 @@ export type getPoolCreationDataQuery = {
allos: Array<Pick<Allo, 'id'>>;
registryCommunity?: Maybe<Pick<RegistryCommunity, 'communityName' | 'isValid'>>;
};
export type getProposalSupportersQueryVariables = Exact<{
proposalId: Scalars['String']['input'];
}>;
export type getProposalSupportersQuery = {
members: Array<(Pick<Member, 'id'> & {
stakes?: Maybe<Array<(Pick<Stake, 'amount'> & {
proposal: Pick<CVProposal, 'proposalNumber' | 'id'>;
})>>;
})>;
};
export type getGardenCommunitiesQueryVariables = Exact<{
chainId: Scalars['BigInt']['input'];
tokenGarden: Scalars['ID']['input'];
Expand Down Expand Up @@ -3715,10 +3729,12 @@ export type getPoolDataQuery = {
export type getProposalDataQueryVariables = Exact<{
garden: Scalars['ID']['input'];
proposalId: Scalars['ID']['input'];
communityId: Scalars['ID']['input'];
}>;
export type getProposalDataQuery = {
allos: Array<Pick<Allo, 'id' | 'chainId' | 'tokenNative'>>;
tokenGarden?: Maybe<Pick<TokenGarden, 'name' | 'symbol' | 'decimals'>>;
registryCommunity?: Maybe<Pick<RegistryCommunity, 'councilSafe'>>;
cvproposal?: Maybe<(Pick<CVProposal, 'id' | 'proposalNumber' | 'beneficiary' | 'blockLast' | 'convictionLast' | 'createdAt' | 'metadataHash' | 'proposalStatus' | 'requestedAmount' | 'requestedToken' | 'stakedAmount' | 'submitter' | 'threshold' | 'updatedAt' | 'version'> & {
metadata?: Maybe<Pick<ProposalMetadata, 'title' | 'description'>>;
strategy: (Pick<CVStrategy, 'id' | 'token' | 'maxCVSupply' | 'totalEffectiveActivePoints' | 'poolId'> & {
Expand Down Expand Up @@ -3839,6 +3855,7 @@ export declare const getMemberStrategyDocument: DocumentNode<getMemberStrategyQu
export declare const isMemberDocument: DocumentNode<isMemberQuery, isMemberQueryVariables>;
export declare const getMemberDocument: DocumentNode<getMemberQuery, getMemberQueryVariables>;
export declare const getPoolCreationDataDocument: DocumentNode<getPoolCreationDataQuery, getPoolCreationDataQueryVariables>;
export declare const getProposalSupportersDocument: DocumentNode<getProposalSupportersQuery, getProposalSupportersQueryVariables>;
export declare const getGardenCommunitiesDocument: DocumentNode<getGardenCommunitiesQuery, getGardenCommunitiesQueryVariables>;
export declare const getCommunityDocument: DocumentNode<getCommunityQuery, getCommunityQueryVariables>;
export declare const getCommunityCreationDataDocument: DocumentNode<getCommunityCreationDataQuery, getCommunityCreationDataQueryVariables>;
Expand All @@ -3864,6 +3881,7 @@ export declare function getSdk<C, E>(requester: Requester<C, E>): {
isMember(variables: isMemberQueryVariables, options?: C): Promise<isMemberQuery>;
getMember(variables: getMemberQueryVariables, options?: C): Promise<getMemberQuery>;
getPoolCreationData(variables: getPoolCreationDataQueryVariables, options?: C): Promise<getPoolCreationDataQuery>;
getProposalSupporters(variables: getProposalSupportersQueryVariables, options?: C): Promise<getProposalSupportersQuery>;
getGardenCommunities(variables: getGardenCommunitiesQueryVariables, options?: C): Promise<getGardenCommunitiesQuery>;
getCommunity(variables: getCommunityQueryVariables, options?: C): Promise<getCommunityQuery>;
getCommunityCreationData(variables?: getCommunityCreationDataQueryVariables, options?: C): Promise<getCommunityCreationDataQuery>;
Expand Down
Loading

0 comments on commit 7124d8d

Please sign in to comment.