first commit
This commit is contained in:
222
features/category/hooks/useCategories.ts
Normal file
222
features/category/hooks/useCategories.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { apiClient } from "@/lib/api"
|
||||
import type { Category, Product, PaginatedResponse, FiltersResponse, ProductFilters } from "@/lib/types/api"
|
||||
|
||||
// Get all categories as tree
|
||||
export function useCategories(options?: { enabled?: boolean }) {
|
||||
return useQuery({
|
||||
queryKey: ["categories"],
|
||||
queryFn: async () => {
|
||||
const response = await apiClient.get<PaginatedResponse<Category>>("/categories", {
|
||||
params: { type: "tree" },
|
||||
})
|
||||
return response.data.data || response.data
|
||||
},
|
||||
enabled: options?.enabled !== false,
|
||||
staleTime: 1000 * 60 * 30, // 30 minutes
|
||||
})
|
||||
}
|
||||
|
||||
// Get single category by ID
|
||||
export function useCategory(id: number | string, options?: { enabled?: boolean }) {
|
||||
return useQuery({
|
||||
queryKey: ["category", id],
|
||||
queryFn: async () => {
|
||||
const response = await apiClient.get<Category>(`/categories/${id}`)
|
||||
return response.data
|
||||
},
|
||||
enabled: options?.enabled !== false && !!id,
|
||||
staleTime: 1000 * 60 * 15,
|
||||
})
|
||||
}
|
||||
|
||||
// Get products for a single category with pagination
|
||||
export function useCategoryProducts(
|
||||
categoryId: number | string,
|
||||
options?: {
|
||||
enabled?: boolean
|
||||
page?: number
|
||||
limit?: number
|
||||
}
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: ["category", categoryId, "products", options?.page, options?.limit],
|
||||
queryFn: async () => {
|
||||
const response = await apiClient.get<PaginatedResponse<Product>>(
|
||||
`/categories/${categoryId}/products`,
|
||||
{
|
||||
params: {
|
||||
page: options?.page || 1,
|
||||
per_page: options?.limit
|
||||
},
|
||||
}
|
||||
)
|
||||
return {
|
||||
data: response.data.data || [],
|
||||
pagination: response.data.pagination || {}
|
||||
}
|
||||
},
|
||||
enabled: options?.enabled !== false && !!categoryId,
|
||||
})
|
||||
}
|
||||
|
||||
// Get ALL products from category and its children - NO pagination (for initial load)
|
||||
export function useAllCategoryProducts(
|
||||
category: Category | undefined,
|
||||
options?: { enabled?: boolean }
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: ["category", category?.id, "all-products"],
|
||||
queryFn: async () => {
|
||||
if (!category) return []
|
||||
|
||||
const fetchProducts = async (categoryId: number) => {
|
||||
const response = await apiClient.get<PaginatedResponse<Product>>(
|
||||
`/categories/${categoryId}/products`
|
||||
)
|
||||
return response.data.data || []
|
||||
}
|
||||
|
||||
let allProducts = await fetchProducts(category.id)
|
||||
|
||||
if (category.children && category.children.length > 0) {
|
||||
for (const child of category.children) {
|
||||
const childProducts = await fetchProducts(child.id)
|
||||
allProducts = [...allProducts, ...childProducts]
|
||||
}
|
||||
}
|
||||
|
||||
return allProducts
|
||||
},
|
||||
enabled: options?.enabled !== false && !!category,
|
||||
})
|
||||
}
|
||||
|
||||
export function useCategoryFilters(
|
||||
categoryId: number | string | undefined,
|
||||
options?: { enabled?: boolean }
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: ["category-filters", categoryId],
|
||||
queryFn: async () => {
|
||||
const response = await apiClient.get<FiltersResponse>(
|
||||
"/filters",
|
||||
{
|
||||
params: { category_id: categoryId },
|
||||
}
|
||||
)
|
||||
return response.data.data
|
||||
},
|
||||
enabled: options?.enabled !== false && !!categoryId,
|
||||
staleTime: 1000 * 60 * 15,
|
||||
})
|
||||
}
|
||||
|
||||
// Get filtered category products
|
||||
export function useFilteredCategoryProducts(
|
||||
categoryId: number | string,
|
||||
filters: ProductFilters,
|
||||
options?: { enabled?: boolean }
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: ["category", categoryId, "filtered-products", filters],
|
||||
queryFn: async () => {
|
||||
const params: Record<string, any> = {
|
||||
page: filters.page || 1,
|
||||
per_page: filters.limit || 6,
|
||||
}
|
||||
|
||||
if (filters.brands && filters.brands.length > 0) {
|
||||
params.brands = filters.brands.join(',')
|
||||
}
|
||||
|
||||
if (filters.categories && filters.categories.length > 0) {
|
||||
params.categories = filters.categories.join(',')
|
||||
}
|
||||
|
||||
if (filters.min_price !== undefined) {
|
||||
params.min_price = filters.min_price
|
||||
}
|
||||
|
||||
if (filters.max_price !== undefined) {
|
||||
params.max_price = filters.max_price
|
||||
}
|
||||
|
||||
const response = await apiClient.get<PaginatedResponse<Product>>(
|
||||
`/categories/${categoryId}/products`,
|
||||
{ params }
|
||||
)
|
||||
|
||||
return {
|
||||
data: response.data.data || [],
|
||||
pagination: response.data.pagination || {}
|
||||
}
|
||||
},
|
||||
enabled: options?.enabled !== false && !!categoryId,
|
||||
})
|
||||
}
|
||||
|
||||
// Get products from category and children WITH pagination (mimics RTK getAllCategoryProductsPaginated)
|
||||
export function useAllCategoryProductsPaginated(
|
||||
category: Category | undefined,
|
||||
options?: {
|
||||
enabled?: boolean
|
||||
page?: number
|
||||
limit?: number
|
||||
}
|
||||
) {
|
||||
const page = options?.page || 1
|
||||
const per_page = options?.limit || 6
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["category", category?.id, "paginated-products", page, per_page],
|
||||
queryFn: async () => {
|
||||
if (!category) {
|
||||
return {
|
||||
data: [],
|
||||
pagination: {
|
||||
currentPage: page,
|
||||
hasMorePages: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const categoryIds = [category.id]
|
||||
if (category.children && category.children.length > 0) {
|
||||
category.children.forEach((child) => categoryIds.push(child.id))
|
||||
}
|
||||
|
||||
const perCategoryLimit = Math.ceil(per_page / categoryIds.length)
|
||||
const hasMoreByCategory: Record<number, boolean> = {}
|
||||
let allPageProducts: Product[] = []
|
||||
|
||||
for (const categoryId of categoryIds) {
|
||||
const response = await apiClient.get<PaginatedResponse<Product>>(
|
||||
`/categories/${categoryId}/products`,
|
||||
{
|
||||
params: {
|
||||
page,
|
||||
per_page: perCategoryLimit
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (response.data.data) {
|
||||
allPageProducts = [...allPageProducts, ...response.data.data]
|
||||
hasMoreByCategory[categoryId] = !!response.data.pagination?.next_page_url
|
||||
}
|
||||
}
|
||||
|
||||
const hasMorePages = Object.values(hasMoreByCategory).some((hasMore) => hasMore)
|
||||
|
||||
return {
|
||||
data: allPageProducts,
|
||||
pagination: {
|
||||
currentPage: page,
|
||||
hasMorePages
|
||||
}
|
||||
}
|
||||
},
|
||||
enabled: options?.enabled !== false && !!category,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user