diff --git a/front/src/main/lib/pagination.ts b/front/src/main/lib/pagination.ts new file mode 100644 index 0000000..ed1213d --- /dev/null +++ b/front/src/main/lib/pagination.ts @@ -0,0 +1,24 @@ +export interface PageRange { + from: number + to: number + pageCount: number +} + +export interface PageQuery { + totalCount: number + pageSize: number + pageNumber: number + dir: 'Asc' | 'Desc' +} + +export function calculateRange({ totalCount, pageSize, pageNumber, dir }: PageQuery): PageRange { + const pageCount = Math.ceil(totalCount / pageSize) + const offset = pageSize * pageNumber + if (dir === 'Asc') { + const from = offset + return { from, to: from + pageSize, pageCount } + } else { + const to = totalCount - offset + return { from: Math.max(0, to - pageSize), to, pageCount } + } +} diff --git a/front/src/main/model/transaction.ts b/front/src/main/model/transaction.ts index 2fe7e1d..c74377c 100644 --- a/front/src/main/model/transaction.ts +++ b/front/src/main/model/transaction.ts @@ -68,7 +68,7 @@ export function publishTx(tx: Transaction): Promise { export async function fetchTxs(address: string, from: number, to: number): Promise { const path = `/v2.1.0/account/transactions?address=${address}&from=${from}&to=${to}` - const remotes = await exec('GET', path) + const remotes = to > from ? await exec('GET', path) : [] return mutableReverse(remotes.map((r, idx) => ({ blockNumber: r.blockNumber, hash: r.hash, @@ -86,9 +86,7 @@ export async function fetchTxs(address: string, from: number, to: number): Promi export async function fetchLastTxs(account: AccountType, { page, size }: { page: number, size: number }) { const to = account.transactionCount - size * page const from = Math.max(0, to - size) - return to > from - ? fetchTxs(account.address, from, to) - : [] + return fetchTxs(account.address, from, to) } export async function fetchPendingTxs(address: string): Promise { diff --git a/front/src/main/panels/delegates.tsx b/front/src/main/panels/delegates.tsx index 4ad7192..b21bf66 100644 --- a/front/src/main/panels/delegates.tsx +++ b/front/src/main/panels/delegates.tsx @@ -36,7 +36,7 @@ type OrderDir = 'Asc' | 'Desc' export interface DelegatesState { remoteData: WebData - fetchTimeoutId: NodeJS.Timer | undefined + fetchTimeoutId: any selectedAccountIdx: number voteAmount: string selectedDelegate: string diff --git a/front/src/main/panels/home.tsx b/front/src/main/panels/home.tsx index 93dea8b..8455440 100644 --- a/front/src/main/panels/home.tsx +++ b/front/src/main/panels/home.tsx @@ -16,7 +16,7 @@ export interface HomeState { block: Maybe accounts: AccountType[] transactions: TransactionType[] - fetchTimeoutId: NodeJS.Timer | undefined + fetchTimeoutId: any } export const initialHomeState: HomeState = { diff --git a/front/src/main/panels/receive.tsx b/front/src/main/panels/receive.tsx index 443653d..ba34de1 100644 --- a/front/src/main/panels/receive.tsx +++ b/front/src/main/panels/receive.tsx @@ -12,7 +12,7 @@ const FETCH_INTERVAL = 20000 export interface ReceiveState { accounts: WebData - fetchTimeoutId: NodeJS.Timer | undefined + fetchTimeoutId: any } export const initialReceiveState: ReceiveState = { diff --git a/front/src/main/panels/transactions.tsx b/front/src/main/panels/transactions.tsx index e85ad8c..5f04002 100644 --- a/front/src/main/panels/transactions.tsx +++ b/front/src/main/panels/transactions.tsx @@ -5,6 +5,8 @@ import { Failure, Loading, NotAsked, Success, WebData, caseWebDataOf, isSuccess, import { TransactionType, fetchPendingTxs, fetchTxs } from '../model/transaction' import { address1st, addresses } from '../model/wallet' import { maybe } from 'tsmonad' +import { calculateRange, PageRange } from '../lib/pagination' +import { fetchAccount } from '../model/account' const LIST_SIZE = 200 const FETCH_INTERVAL = 20000 @@ -12,18 +14,20 @@ const FETCH_INTERVAL = 20000 export interface TxsState { selectedAddress: string pages: { [index: string]: Page } - fetchTimeoutId: NodeJS.Timer | undefined + fetchTimeoutId: any } interface Transactions { - pending: TransactionType[], - completed: TransactionType[], + pending: TransactionType[] + completed: TransactionType[] + pageRange: PageRange } interface Page { address: string from: number to: number + pageNumber: number transactions: WebData } @@ -32,6 +36,7 @@ function blankPage(address: string): Page { address, from: 0, to: LIST_SIZE, + pageNumber: 0, transactions: NotAsked, } } @@ -61,10 +66,23 @@ export const rawTxsActions: TxsActions = { return state } const page = pageOf(state, address) - Promise.all([fetchPendingTxs(address), fetchTxs(address, page.from, page.from + LIST_SIZE)]) - .then(([pending, completed]) => actions.fetchResult({ + + async function fetchCompleted() { + const totalCount = await fetchAccount(address).then((acc) => acc.transactionCount) + const pageRange = calculateRange({ + totalCount, + pageSize: LIST_SIZE, + pageNumber: page.pageNumber, + dir: 'Desc', + }) + const completed = await fetchTxs(address, pageRange.from, pageRange.to) + return { pageRange, completed } + } + + Promise.all([fetchPendingTxs(address), fetchCompleted()]) + .then(([pending, { pageRange, completed }]) => actions.fetchResult({ page, - result: Success({ pending, completed }), + result: Success({ pending, pageRange, completed }), })) .catch((error) => actions.fetchResult({ page, result: Failure(error.message) })) @@ -88,17 +106,17 @@ export const rawTxsActions: TxsActions = { }, fetchResult: ({ page, result }) => (state) => { + const newPage = { + ...page, + from: successOf(result).fmap((r) => r.pageRange.from).valueOr(page.from), + to: successOf(result).fmap((r) => r.pageRange.to).valueOr(page.to), + transactions: result, + } return { ...state, pages: { ...state.pages, - [page.address]: { - ...page, - to: successOf(result) - .fmap((txs) => txs.completed.length + page.from) - .valueOr(page.to), - transactions: result, - }, + [page.address]: newPage, }, } },