diff --git a/src/components/DepositsTable/DataRow.tsx b/src/components/DepositsTable/DataRow.tsx index 3216424d6..667ebaf54 100644 --- a/src/components/DepositsTable/DataRow.tsx +++ b/src/components/DepositsTable/DataRow.tsx @@ -9,6 +9,7 @@ import { fallbackSuggestedRelayerFeePct, suggestedFeesDeviationBufferMultiplier, fixedPointAdjustment, + pendingStateTimeUntilSlow, } from "utils"; import { HeaderCells, ColumnKey } from "./HeadRow"; @@ -28,13 +29,11 @@ type Props = { deposit: Deposit; headerCells: HeaderCells; disabledColumns?: ColumnKey[]; - onClickSpeedUp?: () => void; + onClickSpeedUp?: (deposit: Deposit) => void; }; const config = getConfig(); -const MAX_PENDING_STATE_TIME_UNTIL_SLOW = 15 * 60; // 15 mins - function isColumnDisabled(disabledColumns: ColumnKey[], column: ColumnKey) { return disabledColumns.includes(column); } @@ -59,8 +58,9 @@ export function DataRow({ ); const isSlowRelay = deposit.status === "pending" && - DateTime.fromSeconds(deposit.depositTime).diffNow("seconds").as("seconds") < - MAX_PENDING_STATE_TIME_UNTIL_SLOW; + Math.abs( + DateTime.fromSeconds(deposit.depositTime).diffNow("seconds").as("seconds") + ) > pendingStateTimeUntilSlow; // Hide unsupported or unknown token deposits if (!token) { diff --git a/src/components/DepositsTable/DepositsTable.tsx b/src/components/DepositsTable/DepositsTable.tsx index 0caceea7a..f660f17c8 100644 --- a/src/components/DepositsTable/DepositsTable.tsx +++ b/src/components/DepositsTable/DepositsTable.tsx @@ -4,9 +4,9 @@ import { HeadRow, headerCells, ColumnKey } from "./HeadRow"; import { DataRow } from "./DataRow"; import { Deposit } from "hooks/useDeposits"; -type Props = { +export type DepositsTableProps = { disabledColumns?: ColumnKey[]; - onClickSpeedUp?: () => void; + onClickSpeedUp?: (deposit: Deposit) => void; deposits: Deposit[]; }; @@ -14,7 +14,7 @@ export function DepositsTable({ disabledColumns = [], deposits, onClickSpeedUp, -}: Props) { +}: DepositsTableProps) { return ( @@ -42,7 +42,6 @@ const Wrapper = styled.div` `; const StyledTable = styled.table` - width: 1666px; white-space: nowrap; table-layout: fixed; `; diff --git a/src/components/DepositsTable/HeadRow.tsx b/src/components/DepositsTable/HeadRow.tsx index c29f59a86..79e13a29d 100644 --- a/src/components/DepositsTable/HeadRow.tsx +++ b/src/components/DepositsTable/HeadRow.tsx @@ -16,7 +16,7 @@ export const headerCells = { }, route: { label: "Route", - width: 206, + width: 144, }, address: { label: "Address", diff --git a/src/components/DepositsTable/PaginatedDepositsTable.tsx b/src/components/DepositsTable/PaginatedDepositsTable.tsx new file mode 100644 index 000000000..a8f3f5725 --- /dev/null +++ b/src/components/DepositsTable/PaginatedDepositsTable.tsx @@ -0,0 +1,58 @@ +import styled from "@emotion/styled"; + +import Pagination, { paginate } from "components/Pagination"; +import { DepositsTable, DepositsTableProps } from "./DepositsTable"; + +type Props = DepositsTableProps & { + currentPage: number; + onPageChange: (newPage: number) => void; + currentPageSize: number; + onPageSizeChange: (newPageSize: number) => void; + totalCount: number; + initialPageSize?: number; + pageSizes?: number[]; +}; + +const DEFAULT_PAGE_SIZES = [10, 25, 50]; + +export function PaginatedDepositsTable({ + currentPage, + onPageChange, + currentPageSize, + onPageSizeChange, + totalCount, + initialPageSize = DEFAULT_PAGE_SIZES[0], + pageSizes = DEFAULT_PAGE_SIZES, + ...depositsTableProps +}: Props) { + const paginateValues = paginate({ + elementCount: totalCount, + currentPage, + maxNavigationCount: 5, + elementsPerPage: currentPageSize, + }); + + return ( + <> + + + + + + ); +} + +const PaginationWrapper = styled.div``; diff --git a/src/components/DepositsTable/cells/ActionsCell.tsx b/src/components/DepositsTable/cells/ActionsCell.tsx index 05c7d94ff..62ad43957 100644 --- a/src/components/DepositsTable/cells/ActionsCell.tsx +++ b/src/components/DepositsTable/cells/ActionsCell.tsx @@ -1,3 +1,4 @@ +import { useCallback } from "react"; import styled from "@emotion/styled"; import { ReactComponent as ZapIcon } from "assets/zap.svg"; @@ -11,7 +12,7 @@ type Props = { deposit: Deposit; isSlowRelay?: boolean; isProfitable?: boolean; - onClickSpeedUp?: () => void; + onClickSpeedUp?: (deposit: Deposit) => void; }; export function ActionsCell({ @@ -41,12 +42,16 @@ export function ActionsCell({ ) : null; + const handleClickSpeedUp = useCallback(() => { + onClickSpeedUp?.(deposit); + }, [deposit, onClickSpeedUp]); + const speedUp = deposit.status === "pending" ? ( isProfitable ? ( - + ) : ( - + ) ) : null; 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/components/Pagination/Pagination.styles.tsx b/src/components/Pagination/Pagination.styles.tsx index 6b93c769a..e9bbf8324 100644 --- a/src/components/Pagination/Pagination.styles.tsx +++ b/src/components/Pagination/Pagination.styles.tsx @@ -38,6 +38,10 @@ export const PageSizeSelectButton = styled(UnstyledButton)` svg { margin-left: 6px; } + + @media ${QUERIESV2.sm.andDown} { + padding: 10px 20px; + } `; const PageSelectDropdownRevealAnimation = keyframes` @@ -83,6 +87,10 @@ export const PageSizeOptiontButton = styled(UnstyledButton)` background-color: var(--color-primary); color: var(--color-gray); } + + @media ${QUERIESV2.sm.andDown} { + padding: 6px 20px; + } `; export const PaginationElements = styled.div` diff --git a/src/stories/PaginatedDepositsTable.stories.tsx b/src/stories/PaginatedDepositsTable.stories.tsx new file mode 100644 index 000000000..17c1130b7 --- /dev/null +++ b/src/stories/PaginatedDepositsTable.stories.tsx @@ -0,0 +1,194 @@ +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 [currentPage, setCurrentPage] = useState(0); + const [pageSize, setPageSize] = useState(1); + const [deposits, setDeposits] = useState( + mockedDeposits.slice(0, 1) + ); + + return ( + { + setCurrentPage(page); + setDeposits(mockedDeposits.slice(page, page + pageSize)); + }} + currentPageSize={pageSize} + onPageSizeChange={(size) => { + setPageSize(size); + setDeposits(mockedDeposits.slice(0, size)); + }} + totalCount={mockedDeposits.length} + pageSizes={[1, 2, 3]} + initialPageSize={pageSize} + /> + ); +}; + +export const Default: Story = { + render: () => , +}; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 940b2d73d..82c6aa79c 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -688,3 +688,6 @@ export const walletBlacklist = (process.env.REACT_APP_WALLET_BLACKLIST || "") // Pre-computed gas expenditure for deposits used for estimations export const gasExpenditureDeposit = BigNumber.from(90_000); + +// Used to determine whether to show the "slow" warning in the deposits table +export const pendingStateTimeUntilSlow = 30 * 60; // 30 mins