Can create new blogs

This commit is contained in:
cdricms
2025-02-21 19:46:36 +01:00
parent 7a97961fef
commit 4b005945b2
9 changed files with 362 additions and 99 deletions

View File

@@ -0,0 +1,141 @@
"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 from "@/hooks/use-api";
import sluggify from "@/lib/sluggify";
import { 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";
export default function BlogEditor() {
const { toast } = useToast();
const [title, setTitle] = useState("");
const [imageUrl, setImageUrl] = useState<string>("/placeholder.svg");
const content = localStorage.getItem("blog_draft") ?? "";
useEffect(() => {
const localImage = localStorage.getItem("blog_draft_image");
setImageUrl(
localImage && localImage.length > 0
? localImage
: "/placeholder.svg",
);
}, []);
const [summary, setSummary] = useState("");
const slug = useMemo(() => sluggify(title), [title]);
const {
trigger: newBlog,
isMutating: isSending,
isSuccess,
error,
} = useApiMutation<undefined, NewBlog>(
"/blogs/new",
{},
"POST",
true,
false,
);
return (
<section className="m-10 flex flex-col gap-4">
<div className="flex flex-col gap-4">
<EditableText onChange={setTitle}>
<h1>
{title.length > 0 ? title : "Un titre doit-être fourni"}
</h1>
</EditableText>
<p className="italic">{slug}</p>
<Dialog>
<DialogTrigger>
<img
src={imageUrl}
alt="Blog cover"
className="w-full h-60 object-cover cursor-pointer rounded-lg"
/>
</DialogTrigger>
<DialogTitle></DialogTitle>
<DialogContent>
<Input
type="text"
placeholder="Enter image URL"
value={imageUrl}
onChange={(e) => {
setImageUrl(e.target.value);
localStorage.setItem(
"blog_draft_image",
e.currentTarget.value,
);
}}
/>
</DialogContent>
</Dialog>
<Input
type="text"
placeholder="Enter a summary"
value={summary}
onChange={(e) => setSummary(e.target.value)}
/>
</div>
<div className="flex">
<div className="flex-1">
<LocalEditor content={content} setTitle={setTitle} />
</div>
</div>
<ActionButton
isLoading={isSending}
isSuccess={isSuccess}
error={error}
onClick={async () => {
try {
const blogContent = localStorage.getItem("blog_draft");
if (!blogContent) return;
if (title.length < 1) return;
const res = await newBlog({
title,
summary,
image: imageUrl,
slug,
content: blogContent,
});
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.",
});
}
}}
>
<ActionButtonDefault>Publier</ActionButtonDefault>
<ActionButtonSuccess />
<ActionButtonError />
<ActionButtonLoading />
</ActionButton>
</section>
);
}

View File

@@ -1,73 +1,13 @@
"use client";
import EditableText from "@/components/editable-text";
import { LocalEditor } from "@/components/editor";
import { Button } from "@/components/ui/button";
import useApiMutation from "@/hooks/use-api";
import sluggify from "@/lib/sluggify";
import { NewBlog } from "@/types/types";
import { useMemo, useState } from "react";
export default function BlogEditor() {
const [title, setTitle] = useState("");
const slug = useMemo(() => sluggify(title), [title]);
const {
trigger: newBlog,
isMutating: loading,
isSuccess,
} = useApiMutation<undefined, NewBlog>(
"/blog/new",
undefined,
"POST",
true,
false,
);
import { Loader2 } from "lucide-react";
import dynamic from "next/dynamic";
const content = localStorage.getItem("blog_draft") ?? "";
const BlogEditor = dynamic(() => import("./new").then((mod) => mod.default), {
ssr: false,
loading: () => <Loader2 className="animate-spin" />,
});
return (
<section className="m-10">
{/* This div should have a proper layout, ONLY PART TO BE MODIFIED*/}
<div>
{/*Should have an image or a placeholder that opens a dialog when clicked on to set the url of an image.*/}
<EditableText onChange={setTitle}>
<h1>{title}</h1>
</EditableText>
<p className="text-muted">{slug}</p>
{/*Should have a summary input box or textarea*/}
</div>
<div className="flex">
<div className="flex-1">
<LocalEditor content={content} setTitle={setTitle} />
</div>
</div>
<Button
className="text-black bg-white"
onClick={async () => {
try {
const blogContent = localStorage.getItem("blog_draft");
if (!blogContent) return;
if (title.length < 1) return;
const res = await newBlog({
title,
summary: "A summary",
image: "none",
slug,
content: blogContent,
});
if (!res)
throw new Error("The server hasn't responded.");
if (res.status === "Error")
throw new Error(res.message);
if (res.data) console.log(res.data);
return res;
} catch (error: any) {
throw new Error(error.message);
}
}}
>
Sauvegarder
</Button>
</section>
);
export default function Page() {
return <BlogEditor />;
}

View File

@@ -72,4 +72,8 @@ body {
body {
@apply bg-background text-foreground;
}
h1 {
@apply text-4xl font-bold;
}
}