Enforced approval rights
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
Sparkles,
|
||||
MapPin,
|
||||
FileCheck,
|
||||
Lock,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
getProjects,
|
||||
@@ -194,7 +195,7 @@ export const BeneficiariesPage: React.FC = () => {
|
||||
benForm.reset();
|
||||
success('Beneficiary Registered', 'New project beneficiary profile successfully created.');
|
||||
},
|
||||
onError: (err: any) => toastError('Registration Failed', err),
|
||||
onError: (err: unknown) => toastError('Registration Failed', err),
|
||||
});
|
||||
|
||||
const updateBenMutation = useMutation({
|
||||
@@ -216,7 +217,7 @@ export const BeneficiariesPage: React.FC = () => {
|
||||
benForm.reset();
|
||||
success('Beneficiary Updated', 'Beneficiary details and targets updated.');
|
||||
},
|
||||
onError: (err: any) => toastError('Update Failed', err),
|
||||
onError: (err: unknown) => toastError('Update Failed', err),
|
||||
});
|
||||
|
||||
const createCompMutation = useMutation({
|
||||
@@ -231,7 +232,7 @@ export const BeneficiariesPage: React.FC = () => {
|
||||
compForm.reset();
|
||||
success('Compliance Requirement Logged', 'Compliance item registered for project beneficiaries.');
|
||||
},
|
||||
onError: (err: any) => toastError('Creation Failed', err),
|
||||
onError: (err: unknown) => toastError('Creation Failed', err),
|
||||
});
|
||||
|
||||
const updateCompMutation = useMutation({
|
||||
@@ -251,7 +252,7 @@ export const BeneficiariesPage: React.FC = () => {
|
||||
compForm.reset();
|
||||
success('Compliance Item Updated', 'Status and requirement record updated.');
|
||||
},
|
||||
onError: (err: any) => toastError('Update Failed', err),
|
||||
onError: (err: unknown) => toastError('Update Failed', err),
|
||||
});
|
||||
|
||||
const createOutcomeMutation = useMutation({
|
||||
@@ -265,7 +266,7 @@ export const BeneficiariesPage: React.FC = () => {
|
||||
outcomeForm.reset();
|
||||
success('Outcome Logged', 'Beneficiary outcome and impact metric registered.');
|
||||
},
|
||||
onError: (err: any) => toastError('Failed to Record Outcome', err),
|
||||
onError: (err: unknown) => toastError('Failed to Record Outcome', err),
|
||||
});
|
||||
|
||||
// Filtered & Sorted Beneficiaries
|
||||
@@ -1020,30 +1021,40 @@ export const BeneficiariesPage: React.FC = () => {
|
||||
{editingComp && (
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-slate-300 mb-1">Verification Status</label>
|
||||
<select
|
||||
{...compForm.register('status')}
|
||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-xs text-white focus:outline-none focus:border-blue-500"
|
||||
>
|
||||
{(() => {
|
||||
const canApproveComp = canApproveRecord('beneficiaries', editingComp?.createdBy);
|
||||
const isSelf = isMaker(editingComp?.createdBy);
|
||||
return APPROVAL_STATUS_OPTIONS.map((opt) => {
|
||||
const isApprovedOpt = opt.value === ApprovalStatus.Approved;
|
||||
const isOptDisabled = isApprovedOpt && !canApproveComp;
|
||||
let reason = '';
|
||||
if (isApprovedOpt && !canApprove('beneficiaries')) {
|
||||
reason = ' (Requires Update Permission)';
|
||||
} else if (isApprovedOpt && isSelf) {
|
||||
reason = ' (Maker-Checker: Cannot approve own record)';
|
||||
}
|
||||
return (
|
||||
<option key={opt.value} value={opt.value} disabled={isOptDisabled}>
|
||||
{opt.label}{reason}
|
||||
</option>
|
||||
);
|
||||
});
|
||||
})()}
|
||||
</select>
|
||||
{Number(editingComp.status) === ApprovalStatus.Approved ? (
|
||||
<div
|
||||
className="w-full bg-slate-900 border border-emerald-500/30 rounded-xl px-3 py-2 text-xs text-emerald-300 font-semibold flex items-center gap-1.5 cursor-default"
|
||||
title="Approved compliance records are immutable."
|
||||
>
|
||||
<Lock className="w-3.5 h-3.5 text-emerald-400" />
|
||||
<span>Approved (Immutable - Cannot Be Changed)</span>
|
||||
</div>
|
||||
) : (
|
||||
<select
|
||||
{...compForm.register('status')}
|
||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-xs text-white focus:outline-none focus:border-blue-500"
|
||||
>
|
||||
{(() => {
|
||||
const canApproveComp = canApproveRecord('beneficiaries', editingComp?.createdBy);
|
||||
const isSelf = isMaker(editingComp?.createdBy);
|
||||
return APPROVAL_STATUS_OPTIONS.map((opt) => {
|
||||
const isApprovedOpt = opt.value === ApprovalStatus.Approved;
|
||||
const isOptDisabled = isApprovedOpt && !canApproveComp;
|
||||
let reason = '';
|
||||
if (isApprovedOpt && !canApprove('beneficiaries')) {
|
||||
reason = ' (Requires Update Permission)';
|
||||
} else if (isApprovedOpt && isSelf) {
|
||||
reason = ' (Maker-Checker: Cannot approve own record)';
|
||||
}
|
||||
return (
|
||||
<option key={opt.value} value={opt.value} disabled={isOptDisabled}>
|
||||
{opt.label}{reason}
|
||||
</option>
|
||||
);
|
||||
});
|
||||
})()}
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user