import { useTranslation } from 'react-i18next' 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 const riskLevelColors: Record = { low: { color: '#2e7d32', bgColor: '#e8f5e9' }, medium: { color: '#f57c00', bgColor: '#fff3e0' }, high: { color: '#d84315', bgColor: '#fbe9e7' }, critical: { color: '#c62828', bgColor: '#ffebee' }, } // Schedule status translation keys const scheduleStatusKeys: Record = { on_track: 'status.onTrack', at_risk: 'status.atRisk', delayed: 'status.delayed', } // Resource status translation keys const resourceStatusKeys: Record = { adequate: 'resourceStatus.adequate', constrained: 'resourceStatus.constrained', overloaded: 'resourceStatus.overloaded', } export function ProjectHealthCard({ project, onClick }: ProjectHealthCardProps) { const { t } = useTranslation('health') const healthColor = getHealthScoreColor(project.health_score) const riskColors = riskLevelColors[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} )}
{t(`riskLevel.${project.risk_level}`)}
{/* Health Score */}
{/* Background circle */} {/* Progress circle */}
{project.health_score} {t('card.health')}
{t('card.schedule')} {t(scheduleStatusKeys[project.schedule_status])}
{t('card.resources')} {t(resourceStatusKeys[project.resource_status])}
{project.owner_name && (
{t('card.owner')} {project.owner_name}
)}
{/* Task Progress */}
{t('card.taskProgress')} {project.completed_task_count} / {project.task_count}
{/* Metrics */}
{project.blocker_count} {t('card.blockers')}
0 ? '#f44336' : 'inherit' }}> {project.overdue_task_count} {t('card.overdue')}
{progressPercent}% {t('card.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