import { ProjectHealthItem, RiskLevel, ScheduleStatus, ResourceStatus } from '../services/projectHealth' interface ProjectHealthCardProps { project: ProjectHealthItem onClick?: (projectId: string) => void } // Color mapping for health scores function getHealthScoreColor(score: number): string { if (score >= 80) return '#4caf50' // Green if (score >= 60) return '#ff9800' // Yellow/Orange if (score >= 40) return '#ff5722' // Orange return '#f44336' // Red } // Risk level colors and labels const riskLevelConfig: Record = { low: { color: '#2e7d32', bgColor: '#e8f5e9', label: 'Low Risk' }, medium: { color: '#f57c00', bgColor: '#fff3e0', label: 'Medium Risk' }, high: { color: '#d84315', bgColor: '#fbe9e7', label: 'High Risk' }, critical: { color: '#c62828', bgColor: '#ffebee', label: 'Critical' }, } // Schedule status labels const scheduleStatusLabels: Record = { on_track: 'On Track', at_risk: 'At Risk', delayed: 'Delayed', } // Resource status labels const resourceStatusLabels: Record = { adequate: 'Adequate', constrained: 'Constrained', overloaded: 'Overloaded', } export function ProjectHealthCard({ project, onClick }: ProjectHealthCardProps) { const healthColor = getHealthScoreColor(project.health_score) const riskConfig = riskLevelConfig[project.risk_level] const progressPercent = project.task_count > 0 ? Math.round((project.completed_task_count / project.task_count) * 100) : 0 const handleClick = () => { if (onClick) { onClick(project.project_id) } } return (
{ if (e.key === 'Enter' || e.key === ' ') { handleClick() } }} aria-label={`Project ${project.project_title}, health score ${project.health_score}`} > {/* Header */}

{project.project_title}

{project.space_name && ( {project.space_name} )}
{riskConfig.label}
{/* Health Score */}
{/* Background circle */} {/* Progress circle */}
{project.health_score} Health
Schedule {scheduleStatusLabels[project.schedule_status]}
Resources {resourceStatusLabels[project.resource_status]}
{project.owner_name && (
Owner {project.owner_name}
)}
{/* Task Progress */}
Task Progress {project.completed_task_count} / {project.task_count}
{/* Metrics */}
{project.blocker_count} Blockers
0 ? '#f44336' : 'inherit' }}> {project.overdue_task_count} Overdue
{progressPercent}% Complete
) } const styles: { [key: string]: React.CSSProperties } = { card: { backgroundColor: 'white', borderRadius: '8px', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)', padding: '20px', cursor: 'pointer', transition: 'box-shadow 0.2s ease, transform 0.2s ease', }, header: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '16px', }, titleSection: { flex: 1, minWidth: 0, }, title: { margin: 0, fontSize: '16px', fontWeight: 600, color: '#333', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', }, spaceName: { fontSize: '12px', color: '#666', marginTop: '4px', display: 'block', }, riskBadge: { padding: '4px 10px', borderRadius: '4px', fontSize: '12px', fontWeight: 500, marginLeft: '12px', flexShrink: 0, }, scoreSection: { display: 'flex', alignItems: 'center', gap: '20px', marginBottom: '16px', }, scoreCircle: { position: 'relative', width: '80px', height: '80px', flexShrink: 0, }, scoreText: { position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', textAlign: 'center', }, scoreValue: { fontSize: '24px', fontWeight: 700, display: 'block', lineHeight: 1, }, scoreLabel: { fontSize: '10px', color: '#666', textTransform: 'uppercase', letterSpacing: '0.5px', }, statusSection: { flex: 1, display: 'flex', flexDirection: 'column', gap: '8px', }, statusItem: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', }, statusLabel: { fontSize: '12px', color: '#666', }, statusValue: { fontSize: '12px', fontWeight: 500, color: '#333', }, progressSection: { marginBottom: '16px', }, progressHeader: { display: 'flex', justifyContent: 'space-between', marginBottom: '8px', }, progressLabel: { fontSize: '12px', color: '#666', }, progressValue: { fontSize: '12px', fontWeight: 500, color: '#333', }, progressBarContainer: { height: '6px', backgroundColor: '#e0e0e0', borderRadius: '3px', overflow: 'hidden', }, progressBar: { height: '100%', borderRadius: '3px', transition: 'width 0.3s ease', }, metricsSection: { display: 'flex', justifyContent: 'space-around', paddingTop: '16px', borderTop: '1px solid #eee', }, metricItem: { textAlign: 'center', }, metricValue: { fontSize: '18px', fontWeight: 600, color: '#333', display: 'block', }, metricLabel: { fontSize: '11px', color: '#666', textTransform: 'uppercase', letterSpacing: '0.5px', }, } export default ProjectHealthCard