/** * @file ConfirmDeleteModal.tsx * @description Confirmation modal for deleting a config artifact. Tool- * agnostic — the caller supplies the async delete action; the modal only * tracks the busy state and Escape-to-cancel behavior. * @author Nguyễn Ngọc Trí Vĩ */ import { useCallback, useRef, useState } from "react"; import { useDialog } from "../../hooks/useDialog"; import { useTranslation } from "react-i18next"; import { ShieldAlert, Trash2 } from "lucide-react"; import type { CcArtifactType } from "../../lib/api"; /** See EditorModal.tsx's `DefaultScope` — same reasoning: Codex instantiates * `TScope` as `"user" | "project"` instead of casting into Claude's wider * default. */ export type ConfirmDeleteState< TType extends string = CcArtifactType, TScope extends string = "user" | "project" | "auto-memory", > = { type: TType; scope: TScope; name?: string; path: string; project?: string; // set for type === "auto-memory" } | null; interface ConfirmDeleteModalProps< TType extends string = CcArtifactType, TScope extends string = "user" | "project" | "auto-memory", > { state: NonNullable>; onCancel: () => void; onConfirm: () => Promise; } export function ConfirmDeleteModal< TType extends string = CcArtifactType, TScope extends string = "user" | "project" | "auto-memory", >({ state, onCancel, onConfirm }: ConfirmDeleteModalProps) { const { t } = useTranslation("ccConfig"); const [busy, setBusy] = useState(false); const panelRef = useRef(null); const cancelRef = useRef(null); // Focus starts on Cancel — the safe answer — and Escape cancels. useDialog(true, panelRef, busy ? undefined : onCancel, cancelRef); const handleConfirm = useCallback(async () => { setBusy(true); try { await onConfirm(); } finally { setBusy(false); } }, [onConfirm]); return (
e.stopPropagation()} >
{t("edit.confirmDelete")}

{t("edit.confirmDeleteBody")}

{t("edit.confirmDeletePath", { path: state.path })}
); }