diff --git a/.changelog/1472.trivial.md b/.changelog/1472.trivial.md new file mode 100644 index 000000000..8d7bae83f --- /dev/null +++ b/.changelog/1472.trivial.md @@ -0,0 +1 @@ +Sync Consensus transactions list with updated designs diff --git a/src/app/components/Transactions/ConsensusTransactionDetails.tsx b/src/app/components/Transactions/ConsensusTransactionDetails.tsx new file mode 100644 index 000000000..e43d5ce57 --- /dev/null +++ b/src/app/components/Transactions/ConsensusTransactionDetails.tsx @@ -0,0 +1,84 @@ +import { FC } from 'react' +import { TFunction } from 'i18next' +import Box from '@mui/material/Box' +import { ConsensusTxMethod, Transaction } from '../../../oasis-nexus/api' +import { From, LabelValue, Shares, To } from './TransactionDetailsElements' +import { useTranslation } from 'react-i18next' + +type ConsensusTransactionDetailsProps = { + ownAddress?: string + transaction: Transaction +} + +export const ConsensusTransactionDetails: FC = ({ + ownAddress, + transaction, +}) => { + const { t } = useTranslation() + const details = getConsensusTransactionDetails(t, transaction, ownAddress) + + return {details} +} + +const getConsensusTransactionDetails = (t: TFunction, transaction: Transaction, ownAddress?: string) => { + const scope = { layer: transaction.layer, network: transaction.network } + + switch (transaction.method) { + case ConsensusTxMethod.roothashExecutorCommit: + return ( + <> + + + + ) + case ConsensusTxMethod.stakingAddEscrow: + return ( + <> + + + + ) + case ConsensusTxMethod.stakingAllow: + return ( + <> + + + + ) + case ConsensusTxMethod.stakingReclaimEscrow: + return ( + <> + + + + + ) + case ConsensusTxMethod.stakingTransfer: + return ( + <> + + + + ) + default: + return ( + + ) + } +} diff --git a/src/app/components/Transactions/ConsensusTransactions.tsx b/src/app/components/Transactions/ConsensusTransactions.tsx index 74305a634..e86bc54bf 100644 --- a/src/app/components/Transactions/ConsensusTransactions.tsx +++ b/src/app/components/Transactions/ConsensusTransactions.tsx @@ -1,16 +1,14 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' -import Box from '@mui/material/Box' import { Transaction } from '../../../oasis-nexus/api' import { Table, TableCellAlign, TableColProps } from '../../components/Table' import { RoundedBalance } from '../../components/RoundedBalance' import { TablePaginationProps } from '../Table/TablePagination' -import { BlockLink } from '../Blocks/BlockLink' -import { AccountLink } from '../Account/AccountLink' import { StatusIcon } from '../StatusIcon' import { Age } from '../Age' import { TransactionLink } from './TransactionLink' import { ConsensusTransactionMethod } from '../ConsensusTransactionMethod' +import { ConsensusTransactionDetails } from './ConsensusTransactionDetails' type TableConsensusTransaction = Transaction & { markAsNew?: boolean @@ -28,7 +26,6 @@ type ConsensusTransactionsProps = { isLoading: boolean limit: number pagination: false | TablePaginationProps - verbose?: boolean } export const ConsensusTransactions: FC = ({ @@ -37,28 +34,19 @@ export const ConsensusTransactions: FC = ({ pagination, transactions, ownAddress, - verbose = true, }) => { const { t } = useTranslation() const tableColumns: TableColProps[] = [ { key: 'status', content: t('common.status') }, { key: 'hash', content: t('common.hash') }, - { key: 'block', content: t('common.block') }, { key: 'age', content: t('common.age') }, - ...(verbose - ? [ - { key: 'method', content: t('common.method') }, - { key: 'from', content: t('common.from'), width: '150px' }, - { key: 'to', content: t('common.to'), width: '150px' }, - { key: 'txnFee', content: t('common.transactionFee'), align: TableCellAlign.Right, width: '250px' }, - { key: 'value', align: TableCellAlign.Right, content: t('common.value'), width: '250px' }, - ] - : []), + { key: 'type', content: t('common.type') }, + { key: 'details', content: t('common.details') }, + { align: TableCellAlign.Right, key: 'value', content: t('common.amount') }, ] const tableRows = transactions?.map(transaction => { - const targetAddress = transaction.body.to || transaction.body.account return { key: `${transaction.hash}${transaction.index}`, data: [ @@ -70,64 +58,29 @@ export const ConsensusTransactions: FC = ({ content: , key: 'hash', }, - { - content: , - key: 'round', - }, { content: , key: 'timestamp', }, - ...(verbose - ? [ - { - content: , - key: 'method', - }, - { - align: TableCellAlign.Right, - content: ( - - - - ), - key: 'from', - }, - { - content: targetAddress ? ( - - ) : null, - key: 'to', - }, - { - align: TableCellAlign.Right, - content: , - key: 'fee_amount', - }, - { - align: TableCellAlign.Right, - content: , - key: 'value', - }, - ] - : []), + { + content: , + key: 'method', + }, + + { + content: , + key: 'details', + }, + { + align: TableCellAlign.Right, + content: ( + + ), + key: 'amount', + }, ], highlight: transaction.markAsNew, } diff --git a/src/app/components/Transactions/TransactionDetailsElements.tsx b/src/app/components/Transactions/TransactionDetailsElements.tsx new file mode 100644 index 000000000..902d8fdcc --- /dev/null +++ b/src/app/components/Transactions/TransactionDetailsElements.tsx @@ -0,0 +1,114 @@ +import { FC, PropsWithChildren } from 'react' +import { useTranslation } from 'react-i18next' +import Box from '@mui/material/Box' +import Tooltip from '@mui/material/Tooltip' +import Typography from '@mui/material/Typography' +import { SearchScope } from '../../../types/searchScope' +import { COLORS } from '../../../styles/theme/colors' +import { tooltipDelay } from '../../../styles/theme' +import { RoundedBalance } from '../../components/RoundedBalance' +import { trimLongString } from '../../utils/trimLongString' +import { useScreenSize } from '../../hooks/useScreensize' +import { AccountLink } from '../Account/AccountLink' +import { ValidatorLink } from '../Validators/ValidatorLink' + +const Label: FC = ({ children }) => { + return ( + + {children} + + ) +} + +type FromProps = { + address: string + ownAddress?: string + scope: SearchScope +} + +export const From: FC = ({ address, ownAddress, scope }) => { + const { t } = useTranslation() + + if (!address) { + return null + } + + return ( + + + + + ) +} + +type ToProps = { + address: string | undefined + label?: string + ownAddress?: string + scope: SearchScope + type?: 'account' | 'validator' +} + +export const To: FC = ({ address, label, ownAddress, scope, type = 'account' }) => { + const { t } = useTranslation() + + if (!address) { + return null + } + + return ( + + + {type === 'account' && ( + + )} + {type === 'validator' && } + + ) +} + +type SharesProps = { + value: string +} + +export const Shares: FC = ({ value }) => { + const { t } = useTranslation() + + if (!value) { + return null + } + + return ( + + + + + + + ) +} + +type LabelValueProps = { + label?: string + trimMobile?: boolean + value: string +} + +export const LabelValue: FC = ({ label, trimMobile, value }) => { + const { t } = useTranslation() + const { isTablet } = useScreenSize() + const trimEnabled = trimMobile && isTablet + + return ( + + + {trimEnabled ? ( + + {trimLongString(value, 2, 18)} + + ) : ( + {value} + )} + + ) +} diff --git a/src/app/pages/ConsensusDashboardPage/LatestConsensusTransactions.tsx b/src/app/pages/ConsensusDashboardPage/LatestConsensusTransactions.tsx index 4f92d922a..7e6265f37 100644 --- a/src/app/pages/ConsensusDashboardPage/LatestConsensusTransactions.tsx +++ b/src/app/pages/ConsensusDashboardPage/LatestConsensusTransactions.tsx @@ -10,10 +10,8 @@ import { SearchScope } from '../../../types/searchScope' import { ConsensusTransactions } from '../../components/Transactions' import { NUMBER_OF_ITEMS_ON_DASHBOARD as limit } from '../../config' import { RouteUtils } from '../../utils/route-utils' -import { useScreenSize } from '../../hooks/useScreensize' export const LatestConsensusTransactions: FC<{ scope: SearchScope }> = ({ scope }) => { - const { isTablet } = useScreenSize() const { t } = useTranslation() const { network } = scope @@ -45,7 +43,6 @@ export const LatestConsensusTransactions: FC<{ scope: SearchScope }> = ({ scope isLoading={transactionsQuery.isLoading} limit={limit} pagination={false} - verbose={!isTablet} /> diff --git a/src/app/utils/transaction.ts b/src/app/utils/transaction.ts index 51de9c9aa..3836c3e7b 100644 --- a/src/app/utils/transaction.ts +++ b/src/app/utils/transaction.ts @@ -3,7 +3,7 @@ import { ConsensusTxMethod, Transaction } from '../../oasis-nexus/api' export const getConsensusTransactionToAddress = (transaction: Transaction) => { switch (transaction.method) { case ConsensusTxMethod.stakingAddEscrow: - return transaction.body?.address + return transaction.body?.account case ConsensusTxMethod.stakingAllow: return transaction.body?.beneficiary case ConsensusTxMethod.stakingReclaimEscrow: diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 4cfd8e990..2ddc35cf7 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -63,6 +63,7 @@ "common": { "address": "Address", "age": "Age", + "amount": "Amount", "balance": "Balance", "block": "Block", "blockSizeLimit": "Block size limit", @@ -74,6 +75,7 @@ "copy": "Copy", "data": "Data", "debonding": "Debonding", + "details": "Details", "emerald": "Emerald", "epoch": "Epoch", "cipher": "Cipher", @@ -93,11 +95,11 @@ "hash": "Hash", "height": "Height", "hide": "Hide", + "id": "ID", "invalidVotes": "Invalid votes", "layer": "Layer", "loadMore": "Load more", "lessThanAmount": "< {{value, number}} ", - "method": "Method", "missing": "n/a", "name": "Name", "network": "Network", @@ -153,6 +155,7 @@ "votes": "Votes", "paraTimeOnline": "ParaTime Online", "paraTimeOutOfDate": "ParaTime Out of date", + "recipient": "Recipient", "mainnet": "Mainnet", "testnet": "Testnet", "valuePair": "{{value, number}}" @@ -413,7 +416,7 @@ "stakingAddEscrow": "Start delegate", "stakingReclaimEscrow": "Start undelegate", "stakingAmendCommissionSchedule": "Amend commission schedule", - "stakingAllow": "Set delegate allowance", + "stakingAllow": "Allowance Change", "stakingWithdraw": "Continued delegate", "roothashExecutorCommit": "Executor commit", "roothashExecutorProposerTimeout": "Executor proposer timeout", diff --git a/src/oasis-nexus/api.ts b/src/oasis-nexus/api.ts index 0ac45f797..351cdc9f8 100644 --- a/src/oasis-nexus/api.ts +++ b/src/oasis-nexus/api.ts @@ -174,14 +174,21 @@ export const useGetConsensusTransactions: typeof generated.useGetConsensusTransa return { ...data, transactions: data.transactions.map(tx => { + const amount = getConsensusTransactionAmount(tx) + const to = getConsensusTransactionToAddress(tx) return { ...tx, + amount: amount ? fromBaseUnits(amount, consensusDecimals) : undefined, + to, network, layer: Layer.consensus, ticker, body: { ...tx.body, amount: tx.body?.amount ? fromBaseUnits(tx.body.amount, consensusDecimals) : undefined, + amount_change: tx.body?.amount_change + ? fromBaseUnits(tx.body.amount_change, consensusDecimals) + : undefined, }, } }), diff --git a/src/stories/Transactions.stories.tsx b/src/stories/Transactions.stories.tsx new file mode 100644 index 000000000..b5b793120 --- /dev/null +++ b/src/stories/Transactions.stories.tsx @@ -0,0 +1,167 @@ +import { Meta, StoryFn, StoryObj } from '@storybook/react' +import { withRouter } from 'storybook-addon-react-router-v6' +import Box from '@mui/material/Box' +import { ConsensusTransactions } from '../app/components/Transactions' +import { ConsensusTxMethod, Layer, Transaction } from '../oasis-nexus/api' +import { Network } from '../types/network' +import { Ticker } from '../types/ticker' + +export default { + title: 'Example/Transactions', + decorators: [withRouter], +} satisfies Meta + +const ConsensusListStory: StoryFn = () => { + return ( + + + + ) +} + +export const ConsensusList: StoryObj = { + render: ConsensusListStory, + args: {}, +} + +const mockedTransactions = [ + { + amount: '100', + to: 'oasis1qp0xuvw2a93w4yp8jwthfz93gxy87u7hes9eu2ev', + network: Network.mainnet, + layer: Layer.consensus, + ticker: Ticker.ROSE, + block: 19851448, + body: { + account: 'oasis1qp0xuvw2a93w4yp8jwthfz93gxy87u7hes9eu2ev', + amount: '100', + }, + fee: '0', + gas_limit: '0', + hash: 'd46e9223c45bd52d885673dd574f008b5e377ad879adb08f52af53c292151984', + index: 26, + method: ConsensusTxMethod.stakingAddEscrow, + nonce: 275, + sender: 'oasis1qz0k5q8vjqvu4s4nwxyj406ylnflkc4vrcjghuwk', + success: true, + timestamp: '2024-06-25T06:52:19Z', + }, + { + amount: '10', + to: 'oasis1qrd3mnzhhgst26hsp96uf45yhq6zlax0cuzdgcfc', + network: Network.mainnet, + layer: Layer.consensus, + ticker: Ticker.ROSE, + block: 18818862, + body: { + amount_change: '10', + beneficiary: 'oasis1qrd3mnzhhgst26hsp96uf45yhq6zlax0cuzdgcfc', + }, + fee: '0', + gas_limit: '0', + hash: '2c849b3b9aaf63d73c35502af5b3bbf5881439288ebe3153966c6b78891d1978', + index: 26, + method: ConsensusTxMethod.stakingAllow, + nonce: 266, + sender: 'oasis1qz0k5q8vjqvu4s4nwxyj406ylnflkc4vrcjghuwk', + success: true, + timestamp: '2024-04-15T07:09:52Z', + }, + { + amount: undefined, + to: 'oasis1qq0xmq7r0z9sdv02t5j9zs7en3n6574gtg8v9fyt', + network: Network.mainnet, + layer: Layer.consensus, + ticker: Ticker.ROSE, + block: 19851464, + body: { + account: 'oasis1qq0xmq7r0z9sdv02t5j9zs7en3n6574gtg8v9fyt', + shares: '30027579719', + }, + fee: '0', + gas_limit: '0', + hash: 'e8ca2ea8f664d668603178687bc335c6ebb79dce716ce4e54f33d14a57f9fa5e', + index: 25, + method: ConsensusTxMethod.stakingReclaimEscrow, + nonce: 277, + sender: 'oasis1qz0k5q8vjqvu4s4nwxyj406ylnflkc4vrcjghuwk', + success: true, + timestamp: '2024-06-25T06:53:53Z', + }, + { + amount: '100', + to: 'oasis1qzca4c3gch3ymy3w7e5ffzf9l6alpazpf5ffyytn', + network: Network.mainnet, + layer: Layer.consensus, + ticker: Ticker.ROSE, + block: 19969302, + body: { + amount: '100', + to: 'oasis1qzca4c3gch3ymy3w7e5ffzf9l6alpazpf5ffyytn', + }, + fee: '0', + gas_limit: '0', + hash: 'a06aa6c1535727a1f578638b3754e8feff34293f26449b76cf80d94f216d22ff', + index: 25, + method: ConsensusTxMethod.stakingTransfer, + nonce: 322926, + sender: 'oasis1qzyw98s2qrvf3t78nf0guu98laykw6lzkga5zlzy', + success: true, + timestamp: '2024-07-03T09:23:32Z', + }, + { + amount: undefined, + to: undefined, + network: Network.mainnet, + layer: Layer.consensus, + ticker: Ticker.ROSE, + block: 19969802, + body: { + commits: [ + { + header: { + header: { + in_msgs_hash: 'c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a', + io_root: '6a134a3102e3ea9f4871ece1c5824ce06f4dc06571e0e5dd04e7e282a6348991', + messages_hash: 'c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a', + previous_hash: 'ebb7743594d53594f95585de30b563042724f3d48ac9c7c37b292c299d7b8ddd', + round: 4419548, + state_root: '77824195a9191c802cd83af14a2bdbb974eb16919e5a333cf03f81dc1dc1d688', + }, + rak_sig: + 'OyaCvwnekOqKv+3ymvXJzoQulhb7KVun6g8F2kWabeUXShPxGnFt9JR8J7JEV7Fgs7vlAdjkduSDN2n2GZdJDw==', + scheduler_id: 'drsZxbpqG5h+4tq/JKWqmoVGXmQUirVCjD8GLBuNj9M=', + }, + node_id: 'UCKrtVNlmCaCdKpMMDT8AQxqVs/JP1/zQUH4yxUY4mM=', + sig: 'DGs5KVnCg2EqArJ4yqFufta0ujGiSFzVQlpi0E8LgOIGztiSpnhhk6ktwB7s/Xe5dYSugPeKpCAxwgtgKpoLBw==', + }, + ], + id: '000000000000000000000000000000000000000000000000f80306c9858e7279', + }, + fee: '0', + gas_limit: '0', + hash: '11c58dc52abba9cf838b87bf9aa691dac5aef96c84428aa608a67a2b3a206f46', + index: 0, + method: ConsensusTxMethod.roothashExecutorCommit, + nonce: 942923, + sender: 'oasis1qrxvr94pgj6kt36fkwn4al3uttj2veh5ey8jvapv', + success: true, + timestamp: '2024-07-03T10:12:47Z', + }, + { + amount: undefined, + to: undefined, + network: Network.mainnet, + layer: Layer.consensus, + hash: '11c58dc52abba9cf838b87bf9aa691dac5aef96c84428aa608a67a2b3a206f46', + ticker: Ticker.ROSE, + sender: 'oasis1qzyw98s2qrvf3t78nf0guu98laykw6lzkga5zlzy', + success: true, + timestamp: '2024-07-03T09:23:32Z', + } as Transaction, +]