diff --git a/backend/uploads/blog/1776334244817.png b/backend/uploads/blog/1776334244817.png
new file mode 100644
index 0000000..2bb00ff
Binary files /dev/null and b/backend/uploads/blog/1776334244817.png differ
diff --git a/backend/uploads/blog/1776335808164.png b/backend/uploads/blog/1776335808164.png
new file mode 100644
index 0000000..9086792
Binary files /dev/null and b/backend/uploads/blog/1776335808164.png differ
diff --git a/frontend/src/components/BytescaleUploader/BytescaleUploader.tsx b/frontend/src/components/BytescaleUploader/BytescaleUploader.tsx
index 792612f..540b793 100644
--- a/frontend/src/components/BytescaleUploader/BytescaleUploader.tsx
+++ b/frontend/src/components/BytescaleUploader/BytescaleUploader.tsx
@@ -6,7 +6,7 @@ import axios from "axios";
interface BytescaleUploaderProps {
value: string;
onChange: (url: string) => void;
- folderPath: "/doctors" | "/departments" | "/news";
+ folderPath: "/doctors" | "/departments" | "/news" | "/blog";
}
export function BytescaleUploader({
diff --git a/frontend/src/pages/BlogDetails.tsx b/frontend/src/pages/BlogDetails.tsx
index 7f4c533..5f86276 100644
--- a/frontend/src/pages/BlogDetails.tsx
+++ b/frontend/src/pages/BlogDetails.tsx
@@ -1,72 +1,202 @@
import React, {useEffect, useState} from "react";
import {useParams, useNavigate} from "react-router-dom";
-import axios from "axios";
import {Button} from "@/components/ui/button";
-import {Card, CardContent} from "@/components/ui/card";
import {getBlogByIdApi} from "@/api/blog";
+/* ---------------- LIST RENDERER ---------------- */
+const renderList = (items, style) => {
+ // ✅ Checklist
+ if (style === "checklist") {
+ return (
+
+ {items.map((item, i) => (
+
+
+
+
+ ))}
+
+ );
+ }
+
+ // ✅ Ordered / Unordered
+ const ListTag = style === "ordered" ? "ol" : "ul";
+
+ return (
+
+ {items
+ .filter((item) => item.content)
+ .map((item, i) => (
+
+
+ {item.items?.length > 0 && renderList(item.items, style)}
+
+ ))}
+
+ );
+};
+
+/* ---------------- BLOCK RENDERER ---------------- */
+const renderBlock = (block, index) => {
+ switch (block.type) {
+ case "paragraph":
+ return (
+
+ );
+
+ case "header":
+ return (
+
+ );
+
+ case "image":
+ return (
+
+ );
+
+ case "list":
+ return (
+ {renderList(block.data.items, block.data.style)}
+ );
+
+ case "quote":
+ return (
+
+ {block.data.text}
+
+ );
+
+ case "code":
+ return (
+
+ {block.data.code}
+
+ );
+
+ case "table":
+ return (
+
+
+
+ {block.data.content.map((row, i) => (
+
+ {row.map((cell, j) => (
+ |
+ ))}
+
+ ))}
+
+
+
+ );
+
+ case "delimiter":
+ return
;
+
+ default:
+ return null;
+ }
+};
+
+/* ---------------- MAIN COMPONENT ---------------- */
const BlogDetail = () => {
const {id} = useParams();
const navigate = useNavigate();
- const [blog, setBlog] = useState(null);
+ const [blog, setBlog] = useState(null);
- const fetchBlogById = async () => {
+ const fetchBlog = async () => {
try {
- const response = await getBlogByIdApi(Number(id));
-
- setBlog(response);
- } catch (error) {
- console.error("Error fetching blog", error);
+ const res = await getBlogByIdApi(Number(id));
+ console.log({res});
+ setBlog(res);
+ } catch (err) {
+ console.error("Error fetching blog", err);
}
};
useEffect(() => {
- fetchBlogById();
- }, [id]); // ✅ FIXED dependency
+ fetchBlog();
+ }, [id]);
if (!blog) {
- return Loading...
;
+ return Loading...
;
}
return (
-
-
-
- {/* Back */}
-
+
+ {/* Back Button */}
+
- {/* Title */}
-
- {blog.title}
-
+ {/* Title */}
+
{blog.title}
- {/* Meta */}
-
- {blog.writer} • {new Date(blog.createdAt).toLocaleDateString()}
-
+ {/* Meta */}
+
+ {blog.writer} • {new Date(blog.createdAt).toLocaleDateString()}
+
- {/* Image */}
-

+ {/* Image (only if exists) */}
+ {blog.image?.trim() && (
+

+ )}
- {/* Content */}
-
- {blog.content?.blocks?.map((block: any, index: number) => (
-
{block.data?.text}
- ))}
-
-
-
+ {/* Content */}
+
+ {blog.content?.blocks?.map((block, index) => renderBlock(block, index))}
+
);
};
diff --git a/frontend/src/pages/BlogEditor.tsx b/frontend/src/pages/BlogEditor.tsx
index b0e11c4..142fa78 100644
--- a/frontend/src/pages/BlogEditor.tsx
+++ b/frontend/src/pages/BlogEditor.tsx
@@ -1,6 +1,6 @@
import {useEffect, useRef, useState} from "react";
import {useNavigate, useParams} from "react-router-dom";
-
+import {BytescaleUploader} from "@/components/BytescaleUploader/BytescaleUploader";
import EditorJS, {OutputData} from "@editorjs/editorjs";
import Header from "@editorjs/header";
import List from "@editorjs/list";
@@ -117,18 +117,6 @@ export default function BlogEditorPage() {
initEditor();
}, [id, isEdit]);
- const handleCoverUpload = async (e: React.ChangeEvent) => {
- const file = e.target.files?.[0];
- if (!file) return;
-
- try {
- const res = await uploadImageApi(file);
- setCoverImage(res.file.url);
- } catch (err) {
- console.error(err);
- }
- };
-
const handleSave = async () => {
if (!editorRef.current) return;
@@ -182,7 +170,11 @@ export default function BlogEditorPage() {