Commit 08ed059e authored by isstuev's avatar isstuev

txs validated start

parent 8c6c542b
...@@ -6,8 +6,12 @@ export const tx = { ...@@ -6,8 +6,12 @@ export const tx = {
confirmation_num: 283, confirmation_num: 283,
confirmation_duration: 30, confirmation_duration: 30,
timestamp: 1662623567695, timestamp: 1662623567695,
address_from: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830', address_from: {
address_to: '0x35317007D203b8a86CA727ad44E473E40450E378', hash: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830',
},
address_to: {
hash: '0x35317007D203b8a86CA727ad44E473E40450E378',
},
amount: { amount: {
value: 0.03, value: 0.03,
value_usd: 35.5, value_usd: 35.5,
......
...@@ -5,8 +5,8 @@ export const data = [ ...@@ -5,8 +5,8 @@ export const data = [
id: 1, id: 1,
type: 'call' as TxInternalsType, type: 'call' as TxInternalsType,
status: 'success' as const, status: 'success' as const,
from: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01', from: { hash: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01' },
to: '0xF7A558692dFB5F456e291791da7FAE8Dd046574e', to: { hash: '0xF7A558692dFB5F456e291791da7FAE8Dd046574e' },
value: 0.25207646303, value: 0.25207646303,
gasLimit: 369472, gasLimit: 369472,
}, },
...@@ -14,17 +14,17 @@ export const data = [ ...@@ -14,17 +14,17 @@ export const data = [
id: 2, id: 2,
type: 'delegate_call' as TxInternalsType, type: 'delegate_call' as TxInternalsType,
status: 'success' as const, status: 'success' as const,
from: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', from: { hash: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' },
to: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01', to: { hash: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01' },
value: 0.5633333, value: 0.5633333,
gasLimit: 340022, gasLimit: 340022,
}, },
{ {
id: 3, id: 3,
type: 'static_call' as TxInternalsType, type: 'static_call' as TxInternalsType,
status: 'error' as const, status: 'failed' as const,
from: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830', from: { hash: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830' },
to: '0x35317007D203b8a86CA727ad44E473E40450E378', to: { hash: '0x35317007D203b8a86CA727ad44E473E40450E378' },
value: 0.421152366, value: 0.421152366,
gasLimit: 509333, gasLimit: 509333,
}, },
......
import { tx } from './tx';
export const txs = [
{
...tx,
method: 'Withdraw',
txType: 'transaction',
},
{
...tx,
status: 'failed',
txType: 'contract-call',
method: 'CommitHash CommitHash CommitHash CommitHash',
},
{
...tx,
status: 'pending',
txType: 'token-transfer',
method: 'Multicall',
address_from: {
hash: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830',
alias: 'tkdkdkdkdkdkdkdkdkdkdkdkdkdkd.eth',
},
},
];
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="5" cy="5" r="5" fill="#D9DBE0"/>
<circle cx="5" cy="5" r="2.5" fill="#707886"/>
</svg>
...@@ -21,7 +21,7 @@ export default function useNavItems() { ...@@ -21,7 +21,7 @@ export default function useNavItems() {
return React.useMemo(() => { return React.useMemo(() => {
const mainNavItems = [ const mainNavItems = [
{ text: 'Blocks', url: link('blocks'), icon: blocksIcon, isActive: currentRoute === 'blocks' }, { text: 'Blocks', url: link('blocks'), icon: blocksIcon, isActive: currentRoute === 'blocks' },
{ text: 'Transactions', url: link('txs'), icon: transactionsIcon, isActive: currentRoute.startsWith('tx') }, { text: 'Transactions', url: link('txs_validated'), icon: transactionsIcon, isActive: currentRoute.startsWith('tx') },
{ text: 'Tokens', url: link('tokens'), icon: tokensIcon, isActive: currentRoute === 'tokens' }, { text: 'Tokens', url: link('tokens'), icon: tokensIcon, isActive: currentRoute === 'tokens' },
{ text: 'Apps', url: link('apps'), icon: appsIcon, isActive: currentRoute === 'apps' }, { text: 'Apps', url: link('apps'), icon: appsIcon, isActive: currentRoute === 'apps' },
// there should be custom site sections like Stats, Faucet, More, etc but never an 'other' // there should be custom site sections like Stats, Faucet, More, etc but never an 'other'
......
...@@ -45,10 +45,14 @@ export const ROUTES = { ...@@ -45,10 +45,14 @@ export const ROUTES = {
}, },
// TRANSACTIONS // TRANSACTIONS
txs: { txs_validated: {
pattern: `${ BASE_PATH }/txs`, pattern: `${ BASE_PATH }/txs`,
crossNetworkNavigation: true, crossNetworkNavigation: true,
}, },
txs_pending: {
pattern: `${ BASE_PATH }/pending-transactions`,
crossNetworkNavigation: true,
},
tx_index: { tx_index: {
pattern: `${ BASE_PATH }/tx/[id]`, pattern: `${ BASE_PATH }/tx/[id]`,
}, },
...@@ -70,6 +74,9 @@ export const ROUTES = { ...@@ -70,6 +74,9 @@ export const ROUTES = {
pattern: `${ BASE_PATH }/blocks`, pattern: `${ BASE_PATH }/blocks`,
crossNetworkNavigation: true, crossNetworkNavigation: true,
}, },
block: {
pattern: `${ BASE_PATH }/block/[id]`,
},
// TOKENS // TOKENS
tokens: { tokens: {
......
import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import Transactions from 'ui/pages/Transactions';
type PageParams = {
network_type: string;
network_sub_type: string;
}
type Props = {
pageParams: PageParams;
}
const AddressTagsPage: NextPage<Props> = ({ pageParams }: Props) => {
const title = getNetworkTitle(pageParams);
return (
<>
<Head><title>{ title }</title></Head>
<Transactions tab="mined"/>
</>
);
};
export default AddressTagsPage;
export { getStaticPaths } from 'lib/next/account/getStaticPaths';
export { getStaticProps } from 'lib/next/getStaticProps';
...@@ -53,6 +53,19 @@ const sizes = { ...@@ -53,6 +53,19 @@ const sizes = {
fontWeight: 500, fontWeight: 500,
}, },
}), }),
xs: definePartsStyle({
th: {
px: '6px',
py: '10px',
fontSize: 'sm',
},
td: {
px: '6px',
py: 6,
fontSize: 'sm',
fontWeight: 500,
},
}),
}; };
const variants = { const variants = {
......
...@@ -35,6 +35,7 @@ const baseStyleContainer = defineStyle({ ...@@ -35,6 +35,7 @@ const baseStyleContainer = defineStyle({
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
borderRadius: 'sm', borderRadius: 'sm',
lineHeight: '20px',
...transitionProps, ...transitionProps,
}); });
......
import {
Box,
Tab,
Tabs,
TabList,
TabPanel,
TabPanels,
} from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import useLink from 'lib/link/useLink';
import Page from 'ui/shared/Page';
import PageHeader from 'ui/shared/PageHeader';
import TxsPending from 'ui/txs/TxsPending';
import TxsValidated from 'ui/txs/TxsValidated';
const TABS = [ 'mined', 'pending' ] as const;
type TabName = typeof TABS[number];
type Props = {
tab: TabName;
}
const Transactions = ({ tab }: Props) => {
const [ , setActiveTab ] = useState<TabName>(tab);
const link = useLink();
const onChangeTab = useCallback((index: number) => {
setActiveTab(TABS[index]);
const newUrl = link(TABS[index] === 'mined' ? 'txs_validated' : 'txs_pending');
history.replaceState(history.state, '', newUrl);
}, [ link ]);
return (
<Page>
<Box h="100%">
<PageHeader text="Private tags"/>
<Tabs variant="soft-rounded" colorScheme="blue" isLazy onChange={ onChangeTab } defaultIndex={ TABS.indexOf(tab) }>
<TabList marginBottom={{ base: 6, lg: 8 }}>
<Tab>Validated</Tab>
<Tab>Pending</Tab>
</TabList>
<TabPanels>
<TabPanel padding={ 0 }>
<TxsValidated/>
</TabPanel>
<TabPanel padding={ 0 }>
<TxsPending/>
</TabPanel>
</TabPanels>
</Tabs>
</Box>
</Page>
);
};
export default Transactions;
...@@ -2,16 +2,37 @@ import { Tag, TagLabel, TagLeftIcon } from '@chakra-ui/react'; ...@@ -2,16 +2,37 @@ import { Tag, TagLabel, TagLeftIcon } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import errorIcon from 'icons/status/error.svg'; import errorIcon from 'icons/status/error.svg';
import pendingIcon from 'icons/status/pending.svg';
import successIcon from 'icons/status/success.svg'; import successIcon from 'icons/status/success.svg';
export interface Props { export interface Props {
status: 'success' | 'error'; status: 'success' | 'failed' | 'pending';
} }
const TxStatus = ({ status }: Props) => { const TxStatus = ({ status }: Props) => {
const label = status === 'success' ? 'Success' : 'Error'; let label;
const icon = status === 'success' ? successIcon : errorIcon; let icon;
const colorScheme = status === 'success' ? 'green' : 'red'; let colorScheme;
switch (status) {
case 'success':
label = 'Success';
icon = successIcon;
colorScheme = 'green';
break;
case 'failed':
label = 'Failed';
icon = errorIcon;
colorScheme = 'red';
break;
case 'pending':
label = 'Pending';
icon = pendingIcon;
// FIXME: it's not gray on mockups
// need to implement new color scheme or redefine colors here
colorScheme = 'gray';
break;
}
return ( return (
<Tag colorScheme={ colorScheme } display="inline-flex"> <Tag colorScheme={ colorScheme } display="inline-flex">
......
import { Link, chakra, shouldForwardProp } from '@chakra-ui/react'; import { Link, chakra, shouldForwardProp, Tooltip, Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import useLink from 'lib/link/useLink'; import useLink from 'lib/link/useLink';
...@@ -7,13 +7,14 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; ...@@ -7,13 +7,14 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
interface Props { interface Props {
type?: 'address' | 'transaction' | 'token'; type?: 'address' | 'transaction' | 'token';
alias?: string;
className?: string; className?: string;
hash: string; hash: string;
truncation?: 'constant' | 'dynamic'| 'none'; truncation?: 'constant' | 'dynamic'| 'none';
fontWeight?: string; fontWeight?: string;
} }
const AddressLink = ({ type, className, truncation = 'dynamic', hash, fontWeight }: Props) => { const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, fontWeight }: Props) => {
const link = useLink(); const link = useLink();
let url; let url;
if (type === 'transaction') { if (type === 'transaction') {
...@@ -25,6 +26,13 @@ const AddressLink = ({ type, className, truncation = 'dynamic', hash, fontWeight ...@@ -25,6 +26,13 @@ const AddressLink = ({ type, className, truncation = 'dynamic', hash, fontWeight
} }
const content = (() => { const content = (() => {
if (alias) {
return (
<Tooltip label={ hash }>
<Box overflow="hidden" textOverflow="ellipsis">{ alias }</Box>
</Tooltip>
);
}
switch (truncation) { switch (truncation) {
case 'constant': case 'constant':
return <HashStringShorten hash={ hash }/>; return <HashStringShorten hash={ hash }/>;
......
...@@ -18,11 +18,11 @@ import PrevNext from 'ui/shared/PrevNext'; ...@@ -18,11 +18,11 @@ import PrevNext from 'ui/shared/PrevNext';
import RawInputData from 'ui/shared/RawInputData'; import RawInputData from 'ui/shared/RawInputData';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
import Token from 'ui/shared/Token'; import Token from 'ui/shared/Token';
import type { Props as TxStatusProps } from 'ui/shared/TxStatus';
import TxStatus from 'ui/shared/TxStatus';
import Utilization from 'ui/shared/Utilization'; import Utilization from 'ui/shared/Utilization';
import TokenTransfer from 'ui/tx/TokenTransfer'; import TokenTransfer from 'ui/tx/TokenTransfer';
import TxDecodedInputData from 'ui/tx/TxDecodedInputData'; import TxDecodedInputData from 'ui/tx/TxDecodedInputData';
import type { Props as TxStatusProps } from 'ui/tx/TxStatus';
import TxStatus from 'ui/tx/TxStatus';
const TxDetails = () => { const TxDetails = () => {
const [ isExpanded, setIsExpanded ] = React.useState(false); const [ isExpanded, setIsExpanded ] = React.useState(false);
...@@ -82,9 +82,9 @@ const TxDetails = () => { ...@@ -82,9 +82,9 @@ const TxDetails = () => {
hint="Address (external or contract) sending the transaction." hint="Address (external or contract) sending the transaction."
> >
<Address> <Address>
<AddressIcon hash={ tx.address_from }/> <AddressIcon hash={ tx.address_from.hash }/>
<AddressLink ml={ 2 } hash={ tx.address_from }/> <AddressLink ml={ 2 } hash={ tx.address_from.hash }/>
<CopyToClipboard text={ tx.address_from }/> <CopyToClipboard text={ tx.address_from.hash }/>
</Address> </Address>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
...@@ -93,9 +93,9 @@ const TxDetails = () => { ...@@ -93,9 +93,9 @@ const TxDetails = () => {
flexWrap={{ base: 'wrap', lg: 'nowrap' }} flexWrap={{ base: 'wrap', lg: 'nowrap' }}
> >
<Address mr={ 3 }> <Address mr={ 3 }>
<AddressIcon hash={ tx.address_to }/> <AddressIcon hash={ tx.address_to.hash }/>
<AddressLink ml={ 2 } hash={ tx.address_to }/> <AddressLink ml={ 2 } hash={ tx.address_to.hash }/>
<CopyToClipboard text={ tx.address_to }/> <CopyToClipboard text={ tx.address_to.hash }/>
</Address> </Address>
<Tag colorScheme="orange" variant="solid" flexShrink={ 0 }>SANA</Tag> <Tag colorScheme="orange" variant="solid" flexShrink={ 0 }>SANA</Tag>
<Tooltip label="Contract execution completed"> <Tooltip label="Contract execution completed">
......
...@@ -6,13 +6,13 @@ import Address from 'ui/shared/address/Address'; ...@@ -6,13 +6,13 @@ import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils'; import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
import TxStatus from 'ui/tx/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
interface Props { interface Props {
type: string; type: string;
status: 'success' | 'error'; status: 'success' | 'failed' | 'pending';
from: string; from: { hash: string; alias?: string};
to: string; to: { hash: string; alias?: string};
value: number; value: number;
gasLimit: number; gasLimit: number;
} }
...@@ -32,8 +32,8 @@ const TxInternalTableItem = ({ type, status, from, to, value, gasLimit }: Props) ...@@ -32,8 +32,8 @@ const TxInternalTableItem = ({ type, status, from, to, value, gasLimit }: Props)
</Td> </Td>
<Td> <Td>
<Address> <Address>
<AddressIcon hash={ from }/> <AddressIcon hash={ from.hash }/>
<AddressLink ml={ 2 } fontWeight="500" hash={ from } flexGrow={ 1 }/> <AddressLink ml={ 2 } fontWeight="500" hash={ from.hash } alias={ from.alias } flexGrow={ 1 }/>
</Address> </Address>
</Td> </Td>
<Td px={ 0 }> <Td px={ 0 }>
...@@ -41,8 +41,8 @@ const TxInternalTableItem = ({ type, status, from, to, value, gasLimit }: Props) ...@@ -41,8 +41,8 @@ const TxInternalTableItem = ({ type, status, from, to, value, gasLimit }: Props)
</Td> </Td>
<Td> <Td>
<Address> <Address>
<AddressIcon hash={ to }/> <AddressIcon hash={ to.hash }/>
<AddressLink ml={ 2 } fontWeight="500" hash={ to }/> <AddressLink hash={ to.hash } alias={ to.alias } fontWeight="500" ml={ 2 }/>
</Address> </Address>
</Td> </Td>
<Td isNumeric> <Td isNumeric>
......
import { Tag, TagLabel } from '@chakra-ui/react';
import React from 'react';
export interface Props {
type: 'contract-call' | 'transaction' | 'token-transfer' | 'internal-tx' | 'multicall';
}
const TxStatus = ({ type }: Props) => {
let label;
let colorScheme;
switch (type) {
case 'contract-call':
label = 'Contract call';
colorScheme = 'blue';
break;
case 'transaction':
label = 'Transaction';
colorScheme = 'purple';
break;
case 'token-transfer':
label = 'Token transfer';
colorScheme = 'orange';
break;
case 'internal-tx':
label = 'Internal txn';
colorScheme = 'cyan';
break;
case 'multicall':
label = 'Multicall';
colorScheme = 'teal';
break;
}
return (
<Tag colorScheme={ colorScheme }>
<TagLabel>{ label }</TagLabel>
</Tag>
);
};
export default TxStatus;
import React from 'react';
const TxsPending = () => {
return <div>Привет2</div>;
};
export default TxsPending;
import { Table, Thead, Tbody, Tr, Th, TableContainer, useBreakpointValue } from '@chakra-ui/react';
import React from 'react';
import { txs } from 'data/txs';
import TxsTableItem from './TxsTableItem';
const CURRENCY = 'xDAI';
const TxsTable = () => {
const isLargeScreen = useBreakpointValue({ base: false, xl: true });
return (
<TableContainer width="100%" mt={ 6 }>
<Table variant="simple" minWidth="810px" size="xs">
<Thead>
<Tr>
<Th width="54px"></Th>
<Th width="20%">Type</Th>
<Th width="18%">Txn hash</Th>
<Th width="15%">Method</Th>
<Th width="11%">Block</Th>
<Th width={ isLargeScreen ? '128px' : '58px' }>From</Th>
<Th width={ isLargeScreen ? '36px' : '0' }></Th>
<Th width={ isLargeScreen ? '128px' : '58px' }>To</Th>
<Th width="18%" isNumeric>{ `Value ${ CURRENCY }` }</Th>
<Th width="18%" isNumeric pr={ 5 }>{ `Fee ${ CURRENCY }` }</Th>
</Tr>
</Thead>
<Tbody>
{ txs.map((item) => (
<TxsTableItem
key={ item.hash }
{ ...item }
/>
)) }
</Tbody>
</Table>
</TableContainer>
);
};
export default TxsTable;
import { Box, Tr, Td, Tag, Link, Icon, VStack, Text, useBreakpointValue } from '@chakra-ui/react';
import React from 'react';
import rightArrowIcon from 'icons/arrows/right.svg';
import infoIcon from 'icons/info.svg';
import dayjs from 'lib/date/dayjs';
import useLink from 'lib/link/useLink';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
import TxStatus from 'ui/shared/TxStatus';
import TxType from './TxType';
const TxsTableItem = (item) => {
const link = useLink();
const isLargeScreen = useBreakpointValue({ base: false, xl: true });
const addressFrom = (
<Address>
<AddressIcon hash={ item.address_from.hash }/>
<AddressLink hash={ item.address_from.hash } alias={ item.address_from.alias } fontWeight="500" ml={ 2 }/>
</Address>
);
const addressTo = (
<Address>
<AddressIcon hash={ item.address_to.hash }/>
<AddressLink hash={ item.address_to.hash } alias={ item.address_to.alias } fontWeight="500" ml={ 2 }/>
</Address>
);
return (
<Tr>
<Td pl={ 4 }>
<Icon as={ infoIcon } boxSize={ 5 } color="blue.600"/>
</Td>
<Td>
<VStack alignItems="start">
<TxType type={ item.txType }/>
<TxStatus status={ item.status }/>
</VStack>
</Td>
<Td>
<VStack alignItems="start" lineHeight="24px">
<Address width="100%">
<AddressLink
hash={ item.hash }
type="transaction"
fontWeight="700"
/>
</Address>
<Text color="gray.500" fontWeight="400">{ dayjs(item.timestamp).fromNow() }</Text>
</VStack>
</Td>
<Td>
<TruncatedTextTooltip label={ item.method }>
<Tag
colorScheme={ item.method === 'Multicall' ? 'teal' : 'gray' }
>
{ item.method }
</Tag>
</TruncatedTextTooltip>
</Td>
<Td>
<Link href={ link('block', { id: item.block_num }) }>{ item.block_num }</Link>
</Td>
{ isLargeScreen ? (
<>
<Td>
{ addressFrom }
</Td>
<Td>
<Icon as={ rightArrowIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/>
</Td>
<Td>
{ addressTo }
</Td>
</>
) : (
<Td colSpan={ 3 }>
<Box>
{ addressFrom }
<Icon
as={ rightArrowIcon }
boxSize={ 6 }
mt={ 2 }
mb={ 1 }
color="gray.500"
transform="rotate(90deg)"
/>
{ addressTo }
</Box>
</Td>
) }
<Td isNumeric>
{ item.amount.value.toFixed(8) }
</Td>
<Td isNumeric>
{ item.fee.value.toFixed(8) }
</Td>
</Tr>
);
};
export default TxsTableItem;
import { Box } from '@chakra-ui/react';
import React from 'react';
import Filters from 'ui/shared/Filters';
import TxsTable from './TxsTable';
const TxsValidated = () => {
return (
<>
<Box mb={ 12 }>Only the first 10,000 elements are displayed</Box>
<Box mb={ 6 }><Filters/></Box>
<TxsTable/>
{ /* pagination */ }
</>
);
};
export default TxsValidated;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment