diff --git a/CHANGELOG.md b/CHANGELOG.md index f6aae2f70..e9db4d1c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#871](https://github.com/alleslabs/celatone-frontend/pull/871) Move filter and search logic to API - [#869](https://github.com/alleslabs/celatone-frontend/pull/869) Change GraphQL phoenix-1 endpoint to prod - [#855](https://github.com/alleslabs/celatone-frontend/pull/855) Modify formatPrettyPercent param type to ratio number for better readability - [#843](https://github.com/alleslabs/celatone-frontend/pull/843) Add link to user document diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 111d58f83..d2ccf8847 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -26,6 +26,7 @@ import type { ProposalValidatorVote, ProposalVote, ProposalVotesInfo, + ProposalVoteType, SnakeToCamelCaseNested, } from "lib/types"; import { parseTxHash, parseWithError, snakeToCamel } from "lib/utils"; @@ -298,8 +299,8 @@ export const getProposalVotes = async ( id: number, limit: number, offset: number, - answer?: string, - search?: string + answer: ProposalVoteType, + search: string ): Promise => { let url = `${endpoint}/${encodeURIComponent(id)}/votes?limit=${limit}&offset=${offset}`; url = url.concat(search ? `&search=${encodeURIComponent(search)}` : ""); @@ -317,10 +318,21 @@ export interface ProposalValidatorVotesResponse { export const getProposalValidatorVotes = async ( endpoint: string, - id: number + id: number, + limit: number, + offset: number, + answer: ProposalVoteType, + search: string ): Promise => axios - .get(`${endpoint}/${encodeURIComponent(id)}/validator-votes`) + .get(`${endpoint}/${encodeURIComponent(id)}/validator-votes`, { + params: { + limit, + offset, + answer, + search, + }, + }) .then(({ data }) => { const parsed = parseWithError(zProposalVotesResponse, data); return { diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index f70fa3a3d..b9fa5acd8 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -2,8 +2,7 @@ import type { Coin } from "@cosmjs/amino"; import type { UseQueryOptions, UseQueryResult } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query"; import type { Big } from "big.js"; -import { isUndefined } from "lodash"; -import { useCallback, useMemo } from "react"; +import { useCallback } from "react"; import { CELATONE_QUERY_KEYS, @@ -15,7 +14,7 @@ import { getRelatedProposalsCountByModuleId, } from "lib/query"; import { createQueryFnWithTimeout } from "lib/query-utils"; -import { big, ProposalVoteType } from "lib/types"; +import { big } from "lib/types"; import type { BechAddr, BechAddr20, @@ -27,6 +26,7 @@ import type { ProposalStatus, ProposalType, ProposalVotesInfo, + ProposalVoteType, Token, U, } from "lib/types"; @@ -45,7 +45,6 @@ import type { ProposalAnswerCountsResponse, ProposalDataResponse, ProposalsResponse, - ProposalValidatorVotesResponse, ProposalVotesResponse, RelatedProposalsResponse, UploadAccess, @@ -355,91 +354,53 @@ export const useProposalVotesInfo = (id: number) => { ); }; -export const useProposalValidatorVotes = ( +export const useProposalVotes = ( id: number, limit: number, offset: number, answer: ProposalVoteType, - search: string -) => { + search: string, + options: Pick, "onSuccess"> = {} +): UseQueryResult => { const endpoint = useBaseApiRoute("proposals"); - const { data, ...rest } = useQuery( - [CELATONE_QUERY_KEYS.PROPOSAL_VALIDATOR_VOTES, endpoint, id], - async () => getProposalValidatorVotes(endpoint, id), - { retry: 1, refetchOnWindowFocus: false } + return useQuery( + [ + CELATONE_QUERY_KEYS.PROPOSAL_VOTES, + endpoint, + id, + limit, + offset, + search, + answer, + ], + async () => getProposalVotes(endpoint, id, limit, offset, answer, search), + { retry: 1, refetchOnWindowFocus: false, ...options } ); - - const filteredData = useMemo(() => { - if (isUndefined(data?.items)) return undefined; - - const filteredItemsByAnswer = data.items.filter((vote) => { - switch (answer) { - case ProposalVoteType.YES: - return vote.yes === 1; - case ProposalVoteType.NO: - return vote.no === 1; - case ProposalVoteType.NO_WITH_VETO: - return vote.noWithVeto === 1; - case ProposalVoteType.ABSTAIN: - return vote.abstain === 1; - case ProposalVoteType.WEIGHTED: - return vote.isVoteWeighted; - case ProposalVoteType.DID_NOT_VOTE: - return ( - vote.yes === 0 && - vote.no === 0 && - vote.noWithVeto === 0 && - vote.abstain === 0 && - !vote.isVoteWeighted - ); - case ProposalVoteType.ALL: - default: - return true; - } - }); - - const filteredItemsBySearch = filteredItemsByAnswer.filter((vote) => { - if (!search?.trim()) return true; - - const keyword = search.toLowerCase(); - return ( - (vote.validator?.moniker?.toLowerCase() || "").includes(keyword) || - vote.validator?.validatorAddress.toLowerCase().includes(keyword) - ); - }); - - return { - items: filteredItemsBySearch.slice(offset, offset + limit), - total: filteredItemsBySearch.length, - }; - }, [data?.items, limit, offset, answer, search]); - - return { data: filteredData, ...rest }; }; -export const useProposalVotes = ( +export const useProposalValidatorVotes = ( id: number, limit: number, offset: number, answer: ProposalVoteType, - search: string, - options: Pick, "onSuccess"> = {} -): UseQueryResult => { + search: string +) => { const endpoint = useBaseApiRoute("proposals"); return useQuery( [ - CELATONE_QUERY_KEYS.PROPOSAL_VOTES, + CELATONE_QUERY_KEYS.PROPOSAL_VALIDATOR_VOTES, endpoint, id, limit, offset, - search, answer, + search, ], - async () => getProposalVotes(endpoint, id, limit, offset, answer, search), - { retry: 1, refetchOnWindowFocus: false, ...options } + async () => + getProposalValidatorVotes(endpoint, id, limit, offset, answer, search), + { retry: 1, refetchOnWindowFocus: false } ); };