2022-03-24 18:13:19 +00:00
|
|
|
import dayjs from "dayjs";
|
2022-03-25 11:44:09 +00:00
|
|
|
import cn from "classnames";
|
2022-03-24 18:13:19 +00:00
|
|
|
import { useCallback, useState } from "react";
|
2022-03-25 11:44:09 +00:00
|
|
|
|
2022-03-24 18:13:19 +00:00
|
|
|
import { Alert } from "../Alert";
|
|
|
|
import { Button } from "../Button";
|
|
|
|
import { AddSkylinkToAPIKeyForm } from "../forms/AddSkylinkToAPIKeyForm";
|
2022-03-25 16:47:44 +00:00
|
|
|
import { CogIcon, TrashIcon } from "../Icons";
|
2022-03-24 18:13:19 +00:00
|
|
|
import { Modal } from "../Modal";
|
2022-03-25 11:44:09 +00:00
|
|
|
|
2022-03-24 18:13:19 +00:00
|
|
|
import { useAPIKeyEdit } from "./useAPIKeyEdit";
|
|
|
|
import { useAPIKeyRemoval } from "./useAPIKeyRemoval";
|
|
|
|
|
|
|
|
export const APIKey = ({ apiKey, onRemoved, onEdited, onRemovalError }) => {
|
|
|
|
const { id, name, createdAt, skylinks } = apiKey;
|
|
|
|
const isPublic = apiKey.public === "true";
|
|
|
|
const [error, setError] = useState(null);
|
|
|
|
|
|
|
|
const onSkylinkListEdited = useCallback(() => {
|
|
|
|
setError(null);
|
|
|
|
onEdited();
|
|
|
|
}, [onEdited]);
|
|
|
|
|
|
|
|
const onSkylinkListEditFailure = (errorMessage) => setError(errorMessage);
|
|
|
|
|
|
|
|
const {
|
|
|
|
removalError,
|
|
|
|
removalInitiated,
|
|
|
|
prompt: promptRemoval,
|
|
|
|
abort: abortRemoval,
|
|
|
|
confirm: confirmRemoval,
|
|
|
|
} = useAPIKeyRemoval({
|
|
|
|
key: apiKey,
|
|
|
|
onSuccess: onRemoved,
|
|
|
|
onFailure: onRemovalError,
|
|
|
|
});
|
|
|
|
|
|
|
|
const {
|
|
|
|
editInitiated,
|
|
|
|
prompt: promptEdit,
|
|
|
|
abort: abortEdit,
|
2022-03-25 10:22:36 +00:00
|
|
|
addSkylink,
|
2022-03-24 18:13:19 +00:00
|
|
|
removeSkylink,
|
|
|
|
} = useAPIKeyEdit({
|
|
|
|
key: apiKey,
|
2022-03-25 10:22:36 +00:00
|
|
|
onSkylinkListUpdate: onSkylinkListEdited,
|
|
|
|
onSkylinkListUpdateFailure: onSkylinkListEditFailure,
|
2022-03-24 18:13:19 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const closeEditModal = useCallback(() => {
|
|
|
|
setError(null);
|
|
|
|
abortEdit();
|
|
|
|
}, [abortEdit]);
|
|
|
|
|
2022-03-25 16:47:44 +00:00
|
|
|
const skylinksNumber = skylinks?.length ?? 0;
|
|
|
|
const isNotConfigured = isPublic && skylinksNumber === 0;
|
2022-03-28 06:07:14 +00:00
|
|
|
const skylinksPhrasePrefix = skylinksNumber === 0 ? "No" : skylinksNumber;
|
|
|
|
const skylinksPhrase = `${skylinksPhrasePrefix} ${skylinksNumber === 1 ? "skylink" : "skylinks"} configured`;
|
2022-03-25 11:44:09 +00:00
|
|
|
|
2022-03-24 18:13:19 +00:00
|
|
|
return (
|
2022-03-25 11:44:09 +00:00
|
|
|
<li
|
2022-03-25 16:47:44 +00:00
|
|
|
className={cn(
|
|
|
|
"grid grid-cols-2 sm:grid-cols-[1fr_repeat(2,_max-content)] py-3 px-4 gap-x-8 items-center bg-white odd:bg-palette-100/50"
|
|
|
|
)}
|
2022-03-25 11:44:09 +00:00
|
|
|
>
|
|
|
|
<span className="col-span-2 sm:col-span-1 flex items-center">
|
2022-03-25 16:47:44 +00:00
|
|
|
<span className="flex flex-col">
|
|
|
|
<span className={cn("truncate", { "text-palette-300": !name })}>{name || "unnamed key"}</span>
|
|
|
|
<button
|
|
|
|
onClick={promptEdit}
|
|
|
|
className={cn("text-xs hover:underline decoration-dotted", {
|
|
|
|
"text-error": isNotConfigured,
|
|
|
|
"text-palette-400": !isNotConfigured,
|
|
|
|
})}
|
|
|
|
>
|
2022-03-28 06:07:14 +00:00
|
|
|
{skylinksPhrase}
|
2022-03-25 16:47:44 +00:00
|
|
|
</button>
|
|
|
|
</span>
|
2022-03-25 11:44:09 +00:00
|
|
|
</span>
|
2022-03-24 18:13:19 +00:00
|
|
|
<span className="col-span-2 my-4 border-t border-t-palette-200/50 sm:hidden" />
|
|
|
|
<span className="text-palette-400">{dayjs(createdAt).format("MMM DD, YYYY")}</span>
|
|
|
|
<span className="flex items-center justify-end">
|
|
|
|
{isPublic && (
|
|
|
|
<button
|
2022-03-28 06:07:14 +00:00
|
|
|
title="Add or remove skylinks"
|
2022-04-06 09:10:28 +00:00
|
|
|
aria-label="Add or remove skylinks"
|
2022-03-24 18:13:19 +00:00
|
|
|
className="p-1 transition-colors hover:text-primary"
|
2022-03-25 16:47:44 +00:00
|
|
|
onClick={promptEdit}
|
2022-03-24 18:13:19 +00:00
|
|
|
>
|
|
|
|
<CogIcon size={22} />
|
|
|
|
</button>
|
|
|
|
)}
|
2022-04-06 09:10:28 +00:00
|
|
|
<button
|
|
|
|
title="Delete this API key"
|
|
|
|
aria-label="Delete this API key"
|
|
|
|
className="p-1 transition-colors hover:text-error"
|
|
|
|
onClick={promptRemoval}
|
|
|
|
>
|
2022-03-24 18:13:19 +00:00
|
|
|
<TrashIcon size={16} />
|
|
|
|
</button>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
{removalInitiated && (
|
|
|
|
<Modal onClose={abortRemoval} className="flex flex-col gap-4 text-center">
|
|
|
|
<h4>Delete API key</h4>
|
|
|
|
<div>
|
|
|
|
<p>Are you sure you want to delete the following API key?</p>
|
|
|
|
<p className="font-semibold">{name || id}</p>
|
|
|
|
</div>
|
|
|
|
{removalError && <Alert $variant="error">{removalError}</Alert>}
|
|
|
|
|
|
|
|
<div className="flex gap-4 justify-center mt-4">
|
|
|
|
<Button $primary onClick={abortRemoval}>
|
|
|
|
Cancel
|
|
|
|
</Button>
|
|
|
|
<Button onClick={confirmRemoval}>Delete</Button>
|
|
|
|
</div>
|
|
|
|
</Modal>
|
|
|
|
)}
|
|
|
|
{editInitiated && (
|
|
|
|
<Modal onClose={closeEditModal} className="flex flex-col gap-4 text-center sm:px-8 sm:py-6">
|
2022-03-28 06:07:14 +00:00
|
|
|
<h4>Covered skylinks</h4>
|
2022-03-24 18:13:19 +00:00
|
|
|
{skylinks?.length > 0 ? (
|
|
|
|
<ul className="text-xs flex flex-col gap-2">
|
|
|
|
{skylinks.map((skylink) => (
|
2022-03-25 10:22:36 +00:00
|
|
|
<li key={skylink} className="grid grid-cols-[1fr_min-content] w-full gap-4 items-center">
|
|
|
|
<code className="whitespace-nowrap select-all truncate bg-palette-100 odd:bg-white p-1">
|
2022-03-24 18:13:19 +00:00
|
|
|
{skylink}
|
|
|
|
</code>
|
2022-04-06 09:10:28 +00:00
|
|
|
<button
|
|
|
|
className="p-1 transition-colors hover:text-error"
|
|
|
|
onClick={() => removeSkylink(skylink)}
|
|
|
|
aria-label="Remove skylink"
|
|
|
|
>
|
2022-03-24 18:13:19 +00:00
|
|
|
<TrashIcon size={16} />
|
|
|
|
</button>
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
|
|
|
) : (
|
|
|
|
<Alert $variant="info">No skylinks here yet. You can add the first one below 🙃</Alert>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-4">
|
|
|
|
{error && <Alert $variant="error">{error}</Alert>}
|
2022-03-25 10:22:36 +00:00
|
|
|
<AddSkylinkToAPIKeyForm addSkylink={addSkylink} />
|
2022-03-24 18:13:19 +00:00
|
|
|
</div>
|
|
|
|
<div className="flex gap-4 justify-center mt-4">
|
|
|
|
<Button onClick={closeEditModal}>Close</Button>
|
|
|
|
</div>
|
|
|
|
</Modal>
|
|
|
|
)}
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
};
|