Added, beneficiaries, site visits and change management
This commit is contained in:
@@ -41,6 +41,7 @@ import { HelpTooltip } from '../components/ui/HelpTooltip';
|
||||
import { useToast } from '../components/ui/Toast';
|
||||
import { ExportButton } from '../components/ui/ExportButton';
|
||||
import { ExportColumn } from '../utils/exportUtils';
|
||||
import { useTableSort, SortableTh } from '../utils/tableSort';
|
||||
import { ContractsManagement } from '../components/monitoring/ContractsManagement';
|
||||
import { EvidenceReviewQueue } from '../components/monitoring/EvidenceReviewQueue';
|
||||
import { RiskHeatmapMatrix } from '../components/ui/RiskHeatmapMatrix';
|
||||
@@ -373,6 +374,37 @@ export const MonitoringPage: React.FC = () => {
|
||||
return name.includes(q) || desc.includes(q) || projId.includes(q) || owner.includes(q) || mitig.includes(q);
|
||||
});
|
||||
|
||||
// Table Sorting Hooks
|
||||
const {
|
||||
sortedData: sortedIndicators,
|
||||
sortColumn: indSortCol,
|
||||
sortDirection: indSortDir,
|
||||
handleSort: handleIndSort,
|
||||
} = useTableSort(filteredIndicators, null, null, {
|
||||
name: (ind) => ind.name,
|
||||
projectId: (ind) => ind.projectId,
|
||||
unitOfMeasure: (ind) => getUnitOfMeasureLabel(ind.unitOfMeasure),
|
||||
baselineAmount: (ind) => ind.baselineAmount,
|
||||
targetAmount: (ind) => ind.targetAmount,
|
||||
actualAmount: (ind) => ind.actualAmount,
|
||||
status: (ind) => getIndicatorStatus(ind.actualAmount, ind.targetAmount).label,
|
||||
});
|
||||
|
||||
const {
|
||||
sortedData: sortedRisks,
|
||||
sortColumn: riskSortCol,
|
||||
sortDirection: riskSortDir,
|
||||
handleSort: handleRiskSort,
|
||||
} = useTableSort(filteredRisks, null, null, {
|
||||
name: (rk) => rk.name,
|
||||
projectId: (rk) => rk.projectId,
|
||||
likelihood: (rk) => rk.likelihood,
|
||||
impact: (rk) => rk.impact,
|
||||
residualScore: (rk) => rk.likelihood * rk.impact,
|
||||
owner: (rk) => getUserEmail(rk.owner),
|
||||
mitigationAction: (rk) => rk.mitigationAction || '',
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-6 max-w-7xl mx-auto">
|
||||
{/* Header */}
|
||||
@@ -643,14 +675,28 @@ export const MonitoringPage: React.FC = () => {
|
||||
<table className="w-full text-left text-xs border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-slate-900/60 border-b border-slate-800/80 text-slate-400 uppercase tracking-wider font-semibold">
|
||||
<th className="py-3.5 px-5">Indicator Name</th>
|
||||
<th className="py-3.5 px-4">Project ID</th>
|
||||
<th className="py-3.5 px-4">Unit of Measure</th>
|
||||
<th className="py-3.5 px-4 text-right">Baseline</th>
|
||||
<th className="py-3.5 px-4 text-right">Target</th>
|
||||
<th className="py-3.5 px-4 text-right">Actual Recorded</th>
|
||||
<th className="py-3.5 px-4">Status</th>
|
||||
<th className="py-3.5 px-5 text-right">Action</th>
|
||||
<SortableTh column="name" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} className="py-3.5 px-5">
|
||||
Indicator Name
|
||||
</SortableTh>
|
||||
<SortableTh column="projectId" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} className="py-3.5 px-4">
|
||||
Project ID
|
||||
</SortableTh>
|
||||
<SortableTh column="unitOfMeasure" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} className="py-3.5 px-4">
|
||||
Unit of Measure
|
||||
</SortableTh>
|
||||
<SortableTh column="baselineAmount" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} align="right" className="py-3.5 px-4 text-right">
|
||||
Baseline
|
||||
</SortableTh>
|
||||
<SortableTh column="targetAmount" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} align="right" className="py-3.5 px-4 text-right">
|
||||
Target
|
||||
</SortableTh>
|
||||
<SortableTh column="actualAmount" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} align="right" className="py-3.5 px-4 text-right">
|
||||
Actual Recorded
|
||||
</SortableTh>
|
||||
<SortableTh column="status" currentColumn={indSortCol} direction={indSortDir} onSort={handleIndSort} className="py-3.5 px-4">
|
||||
Status
|
||||
</SortableTh>
|
||||
<th className="py-3.5 px-5 text-right font-medium">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-800/50">
|
||||
@@ -661,7 +707,7 @@ export const MonitoringPage: React.FC = () => {
|
||||
Loading project indicators from API...
|
||||
</td>
|
||||
</tr>
|
||||
) : filteredIndicators.length === 0 ? (
|
||||
) : sortedIndicators.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={8} className="py-12 text-center text-slate-500">
|
||||
<TrendingUp className="w-8 h-8 text-slate-600 mx-auto mb-2" />
|
||||
@@ -671,7 +717,7 @@ export const MonitoringPage: React.FC = () => {
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
filteredIndicators.map((ind) => {
|
||||
sortedIndicators.map((ind) => {
|
||||
const statusObj = getIndicatorStatus(ind.actualAmount, ind.targetAmount);
|
||||
return (
|
||||
<tr key={ind.id} className="hover:bg-slate-800/40 transition-colors">
|
||||
@@ -833,14 +879,28 @@ export const MonitoringPage: React.FC = () => {
|
||||
<table className="w-full text-left text-xs border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-slate-900/60 border-b border-slate-800/80 text-slate-400 uppercase tracking-wider font-semibold">
|
||||
<th className="py-3.5 px-5">Risk Title & Description</th>
|
||||
<th className="py-3.5 px-4">Project ID</th>
|
||||
<th className="py-3.5 px-4 text-center">Likelihood (1–5)</th>
|
||||
<th className="py-3.5 px-4 text-center">Impact (1–5)</th>
|
||||
<th className="py-3.5 px-4 text-center">Residual Score</th>
|
||||
<th className="py-3.5 px-4">Risk Owner</th>
|
||||
<th className="py-3.5 px-5">Mitigation Control</th>
|
||||
<th className="py-3.5 px-4 text-right">Actions</th>
|
||||
<SortableTh column="name" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} className="py-3.5 px-5">
|
||||
Risk Title & Description
|
||||
</SortableTh>
|
||||
<SortableTh column="projectId" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} className="py-3.5 px-4">
|
||||
Project ID
|
||||
</SortableTh>
|
||||
<SortableTh column="likelihood" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} align="center" className="py-3.5 px-4 text-center">
|
||||
Likelihood (1–5)
|
||||
</SortableTh>
|
||||
<SortableTh column="impact" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} align="center" className="py-3.5 px-4 text-center">
|
||||
Impact (1–5)
|
||||
</SortableTh>
|
||||
<SortableTh column="residualScore" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} align="center" className="py-3.5 px-4 text-center">
|
||||
Residual Score
|
||||
</SortableTh>
|
||||
<SortableTh column="owner" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} className="py-3.5 px-4">
|
||||
Risk Owner
|
||||
</SortableTh>
|
||||
<SortableTh column="mitigationAction" currentColumn={riskSortCol} direction={riskSortDir} onSort={handleRiskSort} className="py-3.5 px-5">
|
||||
Mitigation Control
|
||||
</SortableTh>
|
||||
<th className="py-3.5 px-4 text-right font-medium">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-800/50">
|
||||
@@ -851,7 +911,7 @@ export const MonitoringPage: React.FC = () => {
|
||||
Loading risk register from API...
|
||||
</td>
|
||||
</tr>
|
||||
) : filteredRisks.length === 0 ? (
|
||||
) : sortedRisks.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={8} className="py-12 text-center text-slate-500">
|
||||
<ShieldAlert className="w-8 h-8 text-slate-600 mx-auto mb-2" />
|
||||
@@ -861,7 +921,7 @@ export const MonitoringPage: React.FC = () => {
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
filteredRisks.map((rk) => {
|
||||
sortedRisks.map((rk) => {
|
||||
const score = rk.likelihood * rk.impact;
|
||||
const color = getRiskScoreColor(rk.likelihood, rk.impact);
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user