Vitron-Front/app/hooks/useStoreOwnership.ts
Arda Samadi bb44ebf0e5 fix(seller-team): guard owner-only routes + robust useMyStores
Review fixes:
- useMyStores throws on a failed response instead of resolving to [] — a
  transient 401/blip no longer looks like "no stores" and bounces an owner off
  their own dashboard (query stays in error/retry, keeps prior data).
- Add useRequireOwner() guard and apply it to the owner-only routes
  (financial-dashboard + its cash-funds/reports/transactions sub-routes and
  shipping-method) so staff who hit those URLs directly are redirected to the
  dashboard. (Financial data was already backend-protected; this is the matching
  client-side gate.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 17:04:06 +03:30

59 lines
1.9 KiB
TypeScript

import { useEffect } from "react";
import { useNavigate } from "@remix-run/react";
import { useMyStores } from "../requestHandler/use-seller-hooks";
/**
* Guards a store dashboard route. A user may enter a store they OWN or are an
* active STAFF member of. Non-members are redirected away. Returns the user's
* role for this store so callers can gate owner-only UI.
*/
export function useStoreOwnership(storeId: string | undefined, mode?: string) {
const navigate = useNavigate();
const { data: stores, isLoading } = useMyStores();
const current = stores?.find((s) => s.username === storeId);
useEffect(() => {
if (isLoading || mode === "create") return;
if (!storeId) {
navigate("/");
return;
}
if (stores === undefined) return; // not loaded 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("/");
}
}, [stores, current, storeId, isLoading, navigate, mode]);
const ownedOrFirst = stores?.find((s) => s.role === "owner") ?? stores?.[0];
return {
isLoading,
isMember: !!current,
role: current?.role ?? null,
isOwner: current?.role === "owner",
userStoreId: ownedOrFirst?.username,
stores: stores ?? [],
};
}
/**
* Guard for OWNER-ONLY store pages (financial, shipping, edit, team). Redirects
* non-members (via useStoreOwnership) and staff members back to the dashboard.
* Returns { isLoading, isOwner } so callers can render a spinner meanwhile.
*/
export function useRequireOwner(storeId: string | undefined) {
const navigate = useNavigate();
const { isLoading, role } = useStoreOwnership(storeId);
useEffect(() => {
if (!isLoading && role && role !== "owner") {
navigate(`/store/${storeId}`);
}
}, [isLoading, role, storeId, navigate]);
return { isLoading, isOwner: role === "owner" };
}