Implemented rbac
This commit is contained in:
@@ -45,6 +45,7 @@ import { useToast } from '../components/ui/Toast';
|
||||
import { ExportButton } from '../components/ui/ExportButton';
|
||||
import { ExportColumn } from '../utils/exportUtils';
|
||||
import { useTableSort, SortableTh } from '../utils/tableSort';
|
||||
import { useRbac } from '../auth/rbac';
|
||||
import {
|
||||
Award,
|
||||
Budget,
|
||||
@@ -98,6 +99,7 @@ type DisbursementFormValues = z.infer<typeof disbursementSchema>;
|
||||
export const GrantsPage: React.FC = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { success, error: toastError } = useToast();
|
||||
const { canAdd, canApprove, canExport } = useRbac();
|
||||
|
||||
const [activeTab, setActiveTab] = useState<'awards' | 'budgets' | 'disbursements'>('awards');
|
||||
|
||||
@@ -666,7 +668,7 @@ export const GrantsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 relative z-10 self-start md:self-center">
|
||||
{activeTab === 'awards' && (
|
||||
{activeTab === 'awards' && canAdd('grant_financials') && (
|
||||
<button
|
||||
onClick={openCreateAward}
|
||||
className="inline-flex items-center gap-1.5 px-4 py-2.5 text-xs font-semibold text-white bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 rounded-xl shadow-lg shadow-emerald-600/25 transition cursor-pointer"
|
||||
@@ -675,7 +677,7 @@ export const GrantsPage: React.FC = () => {
|
||||
<span>Register Approved Award</span>
|
||||
</button>
|
||||
)}
|
||||
{activeTab === 'budgets' && (
|
||||
{activeTab === 'budgets' && canAdd('grant_financials') && (
|
||||
<button
|
||||
onClick={() => setIsBudgetModalOpen(true)}
|
||||
className="inline-flex items-center gap-1.5 px-4 py-2.5 text-xs font-semibold text-white bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 rounded-xl shadow-lg shadow-emerald-600/25 transition cursor-pointer"
|
||||
@@ -684,7 +686,7 @@ export const GrantsPage: React.FC = () => {
|
||||
<span>Add Budget Line</span>
|
||||
</button>
|
||||
)}
|
||||
{activeTab === 'disbursements' && (
|
||||
{activeTab === 'disbursements' && canAdd('grant_financials') && (
|
||||
<button
|
||||
onClick={openCreateDisbursement}
|
||||
className="inline-flex items-center gap-1.5 px-4 py-2.5 text-xs font-semibold text-white bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 rounded-xl shadow-lg shadow-emerald-600/25 transition cursor-pointer"
|
||||
@@ -802,6 +804,7 @@ export const GrantsPage: React.FC = () => {
|
||||
<span>Refresh Awards</span>
|
||||
</button>
|
||||
<ExportButton
|
||||
claim="grant_financials"
|
||||
title="Grant Awards Registry"
|
||||
subtitle="Official directory of approved beneficiary funding allocations"
|
||||
filename={`pfm-awards-${new Date().toISOString().split('T')[0]}`}
|
||||
@@ -915,6 +918,7 @@ export const GrantsPage: React.FC = () => {
|
||||
<span>Refresh Budgets</span>
|
||||
</button>
|
||||
<ExportButton
|
||||
claim="grant_financials"
|
||||
title="Project Budgets Registry"
|
||||
subtitle="Detailed statutory project budget allocations and category lines"
|
||||
filename={`pfm-budgets-${new Date().toISOString().split('T')[0]}`}
|
||||
@@ -998,7 +1002,7 @@ export const GrantsPage: React.FC = () => {
|
||||
<Edit2 className="w-3 h-3" />
|
||||
<span>Update</span>
|
||||
</button>
|
||||
{b.status !== ApprovalStatus.Approved && (
|
||||
{b.status !== ApprovalStatus.Approved && canApprove('grant_financials') && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={updateBudgetMutation.isPending}
|
||||
@@ -1057,6 +1061,7 @@ export const GrantsPage: React.FC = () => {
|
||||
<span>Refresh Disbursements</span>
|
||||
</button>
|
||||
<ExportButton
|
||||
claim="grant_financials"
|
||||
title="Disbursement Tranches Ledger"
|
||||
subtitle="Milestone-linked funding releases and payment authorizations"
|
||||
filename={`pfm-disbursements-${new Date().toISOString().split('T')[0]}`}
|
||||
@@ -1154,14 +1159,16 @@ export const GrantsPage: React.FC = () => {
|
||||
>
|
||||
<Edit2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => approveMutation.mutate(d.id)}
|
||||
disabled={approveMutation.isPending}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold text-white bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-500 hover:to-indigo-500 rounded-lg shadow-md shadow-blue-500/20 transition cursor-pointer"
|
||||
>
|
||||
<CheckCircle className="w-3.5 h-3.5" />
|
||||
Approve Payment
|
||||
</button>
|
||||
{canApprove('grant_financials') && (
|
||||
<button
|
||||
onClick={() => approveMutation.mutate(d.id)}
|
||||
disabled={approveMutation.isPending}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold text-white bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-500 hover:to-indigo-500 rounded-lg shadow-md shadow-blue-500/20 transition cursor-pointer"
|
||||
>
|
||||
<CheckCircle className="w-3.5 h-3.5" />
|
||||
Approve Payment
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -1555,7 +1562,9 @@ export const GrantsPage: React.FC = () => {
|
||||
onChange={(e) => setSelectedBudgetStatus(Number(e.target.value) as ApprovalStatus)}
|
||||
className="w-full px-3 py-2 text-xs bg-slate-900/80 border border-slate-700/80 rounded-xl text-white focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 font-medium [&>option]:bg-slate-900 [&>option]:text-white"
|
||||
>
|
||||
<option value={ApprovalStatus.Approved}>Approved</option>
|
||||
<option value={ApprovalStatus.Approved} disabled={!canApprove('grant_financials')}>
|
||||
Approved {!canApprove('grant_financials') ? '(Requires Update Permission)' : ''}
|
||||
</option>
|
||||
<option value={ApprovalStatus.Pending}>Pending Review</option>
|
||||
<option value={ApprovalStatus.Rejected}>Rejected / Blocked</option>
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user