1
- import { useCallback , useMemo } from "react" ;
1
+ import { useCallback , useMemo , useState } from "react" ;
2
2
import BigNumber from "bignumber.js" ;
3
3
import { differenceInDays } from "date-fns" ;
4
4
import {
5
5
ProposalDetailScreenQuery ,
6
6
ProposalDetailScreenQueryQuery ,
7
7
ProposalDetailScreenQueryQueryVariables ,
8
+ ProposalVoteSort ,
9
+ ProposalDetailVotesPanelQuery ,
10
+ ProposalDetailVotesPanelQueryQuery ,
11
+ ProposalDetailVotesPanelQueryQueryVariables ,
12
+ ProposalDetailDepositsPanelQuery ,
13
+ ProposalDetailDepositsPanelQueryQuery ,
14
+ ProposalDetailDepositsPanelQueryQueryVariables ,
15
+ ProposalDepositSort ,
8
16
} from "../../generated/graphql" ;
9
17
import { useLazyGraphQLQuery } from "../../hooks/graphql" ;
10
18
import { mapRequestData , RequestState } from "../../models/RequestState" ;
11
19
import { convertMinimalTokenToToken } from "../../utils/coin" ;
12
20
import { getReactionType } from "../reactions/ReactionModel" ;
13
- import { Proposal , ReactionItem } from "./ProposalDetailScreenModel" ;
21
+ import { useQueryClient } from "../../providers/QueryClientProvider" ;
22
+ import { ConnectionStatus , useWallet } from "../../providers/WalletProvider" ;
23
+ import {
24
+ PaginatedProposalVotes ,
25
+ PaginatedProposalDeposits ,
26
+ Proposal ,
27
+ ReactionItem ,
28
+ ProposalVote ,
29
+ ProposalDeposit ,
30
+ ProposalDepositDepositor ,
31
+ ProposalVoteVoter ,
32
+ } from "./ProposalDetailScreenModel" ;
14
33
15
34
const calculateTurnout = ( tallyResult : Proposal [ "tallyResult" ] ) => {
16
35
if ( ! tallyResult ) {
@@ -26,6 +45,249 @@ const calculateTurnout = (tallyResult: Proposal["tallyResult"]) => {
26
45
return turnout . toNumber ( ) ;
27
46
} ;
28
47
48
+ const getVoterOrDepositorAddress = (
49
+ // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
50
+ voterOrDepositor : ProposalVoteVoter | ProposalDepositDepositor
51
+ ) : string | null => {
52
+ if ( voterOrDepositor . __typename === "StringObject" ) {
53
+ return voterOrDepositor . value ;
54
+ }
55
+
56
+ if ( voterOrDepositor . __typename === "Validator" ) {
57
+ return voterOrDepositor . operatorAddress ?? null ;
58
+ }
59
+
60
+ return null ;
61
+ } ;
62
+
63
+ interface UseProposalVotesQuery {
64
+ ( proposalId : string , initialOffset : number , pageSize : number ) : {
65
+ requestState : RequestState < PaginatedProposalVotes > ;
66
+ fetch : ( variables : {
67
+ first : number ;
68
+ after : number ;
69
+ order : ProposalVoteSort ;
70
+ } ) => Promise < void > ;
71
+ } ;
72
+ }
73
+
74
+ export const useProposalVotesQuery : UseProposalVotesQuery = (
75
+ proposalId ,
76
+ initialOffset ,
77
+ pageSize
78
+ ) => {
79
+ const wallet = useWallet ( ) ;
80
+ const { query } = useQueryClient ( ) ;
81
+
82
+ const [ delegatedValidators , setDelegatedValidators ] = useState < string [ ] > ( [ ] ) ;
83
+
84
+ const [ fetch , { requestState } ] = useLazyGraphQLQuery <
85
+ ProposalDetailVotesPanelQueryQuery ,
86
+ ProposalDetailVotesPanelQueryQueryVariables
87
+ > ( ProposalDetailVotesPanelQuery , {
88
+ variables : {
89
+ proposalId,
90
+ input : {
91
+ after : initialOffset ,
92
+ first : pageSize ,
93
+ order : { } ,
94
+ } ,
95
+ } ,
96
+ fetchPolicy : "cache-and-network" ,
97
+ nextFetchPolicy : "cache-first" ,
98
+ } ) ;
99
+
100
+ const callFetch = useCallback (
101
+ async ( {
102
+ first,
103
+ after,
104
+ order,
105
+ } : {
106
+ first : number ;
107
+ after : number ;
108
+ order : ProposalVoteSort ;
109
+ } ) => {
110
+ let delegatedValidators : string [ ] = [ ] ;
111
+
112
+ if ( wallet . status === ConnectionStatus . Connected ) {
113
+ try {
114
+ const delegations = await query . staking . delegatorDelegations (
115
+ wallet . account . address
116
+ ) ;
117
+
118
+ delegatedValidators = delegations . delegationResponses
119
+ . filter ( ( r ) => r . delegation != null )
120
+ . map ( ( r ) => r . delegation ! . validatorAddress ) ;
121
+
122
+ setDelegatedValidators ( delegatedValidators ) ;
123
+ } catch ( err : unknown ) {
124
+ console . error ( "Failed to get user delegations = " , err ) ;
125
+ }
126
+ }
127
+ await fetch ( {
128
+ variables : {
129
+ proposalId,
130
+ input : {
131
+ first,
132
+ after,
133
+ order,
134
+ pinnedValidators : delegatedValidators ,
135
+ } ,
136
+ } ,
137
+ } ) ;
138
+ } ,
139
+ [ fetch , proposalId , wallet , query ]
140
+ ) ;
141
+
142
+ const data = useMemo ( ( ) => {
143
+ return mapRequestData <
144
+ ProposalDetailVotesPanelQueryQuery ,
145
+ PaginatedProposalVotes
146
+ > ( requestState , ( r ) => {
147
+ const allVotes = r . proposalByID ?. votes . edges . map ( ( v ) => v . node ) ?? [ ] ;
148
+ const [ pinnedVotes , votes ] = allVotes . reduce <
149
+ [ ProposalVote [ ] , ProposalVote [ ] ]
150
+ > (
151
+ ( acc , curr ) => {
152
+ const address = getVoterOrDepositorAddress ( curr . voter ) ;
153
+ if ( ! address ) return acc ;
154
+
155
+ acc [ delegatedValidators . includes ( address ) ? 0 : 1 ] . push ( curr ) ;
156
+ return acc ;
157
+ } ,
158
+ [ [ ] , [ ] ]
159
+ ) ;
160
+
161
+ return {
162
+ pinnedVotes,
163
+ votes,
164
+ totalCount : r . proposalByID ?. votes . totalCount ?? 0 ,
165
+ } ;
166
+ } ) ;
167
+ } , [ requestState , delegatedValidators ] ) ;
168
+
169
+ return {
170
+ requestState : data ,
171
+ fetch : callFetch ,
172
+ } ;
173
+ } ;
174
+
175
+ interface UseProposalDepositsQuery {
176
+ ( proposalId : string , initialOffset : number , pageSize : number ) : {
177
+ requestState : RequestState < PaginatedProposalDeposits > ;
178
+ fetch : ( variables : {
179
+ first : number ;
180
+ after : number ;
181
+ order : ProposalDepositSort ;
182
+ } ) => Promise < void > ;
183
+ } ;
184
+ }
185
+
186
+ export const useProposalDepositsQuery : UseProposalDepositsQuery = (
187
+ proposalId ,
188
+ initialOffset ,
189
+ pageSize
190
+ ) => {
191
+ const wallet = useWallet ( ) ;
192
+ const { query } = useQueryClient ( ) ;
193
+
194
+ const [ delegatedValidators , setDelegatedValidators ] = useState < string [ ] > ( [ ] ) ;
195
+ const [ fetch , { requestState } ] = useLazyGraphQLQuery <
196
+ ProposalDetailDepositsPanelQueryQuery ,
197
+ ProposalDetailDepositsPanelQueryQueryVariables
198
+ > ( ProposalDetailDepositsPanelQuery , {
199
+ variables : {
200
+ proposalId,
201
+ input : {
202
+ after : initialOffset ,
203
+ first : pageSize ,
204
+ order : { } ,
205
+ } ,
206
+ } ,
207
+ fetchPolicy : "cache-and-network" ,
208
+ nextFetchPolicy : "cache-first" ,
209
+ } ) ;
210
+
211
+ const callFetch = useCallback (
212
+ async ( {
213
+ first,
214
+ after,
215
+ order,
216
+ } : {
217
+ first : number ;
218
+ after : number ;
219
+ order : ProposalDepositSort ;
220
+ } ) => {
221
+ let delegatedValidators : string [ ] = [ ] ;
222
+
223
+ if ( wallet . status === ConnectionStatus . Connected ) {
224
+ try {
225
+ const delegations = await query . staking . delegatorDelegations (
226
+ wallet . account . address
227
+ ) ;
228
+
229
+ delegatedValidators = delegations . delegationResponses
230
+ . filter ( ( r ) => r . delegation != null )
231
+ . map ( ( r ) => r . delegation ! . validatorAddress ) ;
232
+
233
+ setDelegatedValidators ( delegatedValidators ) ;
234
+ } catch ( err : unknown ) {
235
+ console . error ( "Failed to get user delegations = " , err ) ;
236
+ }
237
+ }
238
+
239
+ await fetch ( {
240
+ variables : {
241
+ proposalId,
242
+ input : {
243
+ first,
244
+ after,
245
+ order,
246
+ pinnedValidators : delegatedValidators ,
247
+ } ,
248
+ } ,
249
+ } ) ;
250
+ } ,
251
+ [ fetch , proposalId , wallet , query ]
252
+ ) ;
253
+
254
+ const data = useMemo ( ( ) => {
255
+ return mapRequestData <
256
+ ProposalDetailDepositsPanelQueryQuery ,
257
+ PaginatedProposalDeposits
258
+ > ( requestState , ( r ) => {
259
+ const allDeposits =
260
+ r . proposalByID ?. deposits . edges . map ( ( v ) => v . node ) ?? [ ] ;
261
+ const [ pinnedDeposits , deposits ] = allDeposits . reduce <
262
+ [ ProposalDeposit [ ] , ProposalDeposit [ ] ]
263
+ > (
264
+ ( acc , curr ) => {
265
+ const address =
266
+ curr . depositor != null
267
+ ? getVoterOrDepositorAddress ( curr . depositor )
268
+ : null ;
269
+ if ( ! address ) return acc ;
270
+
271
+ acc [ delegatedValidators . includes ( address ) ? 0 : 1 ] . push ( curr ) ;
272
+ return acc ;
273
+ } ,
274
+ [ [ ] , [ ] ]
275
+ ) ;
276
+
277
+ return {
278
+ pinnedDeposits,
279
+ deposits,
280
+ totalCount : r . proposalByID ?. deposits . totalCount ?? 0 ,
281
+ } ;
282
+ } ) ;
283
+ } , [ requestState , delegatedValidators ] ) ;
284
+
285
+ return {
286
+ requestState : data ,
287
+ fetch : callFetch ,
288
+ } ;
289
+ } ;
290
+
29
291
export function useProposalQuery ( ) : {
30
292
requestState : RequestState < Proposal | null > ;
31
293
fetch : ( id : string ) => void ;
0 commit comments