import { useState, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { Box, Link, Tabs, Tab, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, useTheme, useMediaQuery } from "@mui/material"; import { getBlockNumber } from "@wagmi/core"; import GhostStyledIcon from "../../../components/Icon/GhostIcon"; import ArrowUpIcon from "../../../assets/icons/arrow-up.svg?react"; import { networkAvgBlockSpeed } from "../../../constants"; import { prettifySecondsInDays, prettifySeconds } from "../../../helpers/timeUtil"; import Chip from "../../../components/Chip/Chip"; import Modal from "../../../components/Modal/Modal"; import Paper from "../../../components/Paper/Paper"; import LinearProgressBar from "../../../components/Progress/LinearProgressBar"; import { PrimaryButton, TertiaryButton } from "../../../components/Button"; import ProposalInfoText from "./ProposalInfoText"; import { convertStatusToTemplate, convertStatusToLabel, MY_PROPOSALS_PREFIX, VOTED_PROPOSALS_PREFIX } from "../helpers"; import { useScreenSize } from "../../../hooks/useScreenSize"; import { useProposals, } from "../../../hooks/governance"; const MAX_PROPOSALS_TO_SHOW = 10; const ProposalsList = ({ chainId, address, config }) => { const isSmallScreen = useScreenSize("md"); const navigate = useNavigate(); const theme = useTheme(); const [proposalsFilter, setProposalFilter] = useState("active"); const myStoredProposals = localStorage.getItem(MY_PROPOSALS_PREFIX); const [myProposals, setMyProposals] = useState( myStoredProposals ? JSON.parse(myStoredProposals).map(id => BigInt(id)) : [] ); const storedVotedProposals = localStorage.getItem(VOTED_PROPOSALS_PREFIX); const [votedProposals, setVotedProposals] = useState( storedVotedProposals ? JSON.parse(storedVotedProposals).map(id => BigInt(id)) : [] ); const searchedIndexes = useMemo(() => { switch (proposalsFilter) { case "voted": return votedProposals; case "created": return myProposals; default: return undefined; } }, [proposalsFilter]); const [blockNumber, setBlockNumber] = useState(0n); const { proposals } = useProposals(chainId, MAX_PROPOSALS_TO_SHOW, searchedIndexes); getBlockNumber(config).then(block => setBlockNumber(block)); if (proposals?.length === 0 && proposalsFilter === "active") { return ( No proposals yet ); } if (isSmallScreen) { return ( Proposals } > {proposals?.map(proposal => ( navigate(`/governance/${proposal.hashes.full}`)} /> ))} {proposalsFilter === "active" && } ); } return ( Proposals View Forum } > {proposals?.map(proposal => ( navigate(`/governance/${proposal.hashes.full}`)} /> ))} {proposalsFilter === "active" && } ); } const ProposalTable = ({ children }) => ( Proposal ID Status Vote Ends Voting Stats {children}
); const ProposalRow = ({ proposal, blockNumber, openProposal, chainId }) => { const theme = useTheme(); const voteValue = useMemo(() => { const againstVotes = proposal?.votes?.at(0)?._value ?? 0n; const forVotes = proposal?.votes?.at(1)?._value ?? 0n; const totalVotes = againstVotes + forVotes; if (totalVotes == 0) { return 0; } return Number(forVotes * 100n / totalVotes); }, [proposal]); const voteTarget = useMemo(() => { const againstVotes = proposal?.votes?.at(0)?._value ?? 0n; const forVotes = proposal?.votes?.at(1)?._value ?? 0n; const totalVotes = againstVotes + forVotes; const first = (5n * againstVotes + forVotes); const second = BigInt(Math.floor(Math.sqrt(Number(totalVotes)))); const bias = 3n * first + second; const denominator = totalVotes + bias; if (denominator === 0n) { return 80; } return Number(totalVotes * 100n / denominator); }, [proposal]); return ( GDP-{proposal.hashes.short} {convertDeadline( proposal.deadline, blockNumber, chainId )} {(proposal.state === "Active" || proposal.state === "Succeeded") && openProposal()} sx={{ maxWidth: "130px" }} > {proposal.state === "Succeeded" ? "Execute" : "Vote"} } {(proposal.state !== "Active" && proposal.state !== "Succeeded") && openProposal()} sx={{ alignSelf: "right", maxWidth: "130px" }} > View } ); } const ProposalCard = ({ proposal, blockNumber, openProposal, chainId }) => { const theme = useTheme(); const isSmallScreen = useMediaQuery('(max-width: 450px)'); return ( GIP-{proposal.hashes.short} {convertDeadline( proposal.deadline, blockNumber, chainId )} {(proposal.state === "Active" || proposal.state === "Succeeded") && openProposal()} > {proposal.state === "Succeeded" ? "Execute" : "Vote"} } {(proposal.state !== "Active" && proposal.state !== "Succeeded") && openProposal()} > View } ); }; const ProposalFilterTrigger = ({ trigger, setTrigger }) => { return ( setTrigger(view)} TabIndicatorProps={{ style: { display: "none" } }} > ) } const convertDeadline = (deadline, blockNumber, chainId) => { const diff = blockNumber > deadline ? blockNumber - deadline : deadline - blockNumber; const voteSeconds = Number(diff * networkAvgBlockSpeed(chainId)); const result = prettifySeconds(voteSeconds, "mins"); if (result === "now") { return new Date(Date.now()).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }); } return `in ${result}`; } export default ProposalsList;