Vitron-Front/app/components/explore/MainSection.tsx
Arda Samadi 252d3f8f50 feat(search/explore): home-style product tiles with seller brand chip
Bring the home product tile to search and explore: seller brand chip
(SellerChip) plus price/discount overlay, instead of a bare image.

- search: map discountPercent/discountPrice/basePrice + sellerName from
  ProductSearchResult (sellerName is already returned, so the chip shows
  now with the initial-letter fallback).
- explore: map sellerName/sellerLogo/sellerUsername (and add them to the
  Product type); these populate once the backend ProductSerializer change
  ships.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:09:58 +03:30

130 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import { useProductsInfiniteQuery } from "../../requestHandler/use-explore-hooks";
import { useGetHomeCategories } from "../../requestHandler/use-home-hooks";
import TabContainer from "./TabContainer";
import { Link } from "@remix-run/react";
import { Telescope } from "lucide-react";
import MondrianProductList from "../MondrianProductList";
import { Skeleton } from "../ui/skeleton";
const MainSection = () => {
const tabs = ["دسته بندی ها", "همه"];
const [activeTab, setActiveTab] = useState(0);
// Use our custom infinite query hook
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
status,
refetch,
} = useProductsInfiniteQuery();
// Use the new categories hook
const {
data: categories,
isLoading: categoriesLoading,
isError: categoriesError,
} = useGetHomeCategories();
// Flatten all products from all pages
const allProducts = data?.pages.flatMap((page) => page.results) || [];
// Loading skeleton for categories
const CategorySkeleton = () => (
<div className="px-4 flex flex-col gap-6 w-full">
<div className="grid grid-cols-2 gap-4 w-full">
{Array.from({ length: 6 }).map((_, index) => (
<div key={index} className="relative">
<Skeleton className="w-full h-[120px] rounded-[15px]" />
<Skeleton className="absolute bottom-2 left-2/4 -translate-x-1/2 w-20 h-4" />
</div>
))}
</div>
<Skeleton className="w-full h-16" />
</div>
);
return (
<div className="flex flex-col gap-6 w-full pb-20 lg:max-w-[1320px] lg:mx-auto lg:px-8 lg:pt-6">
<TabContainer
activeTab={activeTab}
setActiveTab={setActiveTab}
tabs={tabs}
/>
{activeTab === 0 ? (
categoriesLoading ? (
<CategorySkeleton />
) : categoriesError ? (
<div className="px-4 flex flex-col items-center gap-4 py-8">
<Telescope size={80} className="text-GRAY" />
<p className="text-R14 text-GRAY text-center">
خطا در بارگذاری دسته بندی ها
</p>
</div>
) : (
<div className="px-4 lg:px-0 flex flex-col gap-6 w-full">
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 w-full">
{categories?.map((category, index) => {
return (
<Link
className="flex relative w-full cursor-pointer items-center gap-2"
key={category.id || index}
to={`/search/${category.categoryName}`}
>
<img
src={category.imageUrl}
className="w-full h-[120px] lg:h-[180px] object-cover rounded-[15px]"
alt={category.categoryName}
/>
<p className="text-B16 text-center line-clamp-1 w-full font-bold text-white absolute bottom-2 left-2/4 -translate-x-1/2">
{category.categoryName}
</p>
</Link>
);
})}
</div>
<p className="text-R14 text-GRAY">
در ویترون، پوشاک تنها یک انتخاب نیست، بلکه تجربه ای از سبک و کیفیت
است. هر دسته بندی با دقت طراحی شده تا شما را در مسیر ساخت استایل
شخصی و متمایزتان همراهی کند.
</p>
</div>
)
) : (
<MondrianProductList
products={allProducts.map((product) => {
return {
id: product.id,
title: product.title,
images: product.imageUrls || [],
discountPercent: product.discountPercent || 0,
discountPrice: product.discountPrice || 0,
basePrice: product.basePrice
? parseInt(product.basePrice)
: undefined,
sellerName: product.sellerName,
sellerLogo: product.sellerLogo,
sellerUsername: product.sellerUsername,
};
})}
fetchNextPage={fetchNextPage}
hasNextPage={hasNextPage}
isFetchingNextPage={isFetchingNextPage}
isLoading={status === "pending"}
isError={status === "error"}
refetch={refetch}
emptyState={{
image: <Telescope size={80} />,
title: "محصولی در اکسپلور یافت نشد",
description:
"فکر میکنم بهتر باشه یه وقت دیگه تست کنید یا اینکه چیزی جدید بیاید.",
}}
/>
)}
</div>
);
};
export default MainSection;