Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cc866b7

Browse files
authored
useAuth in navbar (#999)
1 parent 9cc39cf commit cc866b7

File tree

6 files changed

+198
-147
lines changed

6 files changed

+198
-147
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// frontend/apps/ui/src/hooks/useAuth.ts
2+
import {useMemo} from "react"
3+
import {useSelector} from "react-redux"
4+
import {selectCurrentUser} from "@/slices/currentUser"
5+
import type {User} from "@/types"
6+
7+
/**
8+
* Centralized Authorization Hook
9+
*
10+
* Provides a consistent way to check user permissions across the application.
11+
*
12+
* @example
13+
* ```tsx
14+
* import { useAuth } from '@/hooks/useAuth'
15+
* import { USER_CREATE, USER_DELETE } from '@/scopes'
16+
*
17+
* function MyComponent() {
18+
* const { hasPermission, isSuperuser } = useAuth()
19+
*
20+
* return (
21+
* <>
22+
* {hasPermission(USER_CREATE) && <CreateButton />}
23+
* {hasPermission(USER_DELETE) && <DeleteButton />}
24+
* {isSuperuser && <AdminPanel />}
25+
* </>
26+
* )
27+
* }
28+
* ```
29+
*/
30+
export function useAuth() {
31+
const user = useSelector(selectCurrentUser) as User | null
32+
33+
// Memoize the scopes set for O(1) lookup performance
34+
const userScopes = useMemo(() => {
35+
if (!user || !user.scopes) {
36+
return new Set<string>()
37+
}
38+
return new Set(user.scopes)
39+
}, [user])
40+
41+
/**
42+
* Check if the current user is a superuser
43+
*/
44+
const isSuperuser = useMemo(() => {
45+
return user?.is_superuser ?? false
46+
}, [user])
47+
48+
/**
49+
* Check if user has a specific permission
50+
* Superusers automatically have all permissions
51+
*
52+
* @param permission - The permission scope to check (e.g., 'user.create')
53+
* @returns true if user has the permission or is superuser
54+
*/
55+
const hasPermission = (permission: string): boolean => {
56+
if (!user) return false
57+
if (isSuperuser) return true
58+
return userScopes.has(permission)
59+
}
60+
61+
/**
62+
* Check if user has ANY of the specified permissions
63+
* Returns true if user has at least one permission
64+
*
65+
* @param permissions - Array of permission scopes
66+
* @returns true if user has any of the permissions or is superuser
67+
*/
68+
const hasAnyPermission = (permissions: string[]): boolean => {
69+
if (!user) return false
70+
if (isSuperuser) return true
71+
return permissions.some(permission => userScopes.has(permission))
72+
}
73+
74+
/**
75+
* Check if user has ALL of the specified permissions
76+
*
77+
* @param permissions - Array of permission scopes
78+
* @returns true if user has all permissions or is superuser
79+
*/
80+
const hasAllPermissions = (permissions: string[]): boolean => {
81+
if (!user) return false
82+
if (isSuperuser) return true
83+
return permissions.every(permission => userScopes.has(permission))
84+
}
85+
86+
/**
87+
* Get all user scopes as an array
88+
*/
89+
const getScopes = (): string[] => {
90+
return Array.from(userScopes)
91+
}
92+
93+
/**
94+
* Check if user has permissions for a specific category and action
95+
*
96+
* @param category - Category prefix (e.g., 'user', 'node', 'document')
97+
* @param action - Specific action (e.g., 'create', 'view', 'update', 'delete')
98+
* @returns true if user has the permission
99+
*/
100+
const hasCategoryPermission = (category: string, action: string): boolean => {
101+
return hasPermission(`${category}.${action}`)
102+
}
103+
104+
return {
105+
user,
106+
isSuperuser,
107+
hasPermission,
108+
hasAnyPermission,
109+
hasAllPermissions,
110+
hasCategoryPermission,
111+
getScopes
112+
}
113+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /