Spaces:
Running
Running
import { useState, useEffect } from "react"; | |
import { useLocation } from "wouter"; | |
import { useQuery } from "@tanstack/react-query"; | |
import { productsApi, categoriesApi } from "@/lib/api"; | |
import Header from "@/components/layout/header"; | |
import ProductCard from "@/components/product/product-card"; | |
import { Button } from "@/components/ui/button"; | |
import { Skeleton } from "@/components/ui/skeleton"; | |
import { ArrowLeft } from "lucide-react"; | |
import { LoadingSpinner } from "@/components/ui/spinner"; | |
export default function SearchResults() { | |
const [, setLocation] = useLocation(); | |
const [searchQuery, setSearchQuery] = useState(""); | |
const [selectedCategory, setSelectedCategory] = useState<string>(""); | |
// Get search parameters from URL | |
useEffect(() => { | |
const urlParams = new URLSearchParams(window.location.search); | |
const query = urlParams.get('q') || ''; | |
const category = urlParams.get('category') || ''; | |
setSearchQuery(query); | |
setSelectedCategory(category); | |
}, []); | |
// Update URL when search parameters change | |
useEffect(() => { | |
const params = new URLSearchParams(); | |
if (searchQuery) params.set('q', searchQuery); | |
if (selectedCategory) params.set('category', selectedCategory); | |
const newUrl = `/search${params.toString() ? '?' + params.toString() : ''}`; | |
window.history.replaceState({}, '', newUrl); | |
}, [searchQuery, selectedCategory]); | |
const { data: categories = [], isLoading: categoriesLoading } = useQuery({ | |
queryKey: ['/api/categories'], | |
queryFn: () => categoriesApi.getAll(), | |
}); | |
const { data: searchResults = [], isLoading: searchLoading } = useQuery({ | |
queryKey: ['/api/products', { search: searchQuery, category: selectedCategory }], | |
queryFn: () => productsApi.getAll({ | |
...(searchQuery && { search: searchQuery }), | |
...(selectedCategory && { category: selectedCategory }) | |
}), | |
enabled: !!(searchQuery || selectedCategory), | |
}); | |
const getPageTitle = () => { | |
if (searchQuery && selectedCategory) { | |
const categoryName = categories.find((c: any) => c.id === selectedCategory)?.name || 'Category'; | |
return `"${searchQuery}" in ${categoryName}`; | |
} else if (searchQuery) { | |
return `"${searchQuery}"`; | |
} else if (selectedCategory) { | |
const categoryName = categories.find((c: any) => c.id === selectedCategory)?.name || 'Category'; | |
return categoryName; | |
} | |
return 'Search Results'; | |
}; | |
return ( | |
<div className="min-h-screen page-gradient"> | |
<Header searchQuery={searchQuery} setSearchQuery={setSearchQuery} /> | |
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8" data-testid="search-results-page"> | |
{/* Back Navigation */} | |
<Button | |
variant="ghost" | |
onClick={() => setLocation('/')} | |
className="mb-6" | |
data-testid="back-to-home" | |
> | |
<ArrowLeft className="mr-2 h-4 w-4" /> | |
Back to Home | |
</Button> | |
{/* Search Header */} | |
<div className="mb-8"> | |
<h1 className="text-3xl font-bold text-gray-900 mb-2" data-testid="search-title"> | |
Search Results for {getPageTitle()} | |
</h1> | |
{!searchLoading && ( | |
<p className="text-gray-600" data-testid="results-count"> | |
{searchResults.length} {searchResults.length === 1 ? 'product' : 'products'} found | |
</p> | |
)} | |
</div> | |
{/* Search Results */} | |
<section data-testid="search-results-section"> | |
{searchLoading ? ( | |
<div className="flex flex-col items-center"> | |
<LoadingSpinner text="Searching products..." /> | |
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 mt-6 w-full"> | |
{[...Array(8)].map((_, i) => ( | |
<div key={i} className="glass-card rounded-2xl p-4"> | |
<Skeleton className="aspect-square w-full mb-4 rounded-xl" /> | |
<Skeleton className="h-4 w-3/4 mb-2" /> | |
<Skeleton className="h-4 w-1/2 mb-2" /> | |
<Skeleton className="h-6 w-1/4" /> | |
</div> | |
))} | |
</div> | |
</div> | |
) : searchResults.length > 0 ? ( | |
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4 sm:gap-5 md:gap-6" data-testid="search-product-grid"> | |
{searchResults.map((product: any) => ( | |
<ProductCard key={product.id} product={product} /> | |
))} | |
</div> | |
) : (searchQuery || selectedCategory) ? ( | |
<div className="text-center py-12" data-testid="no-results"> | |
<h3 className="text-xl font-semibold text-gray-900 mb-2">No products found</h3> | |
<p className="text-gray-600 mb-6"> | |
Try adjusting your search terms or browse all products | |
</p> | |
<Button | |
onClick={() => { | |
setSearchQuery(''); | |
setSelectedCategory(''); | |
setLocation('/'); | |
}} | |
data-testid="browse-all-products" | |
> | |
Browse All Products | |
</Button> | |
</div> | |
) : ( | |
<div className="text-center py-12" data-testid="search-prompt"> | |
<h3 className="text-xl font-semibold text-gray-900 mb-2">Search for products</h3> | |
<p className="text-gray-600"> | |
Use the search bar above or select a category to find products | |
</p> | |
</div> | |
)} | |
</section> | |
</div> | |
</div> | |
); | |
} |