Commit 54951e67 authored by tom's avatar tom

private tags for txs

parent 90780a00
import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams'; import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams';
import { TX_HASH } from './tx';
export const PRIVATE_TAG_ADDRESS = { export const PRIVATE_TAG_ADDRESS = {
address: ADDRESS_PARAMS, address: ADDRESS_PARAMS,
...@@ -6,3 +7,9 @@ export const PRIVATE_TAG_ADDRESS = { ...@@ -6,3 +7,9 @@ export const PRIVATE_TAG_ADDRESS = {
id: '4', id: '4',
name: 'placeholder', name: 'placeholder',
}; };
export const PRIVATE_TAG_TX = {
id: 1,
name: 'placeholder',
transaction_hash: TX_HASH,
};
...@@ -84,16 +84,14 @@ const PrivateAddressTags = () => { ...@@ -84,16 +84,14 @@ const PrivateAddressTags = () => {
Private tags are saved in your account and are only visible when you are logged in. Private tags are saved in your account and are only visible when you are logged in.
</AccountPageDescription> </AccountPageDescription>
{ Boolean(addressTagsData?.length) && list } { Boolean(addressTagsData?.length) && list }
<Box marginTop={ 8 }> <Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block">
<Skeleton isLoaded={ !isPlaceholderData } display="inline-block"> <Button
<Button size="lg"
size="lg" onClick={ addressModalProps.onOpen }
onClick={ addressModalProps.onOpen } >
>
Add address tag Add address tag
</Button> </Button>
</Skeleton> </Skeleton>
</Box>
<AddressModal { ...addressModalProps } onClose={ onAddressModalClose } data={ addressModalData }/> <AddressModal { ...addressModalProps } onClose={ onAddressModalClose } data={ addressModalData }/>
{ deleteModalData && ( { deleteModalData && (
<DeletePrivateTagModal <DeletePrivateTagModal
......
...@@ -5,10 +5,9 @@ import type { TransactionTag } from 'types/api/account'; ...@@ -5,10 +5,9 @@ import type { TransactionTag } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { PRIVATE_TAG_TX } from 'stubs/account';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import DeletePrivateTagModal from './DeletePrivateTagModal'; import DeletePrivateTagModal from './DeletePrivateTagModal';
import TransactionModal from './TransactionModal/TransactionModal'; import TransactionModal from './TransactionModal/TransactionModal';
...@@ -16,7 +15,12 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem ...@@ -16,7 +15,12 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem
import TransactionTagTable from './TransactionTagTable/TransactionTagTable'; import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
const PrivateTransactionTags = () => { const PrivateTransactionTags = () => {
const { data: transactionTagsData, isLoading, isError, error } = useApiQuery('private_tags_tx', { queryOptions: { refetchOnMount: false } }); const { data: transactionTagsData, isPlaceholderData, isError, error } = useApiQuery('private_tags_tx', {
queryOptions: {
refetchOnMount: false,
placeholderData: Array(3).fill(PRIVATE_TAG_TX),
},
});
const transactionModalProps = useDisclosure(); const transactionModalProps = useDisclosure();
const deleteModalProps = useDisclosure(); const deleteModalProps = useDisclosure();
...@@ -52,22 +56,6 @@ const PrivateTransactionTags = () => { ...@@ -52,22 +56,6 @@ const PrivateTransactionTags = () => {
</AccountPageDescription> </AccountPageDescription>
); );
if (isLoading && !transactionTagsData) {
const loader = isMobile ? <SkeletonListAccount/> : (
<>
<SkeletonTable columns={ [ '75%', '25%', '108px' ] }/>
<Skeleton height="44px" width="156px" marginTop={ 8 }/>
</>
);
return (
<>
{ description }
{ loader }
</>
);
}
if (isError) { if (isError) {
if (error.status === 403) { if (error.status === 403) {
throw new Error('Unverified email error', { cause: error }); throw new Error('Unverified email error', { cause: error });
...@@ -77,10 +65,11 @@ const PrivateTransactionTags = () => { ...@@ -77,10 +65,11 @@ const PrivateTransactionTags = () => {
const list = isMobile ? ( const list = isMobile ? (
<Box> <Box>
{ transactionTagsData.map((item) => ( { transactionTagsData?.map((item, index) => (
<TransactionTagListItem <TransactionTagListItem
key={ item.id + (isPlaceholderData ? index : '') }
item={ item } item={ item }
key={ item.id } isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
...@@ -89,6 +78,7 @@ const PrivateTransactionTags = () => { ...@@ -89,6 +78,7 @@ const PrivateTransactionTags = () => {
) : ( ) : (
<TransactionTagTable <TransactionTagTable
data={ transactionTagsData } data={ transactionTagsData }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
...@@ -97,15 +87,15 @@ const PrivateTransactionTags = () => { ...@@ -97,15 +87,15 @@ const PrivateTransactionTags = () => {
return ( return (
<> <>
{ description } { description }
{ Boolean(transactionTagsData.length) && list } { Boolean(transactionTagsData?.length) && list }
<Box marginTop={ 8 }> <Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block">
<Button <Button
size="lg" size="lg"
onClick={ transactionModalProps.onOpen } onClick={ transactionModalProps.onOpen }
> >
Add transaction tag Add transaction tag
</Button> </Button>
</Box> </Skeleton>
<TransactionModal { ...transactionModalProps } onClose={ onAddressModalClose } data={ transactionModalData }/> <TransactionModal { ...transactionModalProps } onClose={ onAddressModalClose } data={ transactionModalData }/>
{ deleteModalData && ( { deleteModalData && (
<DeletePrivateTagModal <DeletePrivateTagModal
......
import { Tag, HStack, Text, Flex } from '@chakra-ui/react'; import { HStack, Text, Flex } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { TransactionTag } from 'types/api/account'; import type { TransactionTag } from 'types/api/account';
import Tag from 'ui/shared/chakra/Tag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
import TransactionSnippet from 'ui/shared/TransactionSnippet'; import TransactionSnippet from 'ui/shared/TransactionSnippet';
interface Props { interface Props {
item: TransactionTag; item: TransactionTag;
isLoading?: boolean;
onEditClick: (data: TransactionTag) => void; onEditClick: (data: TransactionTag) => void;
onDeleteClick: (data: TransactionTag) => void; onDeleteClick: (data: TransactionTag) => void;
} }
const TransactionTagListItem = ({ item, onEditClick, onDeleteClick }: Props) => { const TransactionTagListItem = ({ item, isLoading, onEditClick, onDeleteClick }: Props) => {
const onItemEditClick = useCallback(() => { const onItemEditClick = useCallback(() => {
return onEditClick(item); return onEditClick(item);
}, [ item, onEditClick ]); }, [ item, onEditClick ]);
...@@ -25,15 +27,13 @@ const TransactionTagListItem = ({ item, onEditClick, onDeleteClick }: Props) => ...@@ -25,15 +27,13 @@ const TransactionTagListItem = ({ item, onEditClick, onDeleteClick }: Props) =>
return ( return (
<ListItemMobile> <ListItemMobile>
<Flex alignItems="flex-start" flexDirection="column" maxW="100%"> <Flex alignItems="flex-start" flexDirection="column" maxW="100%">
<TransactionSnippet hash={ item.transaction_hash }/> <TransactionSnippet hash={ item.transaction_hash } isLoading={ isLoading }/>
<HStack spacing={ 3 } mt={ 4 }> <HStack spacing={ 3 } mt={ 4 }>
<Text fontSize="sm" fontWeight={ 500 }>Private tag</Text> <Text fontSize="sm" fontWeight={ 500 }>Private tag</Text>
<Tag> <Tag isLoading={ isLoading } isTruncated>{ item.name }</Tag>
{ item.name }
</Tag>
</HStack> </HStack>
</Flex> </Flex>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick }/> <TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</ListItemMobile> </ListItemMobile>
); );
}; };
......
...@@ -12,12 +12,13 @@ import type { TransactionTags, TransactionTag } from 'types/api/account'; ...@@ -12,12 +12,13 @@ import type { TransactionTags, TransactionTag } from 'types/api/account';
import TransactionTagTableItem from './TransactionTagTableItem'; import TransactionTagTableItem from './TransactionTagTableItem';
interface Props { interface Props {
data: TransactionTags; data?: TransactionTags;
isLoading: boolean;
onEditClick: (data: TransactionTag) => void; onEditClick: (data: TransactionTag) => void;
onDeleteClick: (data: TransactionTag) => void; onDeleteClick: (data: TransactionTag) => void;
} }
const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => { const AddressTagTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) => {
return ( return (
<Table variant="simple" minWidth="600px"> <Table variant="simple" minWidth="600px">
<Thead> <Thead>
...@@ -28,10 +29,11 @@ const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => { ...@@ -28,10 +29,11 @@ const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => {
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
{ data.map((item) => ( { data?.map((item, index) => (
<TransactionTagTableItem <TransactionTagTableItem
key={ item.id + (isLoading ? index : '') }
item={ item } item={ item }
key={ item.id } isLoading={ isLoading }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
......
import { import {
Tag,
Tr, Tr,
Td, Td,
Tooltip,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { TransactionTag } from 'types/api/account'; import type { TransactionTag } from 'types/api/account';
import Tag from 'ui/shared/chakra/Tag';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
import TransactionSnippet from 'ui/shared/TransactionSnippet'; import TransactionSnippet from 'ui/shared/TransactionSnippet';
interface Props { interface Props {
item: TransactionTag; item: TransactionTag;
isLoading?: boolean;
onEditClick: (data: TransactionTag) => void; onEditClick: (data: TransactionTag) => void;
onDeleteClick: (data: TransactionTag) => void; onDeleteClick: (data: TransactionTag) => void;
} }
const TransactionTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => { const TransactionTagTableItem = ({ item, isLoading, onEditClick, onDeleteClick }: Props) => {
const onItemEditClick = useCallback(() => { const onItemEditClick = useCallback(() => {
return onEditClick(item); return onEditClick(item);
}, [ item, onEditClick ]); }, [ item, onEditClick ]);
...@@ -29,17 +29,13 @@ const TransactionTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => ...@@ -29,17 +29,13 @@ const TransactionTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) =>
return ( return (
<Tr alignItems="top" key={ item.id }> <Tr alignItems="top" key={ item.id }>
<Td> <Td>
<TransactionSnippet hash={ item.transaction_hash }/> <TransactionSnippet hash={ item.transaction_hash } isLoading={ isLoading }/>
</Td> </Td>
<Td> <Td>
<Tooltip label={ item.name }> <Tag isLoading={ isLoading } isTruncated>{ item.name }</Tag>
<Tag>
{ item.name }
</Tag>
</Tooltip>
</Td> </Td>
<Td> <Td>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick }/> <TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</Td> </Td>
</Tr> </Tr>
); );
......
...@@ -17,8 +17,8 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props ...@@ -17,8 +17,8 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
if (isLoading) { if (isLoading) {
return ( return (
<HStack spacing={ 6 } alignSelf="flex-end"> <HStack spacing={ 6 } alignSelf="flex-end">
<Skeleton boxSize={ 5 } flexShrink={ 0 } borderRadius="base"/> <Skeleton boxSize={ 5 } flexShrink={ 0 } borderRadius="sm"/>
<Skeleton boxSize={ 5 } flexShrink={ 0 } borderRadius="base"/> <Skeleton boxSize={ 5 } flexShrink={ 0 } borderRadius="sm"/>
</HStack> </HStack>
); );
} }
......
import { Icon, useColorModeValue } from '@chakra-ui/react'; import { Icon, Skeleton, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import transactionIcon from 'icons/transactions.svg'; import transactionIcon from 'icons/transactions.svg';
...@@ -8,14 +8,17 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard'; ...@@ -8,14 +8,17 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard';
interface Props { interface Props {
hash: string; hash: string;
isLoading?: boolean;
} }
const TransactionSnippet = ({ hash }: Props) => { const TransactionSnippet = ({ hash, isLoading }: Props) => {
return ( return (
<Address maxW="100%"> <Address maxW="100%">
<Icon as={ transactionIcon } boxSize={ 6 } color={ useColorModeValue('gray.500', 'gray.400') }/> <Skeleton isLoaded={ !isLoading } boxSize={ 6 } borderRadius="base">
<AddressLink hash={ hash } fontWeight="600" type="transaction" ml={ 2 }/> <Icon as={ transactionIcon } boxSize={ 6 } color={ useColorModeValue('gray.500', 'gray.400') }/>
<CopyToClipboard text={ hash } ml={ 1 }/> </Skeleton>
<AddressLink hash={ hash } fontWeight="600" type="transaction" ml={ 2 } isLoading={ isLoading }/>
<CopyToClipboard text={ hash } isLoading={ isLoading }/>
</Address> </Address>
); );
}; };
......
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