import { format, formatDistanceToNow } from "date-fns"; import React, { FormEvent, useCallback, useMemo, useState } from "react"; import { ApiToken, NewApiToken } from "../api/entities/api-token"; import { useApiTokens } from "../hooks/use-api"; import { useAuthProtection } from "../hooks/use-auth-protection"; import { SpinnerIcon } from "../icons/Spinner"; import TrashcanIcon from "../icons/Trashcan"; import { Spinner } from "./Spinner"; export const AuthApiTokens: React.FC = () => { const { requireUser } = useAuthProtection(); const { apiTokens, isLoading, createToken, revokeToken } = useApiTokens(); const sortedTokens = useMemo( () => apiTokens.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1)), [apiTokens], ); requireUser(); return (

API Tokens

You can use API Tokens to access the Listory API directly. You can find the API docs{" "} here .

Manage Existing Tokens

{isLoading && } {sortedTokens.length === 0 && (

Could not find any api tokens!

)}
{sortedTokens.length > 0 && (
{sortedTokens.map((apiToken) => ( ))}
)}
); }; const NewTokenForm: React.FC<{ createToken: (description: string) => Promise; }> = ({ createToken }) => { const [newTokenDescription, setNewTokenDescription] = useState(""); const [newToken, setNewToken] = useState(null); const [isLoading, setLoading] = useState(false); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [error, setError] = useState(null); const submitForm = useCallback( async (event: FormEvent) => { event.preventDefault(); setLoading(true); setError(null); try { const newToken = await createToken(newTokenDescription); setNewToken(newToken); setNewTokenDescription(""); } catch (err: any) { setError(err); } setLoading(false); }, [ setLoading, setError, newTokenDescription, createToken, setNewToken, setNewTokenDescription, ], ); return (

Create New Token

setNewTokenDescription(event.target.value)} className="shadow appearance-none rounded w-1/3 mb-3 py-2 px-3 outline-none focus:ring ring-green-200 dark:ring-gray-600 bg-gray-200 dark:bg-gray-700" /> {newToken ? : null} ); }; const NewApiTokenItem: React.FC<{ apiToken: NewApiToken }> = ({ apiToken }) => { const copyToken = useCallback(() => { navigator.clipboard.writeText(apiToken.token); }, [apiToken]); return (
Your new API Token:
        {apiToken.token}
      
The token will only be visible once, so make sure to save it!
); }; const ApiTokenItem: React.FC<{ apiToken: ApiToken; revokeToken: (id: string) => Promise; }> = ({ apiToken, revokeToken }) => { const [isBeingRevoked, setIsBeingRevoked] = useState(false); const revokeTokenButton = useCallback(async () => { setIsBeingRevoked(true); await revokeToken(apiToken.id); setIsBeingRevoked(false); }, [setIsBeingRevoked, revokeToken, apiToken]); const description = apiToken.description; const prefix = apiToken.prefix; const timeAgo = formatDistanceToNow(new Date(apiToken.createdAt), { addSuffix: true, }); const dateTime = format(new Date(apiToken.createdAt), "PP p"); const displayRevokeButton = apiToken.revokedAt == null && !isBeingRevoked; const displaySpinner = isBeingRevoked; return (
{description}
{prefix}...
{timeAgo}
{displayRevokeButton && ( )} {displaySpinner && ( )}
); };