Files
at-mintel/packages/payload-ai/src/components/FieldGenerators/AiFieldButton.tsx
Marc Mintel 1c43d12e4d
All checks were successful
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 2s
Monorepo Pipeline / 🧪 Test (push) Successful in 1m20s
Monorepo Pipeline / 🏗️ Build (push) Successful in 3m22s
Monorepo Pipeline / 🧹 Lint (push) Successful in 3m33s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
fix(payload-ai): convert server actions to api endpoints, drop @payload-config dependency
2026-03-03 14:58:35 +01:00

142 lines
5.2 KiB
TypeScript

"use client";
import React, { useState } from "react";
import { useField, useDocumentInfo, useForm } from "@payloadcms/ui";
export function AiFieldButton({ path, field }: { path: string; field: any }) {
const [isGenerating, setIsGenerating] = useState(false);
const [instructions, setInstructions] = useState("");
const [showInstructions, setShowInstructions] = useState(false);
// Payload hooks
const { value, setValue } = useField<string>({ path });
const { title } = useDocumentInfo();
const { fields } = useForm();
const extractText = (lexicalRoot: any): string => {
if (!lexicalRoot) return "";
let text = "";
const iterate = (node: any) => {
if (node.text) text += node.text + " ";
if (node.children) node.children.forEach(iterate);
};
iterate(lexicalRoot);
return text;
};
const handleGenerate = async (e: React.MouseEvent) => {
e.preventDefault();
const lexicalValue = fields?.content?.value as any;
const legacyValue = fields?.legacyMdx?.value as string;
let draftContent = legacyValue || "";
if (!draftContent && lexicalValue?.root) {
draftContent = extractText(lexicalValue.root);
}
setIsGenerating(true);
try {
// Field name is passed as a label usually, fallback to path
const fieldName = typeof field?.label === "string" ? field.label : path;
const fieldDescription =
typeof field?.admin?.description === "string"
? field.admin.description
: "";
const resData = await fetch("/api/api/mintel-ai/generate-single-field", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
documentTitle: (title as string) || "",
documentContent: draftContent,
fieldName,
fieldDescription,
instructions,
}),
});
const res = await resData.json();
if (res.success && res.text) {
setValue(res.text);
} else {
alert("Fehler: " + res.error);
}
} catch (e: any) {
console.error(e)
alert("Fehler bei der Generierung.");
} finally {
setIsGenerating(false);
setShowInstructions(false);
}
};
return (
<div
style={{
marginTop: "8px",
marginBottom: "8px",
display: "flex",
flexDirection: "column",
gap: "8px",
}}
>
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
<button
type="button"
onClick={handleGenerate}
disabled={isGenerating}
style={{
background: "var(--theme-elevation-150)",
border: "1px solid var(--theme-elevation-200)",
color: "var(--theme-text)",
padding: "4px 12px",
borderRadius: "4px",
fontSize: "12px",
cursor: isGenerating ? "not-allowed" : "pointer",
display: "flex",
alignItems: "center",
gap: "6px",
opacity: isGenerating ? 0.6 : 1,
}}
>
{isGenerating ? "✨ AI arbeitet..." : "✨ AI Ausfüllen"}
</button>
<button
type="button"
onClick={(e) => {
e.preventDefault();
setShowInstructions(!showInstructions);
}}
style={{
background: "transparent",
border: "none",
color: "var(--theme-elevation-500)",
fontSize: "12px",
cursor: "pointer",
textDecoration: "underline",
}}
>
{showInstructions ? "Prompt verbergen" : "Mit Prompt..."}
</button>
</div>
{showInstructions && (
<textarea
value={instructions}
onChange={(e) => setInstructions(e.target.value)}
placeholder="Eigene Anweisung an AI (z.B. 'als catchy slogan')"
disabled={isGenerating}
style={{
width: "100%",
padding: "6px 8px",
fontSize: "12px",
borderRadius: "4px",
border: "1px solid var(--theme-elevation-200)",
background: "var(--theme-elevation-50)",
color: "var(--theme-text)",
}}
rows={2}
/>
)}
</div>
);
}