import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { useAethexToast } from "@/hooks/use-aethex-toast"; import { Loader2, X } from "lucide-react"; interface BlogEditorProps { onPublish?: (success: boolean) => void; initialData?: { title: string; excerpt: string; html: string; slug?: string; feature_image?: string; tags?: string[]; meta_title?: string; meta_description?: string; }; } const BlogEditor = ({ onPublish, initialData }: BlogEditorProps) => { const toast = useAethexToast(); const [isLoading, setIsLoading] = useState(false); const [title, setTitle] = useState(initialData?.title || ""); const [excerpt, setExcerpt] = useState(initialData?.excerpt || ""); const [html, setHtml] = useState(initialData?.html || ""); const [slug, setSlug] = useState(initialData?.slug || ""); const [featureImage, setFeatureImage] = useState( initialData?.feature_image || "", ); const [tags, setTags] = useState(initialData?.tags || []); const [tagInput, setTagInput] = useState(""); const [metaTitle, setMetaTitle] = useState(initialData?.meta_title || ""); const [metaDescription, setMetaDescription] = useState( initialData?.meta_description || "", ); // Auto-generate slug from title if not manually set const autoSlug = slug || title .toLowerCase() .replace(/[^\w\s-]/g, "") .trim() .replace(/\s+/g, "-") .replace(/-+/g, "-"); const addTag = () => { if (tagInput.trim() && !tags.includes(tagInput.trim())) { setTags([...tags, tagInput.trim()]); setTagInput(""); } }; const removeTag = (tag: string) => { setTags(tags.filter((t) => t !== tag)); }; const handlePublish = async () => { if (!title.trim() || !html.trim()) { toast.error("Title and body are required"); return; } setIsLoading(true); try { const response = await fetch("/api/blog/publish", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title, excerpt: excerpt || undefined, html, slug: autoSlug, feature_image: featureImage || undefined, tags, meta_title: metaTitle || title, meta_description: metaDescription || excerpt, status: "published", }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || "Failed to publish post"); } const data = await response.json(); toast.success(`Post published: ${data.url}`); onPublish?.(true); // Reset form setTitle(""); setExcerpt(""); setHtml(""); setSlug(""); setFeatureImage(""); setTags([]); setMetaTitle(""); setMetaDescription(""); } catch (error: any) { toast.error(error.message || "Failed to publish post"); onPublish?.(false); } finally { setIsLoading(false); } }; return (
Post Details Publish directly to Ghost.org with AeThex as author {/* Title */}
setTitle(e.target.value)} placeholder="Post title" className="border-border/50" />
{/* Slug */}
setSlug(e.target.value)} placeholder="Leave blank to auto-generate from title" className="border-border/50" /> {!slug && title && (

Auto-slug:{" "} {autoSlug}

)}
{/* Excerpt */}