Intelligence

Artifacts

Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.

Repository
.gitignoreDockerfilenext-env.d.tsnext.config.mjspackage-lock.jsonpackage.jsonpostcss.config.mjsREADME.mdtailwind.config.tstsconfig.jsontsconfig.tsbuildinfo
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
repositories/aaf-holdings/hq01/components/files/file-delete-button.tsx
2.6 KB
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { Trash2, Loader2 } from "lucide-react";
import { cn } from "@/lib/utils";

/**
 * Delete control shown in the file viewer for documents inside the managed
 * governance folders. Uses an inline confirm rather than a modal. On success it
 * navigates to the document's parent folder.
 */
export function FileDeleteButton({ path }: { path: string }) {
  const router = useRouter();
  const [confirming, setConfirming] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function del() {
    setBusy(true);
    setError(null);
    try {
      const res = await fetch("/api/files/document", {
        method: "DELETE",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ path }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.error ?? "Delete failed.");
      const parent = path.split("/").slice(0, -1).join("/");
      router.push(`/artifacts?dir=${encodeURIComponent(parent)}`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Delete failed.");
      setBusy(false);
      setConfirming(false);
    }
  }

  if (confirming) {
    return (
      <div className="flex items-center gap-2 text-[12px]">
        <span className="text-muted-foreground">Delete this document?</span>
        <button
          type="button"
          onClick={del}
          disabled={busy}
          className="inline-flex items-center gap-1 rounded-md bg-destructive px-2 py-1 font-medium text-destructive-foreground hover:bg-destructive/90"
        >
          {busy ? <Loader2 className="h-3 w-3 animate-spin" /> : <Trash2 className="h-3 w-3" />}
          Delete
        </button>
        <button
          type="button"
          onClick={() => setConfirming(false)}
          disabled={busy}
          className="rounded-md px-2 py-1 text-muted-foreground hover:bg-secondary"
        >
          Cancel
        </button>
      </div>
    );
  }

  return (
    <div className="flex items-center gap-2">
      {error && <span className="text-[11px] text-destructive">{error}</span>}
      <button
        type="button"
        onClick={() => setConfirming(true)}
        className={cn(
          "inline-flex items-center gap-1 rounded-md px-2 py-1 text-[12px] text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
        )}
        title="Delete this document"
      >
        <Trash2 className="h-3.5 w-3.5" /> Delete
      </button>
    </div>
  );
}

root · /srv/aaf