Files
tom goriunovandGitHub 24eb4fc014 API resource refactoring (#2699)
* add prefix to API resources

* fix pw tests

* refactor config

* remove unnecessary prefixes in resource names

* fixes

* update screenshots
2025-05-01 15:22:38 +02:00

137 lines
4.5 KiB
TypeScript

import { Box, Text } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import type { ApiKey } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery';
import { API_KEY } from 'stubs/account';
import { Button } from 'toolkit/chakra/button';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import { space } from 'toolkit/utils/htmlEntities';
import ApiKeyModal from 'ui/apiKey/ApiKeyModal/ApiKeyModal';
import ApiKeyListItem from 'ui/apiKey/ApiKeyTable/ApiKeyListItem';
import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable';
import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import PageTitle from 'ui/shared/Page/PageTitle';
import useRedirectForInvalidAuthToken from 'ui/snippets/auth/useRedirectForInvalidAuthToken';
const DATA_LIMIT = 3;
const ApiKeysPage: React.FC = () => {
const apiKeyModalProps = useDisclosure();
const deleteModalProps = useDisclosure();
useRedirectForInvalidAuthToken();
const [ apiKeyModalData, setApiKeyModalData ] = useState<ApiKey>();
const [ deleteModalData, setDeleteModalData ] = useState<ApiKey>();
const { data, isPlaceholderData, isError } = useApiQuery('general:api_keys', {
queryOptions: {
placeholderData: Array(3).fill(API_KEY),
},
});
const onEditClick = useCallback((data: ApiKey) => {
setApiKeyModalData(data);
apiKeyModalProps.onOpen();
}, [ apiKeyModalProps ]);
const onApiKeyModalOpenChange = useCallback(({ open }: { open: boolean }) => {
!open && setApiKeyModalData(undefined);
apiKeyModalProps.onOpenChange({ open });
}, [ apiKeyModalProps ]);
const onDeleteClick = useCallback((data: ApiKey) => {
setDeleteModalData(data);
deleteModalProps.onOpen();
}, [ deleteModalProps ]);
const onDeleteModalOpenChange = useCallback(({ open }: { open: boolean }) => {
!open && setDeleteModalData(undefined);
deleteModalProps.onOpenChange({ open });
}, [ deleteModalProps ]);
const description = (
<AccountPageDescription>
Create API keys to use for your RPC and EthRPC API requests. For more information, see { space }
<Link href="https://docs.blockscout.com/for-users/api#api-keys" target="_blank">“How to use a Blockscout API key”</Link>.
</AccountPageDescription>
);
const content = (() => {
if (isError) {
return <DataFetchAlert/>;
}
const list = (
<>
<Box display={{ base: 'block', lg: 'none' }}>
{ data?.map((item, index) => (
<ApiKeyListItem
key={ item.api_key + (isPlaceholderData ? index : '') }
item={ item }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Box>
<Box display={{ base: 'none', lg: 'block' }}>
<ApiKeyTable
data={ data }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
limit={ DATA_LIMIT }
/>
</Box>
</>
);
const canAdd = !isPlaceholderData ? (data?.length || 0) < DATA_LIMIT : true;
return (
<>
{ description }
{ Boolean(data?.length) && list }
<Skeleton
marginTop={ 8 }
flexDir={{ base: 'column', lg: 'row' }}
alignItems={{ base: 'start', lg: 'center' }}
loading={ isPlaceholderData }
display="inline-flex"
columnGap={ 5 }
rowGap={ 5 }
>
<Button
onClick={ apiKeyModalProps.onOpen }
disabled={ !canAdd }
>
Add API key
</Button>
{ !canAdd && (
<Text fontSize="sm" color="text.secondary">
{ `You have added the maximum number of API keys (${ DATA_LIMIT }). Contact us to request additional keys.` }
</Text>
) }
</Skeleton>
<ApiKeyModal open={ apiKeyModalProps.open } onOpenChange={ onApiKeyModalOpenChange } data={ apiKeyModalData }/>
{ deleteModalData && <DeleteApiKeyModal open={ deleteModalProps.open } onOpenChange={ onDeleteModalOpenChange } data={ deleteModalData }/> }
</>
);
})();
return (
<>
<PageTitle title="API keys"/>
{ content }
</>
);
};
export default ApiKeysPage;