From 3f46efa31714599c35886676a8a2f5f054318307 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Tue, 7 Nov 2023 14:50:03 +0100 Subject: [PATCH] feat: updated paginated deposits table --- .../DepositsTable/DepositsTable.tsx | 2 +- .../DepositsTable/PaginatedDepositsTable.tsx | 57 ++++++ src/components/DepositsTable/index.tsx | 1 + src/hooks/usePagination.ts | 37 ++++ .../PaginatedDepositsTable.stories.tsx | 190 ++++++++++++++++++ 5 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 src/components/DepositsTable/PaginatedDepositsTable.tsx create mode 100644 src/hooks/usePagination.ts create mode 100644 src/stories/PaginatedDepositsTable.stories.tsx diff --git a/src/components/DepositsTable/DepositsTable.tsx b/src/components/DepositsTable/DepositsTable.tsx index 0caceea7a..596dea673 100644 --- a/src/components/DepositsTable/DepositsTable.tsx +++ b/src/components/DepositsTable/DepositsTable.tsx @@ -4,7 +4,7 @@ import { HeadRow, headerCells, ColumnKey } from "./HeadRow"; import { DataRow } from "./DataRow"; import { Deposit } from "hooks/useDeposits"; -type Props = { +export type Props = { disabledColumns?: ColumnKey[]; onClickSpeedUp?: () => void; deposits: Deposit[]; diff --git a/src/components/DepositsTable/PaginatedDepositsTable.tsx b/src/components/DepositsTable/PaginatedDepositsTable.tsx new file mode 100644 index 000000000..ea6c1ca18 --- /dev/null +++ b/src/components/DepositsTable/PaginatedDepositsTable.tsx @@ -0,0 +1,57 @@ +import styled from "@emotion/styled"; + +import Pagination from "components/Pagination"; +import { usePagination } from "hooks/usePagination"; +import { DepositsTable, Props as DepositsTableProps } from "./DepositsTable"; + +type Props = DepositsTableProps & { + onPageChange: (currentPage: number) => void; + onPageSizeChange: (currentPageSize: number) => void; + totalCount: number; + initialPageSize?: number; + pageSizes?: number[]; +}; + +const DEFAULT_PAGE_SIZES = [10, 25, 50]; + +export function PaginatedDepositsTable({ + onPageChange, + onPageSizeChange, + totalCount, + initialPageSize = DEFAULT_PAGE_SIZES[0], + pageSizes = DEFAULT_PAGE_SIZES, + ...depositsTableProps +}: Props) { + const { pageSize, currentPage, setCurrentPage, setPageSize, paginateValues } = + usePagination(totalCount, { initialPageSize }); + + return ( + <> + + + { + setCurrentPage(newPage); + onPageChange(newPage); + }} + onPageSizeChange={(newPageSize) => { + setPageSize(newPageSize); + onPageSizeChange(newPageSize); + }} + pageList={paginateValues.pageList} + activeIndex={paginateValues.activeIndex} + disableBack={paginateValues.disableBack} + disableForward={paginateValues.disableForward} + hideStart={paginateValues.hideStart} + hideEnd={paginateValues.hideEnd} + lastPage={paginateValues.lastPage} + currentPage={currentPage} + pageSize={pageSize} + pageSizes={pageSizes} + /> + + + ); +} + +const PaginationWrapper = styled.div``; diff --git a/src/components/DepositsTable/index.tsx b/src/components/DepositsTable/index.tsx index 06e80a0c1..259881db4 100644 --- a/src/components/DepositsTable/index.tsx +++ b/src/components/DepositsTable/index.tsx @@ -1,3 +1,4 @@ export * from "./DataRow"; export * from "./HeadRow"; export * from "./DepositsTable"; +export * from "./PaginatedDepositsTable"; diff --git a/src/hooks/usePagination.ts b/src/hooks/usePagination.ts new file mode 100644 index 000000000..1565051f4 --- /dev/null +++ b/src/hooks/usePagination.ts @@ -0,0 +1,37 @@ +import { useState } from "react"; + +import { paginate } from "components/Pagination"; + +const DEFAULT_PAGE_SIZE = 10; +const DEFAULT_MAX_NAVIGATION_COUNT = 5; + +export function usePagination( + totalCount: number, + options: Partial<{ + maxNavigationCount: number; + initialPageSize: number; + }> = {} +) { + const { maxNavigationCount = DEFAULT_MAX_NAVIGATION_COUNT, initialPageSize } = + options; + + const [currentPage, setCurrentPage] = useState(0); + const [pageSize, setPageSize] = useState( + initialPageSize || DEFAULT_PAGE_SIZE + ); + + const paginateValues = paginate({ + elementCount: totalCount, + currentPage, + maxNavigationCount, + elementsPerPage: pageSize, + }); + + return { + paginateValues, + currentPage, + setPageSize, + setCurrentPage, + pageSize, + }; +} diff --git a/src/stories/PaginatedDepositsTable.stories.tsx b/src/stories/PaginatedDepositsTable.stories.tsx new file mode 100644 index 000000000..7b371582a --- /dev/null +++ b/src/stories/PaginatedDepositsTable.stories.tsx @@ -0,0 +1,190 @@ +import { useState } from "react"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { PaginatedDepositsTable } from "../components/DepositsTable"; +import { Deposit } from "../hooks/useDeposits"; + +const mockedDeposits: Deposit[] = [ + { + depositId: 1180880, + depositTime: 1698275877, + status: "pending", + filled: "0", + sourceChainId: 324, + destinationChainId: 42161, + assetAddr: "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91", + depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + recipientAddr: "0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A", + message: "0x", + amount: "50000000000000000", + depositTxHash: + "0x13a619b510e643d51f74f5a01f98c16161e1d93c2db6f689478472a3f42ec7e0", + fillTxs: [], + speedUps: [], + depositRelayerFeePct: "4952678372124980", + initialRelayerFeePct: "4952678372124980", + suggestedRelayerFeePct: "4952678372124980", + }, + // Fee too low, i.e. unprofitable + { + depositId: 1144678, + depositTime: 1696447947, + status: "pending", + filled: "0", + sourceChainId: 42161, + destinationChainId: 324, + assetAddr: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", + depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + message: "0x", + amount: "2000000000000000000000", + depositTxHash: + "0x66a7c4e34f91325d0c17bc7bb98350e15c61166d6138a0e89e002637b36fe3e5", + fillTxs: [], + speedUps: [], + depositRelayerFeePct: "0", + initialRelayerFeePct: "0", + suggestedRelayerFeePct: "156172500000000000", + }, + // Finalized with fill time + { + depositId: 1205910, + depositTime: 1698998623, + fillTime: 1698998623 + 99, + status: "filled", + filled: "12000000", + sourceChainId: 324, + destinationChainId: 8453, + assetAddr: "0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4", + depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + message: "0x", + amount: "12000000", + depositTxHash: + "0xe8a2d8ed449a6a2fe7fa3dc24e699a951f945280c27df259a910008683b1e296", + fillTxs: [ + "0x8caf6a0e38a8788f47dfad89e709f1c0854783987558af9c34d0fadb61c20941", + ], + speedUps: [], + depositRelayerFeePct: "24394417866666666", + initialRelayerFeePct: "24394417866666666", + suggestedRelayerFeePct: "28289667866666666", + }, + // Finalized without fill time + { + depositId: 1199308, + depositTime: 1698831959, + status: "filled", + filled: "12000000", + sourceChainId: 42161, + destinationChainId: 8453, + assetAddr: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", + depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + message: "0x", + amount: "12000000", + depositTxHash: + "0x4eecaeee9b6d2df9d06d249b99ce042dd16dbf7bf2fd5d0cc6938e336fdaadd3", + fillTxs: [ + "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806a", + "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806b", + "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806c", + ], + speedUps: [], + depositRelayerFeePct: "28434751200000000", + initialRelayerFeePct: "28434751200000000", + suggestedRelayerFeePct: "28443917866666666", + feeBreakdown: { + bridgeFee: { + pct: "28434751200000000", + usd: "341217014400000000", + }, + destinationGasFee: { + pct: "28434751200000000", + usd: "341217014400000000", + }, + }, + rewards: { + type: "referrals", + rate: 0.4, + amount: "341217014400000000", + usd: "341217014400000000", + }, + }, + { + depositId: 1199309, + depositTime: 1698831959, + status: "filled", + filled: "12000000", + sourceChainId: 42161, + destinationChainId: 8453, + assetAddr: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", + depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + message: "0x", + amount: "12000000", + depositTxHash: + "0x4eecaeee9b6d2df9d06d249b99ce042dd16dbf7bf2fd5d0cc6938e336fdaadd3", + fillTxs: [ + "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806a", + "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806b", + "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806c", + ], + speedUps: [], + depositRelayerFeePct: "28434751200000000", + initialRelayerFeePct: "28434751200000000", + suggestedRelayerFeePct: "28443917866666666", + feeBreakdown: { + bridgeFee: { + pct: "28434751200000000", + usd: "341217014400000000", + }, + destinationGasFee: { + pct: "28434751200000000", + usd: "341217014400000000", + }, + }, + rewards: { + type: "referrals", + rate: 0.4, + amount: "341217014400000000", + usd: "341217014400000000", + }, + }, +]; + +const meta: Meta = { + component: PaginatedDepositsTable, + argTypes: {}, +}; + +export default meta; + +type Story = StoryObj; + +const BasicPagination = () => { + const [pageSize, setPageSize] = useState(1); + const [deposits, setDeposits] = useState( + mockedDeposits.slice(0, 1) + ); + + return ( + { + setDeposits(mockedDeposits.slice(page, page + pageSize)); + }} + onPageSizeChange={(size) => { + setPageSize(size); + setDeposits(mockedDeposits.slice(0, size)); + }} + totalCount={mockedDeposits.length} + pageSizes={[1, 2, 3]} + initialPageSize={pageSize} + /> + ); +}; + +export const Default: Story = { + render: () => , +};