jsg_pricing
v1.1.4
Published
## Permissions System
Readme
JetSetGo Application
Permissions System
The application includes a robust permissions system for managing access control throughout the application. This guide explains how to implement and use the permissions features.
Core Components
1. Permission Guard
The PermissionGuard component provides route-level protection:
import { PermissionGuard } from '../components/common/PermissionGuard';
function SecurePage() {
return (
<PermissionGuard permission="view:reports">
<div>Protected content...</div>
</PermissionGuard>
);
}2. Permissions Hook
The usePermissions hook provides methods for checking permissions:
import { usePermissions } from '../utils/permissions';
function MyComponent() {
const { can, hasAny, hasAll } = usePermissions();
// Check single permission
if (can('manage:users')) {
// User has permission...
}
// Check if user has any of the permissions
if (hasAny(['edit:reports', 'view:reports'])) {
// User has at least one permission...
}
// Check if user has all permissions
if (hasAll(['view:reports', 'edit:reports'])) {
// User has all permissions...
}
}Common Use Cases
1. Protecting Routes
// In your router configuration
<Route
path="/reports"
element={
<PrivateRoute>
<PermissionGuard permission="view:reports">
<ReportsPage />
</PermissionGuard>
</PrivateRoute>
}
/>2. Conditional Button Rendering
function ActionButton() {
const { can } = usePermissions();
if (!can('manage:users')) {
return null;
}
return <button>Manage Users</button>;
}3. Handling Unauthorized Actions
function ManageUsersButton() {
const { can } = usePermissions();
const [showToast, setShowToast] = useState(false);
const handleClick = () => {
if (!can('manage:users')) {
setShowToast(true);
return;
}
// Proceed with action...
};
return (
<>
<button onClick={handleClick}>Manage Users</button>
<Toast
message="You don't have permission to manage users."
isVisible={showToast}
onClose={() => setShowToast(false)}
/>
</>
);
}Best Practices
Always Check Permissions Server-Side
- Client-side permissions are for UI purposes only
- Implement proper server-side authorization checks
Use Specific Permissions
- Create granular permissions (e.g.,
view:reports,edit:reports) - Avoid broad permissions like
admin
- Create granular permissions (e.g.,
Handle Permission Denied Gracefully
- Use the
AccessDeniedcomponent for page-level access - Use the
Toastcomponent for action-level permissions - Provide clear feedback to users
- Use the
Combine with Authentication
- Always wrap permission checks inside authenticated routes
- Use
PrivateRoutebeforePermissionGuard
Available Permissions
Common permissions used in the application:
view:dashboard- Access to main dashboardmanage:users- User management capabilitiesmanage:groups- Group management capabilitiesview:reports- View reportsedit:reports- Edit reportssaveblueprint- Save blueprint configurationsmanagepermissions- Manage user permissions
Error Handling
The system includes built-in error handling:
Page Access Denied
- Shows a friendly error page
- Provides a "Go Back" button
- Automatically handles navigation
Action Access Denied
- Shows a toast notification
- Auto-dismisses after 5 seconds
- Provides clear feedback
TypeScript Support
The permissions system is fully typed:
interface PermissionGuardProps {
permission: string;
children: ReactNode;
}
interface UsePermissionsReturn {
can: (permission: string) => boolean;
hasAny: (permissions: string[]) => boolean;
hasAll: (permissions: string[]) => boolean;
}Testing Permissions
When testing components that use permissions:
import { usePermissions } from '../utils/permissions';
jest.mock('../utils/permissions', () => ({
usePermissions: jest.fn()
}));
describe('MyComponent', () => {
it('shows content when user has permission', () => {
(usePermissions as jest.Mock).mockReturnValue({
can: () => true
});
// Test component...
});
it('hides content when user lacks permission', () => {
(usePermissions as jest.Mock).mockReturnValue({
can: () => false
});
// Test component...
});
});