79 lines
2 KiB
TypeScript
79 lines
2 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Bot, Loader2 } from "lucide-react";
|
|
import { toast } from "sonner";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import getPocketBase from "@/lib/pocketbase";
|
|
|
|
interface RunResponse {
|
|
filled?: number;
|
|
unmatched?: number;
|
|
error?: string | null;
|
|
}
|
|
|
|
function plural(n: number): string {
|
|
return `${n} line${n === 1 ? "" : "s"}`;
|
|
}
|
|
|
|
export function AiFillQuoteButton({
|
|
quoteId,
|
|
onDone,
|
|
size = "sm",
|
|
}: {
|
|
quoteId: string;
|
|
onDone: () => void;
|
|
size?: "sm" | "default";
|
|
}) {
|
|
const [running, setRunning] = useState(false);
|
|
|
|
async function run() {
|
|
if (running) return;
|
|
setRunning(true);
|
|
try {
|
|
const token = getPocketBase().authStore.token;
|
|
const res = await fetch(`/api/v1/quotes/${encodeURIComponent(quoteId)}/assistant/run`, {
|
|
method: "POST",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
const body = (await res.json().catch(() => ({}))) as RunResponse;
|
|
if (!res.ok) {
|
|
toast.error(body.error || `AI fill failed (${res.status})`);
|
|
return;
|
|
}
|
|
const filled = body.filled ?? 0;
|
|
const unmatched = body.unmatched ?? 0;
|
|
if (body.error) {
|
|
toast.error(body.error);
|
|
} else if (filled === 0 && unmatched === 0) {
|
|
toast.info("AI had no open lines to fill");
|
|
} else {
|
|
toast.success(
|
|
unmatched > 0
|
|
? `AI filled ${plural(filled)} · ${unmatched} without a match`
|
|
: `AI filled ${plural(filled)}`,
|
|
);
|
|
}
|
|
onDone();
|
|
} catch (err) {
|
|
toast.error(err instanceof Error ? err.message : "AI fill failed");
|
|
} finally {
|
|
setRunning(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
size={size}
|
|
disabled={running}
|
|
onClick={run}
|
|
className="border-ai/30 text-ai hover:bg-ai/10 hover:text-ai"
|
|
>
|
|
{running ? <Loader2 className="animate-spin" aria-hidden /> : <Bot aria-hidden />}
|
|
{running ? "AI is filling…" : "Let AI fill this quote"}
|
|
</Button>
|
|
);
|
|
}
|