"use client"; import { useEffect, useState } from "react"; import { api } from "@/lib/api"; import { cn } from "@/lib/utils"; import { fetchEventFromRelays, fetchLongformFromRelays } from "@/lib/nostr"; import { Pencil, Trash2, X, Download, Star, EyeOff, } from "lucide-react"; export default function BlogPage() { const [posts, setPosts] = useState([]); const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [importOpen, setImportOpen] = useState(false); const [importInput, setImportInput] = useState(""); const [importPreview, setImportPreview] = useState(null); const [importing, setImporting] = useState(false); const [fetching, setFetching] = useState(false); const [editingPost, setEditingPost] = useState(null); const [editForm, setEditForm] = useState({ title: "", slug: "", excerpt: "", categories: [] as string[], featured: false, visible: true, }); const loadData = async () => { try { const [p, c] = await Promise.all([ api.getPosts({ all: true }), api.getCategories(), ]); setPosts(p.posts || []); setCategories(c); } catch (err: any) { setError(err.message); } finally { setLoading(false); } }; useEffect(() => { loadData(); }, []); const handleFetchPreview = async () => { if (!importInput.trim()) return; setFetching(true); setError(""); try { const isNaddr = importInput.trim().startsWith("naddr"); const event = isNaddr ? await fetchLongformFromRelays(importInput.trim()) : await fetchEventFromRelays(importInput.trim()); if (!event) { setError("Event not found on relays"); setImportPreview(null); return; } const titleTag = event.tags?.find((t: string[]) => t[0] === "title"); setImportPreview({ ...event, title: titleTag?.[1] || "Untitled", }); } catch (err: any) { setError(err.message || "Failed to fetch event"); setImportPreview(null); } finally { setFetching(false); } }; const handleImport = async () => { if (!importPreview) return; setImporting(true); setError(""); try { const isNaddr = importInput.trim().startsWith("naddr"); const excerpt = (importPreview.content || "") .slice(0, 200) .replace(/[#*_\n]/g, "") .trim(); const tags: string[] = (importPreview.tags || []) .filter((t: string[]) => t[0] === "t" && t[1]) .map((t: string[]) => t[1].toLowerCase()); await api.importPost({ nostrEventId: importPreview.id, naddr: isNaddr ? importInput.trim() : undefined, title: importPreview.title || "Untitled", excerpt: excerpt || undefined, authorPubkey: importPreview.pubkey, publishedAt: importPreview.created_at, tags: tags.length > 0 ? tags : undefined, }); setImportInput(""); setImportPreview(null); setImportOpen(false); await loadData(); } catch (err: any) { setError(err.message); } finally { setImporting(false); } }; const openEdit = (post: any) => { setEditingPost(post); setEditForm({ title: post.title || "", slug: post.slug || "", excerpt: post.excerpt || "", categories: post.categories?.map((c: any) => c.categoryId || c.category?.id || c) || [], featured: post.featured || false, visible: post.visible !== false, }); }; const handleSaveEdit = async () => { if (!editingPost) return; setError(""); try { await api.updatePost(editingPost.id, editForm); setEditingPost(null); await loadData(); } catch (err: any) { setError(err.message); } }; const handleDelete = async (id: string) => { if (!confirm("Delete this post?")) return; try { await api.deletePost(id); await loadData(); } catch (err: any) { setError(err.message); } }; const toggleCategory = (catId: string) => { setEditForm((prev) => ({ ...prev, categories: prev.categories.includes(catId) ? prev.categories.filter((c) => c !== catId) : [...prev.categories, catId], })); }; if (loading) { return (
Loading posts...
); } return (

Blog Management

{error &&

{error}

} {importOpen && (

Import from Nostr

setImportInput(e.target.value)} className="bg-surface-container-highest text-on-surface rounded-lg px-4 py-3 w-full focus:outline-none focus:ring-1 focus:ring-primary/40 flex-1" />
{importPreview && (

{importPreview.title || "Untitled"}

{importPreview.content?.slice(0, 300)}...

{(() => { const previewTags = (importPreview.tags || []) .filter((t: string[]) => t[0] === "t" && t[1]) .map((t: string[]) => t[1]); return previewTags.length > 0 ? (
{previewTags.map((tag: string) => ( {tag} ))}
) : null; })()}
)}
)} {editingPost && (

Edit Post Metadata

setEditForm({ ...editForm, title: e.target.value })} className="bg-surface-container-highest text-on-surface rounded-lg px-4 py-3 w-full focus:outline-none focus:ring-1 focus:ring-primary/40" /> setEditForm({ ...editForm, slug: e.target.value })} className="bg-surface-container-highest text-on-surface rounded-lg px-4 py-3 w-full focus:outline-none focus:ring-1 focus:ring-primary/40" />