diff --git a/client/pages/admin/AdminBlogManager.tsx b/client/pages/admin/AdminBlogManager.tsx new file mode 100644 index 00000000..097d1ab8 --- /dev/null +++ b/client/pages/admin/AdminBlogManager.tsx @@ -0,0 +1,194 @@ +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import AdminBlogEditor from "@/components/admin/AdminBlogEditor"; +import { useAuth } from "@/contexts/AuthContext"; +import { useAethexToast } from "@/hooks/use-aethex-toast"; +import { Plus, List, FileText } from "lucide-react"; + +interface BlogPost { + id: string; + title: string; + slug: string; + excerpt?: string; + published_at: string; + author?: string; + source: "ghost" | "supabase"; +} + +const AdminBlogManager = () => { + const { user, userRole } = useAuth(); + const navigate = useNavigate(); + const toast = useAethexToast(); + const [posts, setPosts] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [activeTab, setActiveTab] = useState("editor"); + + // Check authorization + useEffect(() => { + if (!user) { + navigate("/login"); + return; + } + + if (userRole !== "admin" && userRole !== "staff") { + toast.error("Access denied: Admin/Staff only"); + navigate("/dashboard"); + } + + setIsLoading(false); + }, [user, userRole, navigate, toast]); + + // Fetch posts + useEffect(() => { + const fetchPosts = async () => { + try { + const response = await fetch("/api/blog?limit=100"); + if (response.ok) { + const data = await response.json(); + setPosts(data || []); + } + } catch (error) { + console.error("Failed to fetch posts:", error); + } + }; + + fetchPosts(); + }, []); + + const handlePublishSuccess = () => { + setActiveTab("posts"); + // Refresh posts list + setTimeout(() => { + fetch("/api/blog?limit=100") + .then((r) => r.json()) + .then((data) => setPosts(data || [])) + .catch(console.error); + }, 1000); + }; + + if (isLoading) { + return
Loading...
; + } + + if (!user || (userRole !== "admin" && userRole !== "staff")) { + return null; + } + + return ( +
+ {/* Header */} +
+

Blog Management

+

+ Create and publish posts directly to Ghost.org +

+
+ + {/* Tabs */} + + + + + New Post + + + + All Posts ({posts.length}) + + + + {/* New Post Editor Tab */} + + + + + {/* Posts List Tab */} + + {posts.length === 0 ? ( + + + +

No posts yet

+
+
+ ) : ( +
+ {posts.map((post) => ( + + +
+
+ {post.title} + {post.excerpt && ( + + {post.excerpt} + + )} +
+
+ {post.source && ( + + {post.source === "ghost" ? "Ghost" : "Local"} + + )} +
+
+
+ {post.author && {post.author}} + {post.published_at && ( + + {new Date(post.published_at).toLocaleDateString()} + + )} +
+
+ + + +
+ ))} +
+ )} +
+
+ + {/* Info Box */} + + + About Blog Publishing + + +

+ ✓ Posts are published directly to Ghost.org and appear immediately on the blog +

+

+ ✓ All posts are authored by "AeThex Team" in Ghost (respects Ghost guidelines) +

+

+ ✓ Use HTML or paste from your preferred editor (Word, Google Docs, Medium, etc) +

+

+ ✓ Featured image and SEO metadata are optional but recommended +

+

+ ✓ Posts appear at /blog and in the blog listing page +

+
+
+
+ ); +}; + +export default AdminBlogManager;