From d2fd218ee4dad1345b9cccc9215cd27c326ed857 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Mon, 3 Aug 2026 21:44:57 +0500 Subject: [PATCH] fix admin user related issues --- src/components/admin/admin-devices-table.tsx | 4 ++-- src/components/devices-table.tsx | 4 ++-- src/components/ui/app-sidebar.tsx | 4 ++-- src/lib/auth-store.ts | 10 +++++++++ src/lib/types/user.ts | 1 + src/pages/admin/UserAgreement.tsx | 4 ++-- src/pages/admin/UserDetails.tsx | 22 +++++++++++--------- src/pages/admin/UserDevices.tsx | 4 ++-- src/pages/admin/UserPayments.tsx | 4 ++-- src/pages/admin/UserTopups.tsx | 4 ++-- src/pages/admin/UserUpdate.tsx | 4 ++-- src/pages/admin/Users.tsx | 4 ++-- 12 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/components/admin/admin-devices-table.tsx b/src/components/admin/admin-devices-table.tsx index 9dcd564..963a923 100644 --- a/src/components/admin/admin-devices-table.tsx +++ b/src/components/admin/admin-devices-table.tsx @@ -11,7 +11,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; import { cn } from "@/lib/utils"; import { getDevices } from "@/queries/devices"; import BlockDeviceDialog from "../block-device-dialog"; @@ -22,7 +22,7 @@ import Pagination from "../pagination"; export function AdminDevicesTable() { const [searchParams] = useSearchParams(); const user = useAtomValue(userAtom); - const isAdmin = user?.is_admin; + const isAdmin = isAdminUser(user); const page = Number.parseInt(searchParams.get("page") as string) || 1; const limit = 10; diff --git a/src/components/devices-table.tsx b/src/components/devices-table.tsx index b084ea0..a542fbf 100644 --- a/src/components/devices-table.tsx +++ b/src/components/devices-table.tsx @@ -10,7 +10,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; import { getDevices } from "@/queries/devices"; import DevicesTableSkeleton from "./device-table-skeleton"; import ClickableRow from "./clickable-row"; @@ -27,7 +27,7 @@ export function DevicesTable({ }) { const [searchParams] = useSearchParams(); const user = useAtomValue(userAtom); - const isAdmin = user?.is_admin; + const isAdmin = isAdminUser(user); const page = Number.parseInt(searchParams.get("page") as string) || 1; const limit = 10; diff --git a/src/components/ui/app-sidebar.tsx b/src/components/ui/app-sidebar.tsx index 47e22aa..ad3df2b 100644 --- a/src/components/ui/app-sidebar.tsx +++ b/src/components/ui/app-sidebar.tsx @@ -29,7 +29,7 @@ import { SidebarMenuItem, SidebarRail, } from "@/components/ui/sidebar"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; type Permission = { id: number; @@ -141,7 +141,7 @@ export function AppSidebar({ ]; let CATEGORIES: Categories; - if (user?.is_admin) { + if (isAdminUser(user)) { CATEGORIES = categories; } else { // Filter out ADMIN CONTROL category for non-admin users diff --git a/src/lib/auth-store.ts b/src/lib/auth-store.ts index 08db710..63e83ca 100644 --- a/src/lib/auth-store.ts +++ b/src/lib/auth-store.ts @@ -42,6 +42,16 @@ export function getStoredUser(): AuthUser | null { return store.get(userAtom); } +/** + * Single source of truth for "is this user an administrator?" on the client. + * Mirrors the backend `user_is_admin` helper: any of the app-specific + * `is_admin` flag, Django `is_staff`, or `is_superuser` grants admin access. + * Use this for every admin route/UI gate instead of checking `is_admin` alone. + */ +export function isAdminUser(user: AuthUser | null | undefined): boolean { + return Boolean(user && (user.is_admin || user.is_staff || user.is_superuser)); +} + /** Persist token + user on successful login. */ export function setAuth(token: string, user: AuthUser): void { store.set(tokenAtom, token); diff --git a/src/lib/types/user.ts b/src/lib/types/user.ts index 2925bdc..0911c85 100644 --- a/src/lib/types/user.ts +++ b/src/lib/types/user.ts @@ -64,6 +64,7 @@ export interface AuthUser { last_name: string; email: string; is_admin: boolean; + is_staff: boolean; is_superuser: boolean; last_login: string; date_joined: string; diff --git a/src/pages/admin/UserAgreement.tsx b/src/pages/admin/UserAgreement.tsx index 2ab0db5..cf1ac3b 100644 --- a/src/pages/admin/UserAgreement.tsx +++ b/src/pages/admin/UserAgreement.tsx @@ -4,7 +4,7 @@ import { Navigate, useParams } from "react-router-dom"; import ClientErrorMessage from "@/components/client-error-message"; import FullPageLoader from "@/components/full-page-loader"; import UserAgreementForm from "@/components/user/user-agreement-form"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; import { getProfileById } from "@/queries/users"; export default function UserAgreement() { @@ -17,7 +17,7 @@ export default function UserAgreement() { enabled: !!userId, }); - if (!authUser?.is_admin) return ; + if (!isAdminUser(authUser)) return ; if (isLoading) return ; if (error) return ; if (!user) return null; diff --git a/src/pages/admin/UserDetails.tsx b/src/pages/admin/UserDetails.tsx index 8ee34eb..b20661d 100644 --- a/src/pages/admin/UserDetails.tsx +++ b/src/pages/admin/UserDetails.tsx @@ -80,7 +80,7 @@ export default function UserDetails() {
-

Database Information

+

Customer Input Information

-
- id photo -
+ {nationalData?.image_url && ( +
+ id photo +
+ )}
} diff --git a/src/pages/admin/UserDevices.tsx b/src/pages/admin/UserDevices.tsx index c0c124b..128be25 100644 --- a/src/pages/admin/UserDevices.tsx +++ b/src/pages/admin/UserDevices.tsx @@ -2,11 +2,11 @@ import { useAtomValue } from "jotai"; import { Navigate } from "react-router-dom"; import { AdminDevicesTable } from "@/components/admin/admin-devices-table"; import DynamicFilter from "@/components/generic-filter"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; export default function UserDevices() { const user = useAtomValue(userAtom); - if (!user?.is_admin) return ; + if (!isAdminUser(user)) return ; return (
diff --git a/src/pages/admin/UserPayments.tsx b/src/pages/admin/UserPayments.tsx index 1447f50..3c159a4 100644 --- a/src/pages/admin/UserPayments.tsx +++ b/src/pages/admin/UserPayments.tsx @@ -2,11 +2,11 @@ import { useAtomValue } from "jotai"; import { Navigate } from "react-router-dom"; import { UsersPaymentsTable } from "@/components/admin/user-payments-table"; import DynamicFilter from "@/components/generic-filter"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; export default function UserPayments() { const user = useAtomValue(userAtom); - if (!user?.is_admin) return ; + if (!isAdminUser(user)) return ; return (
diff --git a/src/pages/admin/UserTopups.tsx b/src/pages/admin/UserTopups.tsx index 45adeac..babf685 100644 --- a/src/pages/admin/UserTopups.tsx +++ b/src/pages/admin/UserTopups.tsx @@ -2,11 +2,11 @@ import { useAtomValue } from "jotai"; import { Navigate } from "react-router-dom"; import { AdminTopupsTable } from "@/components/admin/admin-topup-table"; import DynamicFilter from "@/components/generic-filter"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; export default function UserTopups() { const user = useAtomValue(userAtom); - if (!user?.is_admin) return ; + if (!isAdminUser(user)) return ; return (
diff --git a/src/pages/admin/UserUpdate.tsx b/src/pages/admin/UserUpdate.tsx index 259c3f5..fed77de 100644 --- a/src/pages/admin/UserUpdate.tsx +++ b/src/pages/admin/UserUpdate.tsx @@ -4,7 +4,7 @@ import { Navigate, useParams } from "react-router-dom"; import ClientErrorMessage from "@/components/client-error-message"; import FullPageLoader from "@/components/full-page-loader"; import UserUpdateForm from "@/components/user/user-update-form"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; import { getProfileById } from "@/queries/users"; export default function UserUpdate() { @@ -17,7 +17,7 @@ export default function UserUpdate() { enabled: !!userId, }); - if (!authUser?.is_admin) return ; + if (!isAdminUser(authUser)) return ; if (isLoading) return ; if (error) return ; if (!user) return null; diff --git a/src/pages/admin/Users.tsx b/src/pages/admin/Users.tsx index 7d719da..ab323c7 100644 --- a/src/pages/admin/Users.tsx +++ b/src/pages/admin/Users.tsx @@ -2,11 +2,11 @@ import { useAtomValue } from "jotai"; import { Navigate } from "react-router-dom"; import DynamicFilter from "@/components/generic-filter"; import { UsersTable } from "@/components/user-table"; -import { userAtom } from "@/lib/auth-store"; +import { isAdminUser, userAtom } from "@/lib/auth-store"; export default function Users() { const user = useAtomValue(userAtom); - if (!user?.is_admin) return ; + if (!isAdminUser(user)) return ; return (