Files

159 lines
5.1 KiB
TypeScript

import React, { useCallback, useState } from 'react';
import type { ApiKey } from 'types/api/account';
import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery';
import { API_KEY } from 'stubs/account';
import { Button } from '@luxfi/ui/button';
import { Link } from 'toolkit/next/link';
import { Skeleton } from '@luxfi/ui/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 AlertWithExternalHtml from 'ui/shared/alerts/AlertWithExternalHtml';
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 apiKeysAlertHtml = config.UI.apiKeysAlert.message;
const feature = config.features.account;
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.lux.network/using-explorer/my-account/api-keys#api-keys" external noIcon>"How to use an API key"</Link>.
</AccountPageDescription>
);
const content = (() => {
if (isError) {
return <DataFetchAlert/>;
}
const list = (
<>
<div className="block lg:hidden">
{ data?.map((item, index) => (
<ApiKeyListItem
key={ item.api_key + (isPlaceholderData ? index : '') }
item={ item }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</div>
<div className="hidden lg:block">
<ApiKeyTable
data={ data }
isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
limit={ DATA_LIMIT }
/>
</div>
</>
);
const canAdd = !isPlaceholderData ? (data?.length || 0) < DATA_LIMIT : true;
const alert = apiKeysAlertHtml ? <AlertWithExternalHtml html={ apiKeysAlertHtml } status="warning" className="mb-6"/> : null;
const button = (() => {
if (!feature.isEnabled || feature.apiKeysButton === false) {
return null;
}
if (typeof feature.apiKeysButton === 'string') {
return (
<Link href={ feature.apiKeysButton } external noIcon>
<Button>Add API key</Button>
</Link>
);
}
return (
<Button
onClick={ apiKeyModalProps.onOpen }
disabled={ !canAdd }
>
Add API key
</Button>
);
})();
return (
<>
{ description }
{ alert }
{ Boolean(data?.length) && list }
<Skeleton
mt={ 8 }
loading={ isPlaceholderData }
display="inline-flex"
className="flex-col lg:flex-row items-start lg:items-center gap-x-5 gap-y-5"
>
{ button }
{ !canAdd && (
<span className="text-sm text-[var(--color-text-secondary)]">
{ `You have added the maximum number of API keys (${ DATA_LIMIT }). Contact us to request additional keys.` }
</span>
) }
</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;