From 6a300b87604461fb4825a74a1ae0369ddcc36225 Mon Sep 17 00:00:00 2001 From: fazli Date: Sat, 18 Jul 2026 13:18:23 +0000 Subject: [PATCH] fix(store): don't bounce owners home, stop cross-user myStores cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- app/hooks/useStoreOwnership.ts | 29 +++++++++++++++++++------- app/requestHandler/use-seller-hooks.ts | 3 +-- app/routes/store.$storeId._index.tsx | 2 ++ app/routes/store.$storeId.tsx | 4 ++-- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/hooks/useStoreOwnership.ts b/app/hooks/useStoreOwnership.ts index 09c475b..f1ac518 100644 --- a/app/hooks/useStoreOwnership.ts +++ b/app/hooks/useStoreOwnership.ts @@ -9,23 +9,36 @@ import { useMyStores } from "../requestHandler/use-seller-hooks"; */ export function useStoreOwnership(storeId: string | undefined, mode?: string) { const navigate = useNavigate(); - const { data: stores, isLoading } = useMyStores(); + const { data: stores, isLoading, isFetching, isError } = useMyStores(); - const current = stores?.find((s) => s.username === storeId); + const current = stores?.find( + (s) => s.username?.toLowerCase() === storeId?.toLowerCase() + ); useEffect(() => { - if (isLoading || mode === "create") return; + if (isLoading || isFetching || isError || mode === "create") return; if (!storeId) { navigate("/"); return; } - if (stores === undefined) return; // not loaded yet + if (!stores || stores.length === 0) return; // nothing to compare against yet if (!current) { - // Not a member of this store → send them to a store they can manage, else home. - if (stores.length > 0) navigate(`/store/${stores[0].username}`); - else navigate("/"); + // The user is a member of at least one OTHER store — send them there. + // If they're not a member of any store, do NOT bounce to home: staying + // put lets an owner see their (empty) dashboard rather than being + // silently kicked out on a transient/mismatched my-stores response. + navigate(`/store/${stores[0].username}`); } - }, [stores, current, storeId, isLoading, navigate, mode]); + }, [ + stores, + current, + storeId, + isLoading, + isFetching, + isError, + navigate, + mode, + ]); const ownedOrFirst = stores?.find((s) => s.role === "owner") ?? stores?.[0]; diff --git a/app/requestHandler/use-seller-hooks.ts b/app/requestHandler/use-seller-hooks.ts index 9f534ca..6b0c5de 100644 --- a/app/requestHandler/use-seller-hooks.ts +++ b/app/requestHandler/use-seller-hooks.ts @@ -39,9 +39,8 @@ export interface StoreMember { export function useMyStores() { const token = useAuthToken(); return useQuery({ - queryKey: ["myStores"], + queryKey: ["myStores", token ?? "anon"], queryFn: async (): Promise => { - if (!token) return []; const res = await fetch(`${getApiBaseUrl()}/api/seller/v1/my-stores/`, { headers: { Authorization: `Bearer ${token}` }, }); diff --git a/app/routes/store.$storeId._index.tsx b/app/routes/store.$storeId._index.tsx index db90e94..383b538 100644 --- a/app/routes/store.$storeId._index.tsx +++ b/app/routes/store.$storeId._index.tsx @@ -36,6 +36,7 @@ import { useStoreOwnership } from "../hooks/useStoreOwnership"; import { LoadingModal } from "./store.add.manual.$storeId"; import SellerLogo from "../components/SellerLogo"; import CallDialog from "../components/CallDialog"; +import { StorePushPromptCard } from "../components/store/StorePushPromptCard"; export default function Store() { const { storeId } = useParams(); @@ -110,6 +111,7 @@ export default function Store() {
+

{data?.followerCount}

diff --git a/app/routes/store.$storeId.tsx b/app/routes/store.$storeId.tsx index e4e2b61..7cf355e 100644 --- a/app/routes/store.$storeId.tsx +++ b/app/routes/store.$storeId.tsx @@ -32,7 +32,7 @@ export default function StoreLayout() { label: "سفارش‌ها", to: `${base}/orders`, icon: ClipboardList, - badge: badges?.seller_orders || 0, + badge: badges?.sellerOrders || 0, }, { label: "مالی", to: `${base}/financial-dashboard`, icon: Wallet }, { label: "روش ارسال", to: `${base}/shipping-method`, icon: Truck }, @@ -40,7 +40,7 @@ export default function StoreLayout() { label: "پیام‌ها", to: `${base}/threads`, icon: MessageCircle, - badge: badges?.chat || 0, + badge: (storeId && badges?.sellerChat?.[storeId]) || 0, }, { label: "تنظیمات", to: `${base}/setting`, icon: Settings }, ];