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;