Skip to content

Commit

Permalink
Merge pull request #3210 from OlympusDAO/voterParticipation
Browse files Browse the repository at this point in the history
add ability to view voter participation and comments
  • Loading branch information
brightiron authored Oct 7, 2024
2 parents a3c651b + 2369395 commit 7b2011e
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 5 deletions.
9 changes: 9 additions & 0 deletions src/helpers/environment/Environment/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ export class Environment {
}),
);

public static getGovernanceSubgraphUrl = (): string => {
const subgraphApiKey = this.getSubgraphApiKey();
return this._get({
first: true,
key: "VITE_GOVERNANCE_SUBGRAPH_URL",
fallback: `https://gateway.thegraph.com/api/${subgraphApiKey}/subgraphs/id/AQoLCXebY1Ga7DrqVaVQ85KMwS7iFof73tv9XMVGRtyJ`,
});
};

public static getNodeUrls = (networkId: NetworkId) => {
switch (networkId) {
case NetworkId.MAINNET:
Expand Down
99 changes: 99 additions & 0 deletions src/views/Governance/Proposals/VoteDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
Box,
Paper,
Tab,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Tabs,
Typography,
} from "@mui/material";
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import { useGetVotes } from "src/views/Governance/hooks/useGetVotes";
import { VoteRow } from "src/views/Governance/Proposals/VoteRow";

// Data for the tables, including a 'reason' field for each row
const tablesData = [
{
id: "For",
},
{
id: "Against",
},
{
id: "Abstain",
},
];

const TabPanel = (props: { children: React.ReactNode; value: number; index: number }) => {
const { children, value, index, ...other } = props;
return (
<div role="tabpanel" hidden={value !== index} id={`tabpanel-${index}`} aria-labelledby={`tab-${index}`} {...other}>
{value === index && <Box p={3}>{children}</Box>}
</div>
);
};

export default function GovernanceTable() {
const { id } = useParams();
const [tabIndex, setTabIndex] = useState(0);
const { data: voteData } = useGetVotes({ proposalId: id, support: tabIndex + 1 });

const handleTabChange = (event: React.SyntheticEvent, newIndex: number) => {
setTabIndex(newIndex);
};

return (
<Box sx={{ width: "100%" }}>
<Tabs
textColor="primary"
aria-label="proposal tabs"
indicatorColor="primary"
value={tabIndex}
onChange={handleTabChange}
//hides the tab underline sliding animation in while <Zoom> is loading
TabIndicatorProps={{ style: { display: "none" } }}
centered
>
{" "}
{tablesData.map((table, index) => (
<Tab label={table.id} key={index} />
))}
</Tabs>

{tablesData.map((table, index) => (
<TabPanel value={tabIndex} index={index} key={index}>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>{tablesData[tabIndex].id}</TableCell>
<TableCell align="right">Votes</TableCell>
</TableRow>
</TableHead>
<TableBody>
{voteData?.length ? (
voteData.map((row, i) => (
<TableRow key={i}>
<VoteRow voter={row.voter} reason={row.reason} votes={row.votes} tx={row.transactionHash} />
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={2} align="center">
<Typography>No votes yet</Typography>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
</TabPanel>
))}
</Box>
);
}
37 changes: 37 additions & 0 deletions src/views/Governance/Proposals/VoteRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Box, Link, TableCell, Tooltip, Typography } from "@mui/material";
import { formatEther } from "ethers/lib/utils.js";
import { abbreviatedNumber } from "src/helpers";
import { truncateEthereumAddress } from "src/helpers/truncateAddress";
import { useEnsName } from "wagmi";

export const VoteRow = ({
voter,
reason,
votes,
tx,
}: {
voter: string;
reason?: string;
votes: string;
tx: string;
}) => {
const { data: ensName } = useEnsName({ address: voter as `0x${string}` });
return (
<>
<TableCell>
<Link href={`https://etherscan.io/tx/${tx}`} target="_blank" rel="noopener noreferrer">
<Tooltip title={voter}>
<Box>{ensName || truncateEthereumAddress(voter)}</Box>
</Tooltip>
</Link>
{/* Render the reason if provided, and style it as a comment */}
{reason && (
<Typography variant="body2" sx={{ color: "gray", fontStyle: "italic", mt: 1 }}>
"{reason}"
</Typography>
)}
</TableCell>
<TableCell align="right">{abbreviatedNumber.format(Number(formatEther(votes) || 0))} gOHM</TableCell>
</>
);
};
8 changes: 3 additions & 5 deletions src/views/Governance/Proposals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { useGetCurrentBlockTime } from "src/views/Governance/hooks/useGetCurrent
import { useGetProposalDetails } from "src/views/Governance/hooks/useGetProposalDetails";
import { useGetProposal } from "src/views/Governance/hooks/useGetProposals";
import { useQueueProposal } from "src/views/Governance/hooks/useQueueProposal";
import VoteDetails from "src/views/Governance/Proposals/VoteDetails";
import { useEnsName, useNetwork, useSwitchNetwork } from "wagmi";

export const ProposalPage = () => {
Expand Down Expand Up @@ -160,7 +161,7 @@ export const ProposalPage = () => {
>
<Tab label="Description" />
<Tab label="Executable Code" />
{/* <Tab label="Comments" /> */}
<Tab label="Participation" />
</Tabs>
</Box>
<Grid container spacing={"24px"}>
Expand Down Expand Up @@ -197,11 +198,8 @@ export const ProposalPage = () => {
)}
{tabIndex === 2 && (
<>
<Typography fontSize="21px" fontWeight={600} mb="15px">
Comments
</Typography>
<Box display="flex" flexDirection="column" gap="15px">
<Typography>No comments yet</Typography>
<VoteDetails />
</Box>
</>
)}
Expand Down
38 changes: 38 additions & 0 deletions src/views/Governance/hooks/useGetVotes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useQuery } from "@tanstack/react-query";
import request, { gql } from "graphql-request";
import { Environment } from "src/helpers/environment/Environment/Environment";

export const useGetVotes = ({ proposalId, support }: { proposalId?: string; support: number }) => {
return useQuery(
["getVotes", proposalId, support],
async () => {
const query = gql`
query MyQuery {
voteCasts(orderBy: votes, orderDirection: desc, where: {proposalId: ${proposalId}, support: ${support} }) {
votes
voter
reason
support
transactionHash
}
}
`;

type votesResponse = {
voteCasts: {
votes: string;
voter: string;
reason: string;
support: number;
transactionHash: string;
}[];
};

const subgraphUrl = Environment.getGovernanceSubgraphUrl();
const response = await request<votesResponse>(subgraphUrl, query);

return response.voteCasts || [];
},
{ enabled: !!proposalId && !!support },
);
};

0 comments on commit 7b2011e

Please sign in to comment.