@jmruthers/pace-core 0.5.164 → 0.5.166
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-HAATGNJY.js → DataTable-Z6IYTME3.js} +3 -3
- package/dist/{chunk-DDB2M4XO.js → chunk-5PH366QI.js} +2 -2
- package/dist/{chunk-GFSYFEVZ.js → chunk-BPIFVNEO.js} +24 -24
- package/dist/chunk-BPIFVNEO.js.map +1 -0
- package/dist/{chunk-G3EZSUTR.js → chunk-JIRBF5HR.js} +6 -23
- package/dist/chunk-JIRBF5HR.js.map +1 -0
- package/dist/{chunk-23YYDN24.js → chunk-SVMR7EVX.js} +2 -2
- package/dist/components.js +3 -3
- package/dist/index.js +4 -4
- package/dist/rbac/index.d.ts +10 -3
- package/dist/rbac/index.js +2 -2
- package/dist/utils.js +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +19 -12
- package/package.json +2 -2
- package/src/__tests__/hooks/usePermissions.test.ts +12 -9
- package/src/components/NavigationMenu/NavigationMenu.tsx +4 -26
- package/src/hooks/__tests__/ServiceHooks.test.tsx +2 -2
- package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +32 -34
- package/src/rbac/hooks/usePermissions.test.ts +34 -32
- package/src/rbac/hooks/usePermissions.ts +41 -28
- package/dist/chunk-G3EZSUTR.js.map +0 -1
- package/dist/chunk-GFSYFEVZ.js.map +0 -1
- /package/dist/{DataTable-HAATGNJY.js.map → DataTable-Z6IYTME3.js.map} +0 -0
- /package/dist/{chunk-DDB2M4XO.js.map → chunk-5PH366QI.js.map} +0 -0
- /package/dist/{chunk-23YYDN24.js.map → chunk-SVMR7EVX.js.map} +0 -0
|
@@ -27,9 +27,13 @@ vi.mock('../../api', () => ({
|
|
|
27
27
|
import { getPermissionMap } from '../../api';
|
|
28
28
|
|
|
29
29
|
const mockUserId = 'user-123';
|
|
30
|
+
const mockOrgId = 'org-123';
|
|
31
|
+
const mockEventId = 'event-123';
|
|
32
|
+
const mockAppId = 'app-123';
|
|
30
33
|
const mockScope = {
|
|
31
|
-
organisationId:
|
|
32
|
-
eventId:
|
|
34
|
+
organisationId: mockOrgId,
|
|
35
|
+
eventId: mockEventId,
|
|
36
|
+
appId: mockAppId
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
const mockPermissionMap = {
|
|
@@ -54,9 +58,9 @@ describe('usePermissions Integration Tests', () => {
|
|
|
54
58
|
describe('Cache Behavior', () => {
|
|
55
59
|
it('fetches permissions only once for same dependencies', async () => {
|
|
56
60
|
const { result, rerender } = renderHook(
|
|
57
|
-
({ userId,
|
|
61
|
+
({ userId, orgId, eventId, appId }) => usePermissions(userId, orgId, eventId, appId),
|
|
58
62
|
{
|
|
59
|
-
initialProps: { userId: mockUserId,
|
|
63
|
+
initialProps: { userId: mockUserId, orgId: mockOrgId, eventId: mockEventId, appId: mockAppId }
|
|
60
64
|
}
|
|
61
65
|
);
|
|
62
66
|
|
|
@@ -75,9 +79,9 @@ describe('usePermissions Integration Tests', () => {
|
|
|
75
79
|
|
|
76
80
|
it('refetches when organisationId changes', async () => {
|
|
77
81
|
const { result, rerender } = renderHook(
|
|
78
|
-
({ userId,
|
|
82
|
+
({ userId, orgId, eventId, appId }) => usePermissions(userId, orgId, eventId, appId),
|
|
79
83
|
{
|
|
80
|
-
initialProps: { userId: mockUserId,
|
|
84
|
+
initialProps: { userId: mockUserId, orgId: mockOrgId, eventId: mockEventId, appId: mockAppId }
|
|
81
85
|
}
|
|
82
86
|
);
|
|
83
87
|
|
|
@@ -95,9 +99,9 @@ describe('usePermissions Integration Tests', () => {
|
|
|
95
99
|
|
|
96
100
|
it('refetches when eventId changes', async () => {
|
|
97
101
|
const { result, rerender } = renderHook(
|
|
98
|
-
({ userId,
|
|
102
|
+
({ userId, orgId, eventId, appId }) => usePermissions(userId, orgId, eventId, appId),
|
|
99
103
|
{
|
|
100
|
-
initialProps: { userId: mockUserId,
|
|
104
|
+
initialProps: { userId: mockUserId, orgId: mockOrgId, eventId: mockEventId, appId: mockAppId }
|
|
101
105
|
}
|
|
102
106
|
);
|
|
103
107
|
|
|
@@ -114,11 +118,10 @@ describe('usePermissions Integration Tests', () => {
|
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
it('refetches when appId changes', async () => {
|
|
117
|
-
const scopeWithApp = { ...mockScope, appId: 'app-1' };
|
|
118
121
|
const { result, rerender } = renderHook(
|
|
119
|
-
({ userId,
|
|
122
|
+
({ userId, orgId, eventId, appId }) => usePermissions(userId, orgId, eventId, appId),
|
|
120
123
|
{
|
|
121
|
-
initialProps: { userId: mockUserId,
|
|
124
|
+
initialProps: { userId: mockUserId, orgId: mockOrgId, eventId: mockEventId, appId: 'app-1' }
|
|
122
125
|
}
|
|
123
126
|
);
|
|
124
127
|
|
|
@@ -137,7 +140,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
137
140
|
|
|
138
141
|
describe('Refetch Scenarios', () => {
|
|
139
142
|
it('refetch updates permissions after external change', async () => {
|
|
140
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
143
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
141
144
|
|
|
142
145
|
await waitFor(() => {
|
|
143
146
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -159,7 +162,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
159
162
|
it('refetch clears error state', async () => {
|
|
160
163
|
// First render with error
|
|
161
164
|
mockGetPermissionMap.mockRejectedValueOnce(new Error('Network error'));
|
|
162
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
165
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
163
166
|
|
|
164
167
|
await waitFor(() => {
|
|
165
168
|
expect(result.current.error).toBeDefined();
|
|
@@ -176,7 +179,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
176
179
|
});
|
|
177
180
|
|
|
178
181
|
it('refetch triggers API call', async () => {
|
|
179
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
182
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
180
183
|
|
|
181
184
|
await waitFor(() => {
|
|
182
185
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -192,7 +195,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
192
195
|
});
|
|
193
196
|
|
|
194
197
|
it('refetch does nothing when userId is empty', async () => {
|
|
195
|
-
const { result } = renderHook(() => usePermissions('',
|
|
198
|
+
const { result } = renderHook(() => usePermissions('', mockOrgId, mockEventId, mockAppId));
|
|
196
199
|
|
|
197
200
|
await waitFor(() => {
|
|
198
201
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -207,8 +210,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
207
210
|
});
|
|
208
211
|
|
|
209
212
|
it('refetch does nothing when organisationId is empty', async () => {
|
|
210
|
-
const
|
|
211
|
-
const { result } = renderHook(() => usePermissions(mockUserId, invalidScope));
|
|
213
|
+
const { result } = renderHook(() => usePermissions(mockUserId, '', mockEventId, mockAppId));
|
|
212
214
|
|
|
213
215
|
await waitFor(() => {
|
|
214
216
|
expect(result.current.isLoading).toBe(true);
|
|
@@ -225,7 +227,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
225
227
|
|
|
226
228
|
describe('Concurrent Permission Checks', () => {
|
|
227
229
|
it('handles rapid permission checks correctly', async () => {
|
|
228
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
230
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
229
231
|
|
|
230
232
|
await waitFor(() => {
|
|
231
233
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -250,8 +252,8 @@ describe('usePermissions Integration Tests', () => {
|
|
|
250
252
|
});
|
|
251
253
|
|
|
252
254
|
it('handles multiple hooks with same scope', async () => {
|
|
253
|
-
const { result: result1 } = renderHook(() => usePermissions(mockUserId,
|
|
254
|
-
const { result: result2 } = renderHook(() => usePermissions(mockUserId,
|
|
255
|
+
const { result: result1 } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
256
|
+
const { result: result2 } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
255
257
|
|
|
256
258
|
await waitFor(() => {
|
|
257
259
|
expect(result1.current.isLoading).toBe(false);
|
|
@@ -266,8 +268,8 @@ describe('usePermissions Integration Tests', () => {
|
|
|
266
268
|
});
|
|
267
269
|
|
|
268
270
|
it('handles refetch from multiple components', async () => {
|
|
269
|
-
const { result: result1 } = renderHook(() => usePermissions(mockUserId,
|
|
270
|
-
const { result: result2 } = renderHook(() => usePermissions(mockUserId,
|
|
271
|
+
const { result: result1 } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
272
|
+
const { result: result2 } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
271
273
|
|
|
272
274
|
await waitFor(() => {
|
|
273
275
|
expect(result1.current.isLoading).toBe(false);
|
|
@@ -286,7 +288,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
286
288
|
|
|
287
289
|
describe('Permission Array Operations', () => {
|
|
288
290
|
it('hasAnyPermission handles complex arrays', async () => {
|
|
289
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
291
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
290
292
|
|
|
291
293
|
await waitFor(() => {
|
|
292
294
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -298,7 +300,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
298
300
|
});
|
|
299
301
|
|
|
300
302
|
it('hasAllPermissions handles complex arrays', async () => {
|
|
301
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
303
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
302
304
|
|
|
303
305
|
await waitFor(() => {
|
|
304
306
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -316,7 +318,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
316
318
|
}
|
|
317
319
|
|
|
318
320
|
mockGetPermissionMap.mockResolvedValue(largePermissionMap);
|
|
319
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
321
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
320
322
|
|
|
321
323
|
await waitFor(() => {
|
|
322
324
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -371,8 +373,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
371
373
|
|
|
372
374
|
describe('Invalid Scope Handling', () => {
|
|
373
375
|
it('handles empty organisationId gracefully', async () => {
|
|
374
|
-
const
|
|
375
|
-
const { result } = renderHook(() => usePermissions(mockUserId, invalidScope));
|
|
376
|
+
const { result } = renderHook(() => usePermissions(mockUserId, '', mockEventId, mockAppId));
|
|
376
377
|
|
|
377
378
|
// Should not fetch with invalid scope
|
|
378
379
|
await waitFor(() => {
|
|
@@ -381,8 +382,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
381
382
|
});
|
|
382
383
|
|
|
383
384
|
it('handles whitespace-only organisationId', async () => {
|
|
384
|
-
const
|
|
385
|
-
const { result } = renderHook(() => usePermissions(mockUserId, invalidScope));
|
|
385
|
+
const { result } = renderHook(() => usePermissions(mockUserId, ' ', mockEventId, mockAppId));
|
|
386
386
|
|
|
387
387
|
// Should not fetch with invalid scope
|
|
388
388
|
await waitFor(() => {
|
|
@@ -391,9 +391,7 @@ describe('usePermissions Integration Tests', () => {
|
|
|
391
391
|
});
|
|
392
392
|
|
|
393
393
|
it('handles missing organisationId', async () => {
|
|
394
|
-
const
|
|
395
|
-
delete (invalidScope as any).organisationId;
|
|
396
|
-
const { result } = renderHook(() => usePermissions(mockUserId, invalidScope));
|
|
394
|
+
const { result } = renderHook(() => usePermissions(mockUserId, undefined, mockEventId, mockAppId));
|
|
397
395
|
|
|
398
396
|
// Should not fetch with invalid scope
|
|
399
397
|
await waitFor(() => {
|
|
@@ -405,9 +403,9 @@ describe('usePermissions Integration Tests', () => {
|
|
|
405
403
|
describe('Memoization', () => {
|
|
406
404
|
it('returns stable references for helpers', async () => {
|
|
407
405
|
const { result, rerender } = renderHook(
|
|
408
|
-
({ userId,
|
|
406
|
+
({ userId, orgId, eventId, appId }) => usePermissions(userId, orgId, eventId, appId),
|
|
409
407
|
{
|
|
410
|
-
initialProps: { userId: mockUserId,
|
|
408
|
+
initialProps: { userId: mockUserId, orgId: mockOrgId, eventId: mockEventId, appId: mockAppId }
|
|
411
409
|
}
|
|
412
410
|
);
|
|
413
411
|
|
|
@@ -23,9 +23,13 @@ import { getPermissionMap } from '../api';
|
|
|
23
23
|
|
|
24
24
|
// Mock data
|
|
25
25
|
const mockUserId = 'user-123';
|
|
26
|
+
const mockOrgId = 'org-123';
|
|
27
|
+
const mockEventId = 'event-123';
|
|
28
|
+
const mockAppId = 'app-123';
|
|
26
29
|
const mockScope = {
|
|
27
|
-
organisationId:
|
|
28
|
-
eventId:
|
|
30
|
+
organisationId: mockOrgId,
|
|
31
|
+
eventId: mockEventId,
|
|
32
|
+
appId: mockAppId
|
|
29
33
|
};
|
|
30
34
|
|
|
31
35
|
const mockPermissionMap = {
|
|
@@ -47,7 +51,7 @@ describe('usePermissions Hook', () => {
|
|
|
47
51
|
describe('Permission Fetching', () => {
|
|
48
52
|
it('fetches permissions for valid user', async () => {
|
|
49
53
|
|
|
50
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
54
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
51
55
|
|
|
52
56
|
expect(result.current.isLoading).toBe(true);
|
|
53
57
|
expect(result.current.permissions).toEqual({});
|
|
@@ -63,7 +67,7 @@ describe('usePermissions Hook', () => {
|
|
|
63
67
|
const error = new Error('Failed to fetch permissions');
|
|
64
68
|
mockGetPermissionMap.mockRejectedValue(error);
|
|
65
69
|
|
|
66
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
70
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
67
71
|
|
|
68
72
|
await waitFor(() => {
|
|
69
73
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -73,7 +77,7 @@ describe('usePermissions Hook', () => {
|
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
it('returns empty permissions for invalid user', async () => {
|
|
76
|
-
const { result } = renderHook(() => usePermissions('',
|
|
80
|
+
const { result } = renderHook(() => usePermissions('', mockOrgId, mockEventId, mockAppId));
|
|
77
81
|
|
|
78
82
|
await waitFor(() => {
|
|
79
83
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -112,7 +116,7 @@ describe('usePermissions Hook', () => {
|
|
|
112
116
|
});
|
|
113
117
|
|
|
114
118
|
it('hasPermission returns correct boolean', async () => {
|
|
115
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
119
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
116
120
|
|
|
117
121
|
await waitFor(() => {
|
|
118
122
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -126,7 +130,7 @@ describe('usePermissions Hook', () => {
|
|
|
126
130
|
});
|
|
127
131
|
|
|
128
132
|
it('hasAnyPermission works with multiple permissions', async () => {
|
|
129
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
133
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
130
134
|
|
|
131
135
|
await waitFor(() => {
|
|
132
136
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -138,7 +142,7 @@ describe('usePermissions Hook', () => {
|
|
|
138
142
|
});
|
|
139
143
|
|
|
140
144
|
it('hasAllPermissions works with multiple permissions', async () => {
|
|
141
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
145
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
142
146
|
|
|
143
147
|
await waitFor(() => {
|
|
144
148
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -150,7 +154,7 @@ describe('usePermissions Hook', () => {
|
|
|
150
154
|
});
|
|
151
155
|
|
|
152
156
|
it('handles empty permission lists', async () => {
|
|
153
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
157
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
154
158
|
|
|
155
159
|
await waitFor(() => {
|
|
156
160
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -165,7 +169,7 @@ describe('usePermissions Hook', () => {
|
|
|
165
169
|
it('refetch function works correctly', async () => {
|
|
166
170
|
mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
|
|
167
171
|
|
|
168
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
172
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
169
173
|
|
|
170
174
|
await waitFor(() => {
|
|
171
175
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -184,7 +188,7 @@ describe('usePermissions Hook', () => {
|
|
|
184
188
|
.mockResolvedValueOnce(mockPermissionMap)
|
|
185
189
|
.mockRejectedValueOnce(new Error('Refetch error'));
|
|
186
190
|
|
|
187
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
191
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
188
192
|
|
|
189
193
|
await waitFor(() => {
|
|
190
194
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -203,7 +207,7 @@ describe('usePermissions Hook', () => {
|
|
|
203
207
|
it('shows loading state during initial fetch', () => {
|
|
204
208
|
mockGetPermissionMap.mockImplementation(() => new Promise(() => {})); // Never resolves
|
|
205
209
|
|
|
206
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
210
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
207
211
|
|
|
208
212
|
expect(result.current.isLoading).toBe(true);
|
|
209
213
|
expect(result.current.permissions).toEqual({});
|
|
@@ -213,7 +217,7 @@ describe('usePermissions Hook', () => {
|
|
|
213
217
|
it('shows loading state during refetch', async () => {
|
|
214
218
|
mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
|
|
215
219
|
|
|
216
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
220
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
217
221
|
|
|
218
222
|
await waitFor(() => {
|
|
219
223
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -233,7 +237,7 @@ describe('usePermissions Hook', () => {
|
|
|
233
237
|
it('handles non-Error exceptions', async () => {
|
|
234
238
|
mockGetPermissionMap.mockRejectedValue('String error');
|
|
235
239
|
|
|
236
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
240
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
237
241
|
|
|
238
242
|
await waitFor(() => {
|
|
239
243
|
expect(result.current.error).toBeInstanceOf(Error);
|
|
@@ -246,7 +250,7 @@ describe('usePermissions Hook', () => {
|
|
|
246
250
|
.mockRejectedValueOnce(new Error('Initial error'))
|
|
247
251
|
.mockResolvedValueOnce(mockPermissionMap);
|
|
248
252
|
|
|
249
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
253
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
250
254
|
|
|
251
255
|
await waitFor(() => {
|
|
252
256
|
expect(result.current.error).toBeDefined();
|
|
@@ -275,7 +279,7 @@ describe('usePermissions Hook', () => {
|
|
|
275
279
|
|
|
276
280
|
mockGetPermissionMap.mockResolvedValue(superAdminPermissions);
|
|
277
281
|
|
|
278
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
282
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
279
283
|
|
|
280
284
|
await waitFor(() => {
|
|
281
285
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -304,7 +308,7 @@ describe('usePermissions Hook', () => {
|
|
|
304
308
|
|
|
305
309
|
mockGetPermissionMap.mockResolvedValue(orgAdminPermissions);
|
|
306
310
|
|
|
307
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
311
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
308
312
|
|
|
309
313
|
await waitFor(() => {
|
|
310
314
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -333,7 +337,7 @@ describe('usePermissions Hook', () => {
|
|
|
333
337
|
|
|
334
338
|
mockGetPermissionMap.mockResolvedValue(eventAdminPermissions);
|
|
335
339
|
|
|
336
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
340
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
337
341
|
|
|
338
342
|
await waitFor(() => {
|
|
339
343
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -363,7 +367,7 @@ describe('usePermissions Hook', () => {
|
|
|
363
367
|
|
|
364
368
|
mockGetPermissionMap.mockResolvedValue(memberPermissions);
|
|
365
369
|
|
|
366
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
370
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
367
371
|
|
|
368
372
|
await waitFor(() => {
|
|
369
373
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -393,7 +397,7 @@ describe('usePermissions Hook', () => {
|
|
|
393
397
|
|
|
394
398
|
mockGetPermissionMap.mockResolvedValue(participantPermissions);
|
|
395
399
|
|
|
396
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
400
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
397
401
|
|
|
398
402
|
await waitFor(() => {
|
|
399
403
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -465,7 +469,7 @@ describe('usePermissions Hook', () => {
|
|
|
465
469
|
|
|
466
470
|
describe('Edge Cases', () => {
|
|
467
471
|
it('handles null userId', async () => {
|
|
468
|
-
const { result } = renderHook(() => usePermissions(null as any,
|
|
472
|
+
const { result } = renderHook(() => usePermissions(null as any, mockOrgId, mockEventId, mockAppId));
|
|
469
473
|
|
|
470
474
|
await waitFor(() => {
|
|
471
475
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -475,7 +479,7 @@ describe('usePermissions Hook', () => {
|
|
|
475
479
|
});
|
|
476
480
|
|
|
477
481
|
it('handles undefined userId', async () => {
|
|
478
|
-
const { result } = renderHook(() => usePermissions(undefined as any,
|
|
482
|
+
const { result } = renderHook(() => usePermissions(undefined as any, mockOrgId, mockEventId, mockAppId));
|
|
479
483
|
|
|
480
484
|
await waitFor(() => {
|
|
481
485
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -487,7 +491,7 @@ describe('usePermissions Hook', () => {
|
|
|
487
491
|
it('handles empty scope', async () => {
|
|
488
492
|
mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
|
|
489
493
|
|
|
490
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
494
|
+
const { result } = renderHook(() => usePermissions(mockUserId, '', undefined, undefined));
|
|
491
495
|
|
|
492
496
|
// Wait for the hook to complete loading
|
|
493
497
|
await waitFor(() => {
|
|
@@ -506,7 +510,7 @@ describe('usePermissions Hook', () => {
|
|
|
506
510
|
|
|
507
511
|
mockGetPermissionMap.mockResolvedValue(largePermissionMap);
|
|
508
512
|
|
|
509
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
513
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
510
514
|
|
|
511
515
|
await waitFor(() => {
|
|
512
516
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -517,7 +521,7 @@ describe('usePermissions Hook', () => {
|
|
|
517
521
|
it('handles empty permission map', async () => {
|
|
518
522
|
mockGetPermissionMap.mockResolvedValue({});
|
|
519
523
|
|
|
520
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
524
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
521
525
|
|
|
522
526
|
await waitFor(() => {
|
|
523
527
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -532,9 +536,8 @@ describe('usePermissions Hook', () => {
|
|
|
532
536
|
});
|
|
533
537
|
|
|
534
538
|
it('handles scope with empty organisationId', async () => {
|
|
535
|
-
const invalidScope = { organisationId: '', eventId: 'event-123' };
|
|
536
539
|
|
|
537
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
540
|
+
const { result } = renderHook(() => usePermissions(mockUserId, '', 'event-123', undefined));
|
|
538
541
|
|
|
539
542
|
await waitFor(() => {
|
|
540
543
|
expect(result.current.isLoading).toBe(true);
|
|
@@ -544,9 +547,8 @@ describe('usePermissions Hook', () => {
|
|
|
544
547
|
});
|
|
545
548
|
|
|
546
549
|
it('handles scope with whitespace-only organisationId', async () => {
|
|
547
|
-
const invalidScope = { organisationId: ' ', eventId: 'event-123' };
|
|
548
550
|
|
|
549
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
551
|
+
const { result } = renderHook(() => usePermissions(mockUserId, ' ', 'event-123', undefined));
|
|
550
552
|
|
|
551
553
|
await waitFor(() => {
|
|
552
554
|
expect(result.current.isLoading).toBe(true);
|
|
@@ -560,7 +562,7 @@ describe('usePermissions Hook', () => {
|
|
|
560
562
|
it('maintains stable references for same permissions', async () => {
|
|
561
563
|
mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
|
|
562
564
|
|
|
563
|
-
const { result, rerender } = renderHook(() => usePermissions(mockUserId,
|
|
565
|
+
const { result, rerender } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
564
566
|
|
|
565
567
|
await waitFor(() => {
|
|
566
568
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -580,7 +582,7 @@ describe('usePermissions Hook', () => {
|
|
|
580
582
|
it('handles rapid permission checks efficiently', async () => {
|
|
581
583
|
mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
|
|
582
584
|
|
|
583
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
585
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
584
586
|
|
|
585
587
|
await waitFor(() => {
|
|
586
588
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -601,7 +603,7 @@ describe('usePermissions Hook', () => {
|
|
|
601
603
|
|
|
602
604
|
describe('[integration] Cache Invalidation', () => {
|
|
603
605
|
it('refetches after cache invalidation', async () => {
|
|
604
|
-
const { result } = renderHook(() => usePermissions(mockUserId,
|
|
606
|
+
const { result } = renderHook(() => usePermissions(mockUserId, mockOrgId, mockEventId, mockAppId));
|
|
605
607
|
|
|
606
608
|
await waitFor(() => {
|
|
607
609
|
expect(result.current.isLoading).toBe(false);
|
|
@@ -27,13 +27,20 @@ import { getRBACLogger } from '../config';
|
|
|
27
27
|
* Hook to get user's permissions in a scope
|
|
28
28
|
*
|
|
29
29
|
* @param userId - User ID
|
|
30
|
-
* @param
|
|
30
|
+
* @param organisationId - Organisation ID
|
|
31
|
+
* @param eventId - Event ID (optional)
|
|
32
|
+
* @param appId - Application ID (optional)
|
|
31
33
|
* @returns Permission state and methods
|
|
32
34
|
*
|
|
33
35
|
* @example
|
|
34
36
|
* ```tsx
|
|
35
37
|
* function MyComponent() {
|
|
36
|
-
* const { permissions, isLoading, error } = usePermissions(
|
|
38
|
+
* const { permissions, isLoading, error } = usePermissions(
|
|
39
|
+
* userId,
|
|
40
|
+
* organisationId,
|
|
41
|
+
* eventId,
|
|
42
|
+
* appId
|
|
43
|
+
* );
|
|
37
44
|
*
|
|
38
45
|
* if (isLoading) return <div>Loading...</div>;
|
|
39
46
|
* if (error) return <div>Error: {error.message}</div>;
|
|
@@ -47,29 +54,28 @@ import { getRBACLogger } from '../config';
|
|
|
47
54
|
* }
|
|
48
55
|
* ```
|
|
49
56
|
*/
|
|
50
|
-
export function usePermissions(
|
|
57
|
+
export function usePermissions(
|
|
58
|
+
userId: UUID,
|
|
59
|
+
organisationId: string | undefined,
|
|
60
|
+
eventId: string | undefined,
|
|
61
|
+
appId: string | undefined
|
|
62
|
+
) {
|
|
51
63
|
const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);
|
|
52
64
|
const [isLoading, setIsLoading] = useState(true);
|
|
53
65
|
const [error, setError] = useState<Error | null>(null);
|
|
54
66
|
const isFetchingRef = useRef(false);
|
|
55
67
|
const logger = getRBACLogger();
|
|
56
68
|
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
const orgId = scope.organisationId || '';
|
|
60
|
-
const eventId = scope.eventId;
|
|
61
|
-
const appId = scope.appId;
|
|
69
|
+
// Normalize organisationId to empty string if undefined
|
|
70
|
+
const orgId = organisationId || '';
|
|
62
71
|
|
|
63
72
|
// Log when hook is called with new scope (every render)
|
|
64
73
|
// This helps us see if React is calling the hook with updated scope
|
|
65
74
|
logger.warn('[usePermissions] Hook called with scope', {
|
|
66
75
|
userId,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
scopeOrgId: scope.organisationId,
|
|
71
|
-
scopeEventId: scope.eventId,
|
|
72
|
-
scopeAppId: scope.appId,
|
|
76
|
+
organisationId: orgId,
|
|
77
|
+
eventId,
|
|
78
|
+
appId,
|
|
73
79
|
hasAppId: !!appId,
|
|
74
80
|
hasOrganisationId: !!orgId
|
|
75
81
|
});
|
|
@@ -78,17 +84,17 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
78
84
|
React.useEffect(() => {
|
|
79
85
|
logger.warn('[usePermissions] Scope changed (useEffect)', {
|
|
80
86
|
userId,
|
|
81
|
-
organisationId:
|
|
82
|
-
eventId
|
|
83
|
-
appId
|
|
84
|
-
hasAppId: !!
|
|
85
|
-
hasOrganisationId: !!
|
|
87
|
+
organisationId: orgId,
|
|
88
|
+
eventId,
|
|
89
|
+
appId,
|
|
90
|
+
hasAppId: !!appId,
|
|
91
|
+
hasOrganisationId: !!orgId
|
|
86
92
|
});
|
|
87
|
-
}, [
|
|
93
|
+
}, [userId, orgId, eventId, appId]);
|
|
88
94
|
|
|
89
95
|
// Add timeout for missing organisation context (3 seconds)
|
|
90
96
|
useEffect(() => {
|
|
91
|
-
if (!
|
|
97
|
+
if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {
|
|
92
98
|
const timeoutId = setTimeout(() => {
|
|
93
99
|
setError(new Error('Organisation context is required for permission checks'));
|
|
94
100
|
setIsLoading(false);
|
|
@@ -100,7 +106,7 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
100
106
|
if (error?.message === 'Organisation context is required for permission checks') {
|
|
101
107
|
setError(null);
|
|
102
108
|
}
|
|
103
|
-
}, [
|
|
109
|
+
}, [orgId, error]);
|
|
104
110
|
|
|
105
111
|
useEffect(() => {
|
|
106
112
|
const fetchPermissions = async () => {
|
|
@@ -176,15 +182,15 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
176
182
|
setIsLoading(true);
|
|
177
183
|
setError(null);
|
|
178
184
|
|
|
179
|
-
// Build scope object
|
|
180
|
-
const
|
|
185
|
+
// Build scope object for API call
|
|
186
|
+
const scope: Scope = {
|
|
181
187
|
organisationId: orgId,
|
|
182
188
|
eventId: eventId,
|
|
183
189
|
appId: appId
|
|
184
190
|
};
|
|
185
191
|
|
|
186
192
|
// Fetch new permissions - don't clear old ones until we have new ones
|
|
187
|
-
const permissionMap = await getPermissionMap({ userId, scope
|
|
193
|
+
const permissionMap = await getPermissionMap({ userId, scope });
|
|
188
194
|
|
|
189
195
|
logger.warn('[usePermissions] Permissions fetched successfully', {
|
|
190
196
|
permissionCount: Object.keys(permissionMap).length,
|
|
@@ -211,7 +217,7 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
211
217
|
};
|
|
212
218
|
|
|
213
219
|
fetchPermissions();
|
|
214
|
-
}, [userId,
|
|
220
|
+
}, [userId, orgId, eventId, appId]);
|
|
215
221
|
|
|
216
222
|
const hasPermission = useCallback((permission: Permission): boolean => {
|
|
217
223
|
if (permissions['*']) {
|
|
@@ -248,7 +254,7 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
248
254
|
|
|
249
255
|
// Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)
|
|
250
256
|
// IMPORTANT: Don't clear existing permissions - keep them until we have new ones
|
|
251
|
-
if (!
|
|
257
|
+
if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {
|
|
252
258
|
// Keep existing permissions, just mark as loading
|
|
253
259
|
setIsLoading(true);
|
|
254
260
|
setError(null);
|
|
@@ -260,6 +266,13 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
260
266
|
setIsLoading(true);
|
|
261
267
|
setError(null);
|
|
262
268
|
|
|
269
|
+
// Build scope object for API call
|
|
270
|
+
const scope: Scope = {
|
|
271
|
+
organisationId: orgId,
|
|
272
|
+
eventId: eventId,
|
|
273
|
+
appId: appId
|
|
274
|
+
};
|
|
275
|
+
|
|
263
276
|
// Fetch new permissions - don't clear old ones until we have new ones
|
|
264
277
|
const permissionMap = await getPermissionMap({ userId, scope });
|
|
265
278
|
|
|
@@ -276,7 +289,7 @@ export function usePermissions(userId: UUID, scope: Scope) {
|
|
|
276
289
|
setIsLoading(false);
|
|
277
290
|
isFetchingRef.current = false;
|
|
278
291
|
}
|
|
279
|
-
}, [userId,
|
|
292
|
+
}, [userId, orgId, eventId, appId]);
|
|
280
293
|
|
|
281
294
|
// Memoize the return object to prevent unnecessary re-renders
|
|
282
295
|
return useMemo(() => ({
|