import { ProgramAccount, Proposal, VoteKind, VoteRecord, getGovernanceAccount, getVoteRecordAddress, } from '@solana/spl-governance' import { VoteCountdown } from './VoteCountdown' import { RawMint } from '@solana/spl-token' import VoteResults from './VoteResult' import QuorumProgress from './VoteProgress' import GovernanceStore from '@store/governanceStore' import Button from '@components/shared/Button' import { ArrowTopRightOnSquareIcon, HandThumbDownIcon, HandThumbUpIcon, } from '@heroicons/react/20/solid' import { BN } from '@coral-xyz/anchor' import { useEffect, useState } from 'react' import { MANGO_GOVERNANCE_PROGRAM } from 'utils/governance/constants' import mangoStore from '@store/mangoStore' import { castVote } from 'utils/governance/instructions/castVote' import { useWallet } from '@solana/wallet-adapter-react' import { relinquishVote } from 'utils/governance/instructions/relinquishVote' import { PublicKey } from '@solana/web3.js' import { notify } from 'utils/notifications' import Loading from '@components/shared/Loading' import { useTranslation } from 'next-i18next' import { resolveProposalDescription } from 'utils/governance/tools' enum PROCESSED_VOTE_TYPE { APPROVE, DENY, RELINQUISH, } const ProposalCard = ({ proposal, mangoMint, }: { proposal: ProgramAccount mangoMint: RawMint }) => { const { t } = useTranslation('governance') const connection = mangoStore((s) => s.connection) const client = mangoStore((s) => s.client) const governances = GovernanceStore((s) => s.governances) const wallet = useWallet() const voter = GovernanceStore((s) => s.voter) const vsrClient = GovernanceStore((s) => s.vsrClient) const updateProposals = GovernanceStore((s) => s.updateProposals) const [processedVoteType, setProcessedVoteType] = useState< PROCESSED_VOTE_TYPE | '' >('') const [voteType, setVoteType] = useState(undefined) const [voteRecordAddress, setVoteRecordAddress] = useState( null, ) const [isVoteCast, setIsVoteCast] = useState(false) const [description, setDescription] = useState('') const governance = governances && governances[proposal.account.governance.toBase58()] const canVote = voter.voteWeight.cmp(new BN(1)) !== -1 const descriptionLink = proposal.account.descriptionLink //Approve 0, deny 1 const vote = async (voteType: VoteKind) => { setProcessedVoteType( voteType === VoteKind.Approve ? PROCESSED_VOTE_TYPE.APPROVE : PROCESSED_VOTE_TYPE.DENY, ) try { await castVote( connection, wallet, proposal, voter.tokenOwnerRecord!, voteType, vsrClient!, client, ) await updateProposals(proposal.pubkey) } catch (e) { notify({ title: 'Error', description: `${e}`, type: 'error', }) } setProcessedVoteType('') } const submitRelinquishVote = async () => { setProcessedVoteType(PROCESSED_VOTE_TYPE.RELINQUISH) try { await relinquishVote( connection, wallet, proposal, voter.tokenOwnerRecord!, client, voteRecordAddress!, ) await updateProposals(proposal.pubkey) } catch (e) { notify({ title: 'Error', description: `${e}`, type: 'error', }) } setProcessedVoteType('') } useEffect(() => { const handleGetVoteRecord = async () => { setIsVoteCast(false) try { await getGovernanceAccount(connection, voteRecordAddress!, VoteRecord) setIsVoteCast(true) // eslint-disable-next-line no-empty } catch (e) {} } if (voteRecordAddress?.toBase58()) { handleGetVoteRecord() } else { setIsVoteCast(false) } }, [voteRecordAddress, proposal.pubkey.toBase58()]) useEffect(() => { const handleGetVoteRecordAddress = async () => { const voteRecordAddress = await getVoteRecordAddress( MANGO_GOVERNANCE_PROGRAM, proposal.pubkey, voter.tokenOwnerRecord!.pubkey!, ) setVoteRecordAddress(voteRecordAddress) try { const governanceAccount = await getGovernanceAccount( connection, voteRecordAddress, VoteRecord, ) setIsVoteCast(true) setVoteType(governanceAccount.account.vote?.voteType) } catch (e) { setIsVoteCast(false) } } if (voter.tokenOwnerRecord?.pubkey.toBase58()) { handleGetVoteRecordAddress() } else { setVoteRecordAddress(null) } }, [proposal.pubkey.toBase58(), voter.tokenOwnerRecord?.pubkey.toBase58()]) useEffect(() => { const handleResolveDescription = async () => { const description = await resolveProposalDescription(descriptionLink!) setDescription(description) } if (descriptionLink) { handleResolveDescription() } else { setDescription('') } }, [descriptionLink]) return governance ? (
{!isVoteCast ? (
) : (
{voteType !== undefined ? (

{t('current-vote')}

{voteType === VoteKind.Approve ? ( {t('yes')} ) : ( {t('no')} )}
) : null}
)}
{mangoMint && (
)}
) : null } export default ProposalCard