This commit is contained in:
2025-10-21 13:54:21 +07:00
parent 6c4d6c49fc
commit f89ff598a2
40 changed files with 40767 additions and 145 deletions

105
src/api/apiService.ts Normal file
View File

@@ -0,0 +1,105 @@
import { ArticleDataType } from "@/types/article";
import { ProductDataType } from "@/types/products";
const BASE_URL = process.env.NEXT_PUBLIC_API_BASE ?? "http://localhost:5000";
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
type QueryValue = string | number | boolean | null | undefined;
type QueryParams = Record<string, QueryValue | QueryValue[]>;
interface RequestOptions<TBody = unknown> {
method?: HttpMethod;
params?: QueryParams;
body?: TBody;
signal?: AbortSignal;
cache?: RequestCache;
next?: NextFetchRequestConfig;
}
export interface ListParams extends QueryParams {
limit?: number; // THÊM limit
page?: number;
offset?: number;
q?: string; // tuỳ chọn (search)
sort?: string;
categoryId?: number | string;
}
function buildURL(path: string, params?: QueryParams) {
const url = new URL(path, BASE_URL);
if (params) {
for (const [k, v] of Object.entries(params)) {
if (Array.isArray(v)) {
v.forEach((vv) => {
if (vv !== undefined && vv !== null) url.searchParams.append(k, String(vv));
});
} else if (v !== undefined && v !== null) {
url.searchParams.set(k, String(v));
}
}
}
return url.toString();
}
async function apiRequest<TResp = unknown, TBody = unknown>(
endpoint: string,
options: RequestOptions<TBody> = {}
): Promise<TResp> {
const {
method = "GET",
params,
body,
signal,
cache = "no-store",
next,
} = options;
const url = buildURL(endpoint, params);
const res = await fetch(url, {
method,
headers: { "Content-Type": "application/json" },
body: body && method !== "GET" ? JSON.stringify(body) : undefined,
signal,
cache,
next,
});
if (!res.ok) {
const msg = await res.text().catch(() => res.statusText);
throw new Error(`API ${method} ${endpoint} failed: ${res.status} ${msg}`);
}
return res.json() as Promise<TResp>;
}
// API cho bài viết
export const fetchListArticles = (params?: ListParams) =>
apiRequest<{ list: ArticleDataType[]; total?: number }>("/article", {
params,
});
// GET /articleDetails?path=:slug
export const fetchArticleDetail = (slug: string) =>
apiRequest<ArticleDataType>("/articleDetails", {
params: { path: slug },
});
// API cho công việc
export const fetchListProduct = (params?: ListParams) =>
apiRequest<{ list: ProductDataType[]; total?: number }>("/product", {
params,
});
export const fetchProductDetail = (slug: string) =>
apiRequest<ProductDataType>("/productDetails", {
params: { path: slug },
});
export const fetchProductsByCategoryId = (
categoryId: number | string,
params?: Omit<ListParams, "categoryId">
) =>
fetchListProduct({
...params,
categoryId,
});