11import { TransactionAccount } from '@sqds/mesh/lib/types'
22import { useRouter } from 'next/router'
3- import { useCallback , useContext , useEffect , useState } from 'react'
3+ import { useCallback , useContext , useEffect , useState , useMemo } from 'react'
44import { ClusterContext } from '../../../contexts/ClusterContext'
55import { useMultisigContext } from '../../../contexts/MultisigContext'
6- import { StatusFilterContext } from '../../../contexts/StatusFilterContext '
6+ import { PROPOSAL_STATUSES } from './utils '
77import ClusterSwitch from '../../ClusterSwitch'
8- import ProposalStatusFilter from '../../ProposalStatusFilter'
98import Loadbar from '../../loaders/Loadbar'
9+ import { Select } from '../../Select'
10+ import { useQueryState , parseAsStringLiteral } from 'nuqs'
1011
1112import { ProposalRow } from './ProposalRow'
1213import { getProposalStatus } from './utils'
1314import { Proposal } from './Proposal'
15+ import { useWallet } from '@solana/wallet-adapter-react'
1416
1517type ProposalType = 'priceFeed' | 'governance'
1618
19+ const VOTE_STATUSES = [
20+ 'any' ,
21+ 'voted' ,
22+ 'approved' ,
23+ 'rejected' ,
24+ 'cancelled' ,
25+ 'notVoted' ,
26+ ] as const
27+ const DEFAULT_VOTE_STATUS = 'any'
28+
29+ const PROPOSAL_STATUS_FILTERS = [ 'all' , ...PROPOSAL_STATUSES ] as const
30+ const DEFAULT_PROPOSAL_STATUS_FILTER = 'all'
31+
1732const Proposals = ( ) => {
1833 const router = useRouter ( )
1934 const [ currentProposal , setCurrentProposal ] = useState < TransactionAccount > ( )
2035 const [ currentProposalPubkey , setCurrentProposalPubkey ] = useState < string > ( )
36+ const [ statusFilter , setStatusFilter ] = useQueryState (
37+ 'status' ,
38+ parseAsStringLiteral ( PROPOSAL_STATUS_FILTERS ) . withDefault (
39+ DEFAULT_PROPOSAL_STATUS_FILTER
40+ )
41+ )
42+ const [ voteStatus , setVoteStatus ] = useQueryState (
43+ 'voteStatus' ,
44+ parseAsStringLiteral ( VOTE_STATUSES ) . withDefault ( DEFAULT_VOTE_STATUS )
45+ )
2146 const { cluster } = useContext ( ClusterContext )
22- const { statusFilter } = useContext ( StatusFilterContext )
47+ const { publicKey : walletPublicKey } = useWallet ( )
2348
2449 const {
2550 upgradeMultisigAccount,
@@ -40,9 +65,6 @@ const Proposals = () => {
4065 proposalType === 'priceFeed'
4166 ? priceFeedMultisigProposals
4267 : upgradeMultisigProposals
43- const [ filteredProposals , setFilteredProposals ] = useState <
44- TransactionAccount [ ]
45- > ( [ ] )
4668
4769 const handleClickBackToProposals = ( ) => {
4870 delete router . query . proposal
@@ -103,19 +125,60 @@ const Proposals = () => {
103125 cluster ,
104126 ] )
105127
106- useEffect ( ( ) => {
107- // filter price feed multisig proposals by status
108- if ( statusFilter === 'all' ) {
109- setFilteredProposals ( multisigProposals )
128+ const proposalsFilteredByStatus = useMemo (
129+ ( ) =>
130+ statusFilter === 'all'
131+ ? multisigProposals
132+ : multisigProposals . filter (
133+ ( proposal ) =>
134+ getProposalStatus ( proposal , multisigAccount ) === statusFilter
135+ ) ,
136+ [ statusFilter , multisigAccount , multisigProposals ]
137+ )
138+
139+ const filteredProposals = useMemo ( ( ) => {
140+ if ( walletPublicKey ) {
141+ switch ( voteStatus ) {
142+ case 'any' :
143+ return proposalsFilteredByStatus
144+ case 'voted' : {
145+ return proposalsFilteredByStatus . filter ( ( proposal ) =>
146+ [
147+ ...proposal . approved ,
148+ ...proposal . rejected ,
149+ ...proposal . cancelled ,
150+ ] . some ( ( vote ) => vote . equals ( walletPublicKey ) )
151+ )
152+ }
153+ case 'approved' : {
154+ return proposalsFilteredByStatus . filter ( ( proposal ) =>
155+ proposal . approved . some ( ( vote ) => vote . equals ( walletPublicKey ) )
156+ )
157+ }
158+ case 'rejected' : {
159+ return proposalsFilteredByStatus . filter ( ( proposal ) =>
160+ proposal . rejected . some ( ( vote ) => vote . equals ( walletPublicKey ) )
161+ )
162+ }
163+ case 'cancelled' : {
164+ return proposalsFilteredByStatus . filter ( ( proposal ) =>
165+ proposal . cancelled . some ( ( vote ) => vote . equals ( walletPublicKey ) )
166+ )
167+ }
168+ case 'notVoted' : {
169+ return proposalsFilteredByStatus . filter ( ( proposal ) =>
170+ [
171+ ...proposal . approved ,
172+ ...proposal . rejected ,
173+ ...proposal . cancelled ,
174+ ] . every ( ( vote ) => ! vote . equals ( walletPublicKey ) )
175+ )
176+ }
177+ }
110178 } else {
111- setFilteredProposals (
112- multisigProposals . filter (
113- ( proposal ) =>
114- getProposalStatus ( proposal , multisigAccount ) === statusFilter
115- )
116- )
179+ return proposalsFilteredByStatus
117180 }
118- } , [ statusFilter , multisigAccount , multisigProposals ] )
181+ } , [ proposalsFilteredByStatus , walletPublicKey , voteStatus ] )
119182
120183 return (
121184 < div className = "relative" >
@@ -167,11 +230,26 @@ const Proposals = () => {
167230 </ div >
168231 ) : (
169232 < >
170- < div className = "flex items-center justify-between pb-4" >
233+ < div className = "flex items-end md:flex-row-reverse justify-between pb-4" >
234+ < div className = "flex flex-col md:flex-row md:items-center gap-4 text-sm" >
235+ { walletPublicKey && (
236+ < Select
237+ label = "Your Vote"
238+ value = { voteStatus }
239+ options = { VOTE_STATUSES }
240+ onChange = { setVoteStatus }
241+ />
242+ ) }
243+ < Select
244+ label = "Proposal Status"
245+ value = { statusFilter }
246+ options = { PROPOSAL_STATUS_FILTERS }
247+ onChange = { setStatusFilter }
248+ />
249+ </ div >
171250 < h4 className = "h4" >
172251 Total Proposals: { filteredProposals . length }
173252 </ h4 >
174- < ProposalStatusFilter />
175253 </ div >
176254 { filteredProposals . length > 0 ? (
177255 < div className = "flex flex-col" >
0 commit comments