feat(search): show sellers and collections in search results
Render a فروشگاهها row (store cards with logo via SellerLogo, linking to the store) and a کالکشنها row (reusing HorizontalCollectionsList) above the product grid on the search page. Sellers/collections read off the first page (they don't paginate); products paginate as before. Types extended (SellerSearchResult.logo, SearchResponse.collections). Degrades gracefully on older backends. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
fea80647fa
commit
8b51c3252a
@ -6,6 +6,8 @@ import { PackageSearch } from "lucide-react";
|
||||
import { useSearchInfinite } from "../requestHandler/use-search-hooks";
|
||||
import MondrianProductList from "~/components/MondrianProductList";
|
||||
import SearchTopBar from "~/components/SearchTopBar";
|
||||
import SellerLogo from "~/components/SellerLogo";
|
||||
import HorizontalCollectionsList from "~/components/HorizontalCollectionsList";
|
||||
|
||||
export default function Search() {
|
||||
const { query } = useParams();
|
||||
@ -30,6 +32,13 @@ export default function Search() {
|
||||
isFetchingNextPage,
|
||||
} = useSearchInfinite(query);
|
||||
|
||||
// Sellers & collections are the same for every page of a query, so read them
|
||||
// off the first page. Products paginate as usual.
|
||||
const firstPage = data?.pages?.[0];
|
||||
const sellers = firstPage?.sellers ?? [];
|
||||
const collections = firstPage?.collections ?? [];
|
||||
const hasNonProduct = sellers.length > 0 || collections.length > 0;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 bg-WHITE lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:py-6">
|
||||
<div className="lg:hidden">
|
||||
@ -57,6 +66,49 @@ export default function Search() {
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Sellers */}
|
||||
{sellers.length > 0 && (
|
||||
<section className="flex flex-col gap-3">
|
||||
<p className="text-B16 lg:text-B24 font-bold px-4 lg:px-0">فروشگاهها</p>
|
||||
<div className="flex gap-4 overflow-x-auto px-4 lg:px-0 pb-1">
|
||||
{sellers.map((seller) => (
|
||||
<Link
|
||||
key={seller.id}
|
||||
to={`/seller/${seller.id}`}
|
||||
className="flex flex-col items-center gap-2 shrink-0 w-[76px]"
|
||||
>
|
||||
<SellerLogo src={seller.logo} alt={seller.name} size="xl" />
|
||||
<p className="text-R12 font-bold text-center line-clamp-1 w-full">
|
||||
{seller.name}
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Collections */}
|
||||
{collections.length > 0 && (
|
||||
<section className="flex flex-col gap-3">
|
||||
<p className="text-B16 lg:text-B24 font-bold px-4 lg:px-0">کالکشنها</p>
|
||||
<HorizontalCollectionsList
|
||||
collections={collections.map((c) => ({
|
||||
id: c.id,
|
||||
title: c.title,
|
||||
coverImageUrl: c.coverImageUrl,
|
||||
productCount: c.productCount,
|
||||
}))}
|
||||
isLoading={false}
|
||||
isError={false}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{hasNonProduct && (
|
||||
<p className="text-B16 lg:text-B24 font-bold px-4 lg:px-0">محصولات</p>
|
||||
)}
|
||||
|
||||
<MondrianProductList
|
||||
products={
|
||||
data?.pages
|
||||
|
||||
@ -4329,6 +4329,24 @@ export interface SearchResponse {
|
||||
* @memberof SearchResponse
|
||||
*/
|
||||
sellers: Array<SellerSearchResult>;
|
||||
/**
|
||||
* Public collections matching the query.
|
||||
* @type {Array<CollectionSearchResult>}
|
||||
* @memberof SearchResponse
|
||||
*/
|
||||
collections?: Array<CollectionSearchResult>;
|
||||
}
|
||||
/**
|
||||
* A collection result in search.
|
||||
* @export
|
||||
* @interface CollectionSearchResult
|
||||
*/
|
||||
export interface CollectionSearchResult {
|
||||
type?: string;
|
||||
id: string;
|
||||
title: string;
|
||||
coverImageUrl?: string | null;
|
||||
productCount?: number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
@ -5546,6 +5564,12 @@ export interface SellerSearchResult {
|
||||
* @memberof SellerSearchResult
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Store logo URL (may be null).
|
||||
* @type {string}
|
||||
* @memberof SellerSearchResult
|
||||
*/
|
||||
logo?: string | null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user