- /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>
69 lines
1.9 KiB
TypeScript
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),
|
|
});
|
|
}
|