From a15ed447d3eb5d83f1a8d52f0e3fc7ad4943561b Mon Sep 17 00:00:00 2001 From: Rico Wong Date: Thu, 30 Jun 2022 02:15:05 +0800 Subject: [PATCH] react-app: Handle sorting proposal vote table refs #128 --- .../ProposalDetailScreenAPI.ts | 41 +++++++++++++++-- .../ProposalVotesPanel.tsx | 46 ++++++++++++++++--- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/react-app/src/components/ProposalDetailScreen/ProposalDetailScreenAPI.ts b/react-app/src/components/ProposalDetailScreen/ProposalDetailScreenAPI.ts index faf387c0a..1b03562a0 100644 --- a/react-app/src/components/ProposalDetailScreen/ProposalDetailScreenAPI.ts +++ b/react-app/src/components/ProposalDetailScreen/ProposalDetailScreenAPI.ts @@ -13,6 +13,7 @@ import { ProposalDetailDepositsPanelQueryQuery, ProposalDetailDepositsPanelQueryQueryVariables, ProposalDepositSort, + Sort, } from "../../generated/graphql"; import { useLazyGraphQLQuery } from "../../hooks/graphql"; import { mapRequestData, RequestState } from "../../models/RequestState"; @@ -60,13 +61,44 @@ const getVoterOrDepositorAddress = ( return null; }; +export enum ProposalVoteSortableColumn { + Voter = "voter", + Option = "option", +} + +function getProposalVoteSortOrderVariable( + order: { + id: ProposalVoteSortableColumn; + direction: "asc" | "desc"; + } | null +): ProposalVoteSort { + if (!order) { + return {}; + } + switch (order.id) { + case ProposalVoteSortableColumn.Voter: + return { + voter: order.direction === "asc" ? Sort.Asc : Sort.Desc, + }; + case ProposalVoteSortableColumn.Option: + return { + option: order.direction === "asc" ? Sort.Asc : Sort.Desc, + }; + default: + return {}; + } +} + interface UseProposalVotesQuery { (proposalId: string, initialOffset: number, pageSize: number): { requestState: RequestState; fetch: (variables: { first: number; after: number; - order: ProposalVoteSort; + order: { + id: ProposalVoteSortableColumn; + direction: "asc" | "desc"; + } | null; }) => Promise; }; } @@ -105,7 +137,10 @@ export const useProposalVotesQuery: UseProposalVotesQuery = ( }: { first: number; after: number; - order: ProposalVoteSort; + order: { + id: ProposalVoteSortableColumn; + direction: "asc" | "desc"; + } | null; }) => { let delegatedValidators: string[] = []; @@ -130,8 +165,8 @@ export const useProposalVotesQuery: UseProposalVotesQuery = ( input: { first, after, - order, pinnedValidators: delegatedValidators, + order: getProposalVoteSortOrderVariable(order), }, }, }); diff --git a/react-app/src/components/ProposalDetailScreen/ProposalVotesPanel.tsx b/react-app/src/components/ProposalDetailScreen/ProposalVotesPanel.tsx index f36d5c1d4..54ab07445 100644 --- a/react-app/src/components/ProposalDetailScreen/ProposalVotesPanel.tsx +++ b/react-app/src/components/ProposalDetailScreen/ProposalVotesPanel.tsx @@ -17,7 +17,10 @@ import { ProposalVote, ProposalVoteVoter, } from "./ProposalDetailScreenModel"; -import { useProposalVotesQuery } from "./ProposalDetailScreenAPI"; +import { + ProposalVoteSortableColumn, + useProposalVotesQuery, +} from "./ProposalDetailScreenAPI"; const PROPOSAL_VOTE_PAGE_SIZE = 5; @@ -149,10 +152,22 @@ const ProposalVotesPanel: React.FC = () => { const { translate } = useLocale(); const [searchParams, setSearchParams] = useSearchParams(); - const currentOffset = useMemo(() => { + const [currentOffset, sortOrder] = useMemo(() => { const page = searchParams.get("page") ?? "1"; + const sortBy = searchParams.get("sortBy"); + const sortDirection = searchParams.get("sortDirection"); + + const sortOrder = + sortBy && sortDirection + ? { + id: sortBy as ProposalVoteSortableColumn, + direction: sortDirection as SectionedTable.ColumnOrder["direction"], + } + : undefined; + + const offset = (parseInt(page, 10) - 1) * PROPOSAL_VOTE_PAGE_SIZE; - return (parseInt(page, 10) - 1) * PROPOSAL_VOTE_PAGE_SIZE; + return [offset, sortOrder]; }, [searchParams]); const { fetch, requestState } = useProposalVotesQuery( @@ -170,6 +185,16 @@ const ProposalVotesPanel: React.FC = () => { [setSearchParams] ); + const setSortOrder = useCallback( + (order: SectionedTable.ColumnOrder) => { + setSearchParams({ + sortBy: order.id, + sortDirection: order.direction, + }); + }, + [setSearchParams] + ); + const tableSections = useMemo((): SectionedTable.SectionItem[] => { if (!isRequestStateLoaded(requestState)) { @@ -202,9 +227,14 @@ const ProposalVotesPanel: React.FC = () => { fetch({ first: PROPOSAL_VOTE_PAGE_SIZE, after: currentOffset, - order: {}, + order: sortOrder + ? { + id: sortOrder.id, + direction: sortOrder.direction, + } + : null, }); - }, [fetch, currentOffset]); + }, [fetch, currentOffset, sortOrder]); useEffect(() => { if (isRequestStateError(requestState)) { @@ -219,16 +249,18 @@ const ProposalVotesPanel: React.FC = () => { sections={tableSections} isLoading={!isRequestStateLoaded(requestState)} emptyMessageID="ProposalDetail.votes.empty" + sortOrder={sortOrder} + onSort={setSortOrder} > - id="voter" + id={ProposalVoteSortableColumn.Voter} titleId="ProposalDetail.votes.voter" sortable={true} > {(item) => } - id="option" + id={ProposalVoteSortableColumn.Option} titleId="ProposalDetail.votes.option" sortable={true} >