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/missions/assignment-dispatch-button.tsx
1.8 KB
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { Send, Loader2, AlertTriangle } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { AssignmentStatus } from "@/lib/missions/types";

/** Dispatch control for an assignment detail page. */
export function AssignmentDispatchButton({
  missionId,
  aid,
  status,
}: {
  missionId: string;
  aid: string;
  status: AssignmentStatus;
}) {
  const router = useRouter();
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const canDispatch = status === "Pending" || status === "Failed";

  async function dispatch() {
    setBusy(true);
    setError(null);
    try {
      const res = await fetch(
        `/api/missions/${missionId}/assignments/${aid}/dispatch`,
        { method: "POST" },
      );
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.error ?? "Dispatch failed.");
      router.refresh();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Dispatch failed.");
      setBusy(false);
    }
  }

  if (!canDispatch) {
    return (
      <span className="text-[12px] text-muted-foreground">
        Already {status.toLowerCase()}.
      </span>
    );
  }

  return (
    <div className="flex flex-col items-end gap-1">
      <Button type="button" size="sm" onClick={dispatch} disabled={busy}>
        {busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Send className="h-3.5 w-3.5" />}
        Dispatch Assignment
      </Button>
      {error && (
        <span className="flex items-center gap-1 text-[11px] text-destructive">
          <AlertTriangle className="h-3 w-3" /> {error}
        </span>
      )}
    </div>
  );
}

root · /srv/aaf