import { BlogListResponse, BlogDetailResponse, BlogFeaturedResponse, BlogRecentResponse, CategoryListResponse, CategoryDetailResponse, TagListResponse, TagDetailResponse, BlogQueryParams, } from '../types/blog'; /** * Lấy API URL từ environment variable * Hỗ trợ cả REACT_APP_API_URL và NEXT_PUBLIC_API_URL */ const getApiUrl = (): string => { // Trong Next.js, client-side env vars cần prefix NEXT_PUBLIC_ const apiUrl = process.env.NEXT_PUBLIC_API_URL; if (!apiUrl) { console.warn('NEXT_PUBLIC_API_URL is not set. Using default http://localhost:3001'); return 'http://localhost:3001'; } return apiUrl; }; /** * Fetch blog list từ API * @param params - Query parameters (page, limit, category, tag, search) * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchBlogList = async ( params?: BlogQueryParams ): Promise => { const apiUrl = getApiUrl(); const queryParams = new URLSearchParams(); if (params?.page) queryParams.append('page', params.page.toString()); if (params?.limit) queryParams.append('limit', params.limit.toString()); if (params?.category) queryParams.append('category', params.category); if (params?.tag) queryParams.append('tag', params.tag); if (params?.search) queryParams.append('search', params.search); const queryString = queryParams.toString(); const url = `${apiUrl}/api/blog${queryString ? `?${queryString}` : ''}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: BlogListResponse = await response.json(); return data; } catch (error) { console.error('Error fetching blog list:', error); throw new Error( `Failed to fetch blog list: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch blog detail by slug từ API * @param slug - Blog post slug * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchBlogDetail = async ( slug: string ): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/${slug}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { if (response.status === 404) { throw new Error('Blog post not found'); } throw new Error(`HTTP error! status: ${response.status}`); } const data: BlogDetailResponse = await response.json(); return data; } catch (error) { console.error('Error fetching blog detail:', error); throw new Error( `Failed to fetch blog detail: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch featured blogs từ API * @param limit - Số lượng blog featured (default: 3) * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchFeaturedBlogs = async ( limit: number = 5 ): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/featured?limit=${limit}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: BlogFeaturedResponse = await response.json(); return data; } catch (error) { console.error('Error fetching featured blogs:', error); throw new Error( `Failed to fetch featured blogs: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch recent blogs từ API * @param limit - Số lượng blog recent (default: 5) * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchRecentBlogs = async ( limit: number = 5 ): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/recent?limit=${limit}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: BlogRecentResponse = await response.json(); return data; } catch (error) { console.error('Error fetching recent blogs:', error); throw new Error( `Failed to fetch recent blogs: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch categories list từ API * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchCategories = async (): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/categories`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: CategoryListResponse = await response.json(); return data; } catch (error) { console.error('Error fetching categories:', error); throw new Error( `Failed to fetch categories: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch category detail by slug từ API * @param slug - Category slug * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchCategoryDetail = async ( slug: string ): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/categories/${slug}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { if (response.status === 404) { throw new Error('Category not found'); } throw new Error(`HTTP error! status: ${response.status}`); } const data: CategoryDetailResponse = await response.json(); return data; } catch (error) { console.error('Error fetching category detail:', error); throw new Error( `Failed to fetch category detail: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch tags list từ API * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchTags = async (): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/tags`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: TagListResponse = await response.json(); return data; } catch (error) { console.error('Error fetching tags:', error); throw new Error( `Failed to fetch tags: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch popular tags từ API * @param limit - Số lượng tags (default: 10) * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchPopularTags = async ( limit: number = 10 ): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/tags/popular?limit=${limit}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: TagListResponse = await response.json(); return data; } catch (error) { console.error('Error fetching popular tags:', error); throw new Error( `Failed to fetch popular tags: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch tag detail by slug từ API * @param slug - Tag slug * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchTagDetail = async ( slug: string ): Promise => { const apiUrl = getApiUrl(); const url = `${apiUrl}/api/blog/tags/${slug}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', }, // Không cache - luôn fetch dữ liệu mới nhất cache: 'no-store', }); if (!response.ok) { if (response.status === 404) { throw new Error('Tag not found'); } throw new Error(`HTTP error! status: ${response.status}`); } const data: TagDetailResponse = await response.json(); return data; } catch (error) { console.error('Error fetching tag detail:', error); throw new Error( `Failed to fetch tag detail: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }; /** * Fetch blogs by category từ API * @param categorySlug - Category slug * @param params - Query parameters (page, limit) * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchBlogsByCategory = async ( categorySlug: string, params?: Omit ): Promise => { // Lấy category name từ slug const categoryResponse = await fetchCategoryDetail(categorySlug); const categoryName = categoryResponse.data.name; return fetchBlogList({ ...params, category: categoryName, }); }; /** * Fetch blogs by tag từ API * @param tagSlug - Tag slug * @param params - Query parameters (page, limit) * @returns Promise * @throws Error nếu fetch thất bại */ export const fetchBlogsByTag = async ( tagSlug: string, params?: Omit ): Promise => { // Lấy tag name từ slug const tagResponse = await fetchTagDetail(tagSlug); const tagName = tagResponse.data.name; return fetchBlogList({ ...params, tag: tagName, }); };