Commit e938c242 authored by tom's avatar tom

skeletons for custom abi page

parent 8e5e0c6d
import type { PublicTag, AddressTag, TransactionTag, ApiKey } from 'types/api/account'; import type { PublicTag, AddressTag, TransactionTag, ApiKey, CustomAbi } from 'types/api/account';
import type { TWatchlistItem } from 'types/client/account'; import type { TWatchlistItem } from 'types/client/account';
import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams'; import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams';
...@@ -61,3 +61,21 @@ export const API_KEY: ApiKey = { ...@@ -61,3 +61,21 @@ export const API_KEY: ApiKey = {
api_key: '9c3ecf44-a1ca-4ff1-b28e-329e8b65f652', api_key: '9c3ecf44-a1ca-4ff1-b28e-329e8b65f652',
name: 'placeholder', name: 'placeholder',
}; };
export const CUSTOM_ABI: CustomAbi = {
abi: [
{
constant: false,
payable: false,
inputs: [ { name: 'target', type: 'address' } ],
name: 'unknownWriteMethod',
outputs: [ { name: 'result', type: 'address' } ],
stateMutability: 'nonpayable',
type: 'function',
},
],
contract_address: ADDRESS_PARAMS,
contract_address_hash: ADDRESS_HASH,
id: '1',
name: 'placeholder',
};
...@@ -102,7 +102,7 @@ export type CustomAbis = Array<CustomAbi> ...@@ -102,7 +102,7 @@ export type CustomAbis = Array<CustomAbi>
export interface CustomAbi { export interface CustomAbi {
name: string; name: string;
id: number; id: string;
contract_address_hash: string; contract_address_hash: string;
contract_address: AddressParam; contract_address: AddressParam;
abi: Array<AbiItem>; abi: Array<AbiItem>;
...@@ -119,7 +119,7 @@ export interface AbiItem { ...@@ -119,7 +119,7 @@ export interface AbiItem {
} }
interface AbiInputOutput { interface AbiInputOutput {
type: 'uint256'; type: 'uint256' | 'address';
name: string; name: string;
} }
......
...@@ -48,7 +48,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -48,7 +48,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
const customAbiKey = (data: Inputs & { id?: number }) => { const customAbiKey = (data: Inputs & { id?: string }) => {
const body = { name: data.name, contract_address_hash: data.contract_address_hash, abi: data.abi }; const body = { name: data.name, contract_address_hash: data.contract_address_hash, abi: data.abi };
if (!data.id) { if (!data.id) {
......
...@@ -8,11 +8,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; ...@@ -8,11 +8,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
interface Props { interface Props {
item: CustomAbi; item: CustomAbi;
isLoading?: boolean;
onEditClick: (item: CustomAbi) => void; onEditClick: (item: CustomAbi) => void;
onDeleteClick: (item: CustomAbi) => void; onDeleteClick: (item: CustomAbi) => void;
} }
const CustomAbiListItem = ({ item, onEditClick, onDeleteClick }: Props) => { const CustomAbiListItem = ({ item, isLoading, onEditClick, onDeleteClick }: Props) => {
const onItemEditClick = useCallback(() => { const onItemEditClick = useCallback(() => {
return onEditClick(item); return onEditClick(item);
...@@ -24,8 +25,8 @@ const CustomAbiListItem = ({ item, onEditClick, onDeleteClick }: Props) => { ...@@ -24,8 +25,8 @@ const CustomAbiListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return ( return (
<ListItemMobile> <ListItemMobile>
<AddressSnippet address={ item.contract_address } subtitle={ item.name }/> <AddressSnippet address={ item.contract_address } subtitle={ item.name } isLoading={ isLoading }/>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick }/> <TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</ListItemMobile> </ListItemMobile>
); );
}; };
......
...@@ -12,12 +12,13 @@ import type { CustomAbis, CustomAbi } from 'types/api/account'; ...@@ -12,12 +12,13 @@ import type { CustomAbis, CustomAbi } from 'types/api/account';
import CustomAbiTableItem from './CustomAbiTableItem'; import CustomAbiTableItem from './CustomAbiTableItem';
interface Props { interface Props {
data: CustomAbis; data?: CustomAbis;
isLoading?: boolean;
onEditClick: (item: CustomAbi) => void; onEditClick: (item: CustomAbi) => void;
onDeleteClick: (item: CustomAbi) => void; onDeleteClick: (item: CustomAbi) => void;
} }
const CustomAbiTable = ({ data, onDeleteClick, onEditClick }: Props) => { const CustomAbiTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) => {
return ( return (
<Table variant="simple" minWidth="600px"> <Table variant="simple" minWidth="600px">
<Thead> <Thead>
...@@ -27,10 +28,11 @@ const CustomAbiTable = ({ data, onDeleteClick, onEditClick }: Props) => { ...@@ -27,10 +28,11 @@ const CustomAbiTable = ({ data, onDeleteClick, onEditClick }: Props) => {
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
{ data.map((item) => ( { data?.map((item, index) => (
<CustomAbiTableItem <CustomAbiTableItem
key={ item.id + (isLoading ? index : '') }
item={ item } item={ item }
key={ item.id } isLoading={ isLoading }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
......
...@@ -11,11 +11,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; ...@@ -11,11 +11,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
interface Props { interface Props {
item: CustomAbi; item: CustomAbi;
isLoading?: boolean;
onEditClick: (item: CustomAbi) => void; onEditClick: (item: CustomAbi) => void;
onDeleteClick: (item: CustomAbi) => void; onDeleteClick: (item: CustomAbi) => void;
} }
const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => { const CustomAbiTableItem = ({ item, isLoading, onEditClick, onDeleteClick }: Props) => {
const onItemEditClick = useCallback(() => { const onItemEditClick = useCallback(() => {
return onEditClick(item); return onEditClick(item);
...@@ -28,10 +29,10 @@ const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => { ...@@ -28,10 +29,10 @@ const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return ( return (
<Tr alignItems="top" key={ item.id }> <Tr alignItems="top" key={ item.id }>
<Td> <Td>
<AddressSnippet address={ item.contract_address } subtitle={ item.name }/> <AddressSnippet address={ item.contract_address } subtitle={ item.name } isLoading={ isLoading }/>
</Td> </Td>
<Td> <Td>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick }/> <TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</Td> </Td>
</Tr> </Tr>
); );
......
import { Box, Button, HStack, Skeleton, useDisclosure } from '@chakra-ui/react'; import { Box, Button, Skeleton, useDisclosure } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { CustomAbi } from 'types/api/account'; import type { CustomAbi } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken'; import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import { CUSTOM_ABI } from 'stubs/account';
import CustomAbiModal from 'ui/customAbi/CustomAbiModal/CustomAbiModal'; import CustomAbiModal from 'ui/customAbi/CustomAbiModal/CustomAbiModal';
import CustomAbiListItem from 'ui/customAbi/CustomAbiTable/CustomAbiListItem'; import CustomAbiListItem from 'ui/customAbi/CustomAbiTable/CustomAbiListItem';
import CustomAbiTable from 'ui/customAbi/CustomAbiTable/CustomAbiTable'; import CustomAbiTable from 'ui/customAbi/CustomAbiTable/CustomAbiTable';
...@@ -13,19 +13,20 @@ import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal'; ...@@ -13,19 +13,20 @@ import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal';
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 PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
const CustomAbiPage: React.FC = () => { const CustomAbiPage: React.FC = () => {
const customAbiModalProps = useDisclosure(); const customAbiModalProps = useDisclosure();
const deleteModalProps = useDisclosure(); const deleteModalProps = useDisclosure();
const isMobile = useIsMobile();
useRedirectForInvalidAuthToken(); useRedirectForInvalidAuthToken();
const [ customAbiModalData, setCustomAbiModalData ] = useState<CustomAbi>(); const [ customAbiModalData, setCustomAbiModalData ] = useState<CustomAbi>();
const [ deleteModalData, setDeleteModalData ] = useState<CustomAbi>(); const [ deleteModalData, setDeleteModalData ] = useState<CustomAbi>();
const { data, isLoading, isError, error } = useApiQuery('custom_abi'); const { data, isPlaceholderData, isError, error } = useApiQuery('custom_abi', {
queryOptions: {
placeholderData: Array(3).fill(CUSTOM_ABI),
},
});
const onEditClick = useCallback((data: CustomAbi) => { const onEditClick = useCallback((data: CustomAbi) => {
setCustomAbiModalData(data); setCustomAbiModalData(data);
...@@ -54,22 +55,6 @@ const CustomAbiPage: React.FC = () => { ...@@ -54,22 +55,6 @@ const CustomAbiPage: React.FC = () => {
); );
const content = (() => { const content = (() => {
if (isLoading && !data) {
const loader = isMobile ? <SkeletonListAccount/> : (
<>
<SkeletonTable columns={ [ '100%', '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,37 +62,42 @@ const CustomAbiPage: React.FC = () => { ...@@ -77,37 +62,42 @@ const CustomAbiPage: React.FC = () => {
return <DataFetchAlert/>; return <DataFetchAlert/>;
} }
const list = isMobile ? ( const list = (
<Box> <>
{ data.map((item) => ( <Box display={{ base: 'block', lg: 'none' }}>
<CustomAbiListItem { data?.map((item, index) => (
item={ item } <CustomAbiListItem
key={ item.id } key={ item.id + (isPlaceholderData ? index : '') }
item={ item }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Box>
<Box display={{ base: 'none', lg: 'block' }}>
<CustomAbiTable
data={ data }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
)) } </Box>
</Box> </>
) : (
<CustomAbiTable
data={ data }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
); );
return ( return (
<> <>
{ description } { description }
{ data.length > 0 && list } { Boolean(data?.length) && list }
<HStack marginTop={ 8 } spacing={ 5 }> <Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block">
<Button <Button
size="lg" size="lg"
onClick={ customAbiModalProps.onOpen } onClick={ customAbiModalProps.onOpen }
> >
Add custom ABI Add custom ABI
</Button> </Button>
</HStack> </Skeleton>
<CustomAbiModal { ...customAbiModalProps } onClose={ onCustomAbiModalClose } data={ customAbiModalData }/> <CustomAbiModal { ...customAbiModalProps } onClose={ onCustomAbiModalClose } data={ customAbiModalData }/>
{ deleteModalData && <DeleteCustomAbiModal { ...deleteModalProps } onClose={ onDeleteModalClose } data={ deleteModalData }/> } { deleteModalData && <DeleteCustomAbiModal { ...deleteModalProps } onClose={ onDeleteModalClose } data={ deleteModalData }/> }
</> </>
......
import { Text, Box } from '@chakra-ui/react'; import { Box, Skeleton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { AddressParam } from 'types/api/addressParams'; import type { AddressParam } from 'types/api/addressParams';
...@@ -22,7 +22,11 @@ const AddressSnippet = ({ address, subtitle, isLoading }: Props) => { ...@@ -22,7 +22,11 @@ const AddressSnippet = ({ address, subtitle, isLoading }: Props) => {
<AddressLink type="address" hash={ address.hash } fontWeight="600" ml={ 2 } isLoading={ isLoading }/> <AddressLink type="address" hash={ address.hash } fontWeight="600" ml={ 2 } isLoading={ isLoading }/>
<CopyToClipboard text={ address.hash } ml={ 1 } isLoading={ isLoading }/> <CopyToClipboard text={ address.hash } ml={ 1 } isLoading={ isLoading }/>
</Address> </Address>
{ subtitle && <Text fontSize="sm" variant="secondary" mt={ 0.5 } ml={ 8 }>{ subtitle }</Text> } { subtitle && (
<Skeleton fontSize="sm" color="text_secondary" mt={ 0.5 } ml={ 8 } display="inline-block" isLoaded={ !isLoading }>
<span>{ subtitle }</span>
</Skeleton>
) }
</Box> </Box>
); );
}; };
......
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