From 45131412d85440f2353fff5a563411656c014556 Mon Sep 17 00:00:00 2001 From: Witold Szczerba Date: Wed, 29 Aug 2018 22:22:02 +0200 Subject: [PATCH] delegates: sort table by selected column #20 --- front/src/main/panels/delegates.tsx | 86 +++++++++++++++++++++++------ front/src/main/panels/send.tsx | 4 +- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/front/src/main/panels/delegates.tsx b/front/src/main/panels/delegates.tsx index f41485f..4ad7192 100644 --- a/front/src/main/panels/delegates.tsx +++ b/front/src/main/panels/delegates.tsx @@ -31,6 +31,9 @@ interface RemoteData { names: Map } +type OrderBy = 'Rank' | 'Name' | 'Address' | 'Votes' | 'MyVotes' +type OrderDir = 'Asc' | 'Desc' + export interface DelegatesState { remoteData: WebData fetchTimeoutId: NodeJS.Timer | undefined @@ -39,6 +42,8 @@ export interface DelegatesState { selectedDelegate: string voteResult: WebData searchPhrase: string + orderBy: OrderBy + orderDir: OrderDir } export const initialDelegatesState: DelegatesState = { @@ -49,6 +54,8 @@ export const initialDelegatesState: DelegatesState = { selectedDelegate: '', voteResult: NotAsked, searchPhrase: '', + orderBy: 'Rank', + orderDir: 'Asc', } export interface DelegatesActions { @@ -62,6 +69,7 @@ export interface DelegatesActions { voteResultOk: () => (s: DelegatesState) => DelegatesState voteResultFailed: (err: string) => (s: DelegatesState) => DelegatesState searchInput: (d: string) => (s: DelegatesState, a: DelegatesActions) => DelegatesState + orderBy: (o: OrderBy) => (s: DelegatesState) => DelegatesState } export const rawDelegatesActions: DelegatesActions = { @@ -156,6 +164,12 @@ export const rawDelegatesActions: DelegatesActions = { }, searchInput: (searchPhrase) => (state, actions) => ({ ...state, searchPhrase }), + + orderBy: (orderBy) => (state) => ({ + ...state, + orderBy, + orderDir: orderBy === state.orderBy && state.orderDir === 'Asc' ? 'Desc' : 'Asc', + }), } export function DelegatesView(rootState: State, rootActions: Actions) { @@ -212,12 +226,12 @@ function voteForm(rootState: State, remoteData: RemoteData, state: DelegatesStat
@@ -266,22 +280,65 @@ function voteForm(rootState: State, remoteData: RemoteData, state: DelegatesStat } function table(remoteData: RemoteData, state: DelegatesState, actions: DelegatesActions) { + function headerCell(text: string, orderBy?: OrderBy, css?: string) { + return orderBy && actions.orderBy(orderBy)} + class={`bb b--black-20 tl pb1 pr2 pl2 ${css || ''}`} + > + {text} + {orderBy + ? (state.orderBy === orderBy ? (state.orderDir === 'Asc' ? '⯅' : '⯆') : '⬦') + : '' + } + + } + + function filterDelegates(delegates: DelegateType[]) { + const { searchPhrase } = state + return searchPhrase + ? delegates.filter(({ name }) => name.toLowerCase().includes(searchPhrase.toLowerCase())) + : delegates + } + + function sortDelegates(delegates: DelegateType[]) { + const { orderBy, orderDir } = state + const dir = (cmp: number) => state.orderDir === 'Asc' ? cmp : -cmp + const cmpFn = (a: DelegateType, b: DelegateType) => { + switch (orderBy) { + case 'Rank': return a.rank - b.rank + case 'Name': return a.name.localeCompare(b.name) + case 'Address': return a.address.localeCompare(b.address) + case 'Votes': return a.votes.comparedTo(b.votes) + case 'MyVotes': { + const myVotesA = myVotesForDelegate(remoteData, state, a.address) + const myVotesB = myVotesForDelegate(remoteData, state, b.address) + return myVotesA.comparedTo(myVotesB) + } + } + } + const byRankWhenEq = (a: DelegateType, b: DelegateType, cmp: number) => { + return cmp === 0 ? a.rank - b.rank : cmp + } + return orderBy === 'Rank' && orderDir === 'Asc' + ? delegates + : Array.from(delegates).sort((a, b) => byRankWhenEq(a, b, dir(cmpFn(a, b)))) + } + return
- - - - - - - - + + {headerCell('Rank', 'Rank')} + {headerCell('Name', 'Name')} + {headerCell('Address', 'Address')} + {headerCell('Votes', 'Votes', 'tr')} + {headerCell('My votes', 'MyVotes', 'tr')} + {headerCell('Status')} { - filterDelegates(remoteData.delegates, state.searchPhrase).map((delegate) => { + sortDelegates(filterDelegates(remoteData.delegates)).map((delegate) => { const myVotes = myVotesForDelegate(remoteData, state, delegate.address) const selected = delegate.address === state.selectedDelegate return {semNoLabel(myVotes)} - - }) } @@ -316,10 +372,6 @@ function table(remoteData: RemoteData, state: DelegatesState, actions: Delegates } -function filterDelegates(delegates: DelegateType[], searchPhrase: string) { - return delegates.filter(({ name }) => name.toLowerCase().includes(searchPhrase.toLowerCase())) -} - function myVotesKey(myAddress: string, delegate: string): string { return myAddress + delegate } diff --git a/front/src/main/panels/send.tsx b/front/src/main/panels/send.tsx index c088027..5b31316 100644 --- a/front/src/main/panels/send.tsx +++ b/front/src/main/panels/send.tsx @@ -10,7 +10,7 @@ import { hexBytes, log } from '../lib/utils' import { publishTx, TX_FEE_NANO } from '../model/transaction' import { fetchAccount, AccountType } from '../model/account' import { addresses, getKey } from '../model/wallet' -import { sem } from '../lib/format' +import { sem, addressAbbr } from '../lib/format' import BigNumber from 'bignumber.js' export interface SendState { @@ -134,7 +134,7 @@ export function SendView(rootState: State, rootActions: Actions) { { accounts.map((acc, idx) => ( )) }
RankNameAddressVotesVotes from MeStatusRate
+ {delegate.validator ? 'Validator' : 'Delegate'} {delegate.rate.toFixed(1)} %