diff --git a/api/axiosInstance.ts b/api/axiosInstance.ts new file mode 100644 index 00000000..47f2040b --- /dev/null +++ b/api/axiosInstance.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; + +const axiosInstance = axios.create({ + baseURL: 'https://dummyjson.com', +}); + +export default axiosInstance; diff --git a/api/endpoints.ts b/api/endpoints.ts new file mode 100644 index 00000000..4116945c --- /dev/null +++ b/api/endpoints.ts @@ -0,0 +1,9 @@ +const API_BASE_URL = 'https://dummyjson.com'; + +const ENDPOINTS = { + BLOGS: { + GET_ALL: (limit: number, skip: number) => `${API_BASE_URL}/posts?limit=${limit}&skip=${skip}`, + }, +}; + +export default ENDPOINTS; diff --git a/api/queries/blogs/getBlogs.ts b/api/queries/blogs/getBlogs.ts new file mode 100644 index 00000000..bbe14161 --- /dev/null +++ b/api/queries/blogs/getBlogs.ts @@ -0,0 +1,17 @@ +import { useQuery } from '@tanstack/react-query'; +import fetchBlogPosts from '../../../app/action'; +import QUERY_KEYS from '../../queryKeys'; + +interface GetBlogsParams { + pageTitle: string; + blogCardsNumber: number; +} + +const useGetBlogs = ({ pageTitle, blogCardsNumber }: GetBlogsParams) => { + return useQuery({ + queryKey: [...QUERY_KEYS.BLOGS.ALL, pageTitle, blogCardsNumber], + queryFn: () => fetchBlogPosts(0, pageTitle, blogCardsNumber), + }); +}; + +export default useGetBlogs; diff --git a/api/queries/blogs/getInfiniteBlogs.ts b/api/queries/blogs/getInfiniteBlogs.ts new file mode 100644 index 00000000..0fad43da --- /dev/null +++ b/api/queries/blogs/getInfiniteBlogs.ts @@ -0,0 +1,32 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import QUERY_KEYS from '../../queryKeys'; +import fetchBlogPosts from '../../../app/action'; +import { BlogCardProps } from '../../../components/reusable-components/blog-card/BlogCard'; + +interface GetInfiniteBlogsParams { + pageTitle: string; + blogCardsNumber: number; +} +const useGetInfiniteBlogs = ({ pageTitle, blogCardsNumber }: GetInfiniteBlogsParams) => { + return useInfiniteQuery< + BlogCardProps[], + Error, + BlogCardProps[], + [string, string, string, string], + number + >({ + queryKey: [ + QUERY_KEYS.BLOGS.INFINITE[0], + QUERY_KEYS.BLOGS.INFINITE[1], + pageTitle, + blogCardsNumber.toString(), + ], + queryFn: ({ pageParam }) => fetchBlogPosts(pageParam, pageTitle, blogCardsNumber), + initialPageParam: 0, + getNextPageParam: (lastPage, allPages) => { + return lastPage.length === blogCardsNumber ? allPages.length * blogCardsNumber : undefined; + }, + }); +}; + +export default useGetInfiniteBlogs; diff --git a/api/queryKeys.ts b/api/queryKeys.ts new file mode 100644 index 00000000..54cd1317 --- /dev/null +++ b/api/queryKeys.ts @@ -0,0 +1,8 @@ +const QUERY_KEYS = { + BLOGS: { + ALL: ['blogPosts'], + INFINITE: ['infiniteBlogPosts', 'infinite'] as const, + }, +} as const; + +export default QUERY_KEYS; diff --git a/app/action.tsx b/app/action.tsx index 6a4feb8f..23d8a7f9 100644 --- a/app/action.tsx +++ b/app/action.tsx @@ -1,16 +1,29 @@ 'use server'; -const fetchBlogPosts = async (nextPosts: number, pageTitle: string, blogCardsNumber: number) => { - try { - const response = await fetch( - `https://dummyjson.com/posts?limit=${blogCardsNumber}&skip=${nextPosts}` - ); - - const data = await response.json(); +import axios from 'axios'; +import axiosInstance from '../api/axiosInstance'; +import { BlogCardProps } from '../components/reusable-components/blog-card/BlogCard'; - return data?.posts; +const fetchBlogPosts = async ( + nextPosts: number, + pageTitle: string, + blogCardsNumber: number +): Promise => { + try { + const { data } = await axiosInstance.get('/posts', { + params: { + limit: blogCardsNumber, + skip: nextPosts, + }, + }); + return data.posts; } catch (error: any) { - throw new Error(error); + if (axios.isAxiosError(error)) { + throw new Error( + error.response?.data?.message || 'An error occurred while fetching blog posts' + ); + } + throw new Error('An unexpected error occurred'); } };