"use client"; import { useEffect, useState } from "react"; import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; import { BlogPost, PostStatus, ContentFormat, UserRole } from "@/lib/types"; import { TiptapEditor } from "@/components/dashboard/tiptap-editor"; import { ImageUploader } from "@/components/dashboard/image-uploader"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Switch } from "@/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, } from "@/components/ui/sheet"; import { Separator } from "@/components/ui/separator"; import { Loader2, FileText, Settings2 } from "lucide-react"; interface Props { open: boolean; onOpenChange: (open: boolean) => void; /** If provided, the sheet is in edit mode. Otherwise, create mode. */ post?: BlogPost | null; userRole: UserRole; onSuccess: () => void; } const defaultStatus = (role: UserRole): PostStatus => role === UserRole.ADMIN ? PostStatus.PUBLISHED : PostStatus.DRAFT; export function PostSheet({ open, onOpenChange, post, userRole, onSuccess }: Props) { const isEdit = !!post; /* ── form state ─────────────────────────────────────────────────────────── */ const [title, setTitle] = useState(""); const [slug, setSlug] = useState(""); const [excerpt, setExcerpt] = useState(""); const [content, setContent] = useState(""); const [contentFormat, setContentFormat] = useState(ContentFormat.HTML); const [status, setStatus] = useState(defaultStatus(userRole)); const [isFeatured, setIsFeatured] = useState(false); const [categories, setCategories] = useState(""); const [tags, setTags] = useState(""); const [imageUrl, setImageUrl] = useState(""); const [imageAlt, setImageAlt] = useState(""); const [loading, setLoading] = useState(false); /* ── populate when sheet opens ──────────────────────────────────────────── */ useEffect(() => { if (!open) return; if (post) { setTitle(post.title); setSlug(post.slug); setExcerpt(post.excerpt ?? ""); setContent(post.content ?? ""); setContentFormat(post.contentFormat); setStatus(post.status); setIsFeatured(post.isFeatured); setCategories(post.categories.join(",")); setTags(post.tags.join(",")); setImageUrl(post.featuredImageUrl ?? ""); setImageAlt(post.featuredImageAlt ?? ""); } else { setTitle(""); setSlug(""); setExcerpt(""); setContent(""); setContentFormat(ContentFormat.HTML); setStatus(defaultStatus(userRole)); setIsFeatured(false); setCategories(""); setTags(""); setImageUrl(""); setImageAlt(""); } }, [open, post, userRole]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!content || content === "

") { toast.error("Content cannot be empty."); return; } const body = { title: title.trim(), slug: slug.trim() || undefined, excerpt: excerpt.trim() || undefined, content, contentFormat, status: userRole !== UserRole.ADMIN ? PostStatus.DRAFT : status, isFeatured, categories: categories.trim() || undefined, tags: tags.trim() || undefined, featuredImageUrl: imageUrl || undefined, featuredImageAlt: imageAlt || undefined, }; setLoading(true); try { if (isEdit && post) { await clientFetch(`/blog-posts/${post.id}`, { method: "PATCH", body: JSON.stringify(body), }); toast.success("Post updated!"); } else { await clientFetch("/blog-posts", { method: "POST", body: JSON.stringify(body), }); toast.success("Post created!"); } onOpenChange(false); onSuccess(); } catch (err: unknown) { toast.error(err instanceof Error ? err.message : "Something went wrong"); } finally { setLoading(false); } }; const statusColor: Record = { [PostStatus.PUBLISHED]: "text-emerald-600", [PostStatus.DRAFT]: "text-zinc-500", [PostStatus.ARCHIVED]: "text-amber-600", }; return ( {/* Wide sheet — takes 60% of screen on large displays */} {/* ── Sheet header ──────────────────────────────────────────────────── */} {isEdit ? "Edit Post" : "New Post"} {isEdit ? `Editing "${post?.title}"` : "Fill in the details below and hit Publish (or save as Draft)."} {/* ── Scrollable form body ──────────────────────────────────────────── */}
{/* Title + Slug */}
setTitle(e.target.value)} placeholder="My awesome post" required className="text-base font-medium" />
setSlug(e.target.value)} placeholder="my-awesome-post" className="font-mono text-xs" />
{/* Content editor */}
{/* Excerpt */}