import { mdiBankOutline, mdiBellOutline, mdiCheckDecagramOutline, mdiChartTimelineVariant, mdiClipboardClockOutline, mdiClipboardListOutline, mdiFileDocumentOutline, mdiPlus, mdiShieldAlertOutline, mdiWalletOutline, } from '@mdi/js'; import axios from 'axios'; import Head from 'next/head'; import Link from 'next/link'; import React, { ReactElement, ReactNode, useEffect, useMemo, useState } from 'react'; import BaseButton from '../components/BaseButton'; import BaseButtons from '../components/BaseButtons'; import BaseIcon from '../components/BaseIcon'; import CardBox from '../components/CardBox'; import NotificationBar from '../components/NotificationBar'; import SectionMain from '../components/SectionMain'; import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'; import { getWorkspaceConfig, type WorkspaceDetailBlockKey, type WorkspaceMetricKey, type WorkspaceQuickLinkIconKey, } from '../helpers/workspace'; import LayoutAuthenticated from '../layouts/Authenticated'; import { getPageTitle } from '../config'; import { useAppSelector } from '../stores/hooks'; interface BudgetByCurrency { USD: number; CDF: number; } interface Summary { approvedBudget: BudgetByCurrency; committedBudget: BudgetByCurrency; disbursedBudget: BudgetByCurrency; budgetVariance: BudgetByCurrency; activeProjects: number; procurementPipeline: number; pendingApprovals: number; contractsNearingExpiry: number; overduePayments: number; vendorComplianceAlerts: number; openRiskAlerts: number; unreadNotifications: number; averageProjectProgress: number; highRiskProjects: number; } interface ApprovalItem { id: string; recordType: string; recordKey: string; status: string; requestedAt: string; workflowName: string; stepName: string; stepOrder: number | null; requestedBy: string; assignedTo: string; } interface ProcurementItem { id: string; requisitionNumber: string; title: string; procurementMethod: string; estimatedAmount: number; currency: 'USD' | 'CDF'; neededByDate: string; status: string; provinceName: string; } interface ContractItem { id: string; contractNumber: string; title: string; contractValue: number; currency: 'USD' | 'CDF'; endDate: string; status: string; vendorName: string; projectName: string; daysToExpiry?: number | null; } interface RiskItem { id: string; alertType: string; severity: string; title: string; details: string; recordType: string; recordKey: string; dueAt: string; status: string; assignedTo: string; } interface ProvinceItem { provinceName: string; totalProjects: number; activeProjects: number; averageCompletion: number; } interface NotificationItem { id: string; type: string; title: string; message: string; read: boolean; sentAt: string; recordType: string; recordKey: string; } interface WorkspaceFocusCard { key: string; title: string; value: string; note: string; href: string; } interface WorkspaceWatchlistCard { key: string; title: string; count: number; note: string; href: string; } interface WorkspacePayload { roleName: string; summaryMetricKeys: Array; focusCards: WorkspaceFocusCard[]; watchlistCards: WorkspaceWatchlistCard[]; } interface ExecutiveSummaryResponse { workspace?: WorkspacePayload; summary: Summary; approvalQueue: ApprovalItem[]; procurementQueue: ProcurementItem[]; contractWatchlist: ContractItem[]; topContracts: ContractItem[]; riskPanel: RiskItem[]; provinceRollout: ProvinceItem[]; recentNotifications: NotificationItem[]; } interface MetricDefinition { title: string; value: string; note: string; icon: string; } const defaultResponse: ExecutiveSummaryResponse = { workspace: { roleName: '', summaryMetricKeys: [], focusCards: [], watchlistCards: [], }, summary: { approvedBudget: { USD: 0, CDF: 0 }, committedBudget: { USD: 0, CDF: 0 }, disbursedBudget: { USD: 0, CDF: 0 }, budgetVariance: { USD: 0, CDF: 0 }, activeProjects: 0, procurementPipeline: 0, pendingApprovals: 0, contractsNearingExpiry: 0, overduePayments: 0, vendorComplianceAlerts: 0, openRiskAlerts: 0, unreadNotifications: 0, averageProjectProgress: 0, highRiskProjects: 0, }, approvalQueue: [], procurementQueue: [], contractWatchlist: [], topContracts: [], riskPanel: [], provinceRollout: [], recentNotifications: [], }; const actionIconMap: Record = { organizations: mdiBankOutline, users: mdiCheckDecagramOutline, approvals: mdiClipboardClockOutline, notifications: mdiBellOutline, projects: mdiChartTimelineVariant, contracts: mdiFileDocumentOutline, payments: mdiWalletOutline, allocations: mdiBankOutline, requisitions: mdiClipboardListOutline, tenders: mdiClipboardListOutline, compliance: mdiShieldAlertOutline, audit: mdiShieldAlertOutline, milestones: mdiChartTimelineVariant, vendors: mdiCheckDecagramOutline, }; const formatCurrency = (value: number, currency: 'USD' | 'CDF') => new Intl.NumberFormat(currency === 'CDF' ? 'fr-CD' : 'en-US', { style: 'currency', currency, maximumFractionDigits: 0, }).format(value || 0); const formatDate = (value?: string | null) => { if (!value) { return '—'; } return new Intl.DateTimeFormat('en-GB', { day: '2-digit', month: 'short', year: 'numeric', }).format(new Date(value)); }; const humanize = (value?: string | null) => (value || '—') .replace(/_/g, ' ') .replace(/\b\w/g, (letter) => letter.toUpperCase()); const statusBadgeClass = (status?: string) => { switch (status) { case 'approved': case 'active': case 'processed': return 'bg-emerald-50 text-emerald-700 border-emerald-200'; case 'pending': case 'submitted': case 'under_review': case 'in_tender': case 'awarded': case 'batched': return 'bg-amber-50 text-amber-700 border-amber-200'; case 'rejected': case 'cancelled': case 'expired': case 'terminated': case 'failed': return 'bg-red-50 text-red-700 border-red-200'; default: return 'bg-slate-100 text-slate-700 border-slate-200'; } }; const severityBadgeClass = (severity?: string) => { switch (severity) { case 'critical': return 'bg-red-100 text-red-800 border-red-200'; case 'high': return 'bg-rose-50 text-rose-700 border-rose-200'; case 'warning': return 'bg-amber-50 text-amber-700 border-amber-200'; default: return 'bg-slate-100 text-slate-700 border-slate-200'; } }; const getRecordLink = (recordType?: string, recordKey?: string) => { if (!recordType || !recordKey) { return '/approvals/approvals-list'; } const allowedDetailPages = new Set([ 'requisitions', 'contracts', 'projects', 'vendors', 'tenders', 'awards', 'invoices', 'payment_requests', 'budget_reallocations', 'grants', ]); if (!allowedDetailPages.has(recordType)) { return '/approvals/approvals-list'; } return `/${recordType}/${recordType}-view?id=${recordKey}`; }; const SectionHeader = ({ eyebrow, title, action, }: { eyebrow: string; title: string; action?: ReactNode; }) => (

{eyebrow}

{title}

{action}
); const SummaryMetric = ({ title, value, note, icon, }: { title: string; value: string; note: string; icon: string; }) => (

{title}

{value}

{note}

); const ExecutiveSummaryPage = () => { const { currentUser } = useAppSelector((state) => state.auth); const [data, setData] = useState(defaultResponse); const [loading, setLoading] = useState(true); const [errorMessage, setErrorMessage] = useState(''); const workspaceConfig = useMemo(() => getWorkspaceConfig(currentUser?.app_role?.name), [currentUser?.app_role?.name]); useEffect(() => { const fetchSummary = async () => { try { setLoading(true); setErrorMessage(''); const response = await axios.get('/executive-summary'); setData(response.data); } catch (error: any) { console.error('Failed to load executive summary', error); setErrorMessage(error?.response?.data?.message || 'Unable to load the executive summary right now.'); } finally { setLoading(false); } }; fetchSummary(); }, []); const metricDefinitions = useMemo>( () => ({ approvedBudget: { title: 'Approved annual budget', value: `${formatCurrency(data.summary.approvedBudget.USD, 'USD')} / ${formatCurrency(data.summary.approvedBudget.CDF, 'CDF')}`, note: 'Approved and active allocation envelope across the institution.', icon: mdiBankOutline, }, committedBudget: { title: 'Committed budget', value: `${formatCurrency(data.summary.committedBudget.USD, 'USD')} / ${formatCurrency(data.summary.committedBudget.CDF, 'CDF')}`, note: 'Open requisition exposure awaiting tendering, award, or conversion.', icon: mdiClipboardListOutline, }, disbursedBudget: { title: 'Disbursed budget', value: `${formatCurrency(data.summary.disbursedBudget.USD, 'USD')} / ${formatCurrency(data.summary.disbursedBudget.CDF, 'CDF')}`, note: 'Processed payments already released to counterparties.', icon: mdiWalletOutline, }, pendingApprovals: { title: 'Pending approvals', value: `${data.summary.pendingApprovals}`, note: 'Approval actions currently sitting in the institutional queue.', icon: mdiClipboardClockOutline, }, contractsNearingExpiry: { title: 'Contracts nearing expiry', value: `${data.summary.contractsNearingExpiry}`, note: 'Active contracts due to expire within the next 60 days.', icon: mdiFileDocumentOutline, }, vendorComplianceAlerts: { title: 'Vendor compliance alerts', value: `${data.summary.vendorComplianceAlerts}`, note: 'Open compliance and missing-document issues requiring follow-up.', icon: mdiCheckDecagramOutline, }, procurementPipeline: { title: 'Procurement pipeline', value: `${data.summary.procurementPipeline}`, note: 'Live requisitions progressing through review, tender, and award.', icon: mdiClipboardListOutline, }, openRiskAlerts: { title: 'Open risk alerts', value: `${data.summary.openRiskAlerts}`, note: 'High-priority compliance or control issues requiring intervention.', icon: mdiShieldAlertOutline, }, averageProjectProgress: { title: 'Average project progress', value: `${data.summary.averageProjectProgress}%`, note: 'Average completion level across active and approved projects.', icon: mdiChartTimelineVariant, }, highRiskProjects: { title: 'High-risk projects', value: `${data.summary.highRiskProjects}`, note: 'Projects flagged high or critical risk in active delivery.', icon: mdiShieldAlertOutline, }, overduePayments: { title: 'Overdue payment requests', value: `${data.summary.overduePayments}`, note: 'Submitted, approved, or batched requests older than 30 days.', icon: mdiWalletOutline, }, activeProjects: { title: 'Active projects', value: `${data.summary.activeProjects}`, note: 'Projects currently being executed across the organization.', icon: mdiChartTimelineVariant, }, unreadNotifications: { title: 'Unread notifications', value: `${data.summary.unreadNotifications}`, note: 'System notices, workflow events, and alerts awaiting attention.', icon: mdiBellOutline, }, }), [data.summary], ); const summaryCards = useMemo(() => { const summaryMetricKeys = data.workspace?.summaryMetricKeys?.length ? (data.workspace.summaryMetricKeys as WorkspaceMetricKey[]) : workspaceConfig.highlightedMetricKeys; return summaryMetricKeys.map((metricKey) => ({ key: metricKey, ...metricDefinitions[metricKey], })); }, [data.workspace?.summaryMetricKeys, metricDefinitions, workspaceConfig.highlightedMetricKeys]); const heroMetricChips = useMemo( () => workspaceConfig.heroMetricKeys.slice(0, 4).map((metricKey) => metricDefinitions[metricKey]), [metricDefinitions, workspaceConfig.heroMetricKeys], ); const focusBlock = Boolean(data.workspace?.focusCards?.length) && (
{data.workspace?.focusCards.map((card) => (

Role focus

{card.title}

{card.value}

{card.note}

))}
); const summaryBlock = (
{summaryCards.map((card) => ( ))}
); const watchlistBlock = Boolean(data.workspace?.watchlistCards?.length) && (
{data.workspace?.watchlistCards.map((card) => (

Watchlist

{card.title}

{card.count}

records in view

{card.note}

))}
); const approvalRiskBlock = (
} /> {loading ? (
Loading approval workload…
) : data.approvalQueue.length ? (
{data.approvalQueue.map((item) => ( ))}
Workflow Step Requested by Assigned to Requested Record
{item.workflowName}
{humanize(item.status)}
{item.stepOrder ? `Step ${item.stepOrder}` : '—'} · {item.stepName} {item.requestedBy} {item.assignedTo} {formatDate(item.requestedAt)}
Open approval {humanize(item.recordType)} record
) : (
No pending approvals are queued right now. Start a new requisition to test the workflow end to end.
)}
{data.summary.openRiskAlerts} open alerts } />

Budget headroom

{formatCurrency(data.summary.budgetVariance.USD, 'USD')} / {formatCurrency(data.summary.budgetVariance.CDF, 'CDF')}

Remaining variance between approved allocations and current commitments.

{data.summary.overduePayments}

Overdue payment requests

{data.summary.highRiskProjects}

High-risk projects

{data.riskPanel.length ? ( data.riskPanel.slice(0, 4).map((risk) => (

{risk.title}

{risk.details || humanize(risk.alertType)}

Assigned to {risk.assignedTo}

{humanize(risk.severity)}
)) ) : (
No open compliance alerts are currently active.
)}
); const operationsBlock = (
} />
1 Requisition created
2 Internal approval
3 Tender / consultation
4 Award and contract
5 Invoice and payment
{data.procurementQueue.length ? ( data.procurementQueue.map((item) => (

{item.requisitionNumber || 'Requisition'}

{item.title}

{humanize(item.procurementMethod)} · {item.provinceName}

{formatCurrency(item.estimatedAmount, item.currency)}

{humanize(item.status)}
Needed by {formatDate(item.neededByDate)} Open record
)) ) : (
No live requisitions were found. Use “New requisition” to begin the procurement chain.
)}
} />
{data.contractWatchlist.length ? ( data.contractWatchlist.map((contract) => (

{contract.contractNumber || 'Contract record'}

{contract.title}

{contract.vendorName}

{humanize(contract.status)}

End date

{formatDate(contract.endDate)}

Days to expiry

{contract.daysToExpiry ?? '—'}

)) ) : (
No active contracts are expiring within the next 60 days.
)}
} />
{data.recentNotifications.length ? ( data.recentNotifications.map((notification) => (

{notification.title}

{notification.message}

{humanize(notification.type)} {formatDate(notification.sentAt)}
)) ) : (
No recent notifications were returned for this user.
)}
); const deliveryBlock = (
} />
{data.provinceRollout.length ? ( data.provinceRollout.map((province) => (

{province.provinceName}

{province.activeProjects} active of {province.totalProjects} total projects

{province.averageCompletion}%

Average completion

)) ) : (
No provincial rollout data is available yet.
)}
} />
{data.topContracts.length ? ( {data.topContracts.map((contract) => ( ))}
Contract Vendor Project Value
{contract.contractNumber || contract.title}

{contract.title}

{contract.vendorName} {contract.projectName} {formatCurrency(contract.contractValue, contract.currency)}
) : (
No contract commitments are available yet.
)}
); const actionsBlock = (

{workspaceConfig.sectionCopy.quickActions.eyebrow}

{workspaceConfig.sectionCopy.quickActions.title}

{workspaceConfig.quickLinks.map((link) => (

{link.label}

{link.description}

))}
); const blockMap: Partial> = { focus: focusBlock, summary: summaryBlock, watchlist: watchlistBlock, approvalRisk: approvalRiskBlock, operations: operationsBlock, delivery: deliveryBlock, actions: actionsBlock, }; return ( <> {getPageTitle(workspaceConfig.pageTitle)}

{workspaceConfig.eyebrow}

{workspaceConfig.heroTitle}

{workspaceConfig.heroDescription}

{heroMetricChips.map((metric) => ( {metric.title}: {metric.value} ))}

User context

{currentUser?.firstName || currentUser?.email || 'Authenticated user'}

{data.workspace?.roleName || currentUser?.app_role?.name || 'Operational access'}

Control indicators

{data.summary.overduePayments}

Overdue payment requests

{data.summary.unreadNotifications}

Unread notifications

{errorMessage && {errorMessage}} {workspaceConfig.blockOrder.map((blockKey) => { const block = blockMap[blockKey]; if (!block) { return null; } return {block}; })}
); }; ExecutiveSummaryPage.getLayout = function getLayout(page: ReactElement) { return {page}; }; export default ExecutiveSummaryPage;