Path: blob/develop/resources/scripts/components/dashboard/AccountApiContainer.tsx
7428 views
import { useEffect, useState } from 'react';1import ContentBox from '@/components/elements/ContentBox';2import CreateApiKeyForm from '@/components/dashboard/forms/CreateApiKeyForm';3import getApiKeys, { ApiKey } from '@/api/account/getApiKeys';4import SpinnerOverlay from '@/components/elements/SpinnerOverlay';5import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';6import { faKey, faTrashAlt } from '@fortawesome/free-solid-svg-icons';7import deleteApiKey from '@/api/account/deleteApiKey';8import FlashMessageRender from '@/components/FlashMessageRender';9import { format } from 'date-fns';10import PageContentBlock from '@/components/elements/PageContentBlock';11import tw from 'twin.macro';12import GreyRowBox from '@/components/elements/GreyRowBox';13import { Dialog } from '@/components/elements/dialog';14import { useFlashKey } from '@/plugins/useFlash';15import Code from '@/components/elements/Code';1617export default () => {18const [deleteIdentifier, setDeleteIdentifier] = useState('');19const [keys, setKeys] = useState<ApiKey[]>([]);20const [loading, setLoading] = useState(true);21const { clearAndAddHttpError } = useFlashKey('account');2223useEffect(() => {24getApiKeys()25.then(keys => setKeys(keys))26.then(() => setLoading(false))27.catch(error => clearAndAddHttpError(error));28}, []);2930const doDeletion = (identifier: string) => {31setLoading(true);3233clearAndAddHttpError();34deleteApiKey(identifier)35.then(() => setKeys(s => [...(s || []).filter(key => key.identifier !== identifier)]))36.catch(error => clearAndAddHttpError(error))37.then(() => {38setLoading(false);39setDeleteIdentifier('');40});41};4243return (44<PageContentBlock title={'Account API'}>45<FlashMessageRender byKey={'account'} />46<div css={tw`md:flex flex-nowrap my-10`}>47<ContentBox title={'Create API Key'} css={tw`flex-none w-full md:w-1/2`}>48<CreateApiKeyForm onKeyCreated={key => setKeys(s => [...s!, key])} />49</ContentBox>50<ContentBox title={'API Keys'} css={tw`flex-1 overflow-hidden mt-8 md:mt-0 md:ml-8`}>51<SpinnerOverlay visible={loading} />52<Dialog.Confirm53title={'Delete API Key'}54confirm={'Delete Key'}55open={!!deleteIdentifier}56onClose={() => setDeleteIdentifier('')}57onConfirmed={() => doDeletion(deleteIdentifier)}58>59All requests using the <Code>{deleteIdentifier}</Code> key will be invalidated.60</Dialog.Confirm>61{keys.length === 0 ? (62<p css={tw`text-center text-sm`}>63{loading ? 'Loading...' : 'No API keys exist for this account.'}64</p>65) : (66keys.map((key, index) => (67<GreyRowBox68key={key.identifier}69css={[tw`bg-neutral-600 flex items-center`, index > 0 && tw`mt-2`]}70>71<FontAwesomeIcon icon={faKey} css={tw`text-neutral-300`} />72<div css={tw`ml-4 flex-1 overflow-hidden`}>73<p css={tw`text-sm break-words`}>{key.description}</p>74<p css={tw`text-2xs text-neutral-300 uppercase`}>75Last used: 76{key.lastUsedAt ? format(key.lastUsedAt, 'MMM do, yyyy HH:mm') : 'Never'}77</p>78</div>79<p css={tw`text-sm ml-4 hidden md:block`}>80<code css={tw`font-mono py-1 px-2 bg-neutral-900 rounded`}>{key.identifier}</code>81</p>82<button css={tw`ml-4 p-2 text-sm`} onClick={() => setDeleteIdentifier(key.identifier)}>83<FontAwesomeIcon84icon={faTrashAlt}85css={tw`text-neutral-400 hover:text-red-400 transition-colors duration-150`}86/>87</button>88</GreyRowBox>89))90)}91</ContentBox>92</div>93</PageContentBlock>94);95};969798