Update src/hooks/useProductCatalog.ts

This commit is contained in:
2026-06-10 10:41:41 +00:00
parent 6ccf82f9ea
commit 3febfd000b

View File

@@ -1,136 +0,0 @@
import { useState, useMemo, useCallback } from "react";
import useProducts from "./useProducts";
type SortOption = "Newest" | "Price: Low-High" | "Price: High-Low";
type CatalogProduct = {
id: string;
name: string;
price: string;
imageSrc: string;
imageAlt?: string;
rating?: number;
reviewCount?: string;
category?: string;
onProductClick?: () => void;
};
type ProductVariant = {
label: string;
options: string[];
selected: string;
onChange: (value: string) => void;
};
type UseProductCatalogOptions = {
onProductClick?: (productId: string) => void;
};
const useProductCatalog = (options: UseProductCatalogOptions = {}) => {
const { onProductClick } = options;
const { products: fetchedProducts, isLoading } = useProducts();
const [search, setSearch] = useState("");
const [category, setCategory] = useState("All");
const [sort, setSort] = useState<SortOption>("Newest");
const handleProductClick = useCallback(
(productId: string) => {
onProductClick?.(productId);
},
[onProductClick]
);
const catalogProducts: CatalogProduct[] = useMemo(() => {
if (fetchedProducts.length === 0) return [];
return fetchedProducts.map((product) => ({
id: product.id,
name: product.name,
price: product.price,
imageSrc: product.imageSrc,
imageAlt: product.imageAlt || product.name,
rating: product.rating || 0,
reviewCount: product.reviewCount,
category: product.brand,
onProductClick: () => handleProductClick(product.id),
}));
}, [fetchedProducts, handleProductClick]);
const categories = useMemo(() => {
const categorySet = new Set<string>();
catalogProducts.forEach((product) => {
if (product.category) {
categorySet.add(product.category);
}
});
return Array.from(categorySet).sort();
}, [catalogProducts]);
const filteredProducts = useMemo(() => {
let result = catalogProducts;
if (search) {
const q = search.toLowerCase();
result = result.filter(
(p) =>
p.name.toLowerCase().includes(q) ||
(p.category?.toLowerCase().includes(q) ?? false)
);
}
if (category !== "All") {
result = result.filter((p) => p.category === category);
}
if (sort === "Price: Low-High") {
result = [...result].sort(
(a, b) =>
parseFloat(a.price.replace("$", "").replace(",", "")) -
parseFloat(b.price.replace("$", "").replace(",", ""))
);
} else if (sort === "Price: High-Low") {
result = [...result].sort(
(a, b) =>
parseFloat(b.price.replace("$", "").replace(",", "")) -
parseFloat(a.price.replace("$", "").replace(",", ""))
);
}
return result;
}, [catalogProducts, search, category, sort]);
const filters: ProductVariant[] = useMemo(
() => [
{
label: "Category",
options: ["All", ...categories],
selected: category,
onChange: setCategory,
},
{
label: "Sort",
options: ["Newest", "Price: Low-High", "Price: High-Low"] as SortOption[],
selected: sort,
onChange: (value) => setSort(value as SortOption),
},
],
[categories, category, sort]
);
return {
products: filteredProducts,
isLoading,
search,
setSearch,
category,
setCategory,
sort,
setSort,
filters,
categories,
};
};
export default useProductCatalog;
export type { SortOption, CatalogProduct, ProductVariant };