Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bridge-ui): add transaction list pagination #13586

Merged
merged 4 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions packages/bridge-ui/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,16 @@
import { CustomTokenService } from './storage/CustomTokenService';
import { userTokens, tokenService } from './store/userToken';
import { RelayerAPIService } from './relayer-api/RelayerAPIService';
import type { RelayerAPI } from './domain/relayerApi';
import { relayerApi, relayerBlockInfoMap } from './store/relayerApi';
import {
DEFAULT_PAGE,
MAX_PAGE_SIZE,
type RelayerAPI,
} from './domain/relayerApi';
import {
paginationInfo,
relayerApi,
relayerBlockInfoMap,
} from './store/relayerApi';
import { chains, mainnetWagmiChain, taikoWagmiChain } from './chain/chains';
import { providers } from './provider/providers';
import { RELAYER_URL } from './constants/envVars';
Expand Down Expand Up @@ -91,9 +99,13 @@
if (store) {
const userAddress = await store.getAddress();

const apiTxs = await $relayerApi.getAllBridgeTransactionByAddress(
userAddress,
);
const { txs: apiTxs, paginationInfo: info } =
await $relayerApi.getAllBridgeTransactionByAddress(userAddress, {
page: DEFAULT_PAGE,
size: MAX_PAGE_SIZE,
});

paginationInfo.set(info);

const blockInfoMap = await $relayerApi.getBlockInfo();
relayerBlockInfoMap.set(blockInfoMap);
Expand Down
93 changes: 93 additions & 0 deletions packages/bridge-ui/src/components/Pagination.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<script lang="ts">
export let totalPages: number;
export let page: number;
const DISABLED_BUTTON_LABEL = '...';

function getPageButtons(pages: number) {
if (pages <= 5) {
return new Array(pages).fill(0).map((_, index) => ({
label: index + 1,
onClick: () => (page = index + 1),
value: index + 1,
}));
} else {
return [
{
label: 1,
onClick: () => (page = 1),
value: 1,
},
{
label: 2,
onClick: () => (page = 2),
value: 2,
},
{
label: DISABLED_BUTTON_LABEL,
onClick: () => {
// do nothing
},
},
{
label: pages - 1,
onClick: () => (page = pages - 2),
value: pages - 1,
},
{
label: pages,
onClick: () => (page = pages - 1),
value: pages,
},
];
}
}

function makeButtons(pages) {
return [
{
label: '<<',
onClick: () => (page = 1),
},
{
label: '<',
onClick: () => {
if (page > 1) {
page -= 1;
}
},
},
...getPageButtons(pages),
{
label: '>',
onClick: () => {
if (page < totalPages) {
page += 1;
}
},
},
{
label: '>>',
onClick: () => (page = pages),
},
];
}

$: buttons = makeButtons(totalPages);
</script>

<div class="btn-group pagination justify-center mt-4">
{#each buttons as button}
<button
class={`btn btn-xs md:btn-md ${
button.value === page ? 'btn-active text-white' : ''
} ${button.label === DISABLED_BUTTON_LABEL ? 'btn-disabled' : ''}`}
on:click={button.onClick}>{button.label}</button>
{/each}
</div>

<style>
.pagination .btn-active {
color: white;
background-color: hsla(var(--af) / var(--tw-bg-opacity, 1));
}
</style>
41 changes: 39 additions & 2 deletions packages/bridge-ui/src/components/Transactions/Transactions.svelte
Original file line number Diff line number Diff line change
@@ -1,20 +1,56 @@
<script lang="ts">
import { transactions } from '../../store/transactions';
import { signer } from '../../store/signer';
import { relayerApi, paginationInfo } from '../../store/relayerApi';
import Transaction from './Transaction.svelte';
import TransactionDetail from './TransactionDetail.svelte';
import MessageStatusTooltip from './MessageStatusTooltip.svelte';
import InsufficientBalanceTooltip from './InsufficientBalanceTooltip.svelte';
import type { BridgeTransaction } from '../../domain/transactions';
import NoticeModal from '../modals/NoticeModal.svelte';
import Pagination from '../Pagination.svelte';
import { MAX_PAGE_SIZE } from '../../domain/relayerApi';

let selectedTransaction: BridgeTransaction;
let showMessageStatusTooltip: boolean;
let showInsufficientBalance: boolean;
let noticeModal: NoticeModal;

let page = 1;
let size = 10;
$: totalPagesInTransactionList = $paginationInfo
? Math.ceil($paginationInfo?.total / size)
: 0;

$: transactionsToShow = $transactions.slice(
(page - 1) * size,
(page - 1) * size + size,
);

async function loadMoreTransactionsFromAPI() {
if ($paginationInfo.page + 1 >= $paginationInfo.max_page) {
return;
}

const userAddress = await $signer.getAddress();
const { txs: apiTxs, paginationInfo: info } =
await $relayerApi.getAllBridgeTransactionByAddress(userAddress, {
page: $paginationInfo.page + 1,
size: MAX_PAGE_SIZE,
});
paginationInfo.set(info);
transactions.set([...$transactions, ...apiTxs]);
}

$: {
if ($transactions.length > 0 && (page + 1) * size > $transactions.length) {
loadMoreTransactionsFromAPI();
}
}
</script>

<div class="my-4 md:px-4">
{#if $transactions.length}
{#if transactionsToShow.length}
<table class="table-auto">
<thead>
<tr class="text-transaction-table">
Expand All @@ -26,7 +62,7 @@
</tr>
</thead>
<tbody class="text-sm md:text-base">
{#each $transactions as transaction (transaction.hash)}
{#each transactionsToShow as transaction (transaction.hash)}
<Transaction
on:claimNotice={({ detail }) => noticeModal.open(detail)}
on:tooltipStatus={() => (showMessageStatusTooltip = true)}
Expand All @@ -38,6 +74,7 @@
{/each}
</tbody>
</table>
<Pagination totalPages={totalPagesInTransactionList} bind:page />
{:else}
No transactions
{/if}
Expand Down
21 changes: 20 additions & 1 deletion packages/bridge-ui/src/domain/relayerApi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import type { Address, ChainID } from './chain';
import type { BridgeTransaction } from './transactions';

export const MAX_PAGE_SIZE = 100;
export const DEFAULT_PAGE = 0;

export type GetAllByAddressResponse = {
txs: BridgeTransaction[];
paginationInfo: PaginationInfo;
};

export type PaginationParams = {
size: typeof MAX_PAGE_SIZE;
page: number;
};

export interface RelayerAPI {
getAllBridgeTransactionByAddress(
address: string,
pagination: PaginationParams,
chainID?: number,
): Promise<BridgeTransaction[]>;
): Promise<GetAllByAddressResponse>;

getBlockInfo(): Promise<Map<number, RelayerBlockInfo>>;
}
Expand Down Expand Up @@ -71,3 +85,8 @@ export type APIResponse = {
first: boolean;
visible: number;
};

export type PaginationInfo = Pick<
APIResponse,
'page' | 'size' | 'max_page' | 'total_pages' | 'total' | 'last' | 'first'
>;
21 changes: 18 additions & 3 deletions packages/bridge-ui/src/relayer-api/RelayerAPIService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import type {
APIRequestParams,
APIResponse,
APIResponseTransaction,
GetAllByAddressResponse,
PaginationInfo,
PaginationParams,
RelayerAPI,
RelayerBlockInfo,
} from '../domain/relayerApi';
Expand Down Expand Up @@ -46,8 +49,9 @@ export class RelayerAPIService implements RelayerAPI {

async getAllBridgeTransactionByAddress(
address: string,
paginationParams: PaginationParams,
chainID?: number,
): Promise<BridgeTransaction[]> {
): Promise<GetAllByAddressResponse> {
if (!address) {
throw new Error('Address need to passed to fetch transactions');
}
Expand All @@ -56,12 +60,23 @@ export class RelayerAPIService implements RelayerAPI {
address,
chainID,
event: 'MessageSent',
...paginationParams,
};

const apiTxs: APIResponse = await this.getTransactionsFromAPI(params);

const paginationInfo: PaginationInfo = {
page: apiTxs.page,
size: apiTxs.size,
total: apiTxs.total,
total_pages: apiTxs.total_pages,
first: apiTxs.first,
last: apiTxs.last,
max_page: apiTxs.max_page,
};

if (apiTxs?.items?.length === 0) {
return [];
return { txs: [], paginationInfo };
}

apiTxs.items.map((t, i) => {
Expand Down Expand Up @@ -193,7 +208,7 @@ export class RelayerAPIService implements RelayerAPI {

bridgeTxs.reverse();
bridgeTxs.sort((tx) => (tx.status === MessageStatus.New ? -1 : 1));
return bridgeTxs;
return { txs: bridgeTxs, paginationInfo };
}

async getBlockInfo(): Promise<Map<number, RelayerBlockInfo>> {
Expand Down
9 changes: 7 additions & 2 deletions packages/bridge-ui/src/store/relayerApi.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { RelayerAPI, RelayerBlockInfo } from '../domain/relayerApi';
import type {
PaginationInfo,
RelayerAPI,
RelayerBlockInfo,
} from '../domain/relayerApi';
import { writable } from 'svelte/store';

const relayerApi = writable<RelayerAPI>();
const relayerBlockInfoMap = writable<Map<number, RelayerBlockInfo>>();
const paginationInfo = writable<PaginationInfo>();

export { relayerApi, relayerBlockInfoMap };
export { relayerApi, relayerBlockInfoMap, paginationInfo };