adds access modifiers for each role
This commit is contained in:
+57
-43
@@ -1,21 +1,18 @@
|
||||
import { ROLES } from '../context/AuthContext';
|
||||
|
||||
// ─── Legacy static permissions (preserved for MaskedData, etc.) ───
|
||||
|
||||
export const PERMISSIONS = {
|
||||
// Admin / Owner Capabilities
|
||||
VIEW_ALL_PROJECTS: 'VIEW_ALL_PROJECTS',
|
||||
VIEW_ALL_PERSONNEL: 'VIEW_ALL_PERSONNEL',
|
||||
VIEW_FINANCIALS: 'VIEW_FINANCIALS',
|
||||
VIEW_SENSITIVE_DATA: 'VIEW_SENSITIVE_DATA', // SSN, Bank Accounts
|
||||
VIEW_SENSITIVE_DATA: 'VIEW_SENSITIVE_DATA',
|
||||
MANAGE_USERS: 'MANAGE_USERS',
|
||||
APPROVE_DOCUMENTS: 'APPROVE_DOCUMENTS',
|
||||
|
||||
// Contractor / Vendor Capabilities
|
||||
VIEW_ASSIGNED_PROJECTS: 'VIEW_ASSIGNED_PROJECTS',
|
||||
UPLOAD_DOCUMENTS: 'UPLOAD_DOCUMENTS',
|
||||
SUBMIT_INVOICES: 'SUBMIT_INVOICES',
|
||||
MANAGE_OWN_CREW: 'MANAGE_OWN_CREW',
|
||||
|
||||
// Subcontractor Capabilities
|
||||
VIEW_ASSIGNED_TASKS: 'VIEW_ASSIGNED_TASKS',
|
||||
UPDATE_TASK_STATUS: 'UPDATE_TASK_STATUS'
|
||||
};
|
||||
@@ -35,7 +32,6 @@ const ROLE_PERMISSIONS = {
|
||||
PERMISSIONS.VIEW_FINANCIALS,
|
||||
PERMISSIONS.MANAGE_USERS,
|
||||
PERMISSIONS.APPROVE_DOCUMENTS
|
||||
// Note: Admin might NOT have VIEW_SENSITIVE_DATA by default without extra auth
|
||||
],
|
||||
[ROLES.CONTRACTOR]: [
|
||||
PERMISSIONS.VIEW_ASSIGNED_PROJECTS,
|
||||
@@ -47,55 +43,73 @@ const ROLE_PERMISSIONS = {
|
||||
PERMISSIONS.VIEW_ASSIGNED_TASKS,
|
||||
PERMISSIONS.UPDATE_TASK_STATUS
|
||||
],
|
||||
[ROLES.FIELD_AGENT]: [
|
||||
// Standard CRM permissions
|
||||
],
|
||||
[ROLES.CUSTOMER]: [
|
||||
// Portal permissions
|
||||
]
|
||||
[ROLES.FIELD_AGENT]: [],
|
||||
[ROLES.CUSTOMER]: []
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a user has a specific permission.
|
||||
* @param {Object} user - The user object from AuthContext
|
||||
* @param {String} permission - The permission key to check
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export const hasPermission = (user, permission) => {
|
||||
if (!user || !user.role) return false;
|
||||
const userPermissions = ROLE_PERMISSIONS[user.role] || [];
|
||||
return userPermissions.includes(permission);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters a list of projects based on user role.
|
||||
* @param {Object} user - The user object
|
||||
* @param {Array} projects - Array of project objects
|
||||
* @returns {Array} - Filtered projects
|
||||
*/
|
||||
export const filterProjectsForUser = (user, projects) => {
|
||||
if (!user) return [];
|
||||
|
||||
if (user.role === ROLES.OWNER || user.role === ROLES.ADMIN) {
|
||||
return projects;
|
||||
}
|
||||
|
||||
if (user.role === ROLES.CONTRACTOR) {
|
||||
return projects.filter(p => p.contractorId === user.id);
|
||||
}
|
||||
|
||||
if (user.role === ROLES.SUBCONTRACTOR) {
|
||||
return projects.filter(p => p.subcontractorIds?.includes(user.id));
|
||||
}
|
||||
|
||||
if (user.role === ROLES.OWNER || user.role === ROLES.ADMIN) return projects;
|
||||
if (user.role === ROLES.CONTRACTOR) return projects.filter(p => p.contractorId === user.id);
|
||||
if (user.role === ROLES.SUBCONTRACTOR) return projects.filter(p => p.subcontractorIds?.includes(user.id));
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if sensitive data should be masked.
|
||||
* @param {Object} user - The viewer
|
||||
* @returns {Boolean} - True if data should be visible (NOT masked), False if it should be masked.
|
||||
*/
|
||||
export const canViewSensitiveData = (user) => {
|
||||
return hasPermission(user, PERMISSIONS.VIEW_SENSITIVE_DATA);
|
||||
};
|
||||
|
||||
// ─── Dynamic org-permission system ───
|
||||
|
||||
const AUTH_ROLE_TO_ORG_KEY = {
|
||||
OWNER: 'OWNER',
|
||||
ADMIN: 'ADMIN',
|
||||
FIELD_AGENT: 'CANVASSER',
|
||||
SUBCONTRACTOR: 'SUBCONTRACTOR',
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the org-level role key for a user.
|
||||
* Priority: orgMembers lookup (exact userId match) → auth-role fallback map.
|
||||
*/
|
||||
export const resolveOrgRoleKey = (user, orgMembers = []) => {
|
||||
if (!user) return null;
|
||||
|
||||
const member = orgMembers.find(
|
||||
m => m.userId === user.id || m.userId === user.empId,
|
||||
);
|
||||
if (member) return member.roleKey;
|
||||
|
||||
return AUTH_ROLE_TO_ORG_KEY[user.role] || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check a single module+action against the orgPermissions matrix.
|
||||
* Owner always returns true.
|
||||
*/
|
||||
export const checkOrgPermission = (orgRoleKey, orgPermissions, moduleKey, action) => {
|
||||
if (!orgRoleKey) return false;
|
||||
if (orgRoleKey === 'OWNER') return true;
|
||||
const actions = orgPermissions?.[moduleKey]?.[orgRoleKey] || [];
|
||||
return actions.includes(action);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute summary stats for a role across the permission matrix.
|
||||
*/
|
||||
export const computeRolePermissionStats = (roleKey, orgPermissions, permissionModules) => {
|
||||
let granted = 0;
|
||||
let total = 0;
|
||||
for (const [moduleKey, mod] of Object.entries(permissionModules)) {
|
||||
total += mod.actions.length;
|
||||
const roleActions = orgPermissions[moduleKey]?.[roleKey] || [];
|
||||
granted += roleActions.length;
|
||||
}
|
||||
return { granted, total };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user