import React, { useState, useMemo } from 'react'; import { createPortal } from 'react-dom'; import { useQuery } from '@tanstack/react-query'; import { X, ShieldAlert, ShieldCheck, AlertTriangle, Scale, FileCheck, Info, Calendar, User, Users, CheckCircle2, Clock, Layers, Sparkles, Filter, MapPin, Target, } from 'lucide-react'; import { Project, Milestone, Activity, ComplianceItem, Risk, Rule, Beneficiary, ComplianceStatus, } from '../../services/api/models'; import { getProjectComplianceItems, getProjectBeneficiaries, getProjectRisks, getRules, } from '../../services/api'; import { formatDate } from '../../lib/formatters'; interface GovernanceInfoModalProps { isOpen: boolean; onClose: () => void; project: Project; milestone?: Milestone | null; activity?: Activity | null; initialTab?: 'compliance' | 'beneficiaries' | 'risks' | 'rules'; } export const GovernanceInfoModal: React.FC = ({ isOpen, onClose, project, milestone, activity, initialTab = 'compliance', }) => { const [activeTab, setActiveTab] = useState<'compliance' | 'beneficiaries' | 'risks' | 'rules'>(initialTab); const [selectedBeneficiaryFilter, setSelectedBeneficiaryFilter] = useState('ALL'); const projectId = project?.id || 0; // 1. Fetch compliance items for project const { data: complianceItems = [], isLoading: isLoadingCompliance } = useQuery({ queryKey: ['governance-compliance', String(projectId)], queryFn: () => getProjectComplianceItems(projectId), enabled: isOpen && Boolean(projectId), }); // 2. Fetch beneficiaries for project (Requirement: explore compliance items by beneficiary) const { data: projectBeneficiaries = [], isLoading: isLoadingBeneficiaries } = useQuery({ queryKey: ['governance-beneficiaries', String(projectId)], queryFn: () => getProjectBeneficiaries(projectId), enabled: isOpen && Boolean(projectId), }); // 3. Fetch risks for project const { data: projectRisks = [], isLoading: isLoadingRisks } = useQuery({ queryKey: ['governance-risks', String(projectId)], queryFn: () => getProjectRisks(projectId), enabled: isOpen && Boolean(projectId), }); // 4. Fetch associated governance rules const { data: governanceRules = [], isLoading: isLoadingRules } = useQuery({ queryKey: ['governance-rules'], queryFn: () => getRules({ page: 1, pageSize: 100 }), enabled: isOpen, }); // Map of beneficiary by ID for fast lookup const beneficiaryMap = useMemo(() => { const map = new Map(); for (const b of projectBeneficiaries) { if (b && b.id !== undefined && b.id !== null) { map.set(String(b.id), b); } } return map; }, [projectBeneficiaries]); // Filter compliance items by selected beneficiary const filteredComplianceItems = useMemo(() => { if (selectedBeneficiaryFilter === 'ALL') { return complianceItems; } if (selectedBeneficiaryFilter === 'PROJECT_WIDE') { return complianceItems.filter( item => !item.beneficiaryId || Number(item.beneficiaryId) === 0 ); } return complianceItems.filter( item => String(item.beneficiaryId) === selectedBeneficiaryFilter ); }, [complianceItems, selectedBeneficiaryFilter]); if (!isOpen || typeof document === 'undefined') return null; const renderComplianceStatus = (status?: number) => { const s = Number(status); if (s === ComplianceStatus.Met || s === ComplianceStatus.Exceeded) { return ( {s === ComplianceStatus.Exceeded ? 'Exceeded' : 'Compliant'} ); } return ( Action Required (Not Met) ); }; return createPortal(
{/* Modal Header */}
Governance & Compliance Guidance {activity ? ( Activity: {activity.title} ) : milestone ? ( Milestone: {milestone.name} ) : ( Project: {project?.name || (project as any)?.title || `#${project?.id || 'PFM'}`} )}

Project Compliance Items, Beneficiaries & Associated Rules

Contractual obligations, beneficiary-linked compliance criteria, risk registers, and institutional rules.

{/* Tab Navigation */}
{/* Tab Content Panels */}
{/* TAB 1: COMPLIANCE ITEMS (With Beneficiary Explorer) */} {activeTab === 'compliance' && (
{/* Beneficiary Filter Bar */}
Explore by Beneficiary:
{isLoadingCompliance ? (
Loading compliance requirements...
) : filteredComplianceItems.length === 0 ? (

No compliance items found matching this beneficiary filter.

Switch to "All Compliance Items" to inspect project-wide statutory deliverables.

) : ( filteredComplianceItems.map((item, idx) => { const linkedBeneficiary = item.beneficiaryId ? beneficiaryMap.get(String(item.beneficiaryId)) : null; return (
{item.title || `Compliance Item #${idx + 1}`} {renderComplianceStatus(item.status)} {linkedBeneficiary ? ( Beneficiary: {linkedBeneficiary.name} ) : ( Project-Wide General )}
Created: {formatDate(item.createdAt)}
{item.requirements && (

{item.requirements}

)}
); }) )}
)} {/* TAB 2: BENEFICIARIES LISTING & EXPLORATION */} {activeTab === 'beneficiaries' && (
{isLoadingBeneficiaries ? (
Loading project beneficiaries...
) : projectBeneficiaries.length === 0 ? (

No individual beneficiary cohorts registered for this project.

Beneficiaries are captured during project execution and onboarding.

) : ( projectBeneficiaries.map(ben => { const linkedItems = complianceItems.filter( ci => String(ci.beneficiaryId) === String(ben.id) ); return (

{ben.name || 'Unnamed Beneficiary'}

Category: {ben.category || 'Direct Participant'} {ben.location && ` • Location: ${ben.location}`}

Target / Reached {ben.reachedCount ?? 0} / {ben.targetCount ?? 0}
); }) )}
)} {/* TAB 3: RISK REGISTER */} {activeTab === 'risks' && (
{isLoadingRisks ? (
Loading risk register...
) : projectRisks.length === 0 ? (

No high-severity risks recorded for this project.

Maintain milestone delivery cadence to preserve low-risk standing.

) : ( projectRisks.map((risk, idx) => (

{risk.title || `Risk Item #${idx + 1}`}

Likelihood: {risk.likelihood ?? 'Medium'} Impact: {risk.impact ?? 'Moderate'}
{risk.description && (

{risk.description}

)} {risk.mitigation && (
Mitigation Strategy: {risk.mitigation}
)}
)) )}
)} {/* TAB 4: ASSOCIATED GOVERNANCE RULES */} {activeTab === 'rules' && (
{isLoadingRules ? (
Loading institutional rules...
) : governanceRules.length === 0 ? (

Standard PFM Funding Portfolio Governance Rules apply.

All disbursements gate against verified milestone deliverables and evidence.

) : ( governanceRules.map((rule, idx) => (

{rule.name || `Rule #${idx + 1}`}

v{rule.version || 1}
{rule.description && (

{rule.description}

)}
)) )}
)}
{/* Modal Footer */}
PFM Governance Architecture • Beneficiary & Compliance Tracking
, document.body ); };