Fixed timeline height

Moved export and fixed data output
Added project budget amount widget to project listing
This commit is contained in:
2026-09-28 11:55:52 +02:00
parent 891801c73d
commit 242a4c6fbb
4 changed files with 134 additions and 30 deletions
@@ -19,8 +19,9 @@ import {
getMilestones,
getProjectIndicators,
getProjectRisks,
getBudgets,
} from '../../services/api';
import { Project, ApprovalStatus } from '../../types';
import { Project, ApprovalStatus, Budget } from '../../types';
import {
formatDate,
formatZAR,
@@ -70,6 +71,21 @@ export const ProjectExpandedRow: React.FC<ProjectExpandedRowProps> = ({
queryFn: () => getProjectRisks(projectId),
});
const { data: allBudgets = [] } = useQuery({
queryKey: ['budgets'],
queryFn: () => getBudgets(1, 100),
});
const projectBudgets = allBudgets.filter((b) => String(b.projectId) === String(projectId));
const approvedBudgets = projectBudgets.filter(
(b) =>
b.status === undefined ||
b.status === null ||
Number(b.status) === ApprovalStatus.Approved ||
Number(b.status) === 3
);
const approvedBudgetTotal = approvedBudgets.reduce((sum, b) => sum + (Number(b.amount) || 0), 0);
const verifiedMilestonesCount = milestones.filter((m) => m.status === ApprovalStatus.Approved).length;
const milestoneProgress = milestones.length > 0 ? Math.round((verifiedMilestonesCount / milestones.length) * 100) : 0;
const totalActivityBudget = activities.reduce((sum, a) => sum + (Number(a.amount) || 0), 0);
@@ -86,6 +102,14 @@ export const ProjectExpandedRow: React.FC<ProjectExpandedRowProps> = ({
<span className="text-xs text-slate-400">
Owner / Created by: <strong className="text-slate-200">{getUserEmail(project.createdBy)}</strong>
</span>
{approvedBudgetTotal > 0 && (
<>
<span className="text-slate-600">&bull;</span>
<span className="text-xs text-emerald-400 font-mono font-semibold">
Approved Budget: {formatZAR(approvedBudgetTotal)}
</span>
</>
)}
</div>
<p className="text-xs text-slate-300 leading-relaxed">{project.description}</p>
</div>
@@ -114,6 +138,8 @@ export const ProjectExpandedRow: React.FC<ProjectExpandedRowProps> = ({
project={project}
milestones={milestones}
activities={activities}
approvedBudgetTotal={approvedBudgetTotal}
approvedBudgetsCount={approvedBudgets.length}
onManageMilestones={onOpenMilestonesModal}
onManageActivities={onOpenActivitiesModal}
/>
@@ -17,6 +17,8 @@ interface ProjectTimelineGanttProps {
project: Project;
milestones: Milestone[];
activities: Activity[];
approvedBudgetTotal?: number;
approvedBudgetsCount?: number;
onManageMilestones: () => void;
onManageActivities: () => void;
}
@@ -25,6 +27,8 @@ export const ProjectTimelineGantt: React.FC<ProjectTimelineGanttProps> = ({
project,
milestones,
activities,
approvedBudgetTotal = 0,
approvedBudgetsCount = 0,
onManageMilestones,
onManageActivities,
}) => {
@@ -362,7 +366,7 @@ export const ProjectTimelineGantt: React.FC<ProjectTimelineGanttProps> = ({
</div>
{/* Bottom Summary KPI Bar */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 pt-2">
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 pt-2">
<div className="p-3 bg-[#090d16] rounded-xl border border-slate-800">
<span className="text-[10px] uppercase font-bold text-slate-500 block">Project Duration</span>
<span className="text-sm font-bold text-white mt-0.5 block">
@@ -379,7 +383,7 @@ export const ProjectTimelineGantt: React.FC<ProjectTimelineGanttProps> = ({
<span className="text-sm font-bold text-emerald-400">{milestoneProgress}%</span>
<span className="text-[10px] text-slate-400">({verifiedMilestonesCount}/{milestones.length})</span>
</div>
<div className="w-full h-1.5 bg-slate-800 rounded-full mt-1.5 overflow-hidden">
<div className="w-full h-1.5 bg-slate-900 rounded-full mt-1.5 overflow-hidden">
<div
className="h-full bg-emerald-500 rounded-full transition-all"
style={{ width: `${milestoneProgress}%` }}
@@ -409,6 +413,19 @@ export const ProjectTimelineGantt: React.FC<ProjectTimelineGanttProps> = ({
</div>
<span className="text-[10px] text-slate-500 mt-0.5 block">Statutory Clearance</span>
</div>
{/* Total Value of Approved Project Budgets Widget */}
<div className="p-3 bg-[#090d16] rounded-xl border border-slate-800">
<span className="text-[10px] uppercase font-bold text-slate-500 block">Approved Budget Value</span>
<span className="text-sm font-bold text-emerald-400 mt-0.5 block font-mono">
{formatZAR(approvedBudgetTotal)}
</span>
<span className="text-[10px] text-slate-400">
{approvedBudgetsCount > 0
? `${approvedBudgetsCount} approved budget line${approvedBudgetsCount === 1 ? '' : 's'}`
: 'Allocated Project Budget'}
</span>
</div>
</div>
</div>
);