import { useState } from "react"; import { useForm } from "react-hook-form"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useDataProvider, useNotify, useGetIdentity, useTranslate, } from "ra-core"; import { generateApiKey, hashApiKey } from "@/lib/api-key-utils"; import { encryptValue } from "@/lib/encryption-utils"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ds/ui/dialog"; import { Button } from "@/components/ds/ui/button"; import { Input } from "@/components/ds/ui/input"; import { Label } from "@/components/ds/ui/label"; import { Checkbox } from "@/components/ds/ui/checkbox"; import { Alert, AlertDescription } from "@/components/ds/ui/alert"; import { Copy, CheckCircle } from "lucide-react"; interface CreateApiKeyDialogProps { open: boolean; onClose: () => void; } const AVAILABLE_SCOPES = [ "contacts:read", "contacts:write", "companies:read", "companies:write", "deals:read", "deals:write", "tasks:read", "tasks:write", "invoices:read", "invoices:write", "activities:write", ]; export const CreateApiKeyDialog = ({ open, onClose, }: CreateApiKeyDialogProps) => { const [createdKey, setCreatedKey] = useState(null); const [copied, setCopied] = useState(false); const dataProvider = useDataProvider(); const notify = useNotify(); const queryClient = useQueryClient(); const { identity } = useGetIdentity(); const translate = useTranslate(); const { register, handleSubmit, watch, setValue, reset } = useForm({ defaultValues: { name: "", scopes: [] as string[], expires_at: "", }, }); const createMutation = useMutation({ mutationFn: async (values: any) => { const apiKey = generateApiKey(); const keyHash = await hashApiKey(apiKey); const keyPrefix = apiKey.substring(0, 12); const encryptedKey = await encryptValue(apiKey); const { data } = await dataProvider.create("api_keys", { data: { name: values.name, key_hash: keyHash, key_prefix: keyPrefix, encrypted_key: encryptedKey, scopes: values.scopes, is_active: true, expires_at: values.expires_at || null, sales_id: identity?.id, created_by_sales_id: identity?.id, }, }); return { data, apiKey }; }, onSuccess: ({ apiKey }) => { setCreatedKey(apiKey); queryClient.invalidateQueries({ queryKey: ["api_keys"] }); notify(translate("crm.integrations.api_keys.notification.created")); }, onError: () => { notify( translate("crm.integrations.api_keys.notification.error_creating"), { type: "error", }, ); }, }); const handleClose = () => { setCreatedKey(null); setCopied(false); reset(); onClose(); }; const copyApiKey = () => { if (createdKey) { navigator.clipboard.writeText(createdKey); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; const toggleScope = (scope: string) => { const currentScopes = watch("scopes"); if (currentScopes.includes(scope)) { setValue( "scopes", currentScopes.filter((s) => s !== scope), ); } else { setValue("scopes", [...currentScopes, scope]); } }; return ( {createdKey ? translate("crm.integrations.api_keys.dialog.created_title") : translate("crm.integrations.api_keys.dialog.create_title")} {createdKey ? translate( "crm.integrations.api_keys.dialog.created_description", ) : translate( "crm.integrations.api_keys.dialog.create_description", )} {createdKey ? (
{translate("crm.integrations.api_keys.dialog.warning_copy")}
) : (
createMutation.mutate(values))} >
{AVAILABLE_SCOPES.map((scope) => (
toggleScope(scope)} />
))}
)}
); };