import { TransactionAccount } from '@sqds/mesh/lib/types' import { useRouter } from 'next/router' import { useCallback, useContext, useEffect, useState, useMemo } from 'react' import { ClusterContext } from '../../../contexts/ClusterContext' import { useMultisigContext } from '../../../contexts/MultisigContext' import { PROPOSAL_STATUSES } from './utils' import ClusterSwitch from '../../ClusterSwitch' import Loadbar from '../../loaders/Loadbar' import { Select } from '../../Select' import { useQueryState, parseAsStringLiteral } from 'nuqs' import { ProposalRow } from './ProposalRow' import { getProposalStatus } from './utils' import { Proposal } from './Proposal' import { useWallet } from '@solana/wallet-adapter-react' type ProposalType = 'priceFeed' | 'governance' const VOTE_STATUSES = [ 'any', 'voted', 'approved', 'rejected', 'cancelled', 'notVoted', ] as const const DEFAULT_VOTE_STATUS = 'any' const PROPOSAL_STATUS_FILTERS = ['all', ...PROPOSAL_STATUSES] as const const DEFAULT_PROPOSAL_STATUS_FILTER = 'all' const Proposals = () => { const router = useRouter() const [currentProposal, setCurrentProposal] = useState() const [currentProposalPubkey, setCurrentProposalPubkey] = useState() const [statusFilter, setStatusFilter] = useQueryState( 'status', parseAsStringLiteral(PROPOSAL_STATUS_FILTERS).withDefault( DEFAULT_PROPOSAL_STATUS_FILTER ) ) const [voteStatus, setVoteStatus] = useQueryState( 'voteStatus', parseAsStringLiteral(VOTE_STATUSES).withDefault(DEFAULT_VOTE_STATUS) ) const { cluster } = useContext(ClusterContext) const { publicKey: walletPublicKey } = useWallet() const { upgradeMultisigAccount, priceFeedMultisigAccount, priceFeedMultisigProposals, upgradeMultisigProposals, isLoading: isMultisigLoading, refreshData, } = useMultisigContext() const [proposalType, setProposalType] = useState('priceFeed') const multisigAccount = proposalType === 'priceFeed' ? priceFeedMultisigAccount : upgradeMultisigAccount const multisigProposals = proposalType === 'priceFeed' ? priceFeedMultisigProposals : upgradeMultisigProposals const handleClickBackToProposals = () => { delete router.query.proposal router.push( { pathname: router.pathname, query: router.query, }, undefined, { scroll: false } ) } useEffect(() => { if (router.query.proposal) { setCurrentProposalPubkey(router.query.proposal as string) } else { setCurrentProposalPubkey(undefined) } }, [router.query.proposal]) const switchProposalType = useCallback(() => { if (proposalType === 'priceFeed') { setProposalType('governance') } else { setProposalType('priceFeed') } }, [proposalType]) useEffect(() => { if (currentProposalPubkey) { const currProposal = multisigProposals.find( (proposal) => proposal.publicKey.toBase58() === currentProposalPubkey ) setCurrentProposal(currProposal) if (currProposal === undefined) { const otherProposals = proposalType !== 'priceFeed' ? priceFeedMultisigProposals : upgradeMultisigProposals if ( otherProposals.findIndex( (proposal) => proposal.publicKey.toBase58() === currentProposalPubkey ) !== -1 ) { switchProposalType() } } } }, [ switchProposalType, priceFeedMultisigProposals, proposalType, upgradeMultisigProposals, currentProposalPubkey, multisigProposals, cluster, ]) const proposalsFilteredByStatus = useMemo( () => statusFilter === 'all' ? multisigProposals : multisigProposals.filter( (proposal) => getProposalStatus(proposal, multisigAccount) === statusFilter ), [statusFilter, multisigAccount, multisigProposals] ) const filteredProposals = useMemo(() => { if (walletPublicKey) { switch (voteStatus) { case 'any': return proposalsFilteredByStatus case 'voted': { return proposalsFilteredByStatus.filter((proposal) => [ ...proposal.approved, ...proposal.rejected, ...proposal.cancelled, ].some((vote) => vote.equals(walletPublicKey)) ) } case 'approved': { return proposalsFilteredByStatus.filter((proposal) => proposal.approved.some((vote) => vote.equals(walletPublicKey)) ) } case 'rejected': { return proposalsFilteredByStatus.filter((proposal) => proposal.rejected.some((vote) => vote.equals(walletPublicKey)) ) } case 'cancelled': { return proposalsFilteredByStatus.filter((proposal) => proposal.cancelled.some((vote) => vote.equals(walletPublicKey)) ) } case 'notVoted': { return proposalsFilteredByStatus.filter((proposal) => [ ...proposal.approved, ...proposal.rejected, ...proposal.cancelled, ].every((vote) => !vote.equals(walletPublicKey)) ) } } } else { return proposalsFilteredByStatus } }, [proposalsFilteredByStatus, walletPublicKey, voteStatus]) return (

{proposalType === 'priceFeed' ? 'Price Feed ' : 'Governance '}{' '} {router.query.proposal === undefined ? 'Proposals' : 'Proposal'}

{router.query.proposal === undefined ? ( <>
{refreshData && ( )}
{isMultisigLoading ? (
) : ( <>
{walletPublicKey && (

Total Proposals: {filteredProposals.length}

{filteredProposals.length > 0 ? (
{filteredProposals.map((proposal, _idx) => ( ))}
) : (
No proposals found. If you're a member of the multisig, you can create a proposal.
)} )}
) : !isMultisigLoading && currentProposal !== undefined ? ( <>
← back to proposals
) : (
)}
) } export default Proposals