"use client"; import { useEffect, useState, useMemo, useCallback } from "react"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Skeleton } from "@/components/ui/skeleton"; import { useTranslations } from "next-intl"; import type { Product } from "@/lib/types/api"; import { useFilteredSearchProducts } from "@/features/search/hooks/useSearch"; import { useCategoryFilters } from "@/features/category/hooks/useCategories"; import CategoryFilters from "@/features/category/components/CategoryFilters"; import CategoryProductsGrid from "@/features/category/components/CategoryProductsGrid"; import CategoryFiltersSheet from "@/features/category/components/CategoryFiltersSheet"; import ErrorPage from "@/components/ErrorPage"; interface SearchPageClientProps { params: { locale: string }; searchParams: { q?: string }; } export default function SearchPageClient({ params, searchParams, }: SearchPageClientProps) { const q = searchParams.q || ""; const t = useTranslations(); const [isSheetOpen, setIsSheetOpen] = useState(false); // State management const [currentPage, setCurrentPage] = useState(1); const [allProducts, setAllProducts] = useState([]); const [priceSort, setPriceSort] = useState< "none" | "lowToHigh" | "highToLow" >("none"); const [priceRange, setPriceRange] = useState<[number, number]>([0, 100000]); const [selectedBrands, setSelectedBrands] = useState>(new Set()); const [selectedFilterCategories, setSelectedFilterCategories] = useState< Set >(new Set()); // Fetch filters (we use generic filters for search page) const { data: filtersData, isLoading: filtersLoading, isError: filtersError, } = useCategoryFilters(undefined); // Build filter params const filterParams = useMemo(() => { const params: any = { page: currentPage, limit: 12, }; if (selectedBrands.size > 0) { params.brands = Array.from(selectedBrands); } if (selectedFilterCategories.size > 0) { params.categories = Array.from(selectedFilterCategories); } params.min_price = priceRange[0]; params.max_price = priceRange[1]; return params; }, [currentPage, selectedBrands, selectedFilterCategories, priceRange]); // Fetch filtered search products const { data: productsData, isFetching, isError: productsError, } = useFilteredSearchProducts(q, filterParams); // Reset on search term change useEffect(() => { setAllProducts([]); setCurrentPage(1); setSelectedBrands(new Set()); setSelectedFilterCategories(new Set()); setPriceRange([0, 100000]); setPriceSort("none"); }, [q]); // Update products list useEffect(() => { if (productsData?.data) { setAllProducts((prev) => { if (currentPage === 1) { return productsData.data; } const existingIds = new Set(prev.map((p) => p.id)); const newProducts = productsData.data.filter( (p: Product) => !existingIds.has(p.id), ); if (newProducts.length === 0) { return prev; } return [...prev, ...newProducts]; }); } }, [productsData?.data, currentPage]); const hasMore = useMemo(() => { if (!productsData?.pagination) return false; if (productsData.pagination.next_page_url) return true; if ( productsData.pagination.current_page && productsData.pagination.last_page ) { return ( productsData.pagination.current_page < productsData.pagination.last_page ); } return productsData.pagination.hasMorePages ?? false; }, [productsData?.pagination]); const loadMoreData = useCallback(() => { if (!hasMore || isFetching) return; setCurrentPage((prev) => prev + 1); }, [hasMore, isFetching]); const sortedProducts = useMemo(() => { const products = [...allProducts]; if (priceSort === "lowToHigh") { return products.sort( (a, b) => parseFloat(a.price_amount || "0") - parseFloat(b.price_amount || "0"), ); } if (priceSort === "highToLow") { return products.sort( (a, b) => parseFloat(b.price_amount || "0") - parseFloat(a.price_amount || "0"), ); } return products; }, [allProducts, priceSort]); // Filter handlers const handleBrandToggle = useCallback((brandId: number) => { setSelectedBrands((prev) => { const newSet = new Set(prev); newSet.has(brandId) ? newSet.delete(brandId) : newSet.add(brandId); return newSet; }); setCurrentPage(1); setAllProducts([]); }, []); const handleCategoryToggle = useCallback((categoryId: number) => { setSelectedFilterCategories((prev) => { const newSet = new Set(prev); newSet.has(categoryId) ? newSet.delete(categoryId) : newSet.add(categoryId); return newSet; }); setCurrentPage(1); setAllProducts([]); }, []); const handlePriceChange = useCallback((values: number[]) => { setPriceRange([values[0], values[1]]); setCurrentPage(1); setAllProducts([]); }, []); const handlePriceSortChange = useCallback( (sortType: "none" | "lowToHigh" | "highToLow") => { setPriceSort(sortType); }, [], ); const resetFilters = useCallback(() => { setSelectedBrands(new Set()); setSelectedFilterCategories(new Set()); setPriceRange([0, 100000]); setPriceSort("none"); setCurrentPage(1); setAllProducts([]); }, []); const filterTranslations = useMemo( () => ({ category: t("category"), brands: t("brands"), sort: t("sort"), default: t("default"), price_low_to_high: t("price_low_to_high"), price_high_to_low: t("price_high_to_low"), price: t("price"), price_from: t("price_from"), price_to: t("price_to"), reset: t("reset"), }), [t], ); if (productsError) { return ; } return (

{t("search_results")}: "{q}"

{productsData?.pagination?.total || allProducts.length}{" "} {t("products_found")}

{/* Products Grid */}
); }