forked from UKSOURCE/ipv6
324 lines
7.8 KiB
TypeScript
324 lines
7.8 KiB
TypeScript
import {
|
|
BlogListResponse,
|
|
BlogDetailResponse,
|
|
BlogFeaturedResponse,
|
|
BlogRecentResponse,
|
|
CategoryListResponse,
|
|
CategoryDetailResponse,
|
|
TagListResponse,
|
|
TagDetailResponse,
|
|
BlogQueryParams,
|
|
} from '../types/blog';
|
|
|
|
/**
|
|
* Lấy API URL từ environment variable
|
|
*/
|
|
const getApiUrl = (): string | null => {
|
|
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
|
|
// Nếu chưa cấu hình API URL, trả về null để skip việc gọi API (tránh lỗi fetch failed)
|
|
if (!apiUrl) {
|
|
return null;
|
|
}
|
|
return apiUrl;
|
|
};
|
|
|
|
/**
|
|
* Fetch blog list từ API, trả về null nếu thất bại (để caller fallback sang local JSON)
|
|
*/
|
|
export const fetchBlogList = async (
|
|
params?: BlogQueryParams
|
|
): Promise<BlogListResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
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' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: BlogListResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch blog detail by slug từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchBlogDetail = async (
|
|
slug: string
|
|
): Promise<BlogDetailResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/${slug}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: BlogDetailResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch featured blogs từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchFeaturedBlogs = async (
|
|
limit: number = 5
|
|
): Promise<BlogFeaturedResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/featured?limit=${limit}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: BlogFeaturedResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch recent blogs từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchRecentBlogs = async (
|
|
limit: number = 5
|
|
): Promise<BlogRecentResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/recent?limit=${limit}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: BlogRecentResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch categories list từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchCategories = async (): Promise<CategoryListResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/categories`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: CategoryListResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch category detail by slug từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchCategoryDetail = async (
|
|
slug: string
|
|
): Promise<CategoryDetailResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/categories/${slug}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: CategoryDetailResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch tags list từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchTags = async (): Promise<TagListResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/tags`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: TagListResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch popular tags từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchPopularTags = async (
|
|
limit: number = 10
|
|
): Promise<TagListResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/tags/popular?limit=${limit}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: TagListResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch tag detail by slug từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchTagDetail = async (
|
|
slug: string
|
|
): Promise<TagDetailResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const url = `${apiUrl}/api/blog/tags/${slug}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data: TagDetailResponse = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch blogs by category từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchBlogsByCategory = async (
|
|
categorySlug: string,
|
|
params?: Omit<BlogQueryParams, 'category'>
|
|
): Promise<BlogListResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const categoryResponse = await fetchCategoryDetail(categorySlug);
|
|
if (!categoryResponse) return null;
|
|
|
|
const categoryName = categoryResponse.data.name;
|
|
return fetchBlogList({ ...params, category: categoryName });
|
|
};
|
|
|
|
/**
|
|
* Fetch blogs by tag từ API, trả về null nếu thất bại
|
|
*/
|
|
export const fetchBlogsByTag = async (
|
|
tagSlug: string,
|
|
params?: Omit<BlogQueryParams, 'tag'>
|
|
): Promise<BlogListResponse | null> => {
|
|
const apiUrl = getApiUrl();
|
|
if (!apiUrl) return null;
|
|
|
|
const tagResponse = await fetchTagDetail(tagSlug);
|
|
if (!tagResponse) return null;
|
|
|
|
const tagName = tagResponse.data.name;
|
|
return fetchBlogList({ ...params, tag: tagName });
|
|
};
|