"use client"; import EditableText from "@/components/editable-text"; import { LocalEditor } from "@/components/editor"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Dialog, DialogTrigger, DialogContent } from "@/components/ui/dialog"; import useApiMutation, { useApi } from "@/hooks/use-api"; import sluggify from "@/lib/sluggify"; import { Blog, Category, NewBlog } from "@/types/types"; import { useEffect, useMemo, useState } from "react"; import { DialogTitle } from "@radix-ui/react-dialog"; import { useToast } from "@/hooks/use-toast"; import { ActionButton, ActionButtonDefault, ActionButtonError, ActionButtonLoading, ActionButtonSuccess, } from "@/components/action-button"; import ComboBox from "@/components/ui/combobox"; export type BlogState = Partial & { [K in keyof Required]?: Blog[K] | null; // Allows null for resetting or un-setting fields }; export default function BlogEditor({ blog }: { blog?: Blog }) { const { toast } = useToast(); const setItem = (b: BlogState) => blog ? localStorage.setItem(`draft_${blog.blogID}`, JSON.stringify(b)) : localStorage.setItem("draft", JSON.stringify(b)); const [draft, setDraft] = useState(() => { if (blog) { setItem(blog); return blog; } const d = { slug: "", content: "", title: "", category: "", image: "/placeholder.svg", }; try { const _draft = localStorage.getItem("draft"); if (_draft) { const draft: BlogState = JSON.parse(_draft); return draft; } } catch (e) {} return d; }); const handleChange = (field: keyof BlogState) => (e: React.ChangeEvent | string) => { const value = typeof e === "string" ? e : e.target.value; setDraft((prev) => { const n: typeof prev = { ...prev, [field]: value, }; setItem(n); return n; }); }; const { data } = useApi( "/blogs/categories", undefined, false, false, ); const [categories, setCategories] = useState( draft.category ? [draft.category] : [], ); useEffect(() => { if (data) setCategories(data.map((c) => c.category) ?? []); }, [data]); const slug = useMemo(() => { const slug = draft.title ? sluggify(draft.title) : ""; handleChange("slug")(slug); return slug; }, [draft.title]); const newBlog = useApiMutation( "/blogs/new", {}, "POST", true, false, ); const updateBlog = useApiMutation( `/blogs/${blog?.blogID}/update`, {}, "PATCH", true, false, ); const handleNewBlog = async () => { try { if (!draft.content) return; if (!draft.title || draft.title.length < 1) return; const res = await newBlog.trigger({ title: draft.title, summary: draft.summary, image: draft.image, slug, content: draft.content, category: draft.category, }); if (!res) { toast({ title: "Aucune réponse du serveur." }); return; } if (res.status === "Error") { toast({ title: "Erreur.", content: "Une erreur est survenue.", }); } if (res.data) console.log(res.data); return res; } catch (error: any) { toast({ title: "Erreur.", content: "Une erreur est survenue.", }); } }; const handleUpdateBlog = async () => { try { if (!draft.content) return; if (!draft.title || draft.title.length < 1) return; const res = await updateBlog.trigger({ title: draft.title, summary: draft.summary, image: draft.image, slug, content: draft.content, category: draft.category, }); if (!res) { toast({ title: "Aucune réponse du serveur." }); return; } if (res.status === "Error") { toast({ title: "Erreur.", content: "Une erreur est survenue.", }); } if (res.data) console.log(res.data); return res; } catch (error: any) { toast({ title: "Erreur.", content: "Une erreur est survenue.", }); } }; return (

{draft.title && draft.title.length > 0 ? draft.title : "Un titre doit-être fourni"}

{slug}

Blog cover
( )} onSubmit={(value) => { setCategories((prev) => { if (prev.includes(value)) return prev; return [...prev, value]; }); handleChange("category")(value); }} > {(Item, element) => ( {element} )}
{blog ? "Modifier" : "Publier"}
); }