Vitron-Front/app/components/explore/MainSection.tsx
Arda Samadi 7845ab5e75 Desktop: explore page (category grid + contained layout)
- explore: hide mobile search bar at lg (global header has search); contain
  content to 1320px; category grid 2-col mobile -> 4-col desktop with taller tiles
- MyLayout: desktop gate now includes /explore
2026-06-16 11:11:46 +03:30

127 lines
4.6 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,
};
})}
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;