diff --git a/backend/uploads/blog/1773296409367.png b/backend/uploads/blog/1773296409367.png deleted file mode 100644 index 2e53760..0000000 Binary files a/backend/uploads/blog/1773296409367.png and /dev/null differ diff --git a/backend/uploads/blog/1773298604982.png b/backend/uploads/blog/1773298604982.png deleted file mode 100644 index 7ac08ce..0000000 Binary files a/backend/uploads/blog/1773298604982.png and /dev/null differ diff --git a/backend/uploads/blog/1773298612512.png b/backend/uploads/blog/1773298612512.png deleted file mode 100644 index 2e53760..0000000 Binary files a/backend/uploads/blog/1773298612512.png and /dev/null differ diff --git a/backend/uploads/blog/1773814232254.png b/backend/uploads/blog/1773814232254.png deleted file mode 100644 index e0bbc79..0000000 Binary files a/backend/uploads/blog/1773814232254.png and /dev/null differ diff --git a/backend/uploads/blog/1773814239753.png b/backend/uploads/blog/1773814239753.png deleted file mode 100644 index 5d333f1..0000000 Binary files a/backend/uploads/blog/1773814239753.png and /dev/null differ diff --git a/backend/uploads/blog/1773814266558.png b/backend/uploads/blog/1773814266558.png deleted file mode 100644 index 5d333f1..0000000 Binary files a/backend/uploads/blog/1773814266558.png and /dev/null differ diff --git a/backend/uploads/blog/1773814356620.png b/backend/uploads/blog/1773814356620.png deleted file mode 100644 index 06e56ca..0000000 Binary files a/backend/uploads/blog/1773814356620.png and /dev/null differ diff --git a/backend/uploads/blog/1773814805822.png b/backend/uploads/blog/1773814805822.png deleted file mode 100644 index 5d333f1..0000000 Binary files a/backend/uploads/blog/1773814805822.png and /dev/null differ diff --git a/backend/uploads/blog/1776156111743.png b/backend/uploads/blog/1776156111743.png deleted file mode 100644 index 0781df1..0000000 Binary files a/backend/uploads/blog/1776156111743.png and /dev/null 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 ( + {block.data.caption + ); + + 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 */} - {blog.title} + {/* Image (only if exists) */} + {blog.image?.trim() && ( + blog + )} - {/* 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() {
    - + setCoverImage(url)} + /> {coverImage && (