Vitron-Front/app/routes/sellers.tsx
Arda Samadi 3156fb4204 Desktop: account area (shared sidebar) + brands list
- new profile.tsx layout: sticky desktop sidebar (user card + menu) wrapping all
  /profile/* pages; mobile renders page content only (unchanged)
- ProfilePagesHeader hidden at lg (one change covers all account sub-pages +
  cart); profile index shows a welcome on desktop (menu lives in the sidebar)
- sellers: 5-col brand grid with name overlay, contained, mobile header hidden
- MyLayout: desktop gate now covers /profile/* and /sellers
2026-06-16 12:46:22 +03:30

154 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { MetaFunction } from "@remix-run/node";
import { Link, useNavigate } from "@remix-run/react";
import { safeGoBack } from "~/utils/helpers";
import { useGetAllSellerTiles } from "~/requestHandler/use-home-hooks";
import { Skeleton } from "~/components/ui/skeleton";
import { Store, RefreshCw, ArrowRight } from "lucide-react";
export default function Sellers() {
const navigate = useNavigate();
const { data, status, refetch } = useGetAllSellerTiles();
const allSellers = data || [];
// Loading skeleton
const SellersSkeleton = () => (
<div className="grid grid-cols-2 lg:grid-cols-5 gap-3 lg:gap-4 px-4 lg:px-0">
{Array.from({ length: 8 }).map((_, index) => (
<Skeleton key={index} className="aspect-square rounded-lg" />
))}
</div>
);
// Empty state
const EmptyState = () => (
<div className="flex flex-col items-center justify-center py-20 px-4">
<div className="w-20 h-20 rounded-full bg-WHITE2 flex items-center justify-center mb-4">
<Store size={40} className="text-GRAY" />
</div>
<h3 className="text-B18 font-bold text-black mb-2">فروشگاهی یافت نشد</h3>
<p className="text-R14 text-GRAY text-center max-w-md">
در حال حاضر فروشگاهی موجود نیست.
</p>
</div>
);
// Error state
const ErrorState = () => (
<div className="flex flex-col items-center justify-center py-20 px-4">
<div className="w-20 h-20 rounded-full bg-red-50 flex items-center justify-center mb-4">
<Store size={40} className="text-red-500" />
</div>
<h3 className="text-B18 font-bold text-black mb-2">
خطا در بارگذاری فروشگاهها
</h3>
<p className="text-R14 text-GRAY text-center max-w-md mb-6">
متاسفانه در بارگذاری فروشگاهها مشکلی پیش آمد.
</p>
<button
onClick={() => refetch()}
className="flex items-center gap-2 bg-black text-white px-6 py-3 rounded-full hover:bg-gray-800 transition-all"
>
<RefreshCw size={16} />
<span className="text-R14 font-bold">تلاش مجدد</span>
</button>
</div>
);
const handleBack = () => {
safeGoBack(navigate);
};
return (
<div className="flex flex-col bg-WHITE pb-20">
{/* Header (mobile) */}
<div className="lg:hidden flex flex-row h-[65px] sticky top-0 z-30 bg-WHITE w-full items-center justify-center border-b border-inner-border">
<ArrowRight
onClick={handleBack}
className="absolute top-5 right-5 cursor-pointer"
/>
<p className="text-B16 font-bold">فروشگاهها</p>
</div>
{/* Content */}
<div className="flex flex-col py-6 lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8">
<h1 className="hidden lg:block text-[28px] font-extrabold mb-6">
فروشگاهها
</h1>
{status === "pending" ? (
<SellersSkeleton />
) : status === "error" ? (
<ErrorState />
) : allSellers.length === 0 ? (
<EmptyState />
) : (
<div className="grid grid-cols-2 lg:grid-cols-5 gap-3 lg:gap-4 px-4 lg:px-0">
{allSellers.map((seller, index) => (
<Link
key={seller.id || index}
to={`/seller/${seller.sellerUsername || seller.sellerId}`}
className="relative aspect-square overflow-hidden rounded-lg group"
>
{/* Background Image */}
{seller.imageUrl ? (
<img
src={seller.imageUrl}
alt={seller.sellerName || "فروشگاه"}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-gray-200 to-gray-300 flex items-center justify-center">
<Store size={48} className="text-gray-400" />
</div>
)}
{seller.sellerName ? (
<>
<div className="hidden lg:block absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
<div className="hidden lg:flex absolute inset-x-0 bottom-0 p-4 items-end">
<span className="text-white font-bold text-[15px] truncate">
{seller.sellerName}
</span>
</div>
</>
) : null}
</Link>
))}
</div>
)}
</div>
</div>
);
}
export const meta: MetaFunction = () => {
const title = "فروشگاه‌های ویترون | برترین فروشندگان";
const description =
"مشاهده برترین فروشگاه‌های ویترون. خرید امن از فروشندگان معتبر با بالاترین کیفیت.";
const imageUrl =
"https://vitrownstatics.s3.ir-thr-at1.arvanstorage.ir/SVG-06.svg?versionId=";
return [
{ title },
{ name: "description", content: description },
{
name: "keywords",
content: "فروشگاه، فروشندگان، ویترون، خرید آنلاین، فروشگاه اینترنتی",
},
{ name: "robots", content: "index, follow" },
// Open Graph
{ property: "og:type", content: "website" },
{ property: "og:title", content: title },
{ property: "og:description", content: description },
{ property: "og:image", content: imageUrl },
{ property: "og:site_name", content: "ویترون" },
{ property: "og:locale", content: "fa_IR" },
// Twitter Card
{ name: "twitter:card", content: "summary_large_image" },
{ name: "twitter:title", content: title },
{ name: "twitter:description", content: description },
{ name: "twitter:image", content: imageUrl },
];
};