diff --git a/.changelog/1488.trivial.md b/.changelog/1488.trivial.md new file mode 100644 index 000000000..2a22cb00b --- /dev/null +++ b/.changelog/1488.trivial.md @@ -0,0 +1 @@ +Move events cards to tabs diff --git a/playwright/tests/accounts.spec.ts b/playwright/tests/accounts.spec.ts index 8e718b0fd..5373f6771 100644 --- a/playwright/tests/accounts.spec.ts +++ b/playwright/tests/accounts.spec.ts @@ -109,7 +109,9 @@ async function setup(page: Page) { }) }) - await page.goto('http://localhost:1234/mainnet/sapphire/address/0x0000000000000000000000000000000000000000') + await page.goto( + 'http://localhost:1234/mainnet/sapphire/address/0x0000000000000000000000000000000000000000/events', + ) } test.describe('Account details page', () => { diff --git a/src/app/pages/RuntimeAccountDetailsPage/AccountEventsCard.tsx b/src/app/pages/RuntimeAccountDetailsPage/AccountEventsCard.tsx index a7e048d27..ccab609eb 100644 --- a/src/app/pages/RuntimeAccountDetailsPage/AccountEventsCard.tsx +++ b/src/app/pages/RuntimeAccountDetailsPage/AccountEventsCard.tsx @@ -1,30 +1,37 @@ import { FC } from 'react' -import { RuntimeEvent } from '../../../oasis-nexus/api' -import { SubPageCard } from 'app/components/SubPageCard' +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import CardContent from '@mui/material/CardContent' import { useTranslation } from 'react-i18next' import { RuntimeEventsDetailedList } from '../../components/RuntimeEvents/RuntimeEventsDetailedList' -import { SearchScope } from '../../../types/searchScope' import { AddressSwitchOption } from '../../components/AddressSwitch' +import { ErrorBoundary } from '../../components/ErrorBoundary' +import { LinkableDiv } from '../../components/PageLayout/LinkableDiv' +import { useAccountEvents } from './hook' +import { RuntimeAccountDetailsContext } from '.' -type AccountEventProps = { - scope: SearchScope - isLoading: boolean - isError: boolean - events: RuntimeEvent[] | undefined -} +export const eventsContainerId = 'events' -export const AccountEventsCard: FC = ({ scope, isLoading, isError, events }) => { +export const AccountEventsCard: FC = ({ scope, address }) => { const { t } = useTranslation() + const { isLoading, isError, events } = useAccountEvents(scope, address) return ( - - - + + + + + + + + + + ) } diff --git a/src/app/pages/RuntimeAccountDetailsPage/index.tsx b/src/app/pages/RuntimeAccountDetailsPage/index.tsx index 10e3400d3..5be7ef502 100644 --- a/src/app/pages/RuntimeAccountDetailsPage/index.tsx +++ b/src/app/pages/RuntimeAccountDetailsPage/index.tsx @@ -4,10 +4,9 @@ import { useHref, useLoaderData, useOutletContext } from 'react-router-dom' import { PageLayout } from '../../components/PageLayout' import { RouterTabs } from '../../components/RouterTabs' import { useAllTokenPrices } from '../../../coin-gecko/api' - import { EvmTokenType, RuntimeAccount } from '../../../oasis-nexus/api' import { accountTokenContainerId } from './AccountTokensCard' -import { useAccount, useAccountEvents } from './hook' +import { useAccount } from './hook' import { useRequiredScopeParam } from '../../hooks/useScopeParam' import { contractCodeContainerId } from './ContractCodeCard' import { useTokenInfo } from '../TokenDashboardPage/hook' @@ -15,7 +14,7 @@ import { accountTokenTransfersContainerId } from './AccountTokenTransfersCard' import { getTokenTypePluralName } from '../../../types/tokens' import { SearchScope } from '../../../types/searchScope' import { RuntimeAccountDetailsCard } from './RuntimeAccountDetailsCard' -import { AccountEventsCard } from './AccountEventsCard' +import { eventsContainerId } from './AccountEventsCard' import { DappBanner } from '../../components/DappBanner' import { AddressLoaderData } from '../../utils/route-utils' import { getFiatCurrencyForScope } from '../../../config' @@ -39,8 +38,7 @@ export const RuntimeAccountDetailsPage: FC = () => { const tokenPrices = useAllTokenPrices(getFiatCurrencyForScope(scope)) - const { isLoading: areEventsLoading, isError: isEventsError, events } = useAccountEvents(scope, address) - + const eventsLink = useHref(`events#${eventsContainerId}`) const tokenTransfersLink = useHref(`token-transfers#${accountTokenTransfersContainerId}`) const erc20Link = useHref(`tokens/erc-20#${accountTokenContainerId}`) const erc721Link = useHref(`tokens/erc-721#${accountTokenContainerId}`) @@ -68,6 +66,7 @@ export const RuntimeAccountDetailsPage: FC = () => { { ]} context={context} /> - ) } diff --git a/src/app/pages/RuntimeBlockDetailPage/EventsCard.tsx b/src/app/pages/RuntimeBlockDetailPage/BlockEventsCard.tsx similarity index 76% rename from src/app/pages/RuntimeBlockDetailPage/EventsCard.tsx rename to src/app/pages/RuntimeBlockDetailPage/BlockEventsCard.tsx index fc5499489..bfea1645a 100644 --- a/src/app/pages/RuntimeBlockDetailPage/EventsCard.tsx +++ b/src/app/pages/RuntimeBlockDetailPage/BlockEventsCard.tsx @@ -1,20 +1,20 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' -import { ScrollingCard } from '../../components/PageLayout/ScrollingCard' +import Card from '@mui/material/Card' import CardHeader from '@mui/material/CardHeader' import CardContent from '@mui/material/CardContent' - import { Layer, useGetRuntimeEvents } from '../../../oasis-nexus/api' import { ErrorBoundary } from '../../components/ErrorBoundary' import { AppErrors } from '../../../types/errors' -import { SearchScope } from '../../../types/searchScope' import { RuntimeEventsDetailedList } from '../../components/RuntimeEvents/RuntimeEventsDetailedList' import { AddressSwitchOption } from '../../components/AddressSwitch' import { EmptyState } from '../../components/EmptyState' +import { LinkableDiv } from '../../components/PageLayout/LinkableDiv' +import { RuntimeBlockDetailsContext } from '.' export const eventsContainerId = 'events' -const EventsList: FC<{ scope: SearchScope; blockHeight: number }> = ({ scope, blockHeight }) => { +const EventsList: FC = ({ scope, blockHeight }) => { const { t } = useTranslation() if (scope.layer === Layer.consensus) { // Loading events for consensus blocks is not yet supported. @@ -52,16 +52,23 @@ const EventsList: FC<{ scope: SearchScope; blockHeight: number }> = ({ scope, bl ) } -export const EventsCard: FC<{ scope: SearchScope; blockHeight: number }> = ({ scope, blockHeight }) => { +export const BlockEventsCard: FC = ({ scope, blockHeight }) => { const { t } = useTranslation() + + if (!blockHeight) { + return null + } + return ( - - + + + + - + ) } diff --git a/src/app/pages/RuntimeBlockDetailPage/TransactionsCard.tsx b/src/app/pages/RuntimeBlockDetailPage/BlockTransactionsCard.tsx similarity index 78% rename from src/app/pages/RuntimeBlockDetailPage/TransactionsCard.tsx rename to src/app/pages/RuntimeBlockDetailPage/BlockTransactionsCard.tsx index 059aeb168..f8ef09afb 100644 --- a/src/app/pages/RuntimeBlockDetailPage/TransactionsCard.tsx +++ b/src/app/pages/RuntimeBlockDetailPage/BlockTransactionsCard.tsx @@ -1,20 +1,20 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' -import { ScrollingCard } from '../../components/PageLayout/ScrollingCard' +import Card from '@mui/material/Card' import CardHeader from '@mui/material/CardHeader' import CardContent from '@mui/material/CardContent' - import { useSearchParamsPagination } from '../../components/Table/useSearchParamsPagination' import { NUMBER_OF_ITEMS_ON_SEPARATE_PAGE } from '../../config' import { Layer, useGetRuntimeTransactions } from '../../../oasis-nexus/api' import { RuntimeTransactions } from '../../components/Transactions' import { ErrorBoundary } from '../../components/ErrorBoundary' import { AppErrors } from '../../../types/errors' -import { SearchScope } from '../../../types/searchScope' +import { LinkableDiv } from '../../components/PageLayout/LinkableDiv' +import { RuntimeBlockDetailsContext } from '.' export const transactionsContainerId = 'transactions' -const TransactionList: FC<{ scope: SearchScope; blockHeight: number }> = ({ scope, blockHeight }) => { +const TransactionList: FC = ({ scope, blockHeight }) => { const txsPagination = useSearchParamsPagination('page') const txsOffset = (txsPagination.selectedPage - 1) * NUMBER_OF_ITEMS_ON_SEPARATE_PAGE if (scope.layer === Layer.consensus) { @@ -52,16 +52,23 @@ const TransactionList: FC<{ scope: SearchScope; blockHeight: number }> = ({ scop ) } -export const TransactionsCard: FC<{ scope: SearchScope; blockHeight: number }> = ({ scope, blockHeight }) => { +export const BlockTransactionsCard: FC = ({ scope, blockHeight }) => { const { t } = useTranslation() + + if (!blockHeight) { + return null + } + return ( - - + + + + - + ) } diff --git a/src/app/pages/RuntimeBlockDetailPage/index.tsx b/src/app/pages/RuntimeBlockDetailPage/index.tsx index 8100ac6e2..77af8fe41 100644 --- a/src/app/pages/RuntimeBlockDetailPage/index.tsx +++ b/src/app/pages/RuntimeBlockDetailPage/index.tsx @@ -1,29 +1,39 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' -import { useParams } from 'react-router-dom' +import { useHref, useOutletContext, useParams } from 'react-router-dom' import { useScreenSize } from '../../hooks/useScreensize' import Link from '@mui/material/Link' import { Layer, RuntimeBlock, useGetRuntimeBlockByHeight } from '../../../oasis-nexus/api' +import { RouterTabs } from '../../components/RouterTabs' import { StyledDescriptionList } from '../../components/StyledDescriptionList' import { PageLayout } from '../../components/PageLayout' import { SubPageCard } from '../../components/SubPageCard' import { CopyToClipboard } from '../../components/CopyToClipboard' import { TextSkeleton } from '../../components/Skeleton' import { useFormattedTimestampStringWithDistance } from '../../hooks/useFormattedTimestamp' -import { TransactionsCard } from './TransactionsCard' import { AppErrors } from '../../../types/errors' import { paraTimesConfig } from '../../../config' -import { transactionsContainerId } from './TransactionsCard' +import { transactionsContainerId } from './BlockTransactionsCard' import { BlockLink, BlockHashLink } from '../../components/Blocks/BlockLink' import { RouteUtils } from '../../utils/route-utils' import { useRequiredScopeParam } from '../../hooks/useScopeParam' import { DashboardLink } from '../ParatimeDashboardPage/DashboardLink' -import { EventsCard } from './EventsCard' +import { eventsContainerId } from './BlockEventsCard' import { RuntimeNextBlockButton, RuntimePrevBlockButton } from '../../components/BlockNavigationButtons' +import { SearchScope } from 'types/searchScope' + +export type RuntimeBlockDetailsContext = { + scope: SearchScope + blockHeight?: number +} + +export const useRuntimeBlockDetailsProps = () => useOutletContext() export const RuntimeBlockDetailPage: FC = () => { const { t } = useTranslation() const scope = useRequiredScopeParam() + const txLink = useHref('') + const eventsLink = useHref(`events#${eventsContainerId}`) if (scope.layer === Layer.consensus) { throw AppErrors.UnsupportedLayer // We should use useGetConsensusBlocksHeight() @@ -38,14 +48,20 @@ export const RuntimeBlockDetailPage: FC = () => { throw AppErrors.NotFoundBlockHeight } const block = data?.data + const context: RuntimeBlockDetailsContext = { scope, blockHeight } return ( - {!!block?.num_transactions && } - + ) } diff --git a/src/routes.tsx b/src/routes.tsx index 5cf6c3cd3..028d7bc15 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -4,7 +4,9 @@ import { RuntimeBlocksPage } from './app/pages/RuntimeBlocksPage' import { RuntimeTransactionsPage } from './app/pages/RuntimeTransactionsPage' import { RuntimeTransactionDetailPage } from './app/pages/RuntimeTransactionDetailPage' import { ParatimeDashboardPage } from './app/pages/ParatimeDashboardPage' -import { RuntimeBlockDetailPage } from './app/pages/RuntimeBlockDetailPage' +import { RuntimeBlockDetailPage, useRuntimeBlockDetailsProps } from './app/pages/RuntimeBlockDetailPage' +import { BlockTransactionsCard } from './app/pages/RuntimeBlockDetailPage/BlockTransactionsCard' +import { BlockEventsCard } from './app/pages/RuntimeBlockDetailPage/BlockEventsCard' import { RuntimeAccountDetailsPage, useRuntimeAccountDetailsProps, @@ -28,6 +30,7 @@ import { RoutingErrorPage } from './app/pages/RoutingErrorPage' import { ThemeByNetwork, withDefaultTheme } from './app/components/ThemeByNetwork' import { useRequiredScopeParam } from './app/hooks/useScopeParam' import { TokensPage } from './app/pages/TokensOverviewPage' +import { AccountEventsCard } from 'app/pages/RuntimeAccountDetailsPage/AccountEventsCard' import { ContractCodeCard } from './app/pages/RuntimeAccountDetailsPage/ContractCodeCard' import { TokenDashboardPage, useTokenDashboardProps } from './app/pages/TokenDashboardPage' import { AccountTokenTransfersCard } from './app/pages/RuntimeAccountDetailsPage/AccountTokenTransfersCard' @@ -216,6 +219,16 @@ export const routes: RouteObject[] = [ path: `block/:blockHeight`, element: , loader: blockHeightParamLoader, + children: [ + { + path: '', + Component: () => , + }, + { + path: 'events', + Component: () => , + }, + ], }, { path: `address/:address`, @@ -226,6 +239,10 @@ export const routes: RouteObject[] = [ path: '', Component: () => , }, + { + path: 'events', + Component: () => , + }, { path: 'token-transfers', Component: () => ,