Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Failing after 2m24s
Build & Deploy / 🏗️ Build (push) Failing after 3m40s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
import { useForm, useField } from "@payloadcms/ui";
|
|
import { generateSlugAction } from "../../actions/generateField";
|
|
import { Button } from "@payloadcms/ui";
|
|
|
|
export function GenerateSlugButton({ path }: { path: string }) {
|
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
const [instructions, setInstructions] = useState("");
|
|
|
|
useEffect(() => {
|
|
if (!isGenerating) return;
|
|
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
|
e.preventDefault();
|
|
e.returnValue =
|
|
"Slug-Generierung läuft noch. Wenn Sie neu laden, bricht der Vorgang ab!";
|
|
};
|
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
}, [isGenerating]);
|
|
|
|
const { fields, replaceState } = useForm();
|
|
const { value, initialValue, setValue } = useField({ path });
|
|
|
|
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 () => {
|
|
const title = (fields?.title?.value as string) || "";
|
|
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 {
|
|
const res = await generateSlugAction(
|
|
title,
|
|
draftContent,
|
|
initialValue as string,
|
|
instructions,
|
|
);
|
|
if (res.success && res.slug) {
|
|
setValue(res.slug);
|
|
} else {
|
|
alert("Fehler: " + res.error);
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
alert("Unerwarteter Fehler.");
|
|
} finally {
|
|
setIsGenerating(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="flex gap-2 items-center mb-4">
|
|
<textarea
|
|
value={instructions}
|
|
onChange={(e) => setInstructions(e.target.value)}
|
|
placeholder="Optionale AI Anweisung für den Slug..."
|
|
disabled={isGenerating}
|
|
style={{
|
|
width: "100%",
|
|
minHeight: "40px",
|
|
padding: "8px 12px",
|
|
fontSize: "14px",
|
|
borderRadius: "4px",
|
|
border: "1px solid var(--theme-elevation-200)",
|
|
background: "var(--theme-elevation-50)",
|
|
color: "var(--theme-text)",
|
|
marginBottom: "8px",
|
|
}}
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={handleGenerate}
|
|
disabled={isGenerating}
|
|
className="btn btn--icon-style-none btn--size-medium ml-auto"
|
|
style={{
|
|
background: "var(--theme-elevation-150)",
|
|
border: "1px solid var(--theme-elevation-200)",
|
|
color: "var(--theme-text)",
|
|
boxShadow: "0 2px 4px rgba(0,0,0,0.05)",
|
|
transition: "all 0.2s ease",
|
|
opacity: isGenerating ? 0.6 : 1,
|
|
cursor: isGenerating ? "not-allowed" : "pointer",
|
|
}}
|
|
>
|
|
<span className="btn__content">
|
|
{isGenerating ? "✨ Generiere (ca 10s)..." : "✨ AI Slug Generieren"}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|