feat(blog): enhance blog data handling with normalization and improved image management

This commit is contained in:
hamed
2026-06-19 00:35:11 +03:30
parent 4dca516598
commit e9136ea42b
10 changed files with 77 additions and 71 deletions
+4 -3
View File
@@ -1,16 +1,17 @@
import React from "react";
import Image from "next/image";
import { sanitizeHtml } from "@/lib/sanitize";
import { imageUrl } from "@/helper";
function Caption({ data }) {
const imageUrl = data?.images?.[0]?.url;
const cover = data?.images?.[0]?.url ? imageUrl(data.images[0].url) : "";
return (
<>
{imageUrl && imageUrl.trim() !== "" && (
{cover && cover.trim() !== "" && (
<div className="relative w-full aspect-video rounded-[8px] overflow-hidden">
<Image
src={imageUrl}
src={cover}
alt={data?.title || "blog cover"}
fill
className="object-cover"
+6 -6
View File
@@ -2,24 +2,24 @@ import CircularLoading from "@/app/component/loading/Circular";
import CustomLoading from "@/app/component/loading/Custom";
import TextLoading from "@/app/component/loading/Text";
import Link from "next/link";
import { convertTimestampToJalali } from "@/helper";
import { convertTimestampToJalali, imageUrl } from "@/helper";
function Item({ data, idx, loading }) {
const imageUrl = data?.images?.[0]?.url;
const cover = data?.images?.[0]?.url ? imageUrl(data.images[0].url) : "";
const createdDate = data?.created ? convertTimestampToJalali(data.created) : "";
return (
<li className="flex relative items-center justify-start gap-[8px] py-[12px] sm:py-[15px] md:py-[18px] lg:py-[20px]">
<CustomLoading width={80} height={72} loading={loading}>
<Link href={`/blog/${data.uuid}`}>
{imageUrl && imageUrl.trim() !== "" ? (
{cover && cover.trim() !== "" ? (
<img
className="
w-[64px] sm:w-[73px] md:w-[85px] lg:w-[97px]
h-[56px] sm:h-[64px] md:h-[75px] lg:h-[88px]
w-[64px] sm:w-[73px] md:w-[85px] lg:w-[97px]
h-[56px] sm:h-[64px] md:h-[75px] lg:h-[88px]
rounded-[8px] overflow-hidden object-cover
"
src={imageUrl}
src={cover}
alt={data.title || "article"}
/>
) : (
+2 -2
View File
@@ -11,9 +11,9 @@ function RelatedContent({ data, loading }) {
</AnimationTextHead>
<ul className="flex w-full lg:w-fit flex-col justify-start items-start">
{data &&
data.length &&
data.length > 0 &&
data?.map((item, idx) => (
<Item idx={idx} data={item} key={item.id} loading={loading} />
<Item idx={idx} data={item} key={item.uuid} loading={loading} />
))}
</ul>
</div>
+7 -35
View File
@@ -1,39 +1,13 @@
"use client";
import { useState, useEffect } from "react";
import CustomLoading from "@/app/component/loading/Custom";
import TextLoading from "@/app/component/loading/Text";
import Link from "next/link";
import { request } from "@/services/response";
// نمایش «بلاگ‌های برتر» فعلاً غیرفعال است (endpoint /api/v1/blogs/top در بک‌اند وجود ندارد).
// markup زیر برای فعال‌سازی بعدی نگه داشته شده؛ تا آن زمان کامپوننت چیزی رندر نمی‌کند.
function Head() {
const [topBlogs, setTopBlogs] = useState([]);
const [isLoading, setIsLoading] = useState(true);
return null;
}
useEffect(() => {
const fetchTopBlogs = async () => {
try {
setIsLoading(true);
const response = await request.getTopBlogs();
setTopBlogs(response || []);
} catch (error) {
console.error("Error fetching top blogs:", error);
setTopBlogs([]);
} finally {
setIsLoading(false);
}
};
fetchTopBlogs();
}, []);
if (isLoading || topBlogs.length === 0) {
return null;
}
const [firstBlog, secondBlog, thirdBlog, fourthBlog] = topBlogs;
return (
<>{/*
/* eslint-disable */
/*
<div className="flex flex-col lg:flex-row mt-[40px] items-center justify-center gap-[16px] sm:gap-[19px] md:gap-[22px] lg:gap-[24px]">
{firstBlog && (
<Link href={`/blog/${firstBlog.uuid}`} className="w-full lg:w-1/2 cover-head-blogs">
@@ -104,8 +78,6 @@ function Head() {
)}
</div>
</div>
*/}</>
);
}
*/
export default Head;
+3 -2
View File
@@ -5,6 +5,7 @@ import Head from "./Head";
import Title from "./title";
import LatestArticles from "./latestArticles";
import { request } from "@/services/response";
import { normalizeBlog } from "@/helper";
function BlogsPage() {
const [blogs, setBlogs] = useState([]);
@@ -25,8 +26,8 @@ function BlogsPage() {
params.tag = selectedTag;
}
const response = await request.getBlogs(params);
setBlogs(response.blogs || []);
setTotalPages(response.page?.totalPages || 1);
setBlogs((response?.data || []).map(normalizeBlog));
setTotalPages(response?.meta?.totalPages || 1);
} catch (error) {
console.error("Error fetching blogs:", error);
setBlogs([]);
+4 -2
View File
@@ -2,10 +2,12 @@ import CustomLoading from "@/app/component/loading/Custom";
import TextLoading from "@/app/component/loading/Text";
import Image from "next/image";
import Link from "next/link";
import { convertTimestampToJalali } from "@/helper";
import { convertTimestampToJalali, imageUrl } from "@/helper";
function Article({ data }) {
const imageSrc = data.images?.[0]?.url || "/assets/images/default-blog.jpg";
const imageSrc = data.images?.[0]?.url
? imageUrl(data.images[0].url, "/assets/images/cover-blog-1.png")
: "/assets/images/cover-blog-1.png";
const createdDate = data.created ? convertTimestampToJalali(data.created) : "";
return (
+1 -1
View File
@@ -15,7 +15,7 @@ function Title({ onTagChange }) {
limit: 100,
};
const response = await request.getBlogTags(params);
setTags(response.data || []);
setTags(response?.data?.data || []);
} catch (error) {
console.error("Error fetching tags:", error);
setTags([]);