refactor: implement i18n in core components (phase 1)
Refactored key components to use react-i18next translations: - ErrorBoundary: error messages and labels - ProgressStepper: step labels - DimensionCard: health status labels, descriptions, benchmark text, action buttons - DashboardTabs: back button, footer, default title Added translation keys to es.json and en.json: - dashboard.defaultTitle - All health status and benchmark keys already existed Build verified successfully. Remaining 31 components to be refactored in subsequent commits. https://claude.ai/code/session_4f888c33-8937-4db8-8a9d-ddc9ac51a725
This commit is contained in:
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { DimensionAnalysis } from '../types';
|
||||
import { motion } from 'framer-motion';
|
||||
import { AlertCircle, AlertTriangle, TrendingUp, CheckCircle, Zap } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import BadgePill from './BadgePill';
|
||||
|
||||
interface HealthStatus {
|
||||
@@ -14,59 +15,59 @@ interface HealthStatus {
|
||||
description: string;
|
||||
}
|
||||
|
||||
const getHealthStatus = (score: number): HealthStatus => {
|
||||
const getHealthStatus = (score: number, t: (key: string) => string): HealthStatus => {
|
||||
if (score >= 86) {
|
||||
return {
|
||||
level: 'excellent',
|
||||
label: 'EXCELENTE',
|
||||
label: t('healthStatus.excellent'),
|
||||
color: 'text-cyan-700',
|
||||
textColor: 'text-cyan-700',
|
||||
bgColor: 'bg-cyan-50',
|
||||
icon: <CheckCircle size={20} className="text-cyan-600" />,
|
||||
description: 'Top quartile, modelo a seguir'
|
||||
description: t('healthStatus.excellentDesc')
|
||||
};
|
||||
}
|
||||
if (score >= 71) {
|
||||
return {
|
||||
level: 'good',
|
||||
label: 'BUENO',
|
||||
label: t('healthStatus.good'),
|
||||
color: 'text-emerald-700',
|
||||
textColor: 'text-emerald-700',
|
||||
bgColor: 'bg-emerald-50',
|
||||
icon: <TrendingUp size={20} className="text-emerald-600" />,
|
||||
description: 'Por encima de benchmarks, desempeño sólido'
|
||||
description: t('healthStatus.goodDesc')
|
||||
};
|
||||
}
|
||||
if (score >= 51) {
|
||||
return {
|
||||
level: 'medium',
|
||||
label: 'MEDIO',
|
||||
label: t('healthStatus.medium'),
|
||||
color: 'text-amber-700',
|
||||
textColor: 'text-amber-700',
|
||||
bgColor: 'bg-amber-50',
|
||||
icon: <AlertTriangle size={20} className="text-amber-600" />,
|
||||
description: 'Oportunidad de mejora identificada'
|
||||
description: t('healthStatus.mediumDesc')
|
||||
};
|
||||
}
|
||||
if (score >= 31) {
|
||||
return {
|
||||
level: 'low',
|
||||
label: 'BAJO',
|
||||
label: t('healthStatus.low'),
|
||||
color: 'text-orange-700',
|
||||
textColor: 'text-orange-700',
|
||||
bgColor: 'bg-orange-50',
|
||||
icon: <AlertTriangle size={20} className="text-orange-600" />,
|
||||
description: 'Requiere mejora, por debajo de benchmarks'
|
||||
description: t('healthStatus.lowDesc')
|
||||
};
|
||||
}
|
||||
return {
|
||||
level: 'critical',
|
||||
label: 'CRÍTICO',
|
||||
label: t('healthStatus.critical'),
|
||||
color: 'text-red-700',
|
||||
textColor: 'text-red-700',
|
||||
bgColor: 'bg-red-50',
|
||||
icon: <AlertCircle size={20} className="text-red-600" />,
|
||||
description: 'Requiere acción inmediata'
|
||||
description: t('healthStatus.criticalDesc')
|
||||
};
|
||||
};
|
||||
|
||||
@@ -79,7 +80,8 @@ const getProgressBarColor = (score: number): string => {
|
||||
};
|
||||
|
||||
const ScoreIndicator: React.FC<{ score: number; benchmark?: number }> = ({ score, benchmark }) => {
|
||||
const healthStatus = getHealthStatus(score);
|
||||
const { t } = useTranslation();
|
||||
const healthStatus = getHealthStatus(score, t);
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
@@ -119,21 +121,21 @@ const ScoreIndicator: React.FC<{ score: number; benchmark?: number }> = ({ score
|
||||
{benchmark !== undefined && (
|
||||
<div className="bg-slate-50 rounded-lg p-3 text-sm">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-slate-600">Benchmark Industria (P50)</span>
|
||||
<span className="text-slate-600">{t('benchmark.title')}</span>
|
||||
<span className="font-bold text-slate-900">{benchmark}/100</span>
|
||||
</div>
|
||||
<div className="text-xs text-slate-500">
|
||||
{score > benchmark ? (
|
||||
<span className="text-emerald-600 font-semibold">
|
||||
↑ {score - benchmark} puntos por encima del promedio
|
||||
{t('benchmark.aboveBenchmark', { points: score - benchmark })}
|
||||
</span>
|
||||
) : score === benchmark ? (
|
||||
<span className="text-amber-600 font-semibold">
|
||||
= Alineado con promedio de industria
|
||||
{t('benchmark.atBenchmark')}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-orange-600 font-semibold">
|
||||
↓ {benchmark - score} puntos por debajo del promedio
|
||||
{t('benchmark.belowBenchmark', { points: benchmark - score })}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -154,7 +156,8 @@ const ScoreIndicator: React.FC<{ score: number; benchmark?: number }> = ({ score
|
||||
};
|
||||
|
||||
const DimensionCard: React.FC<{ dimension: DimensionAnalysis }> = ({ dimension }) => {
|
||||
const healthStatus = getHealthStatus(dimension.score);
|
||||
const { t } = useTranslation();
|
||||
const healthStatus = getHealthStatus(dimension.score, t);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
@@ -226,10 +229,10 @@ const DimensionCard: React.FC<{ dimension: DimensionAnalysis }> = ({ dimension }
|
||||
>
|
||||
<Zap size={16} />
|
||||
{dimension.score < 51
|
||||
? 'Ver Acciones Críticas'
|
||||
? t('dimensionCard.viewCriticalActions')
|
||||
: dimension.score < 71
|
||||
? 'Explorar Mejoras'
|
||||
: 'En buen estado'}
|
||||
? t('dimensionCard.exploreImprovements')
|
||||
: t('dimensionCard.inGoodState')}
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user