From 6320cc07848df118493a235f76f58bf4686b90eb Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Mon, 14 Apr 2025 16:41:25 +0330 Subject: [PATCH] blog --- src/app/blogs/components/Category.tsx | 36 +++++++++++--- src/app/blogs/components/HeroSection.tsx | 59 +++++++++++++++-------- src/app/blogs/components/MiniBlogItem.tsx | 10 ++-- src/app/blogs/components/MostVisited.tsx | 10 ++-- src/app/blogs/hooks/useBlogsData.ts | 39 +++++++++++++-- src/app/blogs/page.tsx | 5 +- src/app/blogs/service/BlogService.ts | 20 +++++++- src/app/blogs/store/BlogStore.ts | 9 ++++ src/app/blogs/types/BlogTypes.ts | 32 +++++++++--- src/shared/types/SharedTypes.ts | 6 +++ 10 files changed, 176 insertions(+), 50 deletions(-) create mode 100644 src/app/blogs/store/BlogStore.ts diff --git a/src/app/blogs/components/Category.tsx b/src/app/blogs/components/Category.tsx index 27e2a85..7f4677a 100644 --- a/src/app/blogs/components/Category.tsx +++ b/src/app/blogs/components/Category.tsx @@ -1,7 +1,14 @@ import { clx } from '@/helpers/utils' import { FC } from 'react' - +import { useGetBlogCategories } from '../hooks/useBlogsData' +import Image from 'next/image' +import { useBlogStore } from '../store/BlogStore' const Category: FC = () => { + const { data } = useGetBlogCategories() + const { selectedCategory, setSelectedCategory } = useBlogStore() + + console.log(data); + return (

@@ -10,16 +17,29 @@ const Category: FC = () => {
+ 'h-10 bg-[#ECEFF6] rounded-xl p-2.5 flex items-center gap-2 ', + selectedCategory === "" ? 'bg-black text-white' : '' + )} onClick={() => setSelectedCategory("")}>
همه
-
-
-
تکنولوژی
-
+ { + data?.data?.categories?.map((item) => { + return ( +
setSelectedCategory(item.id)}> +
+ {item.title} +
+
{item.title}
+
+ ) + }) + } + +

) diff --git a/src/app/blogs/components/HeroSection.tsx b/src/app/blogs/components/HeroSection.tsx index b5b1305..515371b 100644 --- a/src/app/blogs/components/HeroSection.tsx +++ b/src/app/blogs/components/HeroSection.tsx @@ -1,34 +1,53 @@ import BlogItem from '@/components/BlogItem' import Image from 'next/image' import { FC } from 'react' +import { useGetBlogCombined } from '../hooks/useBlogsData' const HeroSection: FC = () => { + + const { data } = useGetBlogCombined() + return (
-
- banner + { + data?.data?.pinnedBlogs?.map((item, index: number) => { + if (index === 0) { + return ( +
+ {item.title} -
-

- سفارش نرم‌افزار اختصاصی: سرمایه‌ای برای آینده یا فقط هزینه‌ای برای امروز؟ -

+
+

+ {item.title} +

+ +

+ {item.previewContent} +

+
+
+ ) + } + }) + } -

- لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه...لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه... -

-
-
- - - + { + data?.data?.mostVisitedBlogs?.map((item, index: number) => { + if (index !== 0) { + return ( + + ) + } + }) + }
) diff --git a/src/app/blogs/components/MiniBlogItem.tsx b/src/app/blogs/components/MiniBlogItem.tsx index d2a552f..681b8df 100644 --- a/src/app/blogs/components/MiniBlogItem.tsx +++ b/src/app/blogs/components/MiniBlogItem.tsx @@ -1,18 +1,18 @@ import Image from 'next/image' import { FC } from 'react' - -const MiniBlogItem: FC = () => { +import { Blog } from '../types/BlogTypes' +const MiniBlogItem: FC<{ item: Blog }> = ({ item }) => { return (
blog
- سفارش نرم‌افزار اختصاصی: سرمایه‌ای برای آینده یا فقط هزینه‌ای برای امروز؟ + {item.title}
) diff --git a/src/app/blogs/components/MostVisited.tsx b/src/app/blogs/components/MostVisited.tsx index e9df34a..c9cd835 100644 --- a/src/app/blogs/components/MostVisited.tsx +++ b/src/app/blogs/components/MostVisited.tsx @@ -1,7 +1,9 @@ import { FC } from 'react' import MiniBlogItem from './MiniBlogItem' +import { useGetBlogCombined } from '../hooks/useBlogsData' const MostVisited: FC = () => { + const { data } = useGetBlogCombined() return (

@@ -9,9 +11,11 @@ const MostVisited: FC = () => {

- - - + { + data?.data?.mostVisitedBlogs?.map((item) => { + return + }) + }
) diff --git a/src/app/blogs/hooks/useBlogsData.ts b/src/app/blogs/hooks/useBlogsData.ts index a0ce630..5905755 100644 --- a/src/app/blogs/hooks/useBlogsData.ts +++ b/src/app/blogs/hooks/useBlogsData.ts @@ -1,15 +1,48 @@ import { useQuery } from "@tanstack/react-query"; -import { getBlogs } from "../service/BlogService"; +import * as api from "../service/BlogService"; // برای client export const useGetBlogs = () => useQuery({ queryKey: ["blogs"], - queryFn: getBlogs, + queryFn: api.getBlogs, + }); + +export const useGetBlogsPinned = () => + useQuery({ + queryKey: ["blogs-pinned"], + queryFn: api.getBlogsPinned, + }); + +export const useGetBlogCategories = () => + useQuery({ + queryKey: ["blog-categories"], + queryFn: api.getBlogCategories, + }); + +export const useGetBlogCombined = () => + useQuery({ + queryKey: ["blog-combined"], + queryFn: api.getCombinedBlogs, }); // برای server prefetch export const blogsQueryOptions = { queryKey: ["blogs"], - queryFn: getBlogs, + queryFn: api.getBlogs, +}; + +export const blogsPinnedQueryOptions = { + queryKey: ["blogs-pinned"], + queryFn: api.getBlogsPinned, +}; + +export const blogCategoriesQueryOptions = { + queryKey: ["blog-categories"], + queryFn: api.getBlogCategories, +}; + +export const blogCombinedQueryOptions = { + queryKey: ["blog-combined"], + queryFn: api.getCombinedBlogs, }; diff --git a/src/app/blogs/page.tsx b/src/app/blogs/page.tsx index 937828d..839d396 100644 --- a/src/app/blogs/page.tsx +++ b/src/app/blogs/page.tsx @@ -1,7 +1,7 @@ import { HydrationBoundary, dehydrate } from '@tanstack/react-query' import { QueryClient } from '@tanstack/react-query' import BlogList from './components/BlogList' -import { blogsQueryOptions } from './hooks/useBlogsData' +import { blogCategoriesQueryOptions, blogsQueryOptions, blogCombinedQueryOptions } from './hooks/useBlogsData' export const metadata = { title: 'مجله داناک | مقالات و آموزش‌ها', @@ -9,8 +9,11 @@ export const metadata = { } export default async function BlogsPage() { + const queryClient = new QueryClient() await queryClient.prefetchQuery(blogsQueryOptions) + await queryClient.prefetchQuery(blogCategoriesQueryOptions) + await queryClient.prefetchQuery(blogCombinedQueryOptions) return ( diff --git a/src/app/blogs/service/BlogService.ts b/src/app/blogs/service/BlogService.ts index e94e0fe..9f6f543 100644 --- a/src/app/blogs/service/BlogService.ts +++ b/src/app/blogs/service/BlogService.ts @@ -1,5 +1,9 @@ import axios from "@/config/axios"; -import { BlogResponse } from "../types/BlogTypes"; +import { + BlogCategoryResponse, + BlogCombinedResponse, + BlogResponse, +} from "../types/BlogTypes"; export const getBlogs = async () => { const { data } = await axios.get(`/blogs`); @@ -7,6 +11,18 @@ export const getBlogs = async () => { }; export const getBlogCategories = async () => { - const { data } = await axios.get(`/blogs/categories/public`); + const { data } = await axios.get( + `/blogs/categories/public` + ); + return data; +}; + +export const getBlogsPinned = async () => { + const { data } = await axios.get(`/blogs/pinned`); + return data; +}; + +export const getCombinedBlogs = async () => { + const { data } = await axios.get(`/blogs/combined`); return data; }; diff --git a/src/app/blogs/store/BlogStore.ts b/src/app/blogs/store/BlogStore.ts new file mode 100644 index 0000000..ebb84b9 --- /dev/null +++ b/src/app/blogs/store/BlogStore.ts @@ -0,0 +1,9 @@ +import { create } from "zustand"; +import { BlogStoreType } from "../types/BlogTypes"; + +export const useBlogStore = create((set) => ({ + selectedCategory: "", + setSelectedCategory(value) { + set({ selectedCategory: value }); + }, +})); diff --git a/src/app/blogs/types/BlogTypes.ts b/src/app/blogs/types/BlogTypes.ts index 1eb0975..b19961b 100644 --- a/src/app/blogs/types/BlogTypes.ts +++ b/src/app/blogs/types/BlogTypes.ts @@ -1,3 +1,5 @@ +import { ApiResponse } from "@/shared/types/SharedTypes"; + export interface Author { id: string; firstName: string; @@ -33,11 +35,25 @@ export interface Pager { nextPage: boolean; } -export interface BlogResponse { - statusCode: number; - success: boolean; - data: { - pager: Pager; - blogs: Blog[]; - }; -} +export type BlogResponse = ApiResponse<{ + pager: Pager; + blogs: Blog[]; +}>; + +export type BlogPinnedResponse = ApiResponse<{ + blogs: Blog[]; +}>; + +export type BlogCategoryResponse = ApiResponse<{ + categories: Category[]; +}>; + +export type BlogCombinedResponse = ApiResponse<{ + pinnedBlogs: Blog[]; + mostVisitedBlogs: Blog[]; +}>; + +export type BlogStoreType = { + selectedCategory: string; + setSelectedCategory: (category: string) => void; +}; diff --git a/src/shared/types/SharedTypes.ts b/src/shared/types/SharedTypes.ts index b681e51..9b68393 100644 --- a/src/shared/types/SharedTypes.ts +++ b/src/shared/types/SharedTypes.ts @@ -2,3 +2,9 @@ export type SharedStoreType = { openSidebar: boolean; setOpenSidebar: (value: boolean) => void; }; + +export interface ApiResponse { + statusCode: number; + success: boolean; + data: T; +}