Added, beneficiaries, site visits and change management

This commit is contained in:
2026-09-27 11:40:28 +02:00
parent fb27cc8c92
commit 36e5d3d7c8
16 changed files with 3132 additions and 212 deletions
@@ -42,6 +42,7 @@ import { useToast } from '../ui/Toast';
import { ProblemDetailsAlert } from '../ui/ProblemDetailsAlert';
import { ExportButton } from '../ui/ExportButton';
import { ExportColumn } from '../../utils/exportUtils';
import { useTableSort, SortableTh } from '../../utils/tableSort';
import {
Contract,
Award,
@@ -406,6 +407,30 @@ export const ContractsManagement: React.FC<ContractsManagementProps> = ({
{ header: 'Document URI', key: 'fileUri', format: (val) => val || '—' },
];
// Table sorting hook
const {
sortedData: sortedContracts,
sortColumn: contractSortCol,
sortDirection: contractSortDir,
handleSort: handleContractSort,
} = useTableSort<Contract>(filteredContracts, null, null, {
id: (c: any) => c.id,
awardId: (c: any) => c.totalValue || c.awardId,
programmeId: (c: any) => {
const a = getAwardForContract(c);
const pr = getProgrammeForAward(a);
return pr?.name || '';
},
organisationId: (c: any) => {
const a = getAwardForContract(c);
const o = getOrganisationForAward(a);
return o?.name || '';
},
signedDate: (c: any) => c.signedDate,
status: (c: any) => getContractStatusBadge(c.status).label,
fileUri: (c: any) => c.fileUri || '',
});
return (
<div className="space-y-6">
{/* Summary Cards */}
@@ -612,18 +637,32 @@ export const ContractsManagement: React.FC<ContractsManagementProps> = ({
<table className="w-full text-left text-xs text-slate-300">
<thead className="bg-[#151b2c]/80 text-slate-400 border-b border-slate-800/80 uppercase font-semibold text-[11px] tracking-wider">
<tr>
<th className="py-3.5 px-4">Contract / Ref</th>
<th className="py-3.5 px-4">Award & Amount</th>
<th className="py-3.5 px-4">Programme & Project</th>
<th className="py-3.5 px-4">Organisation</th>
<th className="py-3.5 px-4">Validity Period</th>
<th className="py-3.5 px-4">Status</th>
<th className="py-3.5 px-4">Document / S3</th>
<th className="py-3.5 px-4 text-right">Actions</th>
<SortableTh column="id" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Contract / Ref
</SortableTh>
<SortableTh column="awardId" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Award & Amount
</SortableTh>
<SortableTh column="programmeId" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Programme & Project
</SortableTh>
<SortableTh column="organisationId" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Organisation
</SortableTh>
<SortableTh column="signedDate" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Validity Period
</SortableTh>
<SortableTh column="status" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Status
</SortableTh>
<SortableTh column="fileUri" currentColumn={contractSortCol} direction={contractSortDir} onSort={handleContractSort} className="py-3.5 px-4">
Document / S3
</SortableTh>
<th className="py-3.5 px-4 text-right font-medium">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/50">
{filteredContracts.map((contract) => {
{sortedContracts.map((contract) => {
const award = getAwardForContract(contract);
const org = getOrganisationForAward(award);
const prog = getProgrammeForAward(award);
@@ -233,7 +233,7 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
if (variables.status === ApprovalStatus.Approved) {
success('Evidence Approved & Verified', 'Approval recorded. Contributes towards contractual milestone sign-off.');
} else if (variables.status === ApprovalStatus.Rejected) {
success('Evidence Rejected', 'Evidence marked as Rejected via verification endpoint.');
success('Evidence Rejected', 'Evidence marked as Rejected by reviewer.');
} else {
success('Status Updated', 'Evidence status updated successfully.');
}
@@ -971,7 +971,7 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
</div>
<p className="text-[11px] text-slate-400 leading-relaxed">
Review the deliverable document against contractual requirements. If the evidence does not satisfy requirements, reject the submission using the endpoint action below. Approved evidence validates progress towards milestone completion.
Review the deliverable document against contractual requirements. If the evidence does not satisfy requirements, reject the submission using the review actions below. Approved evidence validates progress towards milestone completion.
</p>
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pt-1">