rights system
This commit is contained in:
98
frontend/src/contexts/PermissionContext.tsx
Normal file
98
frontend/src/contexts/PermissionContext.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React, { createContext, useContext, useMemo, useCallback, ReactNode } from 'react';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useAuth } from './AuthContext';
|
||||
import { permissionsApi } from '../services/permissions';
|
||||
|
||||
interface PermissionContextType {
|
||||
permissions: Set<string>;
|
||||
maintenance: Record<string, boolean>;
|
||||
isAdmin: boolean;
|
||||
isLoading: boolean;
|
||||
hasPermission: (perm: string) => boolean;
|
||||
hasAnyPermission: (...perms: string[]) => boolean;
|
||||
isFeatureEnabled: (featureGroup: string) => boolean;
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
const PermissionContext = createContext<PermissionContextType | undefined>(undefined);
|
||||
|
||||
interface PermissionProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const PermissionProvider: React.FC<PermissionProviderProps> = ({ children }) => {
|
||||
const { isAuthenticated } = useAuth();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['my-permissions'],
|
||||
queryFn: permissionsApi.getMyPermissions,
|
||||
enabled: isAuthenticated,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const permissions = useMemo(
|
||||
() => new Set(data?.permissions ?? []),
|
||||
[data?.permissions]
|
||||
);
|
||||
|
||||
const maintenance = data?.maintenance ?? {};
|
||||
const isAdmin = data?.isAdmin ?? false;
|
||||
|
||||
const isFeatureEnabled = useCallback(
|
||||
(featureGroup: string): boolean => {
|
||||
if (isAdmin) return true;
|
||||
return !maintenance[featureGroup];
|
||||
},
|
||||
[isAdmin, maintenance]
|
||||
);
|
||||
|
||||
const hasPermission = useCallback(
|
||||
(perm: string): boolean => {
|
||||
if (isAdmin) return true;
|
||||
const featureGroup = perm.split(':')[0];
|
||||
if (!isFeatureEnabled(featureGroup)) return false;
|
||||
return permissions.has(perm);
|
||||
},
|
||||
[isAdmin, permissions, isFeatureEnabled]
|
||||
);
|
||||
|
||||
const hasAnyPermission = useCallback(
|
||||
(...perms: string[]): boolean => {
|
||||
return perms.some(p => hasPermission(p));
|
||||
},
|
||||
[hasPermission]
|
||||
);
|
||||
|
||||
const refetch = useCallback(() => {
|
||||
queryClient.invalidateQueries({ queryKey: ['my-permissions'] });
|
||||
}, [queryClient]);
|
||||
|
||||
const value = useMemo(
|
||||
(): PermissionContextType => ({
|
||||
permissions,
|
||||
maintenance,
|
||||
isAdmin,
|
||||
isLoading: isAuthenticated ? isLoading : false,
|
||||
hasPermission,
|
||||
hasAnyPermission,
|
||||
isFeatureEnabled,
|
||||
refetch,
|
||||
}),
|
||||
[permissions, maintenance, isAdmin, isAuthenticated, isLoading, hasPermission, hasAnyPermission, isFeatureEnabled, refetch]
|
||||
);
|
||||
|
||||
return (
|
||||
<PermissionContext.Provider value={value}>
|
||||
{children}
|
||||
</PermissionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePermissionContext = (): PermissionContextType => {
|
||||
const context = useContext(PermissionContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('usePermissionContext must be used within a PermissionProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
Reference in New Issue
Block a user