import React, { useState, useEffect, useCallback } from 'react'; import { Upload, Building2, ChevronLeft, Loader, AlertCircle, BarChart3, Settings, Trash2, RotateCcw } from 'lucide-react'; import { useAuth } from '../../contexts/AuthContext'; import { PieChart, Pie, Cell, ComposedChart, Bar, BarChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ReferenceLine, ResponsiveContainer } from 'recharts'; import MultiVerticalUploadModal from './MultiVerticalUploadModal'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; const TEAL = '#14B8A6'; const PURPLE = '#A78BFA'; // --------------------------------------------------------------------------- // Styles // --------------------------------------------------------------------------- const PAGE_STYLE = { padding: '1.5rem 2rem', minHeight: '100vh', fontFamily: "'JetBrains Mono', 'Fira Code', monospace", }; const CARD_STYLE = { background: 'rgba(15, 23, 42, 0.6)', border: '1px solid rgba(167, 139, 250, 0.2)', borderRadius: '0.75rem', padding: '1.25rem', }; const STAT_CARD_STYLE = { ...CARD_STYLE, textAlign: 'center', flex: 1, minWidth: '140px', }; const TABLE_STYLE = { width: '100%', borderCollapse: 'collapse', fontSize: '0.8rem', }; const TH_STYLE = { padding: '0.75rem 1rem', textAlign: 'left', color: '#94A3B8', fontWeight: '600', fontSize: '0.7rem', textTransform: 'uppercase', letterSpacing: '0.05em', borderBottom: '1px solid rgba(255,255,255,0.08)', }; const TD_STYLE = { padding: '0.75rem 1rem', color: '#E2E8F0', borderBottom: '1px solid rgba(255,255,255,0.04)', }; // --------------------------------------------------------------------------- // Stats Bar // --------------------------------------------------------------------------- function StatsBar({ stats, onNonCompliantClick, ncExpanded }) { if (!stats) return null; const items = [ { label: 'Total Devices', value: stats.total_devices.toLocaleString(), color: '#94A3B8' }, { label: 'Compliant', value: stats.compliant.toLocaleString(), color: '#10B981' }, { label: 'Non-Compliant', value: stats.non_compliant.toLocaleString(), color: '#EF4444', clickable: true }, { label: 'Current %', value: `${stats.compliance_pct}%`, color: stats.compliance_pct >= stats.target_pct ? '#10B981' : '#F59E0B' }, { label: 'Target %', value: `${stats.target_pct}%`, color: PURPLE }, ]; return (
{items.map(({ label, value, color, clickable }) => (
{ e.currentTarget.style.borderColor = 'rgba(239, 68, 68, 0.5)'; } : undefined} onMouseLeave={clickable ? e => { if (!ncExpanded) e.currentTarget.style.borderColor = 'rgba(167, 139, 250, 0.2)'; } : undefined} >
{label}{clickable && {ncExpanded ? '▾' : '▸'}}
{value}
))}
); } // --------------------------------------------------------------------------- // Metric Breakdown Panel (shown when Non-Compliant is clicked) // --------------------------------------------------------------------------- function MetricBreakdownPanel({ metrics }) { const [showAll, setShowAll] = useState(false); if (!metrics || metrics.length === 0) return null; // Only show metrics with non_compliant > 0 const ncMetrics = metrics.filter(m => m.non_compliant > 0); if (ncMetrics.length === 0) return null; const TOP_COUNT = 8; const displayMetrics = showAll ? ncMetrics : ncMetrics.slice(0, TOP_COUNT); const hasMore = ncMetrics.length > TOP_COUNT; return (
Non-Compliant by Metric
{hasMore && ( )}
{displayMetrics.map(m => { const pct = m.total > 0 ? (m.compliant / m.total) : 0; const target = Number(m.target || 0); const pctColor = pct >= target ? '#10B981' : pct >= target * 0.85 ? '#F59E0B' : '#EF4444'; return (
{m.metric_id} {(pct * 100).toFixed(0)}%
{m.non_compliant.toLocaleString()}
); })}
); } // --------------------------------------------------------------------------- // Donut Chart // --------------------------------------------------------------------------- function DonutChart({ donut }) { if (!donut) return null; const data = [ { name: 'Blocked', count: donut.blocked.count, color: '#EF4444' }, { name: 'In-Progress', count: donut.in_progress.count, color: '#F59E0B' }, ]; const total = donut.blocked.count + donut.in_progress.count; return (
Non-Compliant Status
{data.map((entry, i) => )}
{total}
Total Non-Compliant
Blocked: {donut.blocked.count} ({donut.blocked.pct}%)
In-Progress: {donut.in_progress.count} ({donut.in_progress.pct}%)
); } // --------------------------------------------------------------------------- // Trend Chart // --------------------------------------------------------------------------- function TrendChart({ months }) { if (!months || months.length === 0) return (
No trend data yet. Upload compliance data to generate trends.
); return (
Compliance Trend
); } // --------------------------------------------------------------------------- // Aggregated Burndown Chart // --------------------------------------------------------------------------- function AggregatedBurndownChart({ data, loading, error }) { if (loading) { return (
Loading...
); } if (error) { return (
Error loading burndown data: {error}
); } if (!data) return null; // Empty state: no non-compliant devices if (data.total_non_compliant === 0) { return (
No non-compliant devices across any vertical.
); } // All blockers: no monthly forecast const monthlyKeys = Object.keys(data.monthly_forecast || {}); const hasMonthlyData = monthlyKeys.length > 0; // Prepare chart data const monthlyData = monthlyKeys .sort() .map(month => ({ month, count: data.monthly_forecast[month] })); return (
Aggregated Burndown Forecast
{/* Summary header */}
Non-Compliant
{data.total_non_compliant.toLocaleString()}
Blockers
{data.blockers.toLocaleString()}
In-Progress
{data.with_dates.toLocaleString()}
{data.projected_clear_date && (
Projected Clear
{data.projected_clear_date}
)}
{/* Chart or blocker message */} {hasMonthlyData ? ( ) : (
All {data.blockers.toLocaleString()} non-compliant devices lack remediation dates.
)} {/* Per-vertical contribution table */} {data.by_vertical && data.by_vertical.length > 0 && (
By Vertical
{data.by_vertical.map(v => ( ))}
Vertical Total Blockers With Dates
{v.vertical} {v.total.toLocaleString()} 0 ? '#EF4444' : '#64748B', padding: '0.5rem 1rem' }}>{v.blockers.toLocaleString()} {v.with_dates.toLocaleString()}
)}
); } // --------------------------------------------------------------------------- // Vertical Breakdown Table // --------------------------------------------------------------------------- function VerticalTable({ breakdown, onSelectVertical }) { if (!breakdown || breakdown.length === 0) return null; return (
Vertical Breakdown
{breakdown.map(v => { const pctColor = v.compliance_pct >= 95 ? '#10B981' : v.compliance_pct >= 80 ? '#F59E0B' : '#EF4444'; return ( onSelectVertical(v.vertical)} style={{ cursor: 'pointer', transition: 'background 0.15s' }} onMouseEnter={e => e.currentTarget.style.background = 'rgba(167, 139, 250, 0.08)'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'} > ); })}
Vertical Total Compliant Non-Compliant Compliance % Blockers Last Upload
{v.vertical} {v.total_devices.toLocaleString()} {v.compliant.toLocaleString()} {v.non_compliant.toLocaleString()} {v.compliance_pct}% 0 ? '#EF4444' : '#64748B' }}>{v.blockers} {v.last_upload || '—'}
); } // --------------------------------------------------------------------------- // Vertical Detail View (metric drill-down) // --------------------------------------------------------------------------- function VerticalDetailView({ vertical, onBack, onSelectMetric }) { const [metrics, setMetrics] = useState(null); const [categories, setCategories] = useState(null); const [teams, setTeams] = useState([]); const [burndown, setBurndown] = useState(null); const [loading, setLoading] = useState(true); const [expandedMetrics, setExpandedMetrics] = useState(new Set()); const [teamFilter, setTeamFilter] = useState(''); // '' = all teams (rollup view) // ⚠️ CONVENTION: Missing error state — .catch() silently swallows errors without displaying them to the user. Add an error state and render an error message (see main CCPMetricsPage pattern). useEffect(() => { setLoading(true); Promise.all([ fetch(`${API_BASE}/compliance/vcl-multi/vertical/${encodeURIComponent(vertical)}/metrics`, { credentials: 'include' }).then(r => r.json()), fetch(`${API_BASE}/compliance/vcl-multi/vertical/${encodeURIComponent(vertical)}/burndown`, { credentials: 'include' }).then(r => r.json()), ]).then(([metricsData, burndownData]) => { setMetrics(metricsData.metrics || []); setCategories(metricsData.categories || []); setTeams(metricsData.teams || []); setBurndown(burndownData); setLoading(false); }).catch(() => setLoading(false)); }, [vertical]); const toggleMetricExpand = (metricId) => { setExpandedMetrics(prev => { const next = new Set(prev); if (next.has(metricId)) next.delete(metricId); else next.add(metricId); return next; }); }; if (loading) return
Loading...
; // Filter metrics by team if a team filter is active const displayMetrics = teamFilter ? metrics.filter(m => m.sub_teams && m.sub_teams.some(st => st.team === teamFilter)) : metrics; return (

{vertical}

{/* Burndown summary */} {burndown && (
Non-Compliant
{burndown.total}
With Dates
{burndown.with_dates}
Blockers
{burndown.blockers}
{burndown.projected_clear_date && (
Projected Clear
{burndown.projected_clear_date}
)}
)} {/* Burndown chart */} {burndown && burndown.monthly && Object.keys(burndown.monthly).length > 0 && (
Burndown Forecast
a.localeCompare(b)).map(([month, count]) => ({ month, count }))}>
)} {/* Category summary */} {categories && categories.length > 0 && (
By Category
{categories.map(c => (
{c.category}
= 95 ? '#10B981' : c.compliance_pct >= 80 ? '#F59E0B' : '#EF4444' }}> {c.compliance_pct}%
{c.non_compliant} non-compliant
))}
)} {/* Team filter */} {teams.length > 0 && (
Filter by Team: {teams.map(t => ( ))}
)} {/* Metrics table with expandable sub-team rows */}
Metrics {teamFilter && — {teamFilter}}
{displayMetrics && displayMetrics.map((m) => { const hasSubTeams = m.sub_teams && m.sub_teams.length > 0; const isExpanded = expandedMetrics.has(m.metric_id); // If team filter is active, show the filtered team's data instead of rollup const displayRow = teamFilter && m.sub_teams ? m.sub_teams.find(st => st.team === teamFilter) || m : m; const displayPct = Number(displayRow.compliance_pct || 0); const targetVal = Number(m.target || 0); const pctColor = displayPct >= targetVal ? '#10B981' : displayPct >= (targetVal * 0.85) ? '#F59E0B' : '#EF4444'; return ( {/* Primary metric row */} e.currentTarget.style.background = 'rgba(167, 139, 250, 0.06)'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'} > {/* Expanded sub-team rows */} {isExpanded && !teamFilter && hasSubTeams && m.sub_teams.map(st => { const stPct = Number(st.compliance_pct || 0); const stPctColor = stPct >= targetVal ? '#10B981' : stPct >= (targetVal * 0.85) ? '#F59E0B' : '#EF4444'; return ( ); })} ); })}
Metric Description Category {teamFilter ? 'Team' : ''} Compliant Non-Compliant Total % Target
{hasSubTeams && !teamFilter && ( )} onSelectMetric(m.metric_id, m)} > {m.metric_id} {m.metric_desc} {m.category} {teamFilter || ''} {(displayRow.compliant || 0).toLocaleString()} {(displayRow.non_compliant || 0).toLocaleString()} {(displayRow.total || 0).toLocaleString()} {(displayPct * 100).toFixed(1)}% {(targetVal * 100).toFixed(0)}%
{st.team} {(st.compliant || 0).toLocaleString()} {(st.non_compliant || 0).toLocaleString()} {(st.total || 0).toLocaleString()} {(stPct * 100).toFixed(1)}%
); } // --------------------------------------------------------------------------- // Metric Sub-Team View (intermediate drill-down: metric → sub-teams) // --------------------------------------------------------------------------- function MetricSubTeamView({ vertical, metricId, metricData, onBack, onSelectTeam }) { // metricData contains the metric's sub_teams from the parent view const pctColor = (pct, target) => { const p = Number(pct || 0); const t = Number(target || 0); return p >= t ? '#10B981' : p >= t * 0.85 ? '#F59E0B' : '#EF4444'; }; const targetVal = Number(metricData?.target || 0); return (

{vertical} / Metric {metricId}

{metricData?.metric_desc && (

{metricData.metric_desc}

)} {/* Metric rollup stats */}
Total
{(metricData?.total || 0).toLocaleString()}
Compliant
{(metricData?.compliant || 0).toLocaleString()}
Non-Compliant
{(metricData?.non_compliant || 0).toLocaleString()}
Compliance
{(Number(metricData?.compliance_pct || 0) * 100).toFixed(1)}%
Target
{(targetVal * 100).toFixed(0)}%
{/* Sub-team breakdown table */}
Sub-Team Breakdown
{metricData?.sub_teams && metricData.sub_teams.length > 0 ? ( {metricData.sub_teams.map(st => { const stPct = Number(st.compliance_pct || 0); const stPctColor = pctColor(st.compliance_pct, metricData.target); return ( onSelectTeam(st.team)} style={{ cursor: 'pointer', transition: 'background 0.15s' }} onMouseEnter={e => e.currentTarget.style.background = 'rgba(20, 184, 166, 0.08)'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'} > ); })}
Team Compliant Non-Compliant Total Compliance %
{st.team} {(st.compliant || 0).toLocaleString()} {(st.non_compliant || 0).toLocaleString()} {(st.total || 0).toLocaleString()} {(stPct * 100).toFixed(1)}%
) : (
No sub-team breakdown available for this metric.
)}
); } // --------------------------------------------------------------------------- // Metric Device List (deepest drill-down — filtered by team) // --------------------------------------------------------------------------- function MetricDeviceList({ vertical, metricId, team, onBack }) { const [devices, setDevices] = useState(null); const [loading, setLoading] = useState(true); // ⚠️ CONVENTION: Missing error state — .catch() below silently swallows errors without displaying them to the user. Add an error state and render an error message. useEffect(() => { setLoading(true); let url = `${API_BASE}/compliance/vcl-multi/vertical/${encodeURIComponent(vertical)}/metric/${encodeURIComponent(metricId)}/devices`; if (team) url += `?team=${encodeURIComponent(team)}`; fetch(url, { credentials: 'include' }) .then(r => r.json()) .then(data => { setDevices(data.devices || []); setLoading(false); }) .catch(() => setLoading(false)); }, [vertical, metricId, team]); if (loading) return
Loading...
; return (

{vertical} / Metric {metricId}{team ? ` / ${team}` : ''} — {devices ? devices.length : 0} non-compliant devices

{devices && devices.map((d, i) => ( ))} {devices && devices.length === 0 && ( )}
Hostname IP Address Type Team Seen Count First Seen Last Seen Resolution Date Remediation Plan
{d.hostname} {d.ip_address || '—'} {d.device_type || '—'} {d.team || '—'} {d.seen_count} {d.first_seen || '—'} {d.last_seen || '—'} {d.resolution_date || 'Not set'} {d.remediation_plan || '—'}
No devices found
); } // --------------------------------------------------------------------------- // Data Management Panel // --------------------------------------------------------------------------- function DataManagementPanel({ onClose, onDataChanged }) { const [uploads, setUploads] = useState([]); const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState(null); const [confirmAction, setConfirmAction] = useState(null); // { type, label, action } const [message, setMessage] = useState(null); useEffect(() => { fetchUploads(); }, []); const fetchUploads = () => { setLoading(true); fetch(`${API_BASE}/compliance/vcl-multi/uploads`, { credentials: 'include' }) .then(r => r.json()) .then(data => { setUploads(data.uploads || []); setLoading(false); }) .catch(() => setLoading(false)); }; const handleDeleteVertical = async (vertical) => { setActionLoading(vertical); setMessage(null); try { const res = await fetch(`${API_BASE}/compliance/vcl-multi/vertical/${encodeURIComponent(vertical)}`, { method: 'DELETE', credentials: 'include', }); const data = await res.json(); if (!res.ok) { setMessage({ type: 'error', text: data.error }); } else { setMessage({ type: 'success', text: data.message }); fetchUploads(); onDataChanged(); } } catch (err) { setMessage({ type: 'error', text: err.message }); } setActionLoading(null); setConfirmAction(null); }; const handleRollbackUpload = async (uploadId) => { setActionLoading(uploadId); setMessage(null); try { const res = await fetch(`${API_BASE}/compliance/vcl-multi/upload/${uploadId}`, { method: 'DELETE', credentials: 'include', }); const data = await res.json(); if (!res.ok) { setMessage({ type: 'error', text: data.error }); } else { setMessage({ type: 'success', text: data.message }); fetchUploads(); onDataChanged(); } } catch (err) { setMessage({ type: 'error', text: err.message }); } setActionLoading(null); setConfirmAction(null); }; const handleDeleteAll = async () => { setActionLoading('all'); setMessage(null); try { const res = await fetch(`${API_BASE}/compliance/vcl-multi/all`, { method: 'DELETE', credentials: 'include', }); const data = await res.json(); if (!res.ok) { setMessage({ type: 'error', text: data.error }); } else { setMessage({ type: 'success', text: data.message }); fetchUploads(); onDataChanged(); } } catch (err) { setMessage({ type: 'error', text: err.message }); } setActionLoading(null); setConfirmAction(null); }; // Group uploads by vertical const verticalGroups = {}; for (const u of uploads) { if (!verticalGroups[u.vertical]) verticalGroups[u.vertical] = []; verticalGroups[u.vertical].push(u); } return (
e.stopPropagation()}>

Manage Data

{/* ⚠️ CONVENTION: Use lucide-react icon instead of raw Unicode character */}
{/* Message */} {message && (
{message.text}
)} {/* Confirm dialog */} {confirmAction && (
{confirmAction.label}
)} {/* Delete All button */}
{loading &&
Loading uploads...
} {!loading && uploads.length === 0 && (
No uploads yet.
)} {/* Per-vertical sections */} {!loading && Object.entries(verticalGroups).map(([vertical, vUploads]) => (
{vertical}
{vUploads.slice(0, 5).map((u, i) => (
{u.filename} {u.report_date || '—'} +{u.new_count || 0} / -{u.resolved_count || 0} {i === 0 && ( )}
))} {vUploads.length > 5 && (
...and {vUploads.length - 5} more
)}
))}
); } // --------------------------------------------------------------------------- // Main Page Component // --------------------------------------------------------------------------- export default function CCPMetricsPage() { const { isAdmin, isEditor } = useAuth(); const [stats, setStats] = useState(null); const [trend, setTrend] = useState(null); const [burndownData, setBurndownData] = useState(null); const [burndownLoading, setBurndownLoading] = useState(true); const [burndownError, setBurndownError] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showUpload, setShowUpload] = useState(false); const [showManage, setShowManage] = useState(false); const [showMetricBreakdown, setShowMetricBreakdown] = useState(false); // Drill-down state const [selectedVertical, setSelectedVertical] = useState(null); const [selectedMetric, setSelectedMetric] = useState(null); const [selectedMetricData, setSelectedMetricData] = useState(null); const [selectedTeam, setSelectedTeam] = useState(null); const fetchData = useCallback(() => { setLoading(true); setError(null); setBurndownLoading(true); setBurndownError(null); Promise.all([ fetch(`${API_BASE}/compliance/vcl-multi/stats`, { credentials: 'include' }).then(r => { if (!r.ok) throw new Error('Failed to load stats'); return r.json(); }), fetch(`${API_BASE}/compliance/vcl-multi/trend`, { credentials: 'include' }).then(r => { if (!r.ok) throw new Error('Failed to load trend'); return r.json(); }), ]).then(([statsData, trendData]) => { setStats(statsData); setTrend(trendData); setLoading(false); }).catch(err => { setError(err.message); setLoading(false); }); // Fetch burndown independently so a failure doesn't block the rest of the page fetch(`${API_BASE}/compliance/vcl-multi/burndown`, { credentials: 'include' }) .then(r => { if (!r.ok) throw new Error('Failed to load burndown'); return r.json(); }) .then(data => { setBurndownData(data); setBurndownLoading(false); }) .catch(err => { setBurndownError(err.message); setBurndownLoading(false); }); }, []); useEffect(() => { fetchData(); }, [fetchData]); const handleUploadComplete = () => { setShowUpload(false); fetchData(); }; // Render drill-down views if (selectedTeam !== null && selectedMetric && selectedVertical) { return (
setSelectedTeam(null)} />
); } if (selectedMetric && selectedVertical) { return (
{ setSelectedMetric(null); setSelectedMetricData(null); }} onSelectTeam={(team) => setSelectedTeam(team)} />
); } if (selectedVertical) { return (
setSelectedVertical(null)} onSelectMetric={(metricId, metricData) => { setSelectedMetric(metricId); setSelectedMetricData(metricData); }} />
); } // Main overview return (
{/* Header */}

CCP Metrics — Multi-Vertical VCL

Cross-organizational compliance posture across all verticals

{(isAdmin() || isEditor()) && (
{isAdmin() && ( )}
)}
{/* Loading / Error states */} {loading && (
Loading compliance data...
)} {error && (
{error}
)} {!loading && !error && stats && ( <> {/* Stats bar */} setShowMetricBreakdown(!showMetricBreakdown)} ncExpanded={showMetricBreakdown} /> {/* Metric breakdown (revealed when Non-Compliant is clicked) */} {showMetricBreakdown && ( )} {/* Charts row */}
{/* Aggregated burndown forecast */} {/* Vertical breakdown table */} {/* Last upload info */} {stats.last_upload_date && (
Last upload: {stats.last_upload_date}
)} )} {!loading && !error && (!stats || !stats.vertical_breakdown || stats.vertical_breakdown.length === 0) && (
No multi-vertical data yet
Upload per-vertical compliance xlsx files to generate cross-organizational reports.
{(isAdmin() || isEditor()) && ( )}
)} {/* Upload Modal */} {showUpload && ( setShowUpload(false)} onUploadComplete={handleUploadComplete} /> )} {/* Data Management Panel */} {showManage && ( setShowManage(false)} onDataChanged={fetchData} /> )}
); }