(false);
@@ -238,6 +248,7 @@ const RatecardTable: React.FC = () => {
type="number"
value={roles[index]?.rate ?? 0}
min={0}
+ disabled={!hasEditPermission}
style={{
background: 'transparent',
border: 'none',
@@ -245,10 +256,12 @@ const RatecardTable: React.FC = () => {
padding: 0,
width: 80,
textAlign: 'right',
+ opacity: hasEditPermission ? 1 : 0.7,
+ cursor: hasEditPermission ? 'text' : 'not-allowed'
}}
- onChange={(e) => handleRateChange(e.target.value, index)}
- onBlur={(e) => handleRateBlur(e.target.value, index)}
- onPressEnter={(e) => handleRateBlur(e.target.value, index)}
+ onChange={hasEditPermission ? (e) => handleRateChange(e.target.value, index) : undefined}
+ onBlur={hasEditPermission ? (e) => handleRateBlur(e.target.value, index) : undefined}
+ onPressEnter={hasEditPermission ? (e) => handleRateBlur(e.target.value, index) : undefined}
/>
),
},
@@ -265,15 +278,17 @@ const RatecardTable: React.FC = () => {
) : null;
})}
-
- handleMemberChange(memberId, index, record)}
- memberlist={members}
- assignedMembers={assignedMembers} // Pass assigned members here
- />
-
+ {canAddMembers && (
+
+ handleMemberChange(memberId, index, record)}
+ memberlist={members}
+ assignedMembers={assignedMembers} // Pass assigned members here
+ />
+
+ )}
),
},
@@ -282,14 +297,16 @@ const RatecardTable: React.FC = () => {
key: 'actions',
align: 'center',
render: (_: any, record: JobRoleType, index: number) => (
- handleDelete(record, index)}
- okText={t('yes')}
- cancelText={t('no')}
- >
- } />
-
+ hasEditPermission ? (
+ handleDelete(record, index)}
+ okText={t('yes')}
+ cancelText={t('no')}
+ >
+ } />
+
+ ) : null
),
},
];
@@ -315,9 +332,11 @@ const RatecardTable: React.FC = () => {
loading={isLoading || isLoadingMembers}
footer={() => (
-
+ {hasEditPermission && (
+
+ )}
{/* }
diff --git a/worklenz-frontend/src/utils/finance-permissions.ts b/worklenz-frontend/src/utils/finance-permissions.ts
new file mode 100644
index 00000000..9214f3e8
--- /dev/null
+++ b/worklenz-frontend/src/utils/finance-permissions.ts
@@ -0,0 +1,58 @@
+import { ILocalSession } from '@/types/auth/local-session.types';
+import { IProjectViewModel } from '@/types/project/projectViewModel.types';
+
+/**
+ * Checks if the current user has permission to edit finance data
+ * Only users with project admin, admin or owner roles should be able to:
+ * - Change fixed cost values
+ * - Add members to rate cards
+ * - Change rate per hour values
+ */
+export const hasFinanceEditPermission = (
+ currentSession: ILocalSession | null,
+ currentProject?: IProjectViewModel | null
+): boolean => {
+ if (!currentSession) return false;
+
+ // Team owner or admin always have permission
+ if (currentSession.owner || currentSession.is_admin) {
+ return true;
+ }
+
+ // Project manager has permission
+ if (currentProject?.project_manager?.id === currentSession.team_member_id) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * Checks if the current user can edit fixed costs
+ */
+export const canEditFixedCost = (
+ currentSession: ILocalSession | null,
+ currentProject?: IProjectViewModel | null
+): boolean => {
+ return hasFinanceEditPermission(currentSession, currentProject);
+};
+
+/**
+ * Checks if the current user can edit rate card data
+ */
+export const canEditRateCard = (
+ currentSession: ILocalSession | null,
+ currentProject?: IProjectViewModel | null
+): boolean => {
+ return hasFinanceEditPermission(currentSession, currentProject);
+};
+
+/**
+ * Checks if the current user can add members to rate cards
+ */
+export const canAddMembersToRateCard = (
+ currentSession: ILocalSession | null,
+ currentProject?: IProjectViewModel | null
+): boolean => {
+ return hasFinanceEditPermission(currentSession, currentProject);
+};
\ No newline at end of file