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

[CFE-52]: Feat(components): add bonded token changes delegation related transac… #832

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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#832](https://github.com/alleslabs/celatone-frontend/pull/832) Add bonded token changes delegation related transactions
- [#831](https://github.com/alleslabs/celatone-frontend/pull/831) Update zod schema to apply with new validator delegation related txs api spec
- [#828](https://github.com/alleslabs/celatone-frontend/pull/828) Add validator detail voting power overview section with data from APIs
- [#819](https://github.com/alleslabs/celatone-frontend/pull/819) Add validator detail overview section with data from APIs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { Flex } from "@chakra-ui/react";
import { Box, Flex } from "@chakra-ui/react";

import { RelatedTransactionTable } from "../tables/RelatedTransactionsTable";
import {
RelatedTransactionsMobileCard,
RelatedTransactionTable,
} from "../tables";
import { useMobile } from "lib/app-provider";
import { Pagination } from "lib/components/pagination";
import { usePaginator } from "lib/components/pagination/usePaginator";
import { TableTitle } from "lib/components/table";
import { useValidatorDelegationRelatedTxs } from "lib/services/validatorService";
import type { AssetInfos, Option, ValidatorAddr } from "lib/types";

import { VotingPowerChart } from "./VotingPowerChart";
Expand All @@ -15,13 +23,82 @@ export const BondedTokenChanges = ({
validatorAddress,
singleStakingDenom,
assetInfos,
}: BondedTokenChangesProps) => (
<Flex direction="column" gap={{ base: 4, md: 8 }} pt={6}>
<VotingPowerChart
validatorAddress={validatorAddress}
singleStakingDenom={singleStakingDenom}
assetInfos={assetInfos}
/>
<RelatedTransactionTable />
</Flex>
);
}: BondedTokenChangesProps) => {
const isMobile = useMobile();

const {
pagesQuantity,
setTotalData,
currentPage,
setCurrentPage,
pageSize,
setPageSize,
offset,
} = usePaginator({
initialState: {
pageSize: 10,
currentPage: 1,
isDisabled: false,
},
});

const { data, isLoading } = useValidatorDelegationRelatedTxs(
validatorAddress,
pageSize,
offset,
{
onSuccess: ({ total }) => setTotalData(total),
}
);

const tableHeaderId = "relatedTransactionTableHeader";

return (
<Flex direction="column" gap={{ base: 4, md: 8 }} pt={6}>
<VotingPowerChart
validatorAddress={validatorAddress}
singleStakingDenom={singleStakingDenom}
assetInfos={assetInfos}
/>
<Box>
{isMobile ? (
<RelatedTransactionsMobileCard
delegationRelatedTxs={data?.items}
isLoading={isLoading}
assetInfos={assetInfos}
/>
) : (
<>
<TableTitle
title="Delegation-Related Transactions"
count={data?.total ?? 0}
id={tableHeaderId}
helperText="Shows transactions relevant to changes in delegated tokens, excluding any token reduction due to slashing."
/>
<RelatedTransactionTable
delegationRelatedTxs={data?.items}
isLoading={isLoading}
assetInfos={assetInfos}
/>
</>
)}
{!!data?.total && data.total > 10 && (
<Pagination
currentPage={currentPage}
pagesQuantity={pagesQuantity}
offset={offset}
totalData={data.total}
scrollComponentId={tableHeaderId}
pageSize={pageSize}
onPageChange={setCurrentPage}
onPageSizeChange={(e) => {
const size = Number(e.target.value);
setPageSize(size);
setCurrentPage(1);
}}
/>
)}
</Box>
</Flex>
);
};

This file was deleted.

2 changes: 1 addition & 1 deletion src/lib/pages/validator-details/components/tables/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from "./ProposedBlocksTable";
export * from "./RelatedTransactionsTable";
export * from "./related-transactions";
export * from "./VotedProposalsTable";
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Box, Flex, Text } from "@chakra-ui/react";
import type { BigSource } from "big.js";

import { TokenImageRender } from "lib/components/token";
import { getUndefinedTokenIcon } from "lib/pages/pools/utils";
import type { AssetInfos, Coin, Option, USD } from "lib/types";
import {
coinToTokenWithValue,
formatPrice,
formatUTokenWithPrecision,
} from "lib/utils";

interface RelatedTransactionsBondedTokenChangesProps {
txHash: string;
token: Coin;
assetInfos: Option<AssetInfos>;
}

export const RelatedTransactionsBondedTokenChanges = ({
txHash,
token,
assetInfos,
}: RelatedTransactionsBondedTokenChangesProps) => {
const tokenWithValue = coinToTokenWithValue(
token?.denom,
token?.amount,
assetInfos
);

const formattedAmount = formatUTokenWithPrecision(
tokenWithValue.amount,
tokenWithValue.precision ?? 0,
false,
2,
true
);

const isPositiveAmount = tokenWithValue.amount.gte(0);

return (
<Flex
gap={2}
key={`${txHash}-${token.denom}`}
w="100%"
justifyContent={{ base: "start", md: "end" }}
alignItems="center"
>
<Box textAlign={{ base: "left", md: "right" }}>
<Text>
<Text
as="span"
fontWeight={700}
color={isPositiveAmount ? "success.main" : "error.main"}
>
{formattedAmount}
</Text>{" "}
{tokenWithValue.symbol}
</Text>
<Text variant="body3" color="text.dark">
({formatPrice(tokenWithValue.value?.abs() as USD<BigSource>)})
</Text>
</Box>
<TokenImageRender
boxSize={6}
logo={
tokenWithValue.logo ?? getUndefinedTokenIcon(tokenWithValue.denom)
}
/>
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Badge, Box, Flex, Grid, GridItem, Text } from "@chakra-ui/react";

import { ExplorerLink } from "lib/components/ExplorerLink";
import { Loading } from "lib/components/Loading";
import { MobileCardTemplate, MobileTableContainer } from "lib/components/table";
import type { ValidatorDelegationRelatedTxsResponseItem } from "lib/services/validator";
import type { AssetInfos, Option } from "lib/types";
import { dateFromNow, extractMsgType, formatUTC } from "lib/utils";

import { RelatedTransactionsBondedTokenChanges } from "./RelatedTransactionsBondedTokenChanges";

interface RelatedTransactionsMobileCardProps {
delegationRelatedTxs: Option<ValidatorDelegationRelatedTxsResponseItem[]>;
isLoading: boolean;
assetInfos: Option<AssetInfos>;
}

export const RelatedTransactionsMobileCard = ({
delegationRelatedTxs,
isLoading,
assetInfos,
}: RelatedTransactionsMobileCardProps) => {
if (isLoading) return <Loading />;

return (
<MobileTableContainer>
{delegationRelatedTxs?.map((delegationRelatedTx) => (
<MobileCardTemplate
topContent={
<Flex w="100%" flexDirection="column" gap={2}>
<Grid templateColumns="1fr 1fr" gap={2}>
<GridItem>
<Text variant="body3" color="text.dark" fontWeight={600}>
Transaction Hash
</Text>
<ExplorerLink
value={delegationRelatedTx.txHash.toLocaleUpperCase()}
type="tx_hash"
showCopyOnHover
/>
{delegationRelatedTx.messages.length > 1 && (
<Badge variant="secondary" ml={2}>
{delegationRelatedTx.messages.length}
</Badge>
)}
</GridItem>
<GridItem>
<Text variant="body3" color="text.dark" fontWeight={600}>
Sender
</Text>
<ExplorerLink
value={delegationRelatedTx.sender}
type="user_address"
showCopyOnHover
/>
</GridItem>
</Grid>
<Box>
<Text variant="body3" color="text.dark" fontWeight={600}>
Action
</Text>
<Text variant="body2" color="white">
{delegationRelatedTx.messages.length > 1
? `${delegationRelatedTx.messages.length} Messages`
: extractMsgType(delegationRelatedTx.messages[0].type)}
</Text>
</Box>
<Box>
<Text variant="body3" color="text.dark" fontWeight={600}>
Bonded Token Changes
</Text>
{delegationRelatedTx.tokens.map((token) => (
<RelatedTransactionsBondedTokenChanges
txHash={delegationRelatedTx.txHash}
token={token}
assetInfos={assetInfos}
/>
))}
</Box>
</Flex>
}
bottomContent={
<Box>
<Text variant="body2" color="text.dark">
{formatUTC(delegationRelatedTx.timestamp)}
</Text>
<Text variant="body3" color="text.disabled">
{`(${dateFromNow(delegationRelatedTx.timestamp)})`}
</Text>
</Box>
}
/>
))}
</MobileTableContainer>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Loading } from "lib/components/Loading";
import { TableContainer } from "lib/components/table";
import type { ValidatorDelegationRelatedTxsResponseItem } from "lib/services/validator";
import type { AssetInfos, Option } from "lib/types";

import { RelatedTransactionsTableHeader } from "./RelatedTransactionsTableHeader";
import { RelatedTransactionsTableRow } from "./RelatedTransactionsTableRow";

interface RelatedTransactionTableProps {
delegationRelatedTxs: Option<ValidatorDelegationRelatedTxsResponseItem[]>;
isLoading: boolean;
assetInfos: Option<AssetInfos>;
}

export const RelatedTransactionTable = ({
delegationRelatedTxs = [],
isLoading,
assetInfos,
}: RelatedTransactionTableProps) => {
if (isLoading) return <Loading />;

const templateColumns = "max(180px) max(180px) max(180px) 1fr max(280px)";

return (
<TableContainer>
<RelatedTransactionsTableHeader templateColumns={templateColumns} />
{delegationRelatedTxs.map((delegationRelatedTx) => (
<RelatedTransactionsTableRow
key={delegationRelatedTx.txHash}
templateColumns={templateColumns}
delegationRelatedTx={delegationRelatedTx}
assetInfos={assetInfos}
/>
))}
</TableContainer>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Grid } from "@chakra-ui/react";

import { TableHeader } from "lib/components/table";

interface RelatedTransactionsTableHeaderProps {
templateColumns: string;
}

export const RelatedTransactionsTableHeader = ({
templateColumns,
}: RelatedTransactionsTableHeaderProps) => (
<Grid templateColumns={templateColumns} minW="min-content">
<TableHeader>Transaction Hash</TableHeader>
<TableHeader>Sender</TableHeader>
<TableHeader>Action</TableHeader>
<TableHeader w="100%" textAlign="end">
Bonded Token Changes
</TableHeader>
<TableHeader>Timestamp</TableHeader>
</Grid>
);
Loading