Vitron-Front/app/requestHandler/use-admin-hooks.ts
Arda Samadi 0360780411 feat(admin): admin-panel foundation shell + overview (slice 0)
- /admin opted out of shopper chrome in MyLayout; /admin added to server
  protectedRoutes; useRequireAdmin() gates to superusers (UserProfile.isSuperuser).
- Admin shell (admin.tsx) with sidebar nav (Overview live; other sections stubbed)
  and a mobile top bar; Overview dashboard (KPI cards + 14-day orders chart) via
  use-admin-hooks.ts hitting /api/adminpanel/v1/overview/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 12:00:49 +03:30

69 lines
1.9 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { useAuthToken } from "~/hooks/use-root-data";
import { getApiBaseUrl } from "~/utils/api-config";
/* ------------------------------------------------------------------ *
* Admin panel data hooks (superuser only). The admin API is a new,
* fast-moving surface, so these call it directly with fetch (same
* pattern as use-seller-hooks' useMyStores) rather than the generated
* client. Responses are camelCased by the backend renderer.
* ------------------------------------------------------------------ */
export interface AdminOverview {
generatedAt: string;
users: {
total: number;
active: number;
sellers: number;
new7d: number;
new30d: number;
};
sellers: {
total: number;
pending: number;
approved: number;
rejected: number;
verified: number;
};
products: { total: number; active: number };
orders: {
total: number;
pending: number;
confirmed: number;
shipped: number;
delivered: number;
cancelled: number;
paidCount: number;
revenueTotal: number;
ordersToday: number;
revenueToday: number;
};
money: {
walletHeld: number;
sellerPayable: number;
payoutsPendingCount: number;
payoutsPendingAmount: number;
};
ordersSeries: Array<{ date: string; orders: number; revenue: number }>;
}
async function adminGet<T>(path: string, token: string): Promise<T> {
const res = await fetch(`${getApiBaseUrl()}/api/adminpanel/v1/${path}`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
throw new Error(`Admin request failed (${res.status})`);
}
return res.json();
}
export function useAdminOverview() {
const token = useAuthToken();
return useQuery({
queryKey: ["admin", "overview"],
enabled: !!token,
refetchInterval: 60_000,
queryFn: () => adminGet<AdminOverview>("overview/", token as string),
});
}