From ae3f7d4190899e9ab1a4491b27cf9f1c13a3cece Mon Sep 17 00:00:00 2001 From: Enes1998 <104234112+Enes1998@users.noreply.github.com> Date: Sun, 7 Jun 2026 19:18:09 +0200 Subject: [PATCH] fix(web): normalize role in AdminGuard + getting-started checklist The API serializes the user role as PascalCase ("Admin"/"Enterprise"/"Freelancer"). AdminGuard checked `role === "admin" || role === 2`, so a real admin was shown the "Admin access required" screen. Route both raw role comparisons through normalizeRole (case/format-insensitive), matching the rest of the app. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/client/components/auth/AdminGuard.tsx | 5 ++++- frontend/client/hooks/useGettingStartedChecklist.ts | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/client/components/auth/AdminGuard.tsx b/frontend/client/components/auth/AdminGuard.tsx index 2bb4130..c49994c 100644 --- a/frontend/client/components/auth/AdminGuard.tsx +++ b/frontend/client/components/auth/AdminGuard.tsx @@ -3,6 +3,7 @@ import { useEffect, useRef, useSyncExternalStore } from "react"; import { useRouter } from "next/navigation"; import { useAuthStore } from "@/stores/authStore"; +import { normalizeRole } from "@/lib/auth/role"; import { isAdminHost } from "@/lib/host"; type Props = { @@ -14,7 +15,9 @@ function subscribe() { } function isAdmin(role: unknown): boolean { - return role === "admin" || role === 2; + // The API returns the role as PascalCase ("Admin"); normalize so the check is + // case/format-insensitive (string or numeric enum). + return normalizeRole(role) === "admin"; } export function AdminGuard({ children }: Props) { diff --git a/frontend/client/hooks/useGettingStartedChecklist.ts b/frontend/client/hooks/useGettingStartedChecklist.ts index 91dd3bf..fbc8600 100644 --- a/frontend/client/hooks/useGettingStartedChecklist.ts +++ b/frontend/client/hooks/useGettingStartedChecklist.ts @@ -3,6 +3,7 @@ import { useMemo, useState, useEffect, useCallback } from "react"; import { useQuery, useQueryClient, type InfiniteData } from "@tanstack/react-query"; import { useAuthStore } from "@/stores/authStore"; +import { normalizeRole } from "@/lib/auth/role"; import { useMyInvitations } from "@/hooks/useProjects"; import { useProfileCompleteness } from "@/hooks/useProfileCompleteness"; import { fetchProjects } from "@/lib/api/projects"; @@ -82,7 +83,7 @@ export function useGettingStartedChecklist() { }, [qc]); const items: ChecklistItem[] = useMemo(() => { - const isEnterprise = role === "enterprise" || role === 1; + const isEnterprise = normalizeRole(role) === "enterprise"; if (isEnterprise) { return [