Vitron-Front/app/routes/store.$storeId.tsx
fazli 6a300b8760 fix(store): don't bounce owners home, stop cross-user myStores cache
- app/hooks/useStoreOwnership.ts: the old redirect logic sent owners to /
  the moment useMyStores briefly resolved to []. That empty array came from
  useMyStores's dead `if (!token) return []` inside the queryFn, so any
  transient auth blip left the store page thinking the user has no stores.
  Now compares usernames case-insensitively, only redirects while the query
  is settled (!isLoading && !isFetching && !isError), and never bounces to
  home on empty — worst case the seller sees an empty dashboard rather than
  a silent kick-out.
- app/requestHandler/use-seller-hooks.ts: removed the unreachable
  `if (!token) return []` in useMyStores and added the token to the
  queryKey so a login switch stops serving the previous user's cached list.
- app/routes/store.$storeId._index.tsx: mount StorePushPromptCard at the
  top of the store dashboard.
- app/routes/store.$storeId.tsx: sidebar "پیام‌ها" badge reads
  badges.sellerChat[storeId] (per-store) instead of the buyer-side
  badges.chat, matching the badge-serializer split.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-18 13:18:23 +00:00

104 lines
3.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 { Link, Outlet, useLocation, useParams } from "@remix-run/react";
import {
LayoutGrid,
Package,
ClipboardList,
Wallet,
Truck,
MessageCircle,
Settings,
ArrowRight,
} from "lucide-react";
import { useSellerData } from "~/requestHandler/use-seller-hooks";
import SellerLogo from "~/components/SellerLogo";
import { useBadgeCounts } from "~/hooks/useBadgeCounts";
/**
* Desktop layout for the seller dashboard. Renders a sticky admin sidebar
* next to the page content at lg+; on mobile it's just the page content
* (the existing mobile dashboard, with its store-mode bottom nav, is unchanged).
*/
export default function StoreLayout() {
const { storeId } = useParams();
const location = useLocation();
const { data } = useSellerData(storeId);
const { data: badges } = useBadgeCounts();
const base = `/store/${storeId}`;
const NAV = [
{ label: "فروشگاه", to: base, icon: LayoutGrid, exact: true },
{ label: "محصولات", to: `${base}/products`, icon: Package },
{
label: "سفارش‌ها",
to: `${base}/orders`,
icon: ClipboardList,
badge: badges?.sellerOrders || 0,
},
{ label: "مالی", to: `${base}/financial-dashboard`, icon: Wallet },
{ label: "روش ارسال", to: `${base}/shipping-method`, icon: Truck },
{
label: "پیام‌ها",
to: `${base}/threads`,
icon: MessageCircle,
badge: (storeId && badges?.sellerChat?.[storeId]) || 0,
},
{ label: "تنظیمات", to: `${base}/setting`, icon: Settings },
];
const isActive = (item: { to: string; exact?: boolean }) =>
item.exact
? location.pathname === item.to
: location.pathname.startsWith(item.to);
return (
<div className="lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:py-8 lg:grid lg:grid-cols-[260px_1fr] lg:gap-7 lg:items-start">
{/* Desktop admin sidebar */}
<aside className="hidden lg:block lg:sticky lg:top-6 border border-WHITE3 rounded-2xl overflow-hidden">
<div className="p-4 border-b border-WHITE3 flex items-center gap-3">
<SellerLogo size="sm" src={data?.storeLogo} alt="store" />
<div className="min-w-0">
<p className="font-bold text-[15px] truncate">
{data?.storeName || "فروشگاه من"}
</p>
<p className="text-GRAY text-[12px]">پنل مدیریت</p>
</div>
</div>
<nav className="p-2.5 flex flex-col gap-0.5">
{NAV.map((n) => (
<Link
key={n.to}
to={n.to}
prefetch="intent"
className={`flex items-center gap-3 px-3.5 py-3 rounded-xl text-[14.5px] font-semibold transition-colors ${
isActive(n)
? "bg-BLACK text-white"
: "text-BLACK2 hover:bg-WHITE2"
}`}
>
<n.icon size={20} />
{n.label}
{n.badge && n.badge > 0 ? (
<span className="ml-auto min-w-[18px] h-[18px] px-1 rounded-full bg-RED text-white text-[10px] font-bold flex items-center justify-center leading-none">
{n.badge > 99 ? "99+" : n.badge}
</span>
) : null}
</Link>
))}
<Link
to="/"
className="flex items-center gap-3 px-3.5 py-3 rounded-xl text-[14.5px] font-semibold text-BLACK2 hover:bg-WHITE2 transition-colors"
>
<ArrowRight size={20} />
بازگشت به فروشگاه
</Link>
</nav>
</aside>
{/* Page content */}
<div className="min-w-0">
<Outlet />
</div>
</div>
);
}